summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Lindstrom <mouring@eviladmin.org>2001-03-17 00:34:46 +0000
committerBen Lindstrom <mouring@eviladmin.org>2001-03-17 00:34:46 +0000
commitc8d1c30c312003ecbeba9a383f0a61ed45ad0c04 (patch)
treede4f4b94c8d94f24164b03ea6e114d02e81d216a
parent86fe8686b920b7da020b96aaf2303a7b596c36a4 (diff)
- djm@cvs.openbsd.org 2001/03/16 08:16:18
[sftp-client.c sftp-client.h sftp-glob.c sftp-int.c] Revise globbing for get/put to be more shell-like. In particular, "get/put file* directory/" now works. ok markus@
-rw-r--r--ChangeLog6
-rw-r--r--sftp-client.c32
-rw-r--r--sftp-client.h10
-rw-r--r--sftp-glob.c6
-rw-r--r--sftp-int.c288
5 files changed, 249 insertions, 93 deletions
diff --git a/ChangeLog b/ChangeLog
index 191ee72e..7f972e30 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,10 @@
- markus@cvs.openbsd.org 2001/03/15 22:07:08
[session.c]
pass Session to do_child + KNF
+ - djm@cvs.openbsd.org 2001/03/16 08:16:18
+ [sftp-client.c sftp-client.h sftp-glob.c sftp-int.c]
+ Revise globbing for get/put to be more shell-like. In particular,
+ "get/put file* directory/" now works. ok markus@
20010315
- OpenBSD CVS Sync
@@ -4570,4 +4574,4 @@
- Wrote replacements for strlcpy and mkdtemp
- Released 1.0pre1
-$Id: ChangeLog,v 1.963 2001/03/17 00:32:57 mouring Exp $
+$Id: ChangeLog,v 1.964 2001/03/17 00:34:46 mouring Exp $
diff --git a/sftp-client.c b/sftp-client.c
index 87f3053f..b0007a73 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -29,7 +29,7 @@
/* XXX: copy between two remote sites */
#include "includes.h"
-RCSID("$OpenBSD: sftp-client.c,v 1.13 2001/03/14 08:57:14 markus Exp $");
+RCSID("$OpenBSD: sftp-client.c,v 1.14 2001/03/16 08:16:17 djm Exp $");
#include "ssh.h"
#include "buffer.h"
@@ -180,7 +180,7 @@ get_handle(int fd, u_int expected_id, u_int *len)
}
Attrib *
-get_decode_stat(int fd, u_int expected_id)
+get_decode_stat(int fd, u_int expected_id, int quiet)
{
Buffer msg;
u_int type, id;
@@ -198,7 +198,10 @@ get_decode_stat(int fd, u_int expected_id)
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
- error("Couldn't stat remote file: %s", fx2txt(status));
+ if (quiet)
+ debug("Couldn't stat remote file: %s", fx2txt(status));
+ else
+ error("Couldn't stat remote file: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
@@ -455,34 +458,33 @@ do_rmdir(int fd_in, int fd_out, char *path)
}
Attrib *
-do_stat(int fd_in, int fd_out, char *path)
+do_stat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
- return(get_decode_stat(fd_in, id));
+ return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
-do_lstat(int fd_in, int fd_out, char *path)
+do_lstat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
- return(get_decode_stat(fd_in, id));
+ return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
-do_fstat(int fd_in, int fd_out, char *handle,
- u_int handle_len)
+do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
- return(get_decode_stat(fd_in, id));
+ return(get_decode_stat(fd_in, id, quiet));
}
int
@@ -677,7 +679,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
Attrib junk, *a;
int status;
- a = do_stat(fd_in, fd_out, remote_path);
+ a = do_stat(fd_in, fd_out, remote_path, 0);
if (a == NULL)
return(-1);
@@ -687,11 +689,17 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
else
mode = 0666;
+ if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
+ (a->perm & S_IFDIR)) {
+ error("Cannot download a directory: %s", remote_path);
+ return(-1);
+ }
+
local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
- return(errno);
+ return(-1);
}
buffer_init(&msg);
diff --git a/sftp-client.h b/sftp-client.h
index e7ba02ad..a935736e 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.3 2001/03/13 22:42:54 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.4 2001/03/16 08:16:18 djm Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
@@ -62,14 +62,14 @@ int do_mkdir(int fd_in, int fd_out, char *path, Attrib *a);
int do_rmdir(int fd_in, int fd_out, char *path);
/* Get file attributes of 'path' (follows symlinks) */
-Attrib *do_stat(int fd_in, int fd_out, char *path);
+Attrib *do_stat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of 'path' (does not follow symlinks) */
-Attrib *do_lstat(int fd_in, int fd_out, char *path);
+Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of open file 'handle' */
-Attrib *do_fstat(int fd_in, int fd_out, char *handle,
- u_int handle_len);
+Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len,
+ int quiet);
/* Set file attributes of 'path' */
int do_setstat(int fd_in, int fd_out, char *path, Attrib *a);
diff --git a/sftp-glob.c b/sftp-glob.c
index aec6d273..79dca00f 100644
--- a/sftp-glob.c
+++ b/sftp-glob.c
@@ -23,7 +23,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sftp-glob.c,v 1.1 2001/03/13 22:42:54 djm Exp $");
+RCSID("$OpenBSD: sftp-glob.c,v 1.2 2001/03/16 08:16:18 djm Exp $");
#include "ssh.h"
#include "buffer.h"
@@ -119,7 +119,7 @@ int fudge_lstat(const char *path, struct stat *st)
{
Attrib *a;
- if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path)))
+ if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);
@@ -131,7 +131,7 @@ int fudge_stat(const char *path, struct stat *st)
{
Attrib *a;
- if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path)))
+ if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);
diff --git a/sftp-int.c b/sftp-int.c
index cf86012e..fdadf23b 100644
--- a/sftp-int.c
+++ b/sftp-int.c
@@ -26,7 +26,7 @@
/* XXX: recursive operations */
#include "includes.h"
-RCSID("$OpenBSD: sftp-int.c,v 1.28 2001/03/14 15:15:58 markus Exp $");
+RCSID("$OpenBSD: sftp-int.c,v 1.29 2001/03/16 08:16:18 djm Exp $");
#include "buffer.h"
#include "xmalloc.h"
@@ -195,18 +195,50 @@ local_do_ls(const char *args)
}
char *
+path_append(char *p1, char *p2)
+{
+ char *ret;
+
+ ret = xmalloc(strlen(p1) + strlen(p2) + 2);
+ strcpy(ret, p1);
+ strcat(ret, "/");
+ strcat(ret, p2);
+
+ return(ret);
+}
+
+char *
make_absolute(char *p, char *pwd)
{
- char buf[2048];
+ char *abs;
/* Derelativise */
if (p && p[0] != '/') {
- snprintf(buf, sizeof(buf), "%s/%s", pwd, p);
+ abs = path_append(pwd, p);
xfree(p);
- p = xstrdup(buf);
+ return(abs);
+ } 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]) {
+ error("Invalid path");
+ return(-1);
}
- return(p);
+ *ifp = xstrdup(cp + 1);
+ return(0);
}
int
@@ -281,23 +313,182 @@ get_pathname(const char **cpp, char **path)
}
int
-infer_path(const char *p, char **ifp)
+is_dir(char *path)
{
- char *cp;
+ struct stat sb;
- cp = strrchr(p, '/');
- if (cp == NULL) {
- *ifp = xstrdup(p);
+ /* XXX: report errors? */
+ if (stat(path, &sb) == -1)
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;
}
- if (!cp[1]) {
- error("Invalid path");
- return(-1);
+ /* Only one match, dst may be file, directory or unspecified */
+ if (g.gl_pathv[0] && g.gl_matchc == 1) {
+ if (dst) {
+ /* 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;
}
- *ifp = xstrdup(cp + 1);
- return(0);
+ /* Multiple matches, dst may be directory or unspecified */
+ if (dst && !is_dir(dst)) {
+ 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
+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
@@ -459,66 +650,17 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
+ memset(&g, 0, sizeof(g));
+
/* Perform command */
switch (cmdnum) {
case -1:
break;
case I_GET:
- 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);
- }
+ err = process_get(in, out, path1, path2, *pwd, pflag);
break;
case I_PUT:
- 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);
- }
+ err = process_put(in, out, path1, path2, *pwd, pflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
@@ -561,7 +703,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
err = 1;
break;
}
- if ((aa = do_stat(in, out, tmp)) == NULL) {
+ if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
xfree(tmp);
err = 1;
break;
@@ -592,7 +734,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
break;
xfree(path1);
path1 = tmp;
- if ((aa = do_stat(in, out, path1)) == NULL)
+ if ((aa = do_stat(in, out, path1, 0)) == NULL)
break;
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
!S_ISDIR(aa->perm)) {
@@ -640,7 +782,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
- if (!(aa = do_stat(in, out, g.gl_pathv[i])))
+ if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
@@ -657,7 +799,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
- if (!(aa = do_stat(in, out, g.gl_pathv[i])))
+ if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
@@ -693,6 +835,8 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
fatal("%d is not implemented", cmdnum);
}
+ if (g.gl_pathc)
+ globfree(&g);
if (path1)
xfree(path1);
if (path2)