version 1.26.2.2, 2001/03/21 18:53:05 |
version 1.27, 2001/03/13 22:42:54 |
|
|
#define I_RMDIR 19 |
#define I_RMDIR 19 |
#define I_SHELL 20 |
#define I_SHELL 20 |
#define I_SYMLINK 21 |
#define I_SYMLINK 21 |
#define I_VERSION 22 |
|
|
|
struct CMD { |
struct CMD { |
const char *c; |
const char *c; |
|
|
{ "rm", I_RM }, |
{ "rm", I_RM }, |
{ "rmdir", I_RMDIR }, |
{ "rmdir", I_RMDIR }, |
{ "symlink", I_SYMLINK }, |
{ "symlink", I_SYMLINK }, |
{ "version", I_VERSION }, |
|
{ "!", I_SHELL }, |
{ "!", I_SHELL }, |
{ "?", I_HELP }, |
{ "?", I_HELP }, |
{ NULL, -1} |
{ NULL, -1} |
|
|
printf("rmdir path Remove remote directory\n"); |
printf("rmdir path Remove remote directory\n"); |
printf("rm path Delete remote file\n"); |
printf("rm path Delete remote file\n"); |
printf("symlink oldpath newpath Symlink remote file\n"); |
printf("symlink oldpath newpath Symlink remote file\n"); |
printf("version Show SFTP version\n"); |
|
printf("!command Execute 'command' in local shell\n"); |
printf("!command Execute 'command' in local shell\n"); |
printf("! Escape to local shell\n"); |
printf("! Escape to local shell\n"); |
printf("? Synonym for help\n"); |
printf("? Synonym for help\n"); |
|
|
} |
} |
|
|
char * |
char * |
path_append(char *p1, char *p2) |
|
{ |
|
char *ret; |
|
int len = strlen(p1) + strlen(p2) + 2; |
|
|
|
ret = xmalloc(len); |
|
strlcpy(ret, p1, len); |
|
strlcat(ret, "/", len); |
|
strlcat(ret, p2, len); |
|
|
|
return(ret); |
|
} |
|
|
|
char * |
|
make_absolute(char *p, char *pwd) |
make_absolute(char *p, char *pwd) |
{ |
{ |
char *abs; |
char buf[2048]; |
|
|
/* Derelativise */ |
/* Derelativise */ |
if (p && p[0] != '/') { |
if (p && p[0] != '/') { |
abs = path_append(pwd, p); |
snprintf(buf, sizeof(buf), "%s/%s", pwd, p); |
xfree(p); |
xfree(p); |
return(abs); |
p = xstrdup(buf); |
} else |
|
return(p); |
|
} |
|
|
|
int |
|
infer_path(const char *p, char **ifp) |
|
{ |
|
char *cp; |
|
|
|
cp = strrchr(p, '/'); |
|
if (cp == NULL) { |
|
*ifp = xstrdup(p); |
|
return(0); |
|
} |
} |
|
|
if (!cp[1]) { |
return(p); |
error("Invalid path"); |
|
return(-1); |
|
} |
|
|
|
*ifp = xstrdup(cp + 1); |
|
return(0); |
|
} |
} |
|
|
int |
int |
|
|
/* Check for quoted filenames */ |
/* Check for quoted filenames */ |
if (*cp == '\"' || *cp == '\'') { |
if (*cp == '\"' || *cp == '\'') { |
quot = *cp++; |
quot = *cp++; |
|
|
end = strchr(cp, quot); |
end = strchr(cp, quot); |
if (end == NULL) { |
if (end == NULL) { |
error("Unterminated quote"); |
error("Unterminated quote"); |
|
|
} |
} |
|
|
int |
int |
is_dir(char *path) |
infer_path(const char *p, char **ifp) |
{ |
{ |
struct stat sb; |
char *cp; |
|
|
/* XXX: report errors? */ |
cp = strrchr(p, '/'); |
if (stat(path, &sb) == -1) |
if (cp == NULL) { |
|
*ifp = xstrdup(p); |
return(0); |
return(0); |
|
|
return(sb.st_mode & S_IFDIR); |
|
} |
|
|
|
int |
|
remote_is_dir(int in, int out, char *path) |
|
{ |
|
Attrib *a; |
|
|
|
/* XXX: report errors? */ |
|
if ((a = do_stat(in, out, path, 1)) == NULL) |
|
return(0); |
|
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) |
|
return(0); |
|
return(a->perm & S_IFDIR); |
|
} |
|
|
|
int |
|
process_get(int in, int out, char *src, char *dst, char *pwd, int pflag) |
|
{ |
|
char *abs_src = NULL; |
|
char *abs_dst = NULL; |
|
char *tmp; |
|
glob_t g; |
|
int err = 0; |
|
int i; |
|
|
|
abs_src = xstrdup(src); |
|
abs_src = make_absolute(abs_src, pwd); |
|
|
|
memset(&g, 0, sizeof(g)); |
|
debug3("Looking up %s", abs_src); |
|
if (remote_glob(in, out, abs_src, 0, NULL, &g)) { |
|
error("File \"%s\" not found.", abs_src); |
|
err = -1; |
|
goto out; |
|
} |
} |
|
|
/* Only one match, dst may be file, directory or unspecified */ |
if (!cp[1]) { |
if (g.gl_pathv[0] && g.gl_matchc == 1) { |
error("Invalid path"); |
if (dst) { |
return(-1); |
/* If directory specified, append filename */ |
|
if (is_dir(dst)) { |
|
if (infer_path(g.gl_pathv[0], &tmp)) { |
|
err = 1; |
|
goto out; |
|
} |
|
abs_dst = path_append(dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = xstrdup(dst); |
|
} else if (infer_path(g.gl_pathv[0], &abs_dst)) { |
|
err = -1; |
|
goto out; |
|
} |
|
printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); |
|
err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag); |
|
goto out; |
|
} |
} |
|
|
/* Multiple matches, dst may be directory or unspecified */ |
*ifp = xstrdup(cp + 1); |
if (dst && !is_dir(dst)) { |
return(0); |
error("Multiple files match, but \"%s\" is not a directory", |
|
dst); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (infer_path(g.gl_pathv[i], &tmp)) { |
|
err = -1; |
|
goto out; |
|
} |
|
if (dst) { |
|
abs_dst = path_append(dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = tmp; |
|
|
|
printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
|
if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) |
|
err = -1; |
|
xfree(abs_dst); |
|
abs_dst = NULL; |
|
} |
|
|
|
out: |
|
xfree(abs_src); |
|
if (abs_dst) |
|
xfree(abs_dst); |
|
globfree(&g); |
|
return(err); |
|
} |
} |
|
|
int |
int |
process_put(int in, int out, char *src, char *dst, char *pwd, int pflag) |
|
{ |
|
char *tmp_dst = NULL; |
|
char *abs_dst = NULL; |
|
char *tmp; |
|
glob_t g; |
|
int err = 0; |
|
int i; |
|
|
|
if (dst) { |
|
tmp_dst = xstrdup(dst); |
|
tmp_dst = make_absolute(tmp_dst, pwd); |
|
} |
|
|
|
memset(&g, 0, sizeof(g)); |
|
debug3("Looking up %s", src); |
|
if (glob(src, 0, NULL, &g)) { |
|
error("File \"%s\" not found.", src); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
/* Only one match, dst may be file, directory or unspecified */ |
|
if (g.gl_pathv[0] && g.gl_matchc == 1) { |
|
if (tmp_dst) { |
|
/* If directory specified, append filename */ |
|
if (remote_is_dir(in, out, tmp_dst)) { |
|
if (infer_path(g.gl_pathv[0], &tmp)) { |
|
err = 1; |
|
goto out; |
|
} |
|
abs_dst = path_append(tmp_dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = xstrdup(tmp_dst); |
|
} else if (infer_path(g.gl_pathv[0], &abs_dst)) { |
|
err = -1; |
|
goto out; |
|
} |
|
printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst); |
|
err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag); |
|
goto out; |
|
} |
|
|
|
/* Multiple matches, dst may be directory or unspecified */ |
|
if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) { |
|
error("Multiple files match, but \"%s\" is not a directory", |
|
tmp_dst); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (infer_path(g.gl_pathv[i], &tmp)) { |
|
err = -1; |
|
goto out; |
|
} |
|
if (tmp_dst) { |
|
abs_dst = path_append(tmp_dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = make_absolute(tmp, pwd); |
|
|
|
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); |
|
if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) |
|
err = -1; |
|
} |
|
|
|
out: |
|
if (abs_dst) |
|
xfree(abs_dst); |
|
if (tmp_dst) |
|
xfree(tmp_dst); |
|
return(err); |
|
} |
|
|
|
int |
|
parse_args(const char **cpp, int *pflag, unsigned long *n_arg, |
parse_args(const char **cpp, int *pflag, unsigned long *n_arg, |
char **path1, char **path2) |
char **path1, char **path2) |
{ |
{ |
|
|
case I_PWD: |
case I_PWD: |
case I_LPWD: |
case I_LPWD: |
case I_HELP: |
case I_HELP: |
case I_VERSION: |
|
break; |
break; |
default: |
default: |
fatal("Command not implemented"); |
fatal("Command not implemented"); |
|
|
path1 = path2 = NULL; |
path1 = path2 = NULL; |
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); |
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); |
|
|
memset(&g, 0, sizeof(g)); |
|
|
|
/* Perform command */ |
/* Perform command */ |
switch (cmdnum) { |
switch (cmdnum) { |
case -1: |
case -1: |
break; |
break; |
case I_GET: |
case I_GET: |
err = process_get(in, out, path1, path2, *pwd, pflag); |
memset(&g, 0, sizeof(g)); |
|
if (!remote_glob(in, out, path1, 0, NULL, &g)) { |
|
if (path2) { |
|
/* XXX: target should be directory */ |
|
error("You cannot specify a target when " |
|
"downloading multiple files"); |
|
err = -1; |
|
break; |
|
} |
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (!infer_path(g.gl_pathv[i], &path2)) { |
|
printf("Fetching %s\n", g.gl_pathv[i]); |
|
if (do_download(in, out, g.gl_pathv[i], |
|
path2, pflag) == -1) |
|
err = -1; |
|
free(path2); |
|
path2 = NULL; |
|
} else |
|
err = -1; |
|
} |
|
} else { |
|
if (!path2 && infer_path(path1, &path2)) { |
|
err = -1; |
|
break; |
|
} |
|
err = do_download(in, out, path1, path2, pflag); |
|
} |
break; |
break; |
case I_PUT: |
case I_PUT: |
err = process_put(in, out, path1, path2, *pwd, pflag); |
if (!glob(path1, 0, NULL, &g)) { |
|
if (path2) { |
|
error("You cannot specify a target when " |
|
"uploading multiple files"); |
|
err = -1; |
|
break; |
|
} |
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (!infer_path(g.gl_pathv[i], &path2)) { |
|
path2 = make_absolute(path2, *pwd); |
|
printf("Uploading %s\n", g.gl_pathv[i]); |
|
if (do_upload(in, out, g.gl_pathv[i], |
|
path2, pflag) == -1) |
|
err = -1; |
|
free(path2); |
|
path2 = NULL; |
|
} else |
|
err = -1; |
|
} |
|
} else { |
|
if (!path2 && infer_path(path1, &path2)) { |
|
err = -1; |
|
break; |
|
} |
|
err = do_upload(in, out, path1, path2, pflag); |
|
} |
break; |
break; |
case I_RENAME: |
case I_RENAME: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
|
|
err = 1; |
err = 1; |
break; |
break; |
} |
} |
if ((aa = do_stat(in, out, tmp, 0)) == NULL) { |
if ((aa = do_stat(in, out, tmp)) == NULL) { |
xfree(tmp); |
xfree(tmp); |
err = 1; |
err = 1; |
break; |
break; |
|
|
break; |
break; |
xfree(path1); |
xfree(path1); |
path1 = tmp; |
path1 = tmp; |
if ((aa = do_stat(in, out, path1, 0)) == NULL) |
if ((aa = do_stat(in, out, path1)) == NULL) |
break; |
break; |
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
!S_ISDIR(aa->perm)) { |
!S_ISDIR(aa->perm)) { |
error("Can't ls: \"%s\" is not a directory", path1); |
error("Can't ls: \"%s\" is not a directory", path1); |
break; |
break; |
|
|
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
for(i = 0; g.gl_pathv[i]; i++) { |
for(i = 0; g.gl_pathv[i]; i++) { |
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) |
if (!(aa = do_stat(in, out, g.gl_pathv[i]))) |
continue; |
continue; |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
error("Can't get current ownership of " |
error("Can't get current ownership of " |
|
|
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
for(i = 0; g.gl_pathv[i]; i++) { |
for(i = 0; g.gl_pathv[i]; i++) { |
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) |
if (!(aa = do_stat(in, out, g.gl_pathv[i]))) |
continue; |
continue; |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
error("Can't get current ownership of " |
error("Can't get current ownership of " |
|
|
case I_HELP: |
case I_HELP: |
help(); |
help(); |
break; |
break; |
case I_VERSION: |
|
printf("SFTP protocol version %d\n", version); |
|
break; |
|
default: |
default: |
fatal("%d is not implemented", cmdnum); |
fatal("%d is not implemented", cmdnum); |
} |
} |
|
|
if (g.gl_pathc) |
|
globfree(&g); |
|
if (path1) |
if (path1) |
xfree(path1); |
xfree(path1); |
if (path2) |
if (path2) |