afpfs-ng-mac/cmdline/cmdline_afp.c

1241 lines
24 KiB
C

/*
portions Copyright (C) 2007 Alex deVries
*/
#include "afpfs-ng/afp.h"
#include "afpfs-ng/midlevel.h"
#include "afpfs-ng/map_def.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <ctype.h>
#include "cmdline_main.h"
static char curdir[AFP_MAX_PATH];
static struct afp_url url;
int full_url=0;
#define DEFAULT_DIRECTORY "/"
static struct afp_server * server = NULL;
struct afp_volume * vol= NULL;
static int recursive_get(char * path);
static int escape_paths(char * outgoing1, char * outgoing2, char * incoming)
{
char * writeto=outgoing1;
int inquote=0, inescape=0, donewith1=0;
char *p = incoming;
if ((outgoing1==NULL) || (strlen(incoming)==0)) {
goto error;
}
memset(outgoing1,0,AFP_MAX_PATH);
if (outgoing2) memset(outgoing2,0,AFP_MAX_PATH);
for (p=incoming;p<incoming+strlen(incoming);p++) {
if (*p=='\\') {
if (inescape) {
inescape=0;
goto add;
} else {
inescape=1;
continue;
}
}
if (*p=='"') {
inquote=1;
continue;
}
if (inquote) {
if (*p=='"') {
inquote=0;
goto add;
}
} else {
if (*p==' ') {
if (inescape)
goto add;
if ((donewith1==1)||(outgoing2==NULL))
goto out;
writeto=outgoing2;
donewith1=1;
}
}
add:
*writeto=*p;
writeto++;
}
out:
if ((outgoing2!=NULL) && (donewith1==0))
goto error;
return 0;
error:
return -1;
}
static unsigned int tvdiff(struct timeval * starttv, struct timeval * endtv)
{
unsigned int d;
d=(endtv->tv_sec - starttv->tv_sec) * 1000;
d+= (endtv->tv_usec - starttv->tv_usec) / 1000;
return d;
}
static void printdiff(struct timeval * starttv, struct timeval *endtv,
unsigned long long * amount_written)
{
unsigned int diff;
unsigned long long kb_written;
diff=tvdiff(starttv,endtv);
float frac = ((float) diff) / 1000.0; /* Now in seconds */
printf("Transferred %lld bytes in ",*amount_written);
printf("%.3f seconds. ",frac);
/* Now calculate the transfer rate */
kb_written = (*amount_written/1000);
float rate = (kb_written)/frac;
printf("(%.0f kB/s)\n", rate);
}
static int cmdline_getpass(void)
{
char * passwd;
if (strcmp(url.password,"-")==0) {
passwd=getpass("Password:");
strncpy(url.password,passwd,AFP_MAX_PASSWORD_LEN);
}
return 0;
}
static int get_server_path(char * filename,char * server_fullname)
{
if (filename[0]!='/') {
if (strlen(curdir)==1)
snprintf(server_fullname,PATH_MAX,"/%s",filename);
else
snprintf(server_fullname,PATH_MAX,"%s/%s",curdir,filename);
} else {
snprintf(server_fullname,PATH_MAX,"%s",filename);
}
return 0;
}
static void print_file_details(struct afp_file_info * p)
{
struct tm * mtime;
time_t t,t2;
#define DATE_LEN 32
char datestr[DATE_LEN];
char mode_str[11];
uint32_t mode;
struct stat stat;
afp_unixpriv_to_stat(p,&stat);
mode=stat.st_mode;
sprintf(mode_str,"----------");
t2=time(NULL);
t=p->modification_date;
mtime=localtime(&t);
if (p->isdir) mode_str[0]='d';
if (mode & S_IRUSR) mode_str[1]='r';
if (mode & S_IWUSR) mode_str[2]='w';
if (mode & S_IXUSR) mode_str[3]='x';
if (mode & S_IRGRP) mode_str[4]='r';
if (mode & S_IWGRP) mode_str[5]='w';
if (mode & S_IXGRP) mode_str[6]='x';
if (mode & S_IROTH) mode_str[7]='r';
if (mode & S_IWOTH) mode_str[8]='w';
if (mode & S_IXOTH) mode_str[9]='x';
strftime(datestr,DATE_LEN,"%F %H:%M", mtime);
printf("%s %6lld %s %s\n",mode_str,p->size,datestr,p->name);
}
static int connect_volume(const char * volumename)
{
if (strlen(volumename)==0) goto error;
/* Ah, we're not connected to a volume*/
unsigned int len=0;
char mesg[1024];
if ((vol = find_volume_by_name(server,volumename))==NULL)
{
printf("Could not find a volume called %s\n",volumename);
goto error;
}
vol->mapping= AFP_MAPPING_LOGINIDS;
vol->extra_flags |= VOLUME_EXTRA_FLAGS_NO_LOCKING;
if (afp_connect_volume(vol,server,mesg,&len,1024 ))
{
printf("Could not access volume %s\n",
vol->volume_name);
goto error;
}
printf("Connected to volume %s\n",vol->volume_name_printable);
return 0;
error:
return -1;
}
static int server_subconnect(void)
{
struct afp_connection_request * conn_req;
#define BUFFER_SIZE 2048
conn_req = malloc(sizeof(struct afp_connection_request));
memset(conn_req, 0,sizeof(struct afp_connection_request));
conn_req->url=url;
conn_req->url.requested_version=31;
if (strlen(url.uamname)>0) {
if ((conn_req->uam_mask = find_uam_by_name(url.uamname))==0) {
printf("I don't know about UAM %s\n",url.uamname);
return -1;
}
} else {
conn_req->uam_mask=default_uams_mask();
}
if ((server=afp_server_full_connect(NULL, conn_req))==NULL) {
goto error;
}
printf("Connected to server %s using UAM \"%s\"\n",
server->server_name_printable, uam_bitmap_to_string(server->using_uam));
free(conn_req);
return 0;
error:
free(conn_req);
printf("Could not connect\n");
return -1;
}
int com_pass(char * arg)
{
if ((strlen(arg)==0) || (strcmp(arg,"-"))) {
getpass("Password: ");
return -1;
}
printf("Password set.\n");
strncpy(url.password,arg,AFP_MAX_PASSWORD_LEN);
return 0;
}
int com_user(char * arg)
{
if (strlen(arg)==0) {
printf("You must specify a user\n");
return -1;
}
strncpy(url.username,arg,AFP_MAX_PASSWORD_LEN);
printf("username is now %s\n",url.username);
return 0;
}
int com_disconnect(char * arg)
{
if (server==NULL) {
printf("You're not connected yet to a server\n");
goto error;
}
afp_unmount_volume(vol);
vol=NULL;
server=NULL;
snprintf(curdir,AFP_MAX_PATH,"/");
return 0;
error:
return -1;
}
int com_connect(char * arg)
{
struct afp_url tmpurl;
if (!arg)
arg = "";
if (server) {
printf("You're already connected to a server\n");
goto error;
}
afp_default_url(&tmpurl);
/* First, try to parse the URL */
if (afp_parse_url(&tmpurl,arg,0)!=0) {
/* Okay, this isn't a real URL */
printf("Could not parse url, let me see if this is a server name...\n");
if (gethostbyname(arg))
memcpy(&url.servername,arg,AFP_SERVER_NAME_LEN);
else {
printf("Cannot understand server name or url %s\n",arg);
return -1;
}
} else {
url=tmpurl;
}
cmdline_getpass();
if (server_subconnect()) {
printf("Could not connect\n");
goto error;
};
connect_volume(url.volumename);
return 0;
error:
return -1;
}
int com_dir(char * arg)
{
if (!arg)
arg = "";
struct afp_file_info *filebase = NULL, *p;
if (server==NULL) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (strlen(url.volumename)==0) {
char names[1024];
afp_list_volnames(server,names,1024);
printf("You're not connected to a volume, choose from %s\n",
names);
goto out;
}
if (ml_readdir(vol,curdir,&filebase)) goto error;
if (filebase==NULL) goto out;
for (p=filebase;p;p=p->next) {
print_file_details(p);
}
afp_ml_filebase_free(&filebase);
out:
return 0;
error:
return -1;
}
int com_touch(char * arg)
{
char server_fullname[AFP_MAX_PATH];
int ret;
char filename[AFP_MAX_PATH];
char * basename = filename;
if (escape_paths(filename,NULL,arg)) {
printf("Syntax: touch <newfile>\n");
goto error;
}
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
get_server_path(basename,server_fullname);
ret=ml_creat(vol,server_fullname,0600);
return 0;
error:
return -1;
return 0;
}
int com_chmod(char * arg)
{
unsigned int mode;
char basename[PATH_MAX];
char server_fullname[AFP_MAX_PATH];
char modestring[100];
int ret;
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (escape_paths(modestring,basename,arg)) {
printf("expecting format: chmod <privs> <filename>\n");
goto error;
}
if (sscanf(modestring,"%o",&mode)!=1) {
printf("Mode of %s isn't octal\n", modestring);
goto error;
}
get_server_path(basename,server_fullname);
printf("Changing mode of %s to %o\n",server_fullname,mode);
ret=ml_chmod(vol,server_fullname,mode);
return 0;
error:
return -1;
}
int com_put(char *arg)
{
int ret, amount_read;
struct afp_file_info *fp;
int offset=0;
#define PUT_BUFSIZE 102400
char buf[PUT_BUFSIZE];
int fd;
char server_fullname[AFP_MAX_PATH];
char * basename;
uid_t uid;
gid_t gid;
struct stat localstat;
unsigned long long amount_written=0;
struct timeval starttv,endtv;
char filename[AFP_MAX_PATH];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if ((escape_paths(filename,NULL,arg))) {
printf("expecting format: put <filename>\n");
goto error;
}
/* FIXME find basename */
basename=filename;
get_server_path(basename,server_fullname);
/* FIXME need a better way to get server's uid/gid */
uid=getuid();
gid=getgid();
if (stat(filename, &localstat)!=0) {
perror("Opening local file");
}
fd = open(filename,O_RDONLY);
if (fd<0) {
perror("Opening local file");
goto error;
}
gettimeofday(&starttv,NULL);
ret = ml_open(vol,server_fullname,O_CREAT | O_RDWR,&fp);
if (ret<0) {
printf("Problem opening file %s on server\n",basename);
goto out;
}
/* Now set various permissions */
ret=ml_chmod(vol,server_fullname,localstat.st_mode);
if (ret==-ENOSYS) printf("cannot change permissions\n");
if (ret) {
printf("Could not change permissions to 0%o\n",
localstat.st_mode);
}
while (1) {
amount_read=read(fd,buf,PUT_BUFSIZE);
if (amount_read<0) {
perror("Reading");
goto out;
}
if (amount_read==0) goto out;
ret=ml_write(vol,server_fullname,buf,amount_read,
offset,fp,uid,gid);
offset+=amount_read;
amount_written+=amount_read;
if (ret<0) {
printf("IO error when writing to server, error %d\n",
ret);
goto out;
}
}
/* FIXME time */
out:
gettimeofday(&endtv,NULL);
printdiff(&starttv, &endtv,&amount_written);
close(fd);
ml_close(vol,server_fullname,fp);
return 0;
error:
return -1;
}
static int retrieve_file(char * arg,int fd, int silent,
struct stat *stat, unsigned long long * amount_written)
{
int flags=O_RDONLY;
int ret=0;
struct afp_file_info * fp;
char path[PATH_MAX];
off_t offset = 0;
#define BUF_SIZE 102400
size_t size = BUF_SIZE;
char buf[BUF_SIZE];
int eof;
unsigned long long total=0;
struct timeval starttv,endtv;
*amount_written=0;
if (server==NULL) {
printf("You're not connected yet to a volume\n");
goto error;
}
get_server_path(arg,path);
gettimeofday(&starttv,NULL);
if ((ret=ml_getattr(vol,path,stat))!=0) {
printf("Could not get file attributes for file %s, return code %d\n",path,ret);
goto error;
}
ret = ml_open(vol,path,flags,&fp);
if (ret) {
printf("Could not open %s on server, AFP error %d\n",arg,ret);
goto error;
}
ret =1; /* to get the loop going */
while (ret)
{
memset(buf,0,BUF_SIZE);
ret = ml_read(vol,path,buf,size,offset,fp,&eof);
if (ret<=0) goto out;
total+=write(fd,buf,ret);
offset+=ret;
if ((eof==1) || (ret==0)) goto out;
}
out:
if (fd>1) close(fd);
ml_close(vol,path,fp);
free(fp);
if (silent==0) {
gettimeofday(&endtv,NULL);
printdiff(&starttv, &endtv,&total);
}
*amount_written=total;
return 0;
error:
return -1;
}
static int com_get_file(char * arg, int silent,
unsigned long long * total)
{
int fd;
struct stat stat;
char * localfilename;
char filename[AFP_MAX_PATH];
char getattr_path[AFP_MAX_PATH];
int ret;
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if ((escape_paths(filename,NULL,arg))) {
printf("expecting format: get <filename>\n");
goto error;
}
localfilename=basename(filename);
printf(" Getting file %s\n",filename);
if ((access(localfilename,W_OK)) && (errno!=ENOENT)) {
printf("Trying to access %s\n",localfilename);
perror("Access local file for write");
goto error;
}
get_server_path(filename,getattr_path);
if ((ret=ml_getattr(vol,getattr_path,&stat))!=0) {
printf("Could not get file attributes for file %s, return code %d\n",filename,ret);
goto error;
}
fd=open(localfilename,O_CREAT | O_TRUNC| O_RDWR, stat.st_mode);
if (fd<0) {
perror("Opening local file");
goto error;
}
chmod(localfilename,stat.st_mode);
chown(localfilename,stat.st_uid,stat.st_gid);
retrieve_file(filename,fd,silent,&stat, total);
close(fd);
return 0;
error:
return -1;
}
int com_get (char *arg)
{
unsigned long long amount_written;
char newpath[255];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if ((arg[0]=='-') && (arg[1]=='r') && (arg[2]==' ')) {
arg+=3;
while ((arg) && (isspace(arg[0]))) arg++;
snprintf(newpath,255,"%s/%s",curdir,arg);
return recursive_get(newpath);
} else
return com_get_file(arg,0, &amount_written);
error:
return -1;
}
int com_view (char * arg)
{
unsigned long long amount_written;
char filename[AFP_MAX_PATH];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if ((escape_paths(filename,NULL,arg))) {
printf("expecting format: view <filename>\n");
goto error;
}
printf("Viewing: %s\n",filename);
retrieve_file(filename,fileno(stdout),1,NULL, &amount_written);
return 0;
error:
return -1;
}
int com_rename (char * arg)
{
char from_path[AFP_MAX_PATH], to_path[AFP_MAX_PATH];
char full_from_path[AFP_MAX_PATH], full_to_path[AFP_MAX_PATH];
struct stat stbuf;
int ret;
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (escape_paths(from_path,to_path,arg)) {
printf("Syntax: mv <fromfile> <tofile>\n");
goto error;
}
get_server_path(from_path,full_from_path);
get_server_path(to_path,full_to_path);
printf("Moving from %s to %s\n",full_from_path,full_to_path);
/* Make sure from_file exists */
if ((ret=ml_getattr(vol,full_from_path,&stbuf))) {
printf("Could not find file %s, error was %d\n",
full_from_path,ret);
goto error;
}
/* Make sure to_file doesn't exist */
ret=ml_getattr(vol,full_to_path,&stbuf);
if ((ret==0) && ((stbuf.st_mode & S_IFDIR)==0)) {
printf("File %s already exists, error: %d\n",
full_to_path,ret);
goto error;
}
if ((ret=ml_rename(vol,full_from_path, full_to_path))) goto error;
return 0;
error:
return -1;
}
int com_delete (char *arg)
{
int ret;
char server_fullname[AFP_MAX_PATH];
char filename[AFP_MAX_PATH];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (escape_paths(filename,NULL,arg)) {
printf("Syntax: del <filename>\n");
goto error;
}
get_server_path(filename,server_fullname);
if ((ret=ml_unlink(vol,server_fullname))) {
printf("Could not remove %s, error code is %d\n",
filename,ret);
goto error;
}
printf("Removed file %s\n",filename);
return (1);
error:
return -1;
}
int com_mkdir(char *arg)
{
int ret;
char server_fullname[AFP_MAX_PATH];
char filename[AFP_MAX_PATH];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (escape_paths(filename,NULL,arg)) {
printf("Syntax: mkdir <dirname>\n");
goto error;
}
get_server_path(filename,server_fullname);
if ((ret=ml_mkdir(vol,server_fullname,0755))) {
printf("Could not create directory %s, error code is %d\n",
filename,ret);
goto error;
}
printf("Created directory %s\n",filename);
return 0;
error:
return -1;
}
int com_rmdir(char *arg)
{
int ret;
char server_fullname[AFP_MAX_PATH];
char filename[AFP_MAX_PATH];
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected yet to a volume\n");
goto error;
}
if (escape_paths(filename,NULL,arg)) {
printf("Syntax: rmdir <dirname>\n");
goto error;
}
get_server_path(filename,server_fullname);
if ((ret=ml_rmdir(vol,server_fullname))) {
printf("Could not remove directory %s, error code is %d\n",
filename,ret);
goto error;
}
printf("Removed directory %s\n",filename);
return 0;
error:
return -1;
}
int com_status(char * arg)
{
int len=40960;
char text[40960];
afp_status_header(text,&len);
printf("%s", text);
len=40960;
afp_status_server(server,text,&len);
printf("%s", text);
return 0;
}
int com_passwd(char * arg)
{
char * p;
int ret;
char newpass[AFP_MAX_PASSWORD_LEN];
if (!server) {
printf("Not connected to a server\n");
goto error;
}
p = getpass("New password: ");
strncpy(newpass,p,AFP_MAX_PASSWORD_LEN);
ret=ml_passwd(server,url.username,url.password,newpass);
if (ret) {
printf("Could not change password\n");
goto error;
}
return 0;
error:
return -1;
}
static void print_size(unsigned long l)
{
if (l>(1073741824)) {
printf("%4ldTb",l/1073741824);
return;
}
if (l>(1048576)) {
printf("%4ldGb",l/1048576);
return;
}
if (l>(1024)) {
printf("%4ldMb",l>>10);
return;
}
printf("%4ldKb\n",l);
}
int com_statvfs(char * arg)
{
struct statvfs stat;
unsigned long avail, used,total;
unsigned int portion;
int i;
if ((server==NULL) || (vol==NULL)) {
printf("Not connected to a volume\n");
goto error;
}
ml_statfs(vol,"/",&stat);
avail=stat.f_bavail*4;
used=(stat.f_blocks-stat.f_bavail)*4;
total=avail+used;
portion = (unsigned int) (((float) used*100)/((float) avail+(float) used));
printf("Volume ");
for (i=strlen(vol->volume_name_printable)-6;i>0;i--) printf(" ");
if (strstr(arg,"-h")) {
printf(" Size Used Avail Capacity\n");
printf("%s ", vol->volume_name_printable);
print_size(total); printf(" ");
print_size(used); printf(" ");
print_size(avail); printf(" ");
printf(" %d%%\n",portion);
} else {
avail*=2;
used*=2;
total*=2;
printf(" 512-blocks Used Available Use%%\n");
printf("%s %10ld %10ld %10ld %d%%\n", vol->volume_name_printable,
total, used, avail,portion);
}
return 0;
error:
return -1;
}
int com_lcd(char * path)
{
int ret;
char curpath[PATH_MAX];
ret=chdir(path);
if (ret!=0)
perror("Changing directories");
else {
getcwd(curpath,PATH_MAX);
printf("Now in local directory %s\n",curpath);
}
return ret;
}
/* Change to the directory ARG. */
int com_cd (char *arg)
{
int ret;
char newdir[AFP_MAX_PATH];
char * p;
struct stat stbuf;
char tmppath[AFP_MAX_PATH];
char * path = tmppath;
memset(newdir,'\0',AFP_MAX_PATH);
memset(path,'\0',AFP_MAX_PATH);
if (server==NULL) {
printf("You're not connected to a server yet\n");
goto error;
}
if (strlen(url.volumename)==0) {
char * volumename, *t;
if (escape_paths(path,NULL,arg)) {
printf("Syntax: cd <volumename>\n");
goto error;
}
volumename=path;
if ((t=strchr(path,'/'))) {
path=t+1;
*t='\0';
} else
path=NULL;
if (connect_volume(volumename)==0) {
memcpy(url.volumename,vol->volume_name,
AFP_VOLUME_NAME_UTF8_LEN);
if (path==NULL) {
return 0;
}
}
else return -1;
} else {
if (escape_paths(path,NULL,arg))
memset(path,'\0',AFP_MAX_PATH);
}
/* Chop off the last / */
if (((strlen(path)>1) && (path[strlen(path)-1]=='/')))
path[strlen(path)-1]='\0';
if (((strlen(curdir)>1) && (curdir[strlen(curdir)-1]=='/')))
curdir[strlen(curdir)-1]='\0';
if (strncmp(path,"..", AFP_MAX_PATH)==0) {
/* go back one */
if (strlen(curdir)==1) {
printf("Already at top level\n");
return 0;
}
if ((p=strrchr(curdir,'/'))) {
if (p==curdir) snprintf(curdir,AFP_MAX_PATH,"/");
else *p='\0';
} else {
printf("Internal error\n");
goto error;
}
} else {
if (path[0]=='/') {
memcpy(newdir,path, AFP_MAX_PATH);
} else {
if (((strlen(path)==1) && (path[0]=='/')) ||
(((strlen(curdir)==1) && (curdir[0]=='/')))) {
snprintf(newdir,AFP_MAX_PATH,"/%s",path);
} else {
snprintf(newdir,AFP_MAX_PATH,
"%s/%s",curdir,path);
}
}
ret=ml_getattr(vol,newdir,&stbuf);
if ((ret==0) && (stbuf.st_mode & S_IFDIR)) {
memcpy(curdir,newdir,AFP_MAX_PATH);
printf("Now in directory %s\n",curdir);
} else {
if ((stbuf.st_mode & S_IFDIR)==0) {
printf("%s is not a directory, mode is 0%o\n",newdir,
stbuf.st_mode);
} else {
printf("Error %d\n",ret);
goto error;
}
}
}
/* To change directory, get a file list and grab the did. */
return 0;
error:
return -1;
}
/* Print out the current working directory locally. */
int com_lpwd (char * ignore)
{
char dir[255];
getcwd(dir,255);
printf("Now in local directory %s\n",dir);
return 0;
}
/* Print out the current working directory. */
int com_pwd (char * ignore)
{
if ((server==NULL) || (vol==NULL)) {
printf("You're not connected to a volume yet\n");
goto error;
}
printf("Now in directory %s on volume %s.\n",curdir, vol->volume_name_printable);
return 0;
error:
return -1;
}
static int get_dir(char * server_base, char * path,
unsigned long long * total)
{
struct afp_file_info * p, *filebase;
char total_path[AFP_MAX_PATH];
unsigned long long amount_written, local_total=0;
if (strcmp(server_base,"/")==0)
snprintf(total_path,AFP_MAX_PATH,"/%s",path);
else
snprintf(total_path,AFP_MAX_PATH,"%s/%s",server_base,path);
printf("Getting directory %s\n",total_path);
mkdir(path,0755);
chdir(path);
if (ml_readdir(vol,total_path,&filebase)) goto error;
if (filebase==NULL) goto out;
for (p=filebase;p;p=p->next) {
if (p->isdir) {
get_dir(total_path,p->name, &amount_written);
} else {
snprintf(curdir,AFP_MAX_PATH,"%s",total_path);
com_get_file(p->name,1, &amount_written);
}
local_total+=amount_written;
}
afp_ml_filebase_free(&filebase);
out:
*total=local_total;
chdir("..");
return 0;
error:
chdir("..");
return -1;
}
static int recursive_get(char * path)
{
char * dirc = strdup(path);
char * base = basename(path);
char * dir = dirname(dirc);
struct timeval starttv, endtv;
unsigned long long amount_written;
gettimeofday(&starttv,NULL);
get_dir(dir,base, &amount_written);
gettimeofday(&endtv,NULL);
printdiff(&starttv,&endtv, &amount_written);
return 0;
}
static struct libafpclient afpclient = {
.unmount_volume = NULL,
.log_for_client = stdout_log_for_client,
.forced_ending_hook = cmdline_forced_ending_hook,
.scan_extra_fds = NULL,
.loop_started = cmdline_loop_started,
};
static void * cmdline_server_startup(int recursive)
{
struct stat stbuf;
int ret;
full_url=1;
if (server_subconnect()) goto error;
if (strlen(url.volumename)==0) {
int i;
char names[1024];
afp_list_volnames(server,names,1024);
printf("Specify a volume with 'cd volume'. Choose one of: %s\n",
names);
trigger_connected();
return NULL;
}
ret=connect_volume(url.volumename);
if (ret) {
printf("Could not connect to volume %s on server\n",url.volumename);
just_end_it_now(NULL);
goto error;
}
trigger_connected();
if (strlen(url.path)==0)
return NULL;
ret=ml_getattr(vol,url.path,&stbuf);
if (ret) {
printf("Could not open %s on server\n",url.path);
just_end_it_now(NULL);
goto error;
}
if (stbuf.st_mode & S_IFDIR) {
snprintf(curdir,AFP_MAX_PATH,"%s",url.path);
printf("In directory %s\n",url.path);
if (recursive) {
recursive_get(url.path);
}
} else {
com_get(url.path);
just_end_it_now(NULL);
}
return NULL;
error:
printf("Error\n");
return (void *) -1;
}
void cmdline_afp_exit(void)
{
afp_unmount_volume(vol);
}
void cmdline_afp_setup_client(void)
{
libafpclient_register(&afpclient);
}
int cmdline_afp_setup(int recursive, char * url_string)
{
struct passwd * passwd;
snprintf(curdir, sizeof(curdir), DEFAULT_DIRECTORY);
if (init_uams()<0) return -1;
afp_default_url(&url);
passwd = getpwuid(getuid());
strncpy(url.username, passwd->pw_name,AFP_MAX_USERNAME_LEN);
if ((url_string) && (strlen(url_string)>1)) {
if (afp_parse_url(&url,url_string,1)) {
printf("Could not parse url.\n");
}
cmdline_getpass();
trigger_connected();
cmdline_server_startup(recursive);
}
return 0;
}