diff options
author | Damien Miller <djm@mindrot.org> | 2001-03-14 10:27:09 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2001-03-14 10:27:09 +1100 |
commit | 4870afd7c73a605778794378915eab0c26e8c353 (patch) | |
tree | 76d93d5002452636a8884c83ba0aba2f6c0a3f58 | |
parent | 056ddf7af3504a688c34f2daf50bcd20abfef3ba (diff) |
- djm@cvs.openbsd.org 2001/03/13 22:42:54
[sftp-client.c sftp-client.h sftp-glob.c sftp-glob.h sftp-int.c]
sftp client filename globbing for get, put, ch{mod,grp,own}. ok markus@
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | sftp-client.c | 53 | ||||
-rw-r--r-- | sftp-client.h | 16 | ||||
-rw-r--r-- | sftp-glob.c | 160 | ||||
-rw-r--r-- | sftp-glob.h | 32 | ||||
-rw-r--r-- | sftp-int.c | 133 |
7 files changed, 361 insertions, 44 deletions
@@ -3,6 +3,9 @@ | |||
3 | - markus@cvs.openbsd.org 2001/03/13 17:34:42 | 3 | - markus@cvs.openbsd.org 2001/03/13 17:34:42 |
4 | [auth-options.c] | 4 | [auth-options.c] |
5 | missing xfree, deny key on parse error; ok stevesk@ | 5 | missing xfree, deny key on parse error; ok stevesk@ |
6 | - djm@cvs.openbsd.org 2001/03/13 22:42:54 | ||
7 | [sftp-client.c sftp-client.h sftp-glob.c sftp-glob.h sftp-int.c] | ||
8 | sftp client filename globbing for get, put, ch{mod,grp,own}. ok markus@ | ||
6 | 9 | ||
7 | 20010313 | 10 | 20010313 |
8 | - OpenBSD CVS Sync | 11 | - OpenBSD CVS Sync |
@@ -4537,4 +4540,4 @@ | |||
4537 | - Wrote replacements for strlcpy and mkdtemp | 4540 | - Wrote replacements for strlcpy and mkdtemp |
4538 | - Released 1.0pre1 | 4541 | - Released 1.0pre1 |
4539 | 4542 | ||
4540 | $Id: ChangeLog,v 1.952 2001/03/13 23:15:20 djm Exp $ | 4543 | $Id: ChangeLog,v 1.953 2001/03/13 23:27:09 djm Exp $ |
diff --git a/Makefile.in b/Makefile.in index bc54cb677..b25ca00cd 100644 --- a/Makefile.in +++ b/Makefile.in | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: Makefile.in,v 1.159 2001/03/12 05:16:19 mouring Exp $ | 1 | # $Id: Makefile.in,v 1.160 2001/03/13 23:27:09 djm Exp $ |
2 | 2 | ||
3 | prefix=@prefix@ | 3 | prefix=@prefix@ |
4 | exec_prefix=@exec_prefix@ | 4 | exec_prefix=@exec_prefix@ |
@@ -116,8 +116,8 @@ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a log.o ssh-keyscan.o | |||
116 | sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o log.o sftp-server.o | 116 | sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o log.o sftp-server.o |
117 | $(LD) -o $@ sftp-server.o sftp-common.o log.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | 117 | $(LD) -o $@ sftp-server.o sftp-common.o log.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
118 | 118 | ||
119 | sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o | 119 | sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o sftp-glob.o |
120 | $(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) | 120 | $(LD) -o $@ sftp.o sftp-client.o sftp-common.o sftp-int.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) |
121 | 121 | ||
122 | # test driver for the loginrec code - not built by default | 122 | # test driver for the loginrec code - not built by default |
123 | logintest: logintest.o $(LIBCOMPAT) libssh.a log.o loginrec.o | 123 | logintest: logintest.o $(LIBCOMPAT) libssh.a log.o loginrec.o |
diff --git a/sftp-client.c b/sftp-client.c index d1e4ebacc..9f77d366c 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -29,7 +29,7 @@ | |||
29 | /* XXX: copy between two remote sites */ | 29 | /* XXX: copy between two remote sites */ |
30 | 30 | ||
31 | #include "includes.h" | 31 | #include "includes.h" |
32 | RCSID("$OpenBSD: sftp-client.c,v 1.11 2001/03/07 10:11:22 djm Exp $"); | 32 | RCSID("$OpenBSD: sftp-client.c,v 1.12 2001/03/13 22:42:54 djm Exp $"); |
33 | 33 | ||
34 | #include "ssh.h" | 34 | #include "ssh.h" |
35 | #include "buffer.h" | 35 | #include "buffer.h" |
@@ -275,11 +275,13 @@ do_close(int fd_in, int fd_out, char *handle, u_int handle_len) | |||
275 | return(status); | 275 | return(status); |
276 | } | 276 | } |
277 | 277 | ||
278 | |||
278 | int | 279 | int |
279 | do_ls(int fd_in, int fd_out, char *path) | 280 | do_lsreaddir(int fd_in, int fd_out, char *path, int printflag, |
281 | SFTP_DIRENT ***dir) | ||
280 | { | 282 | { |
281 | Buffer msg; | 283 | Buffer msg; |
282 | u_int type, id, handle_len, i, expected_id; | 284 | u_int type, id, handle_len, i, expected_id, ents; |
283 | char *handle; | 285 | char *handle; |
284 | 286 | ||
285 | id = msg_id++; | 287 | id = msg_id++; |
@@ -296,6 +298,13 @@ do_ls(int fd_in, int fd_out, char *path) | |||
296 | if (handle == NULL) | 298 | if (handle == NULL) |
297 | return(-1); | 299 | return(-1); |
298 | 300 | ||
301 | if (dir) { | ||
302 | ents = 0; | ||
303 | *dir = xmalloc(sizeof(**dir)); | ||
304 | (*dir)[0] = NULL; | ||
305 | } | ||
306 | |||
307 | |||
299 | for(;;) { | 308 | for(;;) { |
300 | int count; | 309 | int count; |
301 | 310 | ||
@@ -350,7 +359,18 @@ do_ls(int fd_in, int fd_out, char *path) | |||
350 | longname = buffer_get_string(&msg, NULL); | 359 | longname = buffer_get_string(&msg, NULL); |
351 | a = decode_attrib(&msg); | 360 | a = decode_attrib(&msg); |
352 | 361 | ||
353 | printf("%s\n", longname); | 362 | if (printflag) |
363 | printf("%s\n", longname); | ||
364 | |||
365 | if (dir) { | ||
366 | *dir = xrealloc(*dir, sizeof(**dir) * | ||
367 | (ents + 2)); | ||
368 | (*dir)[ents] = xmalloc(sizeof(***dir)); | ||
369 | (*dir)[ents]->filename = xstrdup(filename); | ||
370 | (*dir)[ents]->longname = xstrdup(longname); | ||
371 | memcpy(&(*dir)[ents]->a, a, sizeof(*a)); | ||
372 | (*dir)[++ents] = NULL; | ||
373 | } | ||
354 | 374 | ||
355 | xfree(filename); | 375 | xfree(filename); |
356 | xfree(longname); | 376 | xfree(longname); |
@@ -365,6 +385,30 @@ do_ls(int fd_in, int fd_out, char *path) | |||
365 | } | 385 | } |
366 | 386 | ||
367 | int | 387 | int |
388 | do_ls(int fd_in, int fd_out, char *path) | ||
389 | { | ||
390 | return(do_lsreaddir(fd_in, fd_out, path, 1, NULL)); | ||
391 | } | ||
392 | |||
393 | int | ||
394 | do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir) | ||
395 | { | ||
396 | return(do_lsreaddir(fd_in, fd_out, path, 0, dir)); | ||
397 | } | ||
398 | |||
399 | void free_sftp_dirents(SFTP_DIRENT **s) | ||
400 | { | ||
401 | int i; | ||
402 | |||
403 | for(i = 0; s[i]; i++) { | ||
404 | xfree(s[i]->filename); | ||
405 | xfree(s[i]->longname); | ||
406 | xfree(s[i]); | ||
407 | } | ||
408 | xfree(s); | ||
409 | } | ||
410 | |||
411 | int | ||
368 | do_rm(int fd_in, int fd_out, char *path) | 412 | do_rm(int fd_in, int fd_out, char *path) |
369 | { | 413 | { |
370 | u_int status, id; | 414 | u_int status, id; |
@@ -875,3 +919,4 @@ done: | |||
875 | buffer_free(&msg); | 919 | buffer_free(&msg); |
876 | return status; | 920 | return status; |
877 | } | 921 | } |
922 | |||
diff --git a/sftp-client.h b/sftp-client.h index e836c0d66..e7ba02ad6 100644 --- a/sftp-client.h +++ b/sftp-client.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.h,v 1.2 2001/03/07 10:11:23 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.h,v 1.3 2001/03/13 22:42:54 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2001 Damien Miller. All rights reserved. |
@@ -26,6 +26,14 @@ | |||
26 | 26 | ||
27 | /* Client side of SSH2 filexfer protocol */ | 27 | /* Client side of SSH2 filexfer protocol */ |
28 | 28 | ||
29 | typedef struct SFTP_DIRENT SFTP_DIRENT; | ||
30 | |||
31 | struct SFTP_DIRENT { | ||
32 | char *filename; | ||
33 | char *longname; | ||
34 | Attrib a; | ||
35 | }; | ||
36 | |||
29 | /* | 37 | /* |
30 | * Initialiase a SSH filexfer connection. Returns -1 on error or | 38 | * Initialiase a SSH filexfer connection. Returns -1 on error or |
31 | * protocol version on success. | 39 | * protocol version on success. |
@@ -38,6 +46,12 @@ int do_close(int fd_in, int fd_out, char *handle, u_int handle_len); | |||
38 | /* List contents of directory 'path' to stdout */ | 46 | /* List contents of directory 'path' to stdout */ |
39 | int do_ls(int fd_in, int fd_out, char *path); | 47 | int do_ls(int fd_in, int fd_out, char *path); |
40 | 48 | ||
49 | /* Read contents of 'path' to NULL-terminated array 'dir' */ | ||
50 | int do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir); | ||
51 | |||
52 | /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ | ||
53 | void free_sftp_dirents(SFTP_DIRENT **s); | ||
54 | |||
41 | /* Delete file 'path' */ | 55 | /* Delete file 'path' */ |
42 | int do_rm(int fd_in, int fd_out, char *path); | 56 | int do_rm(int fd_in, int fd_out, char *path); |
43 | 57 | ||
diff --git a/sftp-glob.c b/sftp-glob.c new file mode 100644 index 000000000..17f46a151 --- /dev/null +++ b/sftp-glob.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2001 Damien Miller. All rights reserved. | ||
3 | * | ||
4 | * Redistribution and use in source and binary forms, with or without | ||
5 | * modification, are permitted provided that the following conditions | ||
6 | * are met: | ||
7 | * 1. Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * 2. Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * | ||
13 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
14 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
15 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
16 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
17 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
18 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
19 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
20 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
23 | */ | ||
24 | |||
25 | #include "includes.h" | ||
26 | RCSID("$OpenBSD: sftp-glob.c,v 1.1 2001/03/13 22:42:54 djm Exp $"); | ||
27 | |||
28 | #include <glob.h> | ||
29 | |||
30 | #include "ssh.h" | ||
31 | #include "buffer.h" | ||
32 | #include "bufaux.h" | ||
33 | #include "getput.h" | ||
34 | #include "xmalloc.h" | ||
35 | #include "log.h" | ||
36 | #include "atomicio.h" | ||
37 | #include "pathnames.h" | ||
38 | |||
39 | #include "sftp.h" | ||
40 | #include "sftp-common.h" | ||
41 | #include "sftp-client.h" | ||
42 | #include "sftp-glob.h" | ||
43 | |||
44 | struct SFTP_OPENDIR { | ||
45 | SFTP_DIRENT **dir; | ||
46 | int offset; | ||
47 | }; | ||
48 | |||
49 | static struct { | ||
50 | int fd_in; | ||
51 | int fd_out; | ||
52 | } cur; | ||
53 | |||
54 | void *fudge_opendir(const char *path) | ||
55 | { | ||
56 | struct SFTP_OPENDIR *r; | ||
57 | |||
58 | r = xmalloc(sizeof(*r)); | ||
59 | |||
60 | if (do_readdir(cur.fd_in, cur.fd_out, (char*)path, &r->dir)) | ||
61 | return(NULL); | ||
62 | |||
63 | r->offset = 0; | ||
64 | |||
65 | return((void*)r); | ||
66 | } | ||
67 | |||
68 | struct dirent *fudge_readdir(struct SFTP_OPENDIR *od) | ||
69 | { | ||
70 | static struct dirent ret; | ||
71 | #ifdef __GNU_LIBRARY__ | ||
72 | static int inum = 1; | ||
73 | #endif /* __GNU_LIBRARY__ */ | ||
74 | |||
75 | if (od->dir[od->offset] == NULL) | ||
76 | return(NULL); | ||
77 | |||
78 | memset(&ret, 0, sizeof(ret)); | ||
79 | strlcpy(ret.d_name, od->dir[od->offset++]->filename, | ||
80 | sizeof(ret.d_name)); | ||
81 | |||
82 | #ifdef __GNU_LIBRARY__ | ||
83 | /* | ||
84 | * Idiot glibc uses extensions to struct dirent for readdir with | ||
85 | * ALTDIRFUNCs. Not that this is documented anywhere but the | ||
86 | * source... Fake an inode number to appease it. | ||
87 | */ | ||
88 | ret.d_ino = inum++; | ||
89 | if (!inum) | ||
90 | inum = 1; | ||
91 | #endif /* __GNU_LIBRARY__ */ | ||
92 | |||
93 | return(&ret); | ||
94 | } | ||
95 | |||
96 | void fudge_closedir(struct SFTP_OPENDIR *od) | ||
97 | { | ||
98 | free_sftp_dirents(od->dir); | ||
99 | free(od); | ||
100 | } | ||
101 | |||
102 | void attrib_to_stat(Attrib *a, struct stat *st) | ||
103 | { | ||
104 | memset(st, 0, sizeof(*st)); | ||
105 | |||
106 | if (a->flags & SSH2_FILEXFER_ATTR_SIZE) | ||
107 | st->st_size = a->size; | ||
108 | if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) { | ||
109 | st->st_uid = a->uid; | ||
110 | st->st_gid = a->gid; | ||
111 | } | ||
112 | if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) | ||
113 | st->st_mode = a->perm; | ||
114 | if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { | ||
115 | st->st_atime = a->atime; | ||
116 | st->st_mtime = a->mtime; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | int fudge_lstat(const char *path, struct stat *st) | ||
121 | { | ||
122 | Attrib *a; | ||
123 | |||
124 | if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path))) | ||
125 | return(-1); | ||
126 | |||
127 | attrib_to_stat(a, st); | ||
128 | |||
129 | return(0); | ||
130 | } | ||
131 | |||
132 | int fudge_stat(const char *path, struct stat *st) | ||
133 | { | ||
134 | Attrib *a; | ||
135 | |||
136 | if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path))) | ||
137 | return(-1); | ||
138 | |||
139 | attrib_to_stat(a, st); | ||
140 | |||
141 | return(0); | ||
142 | } | ||
143 | |||
144 | int | ||
145 | remote_glob(int fd_in, int fd_out, const char *pattern, int flags, | ||
146 | const int (*errfunc)(const char *, int), glob_t *pglob) | ||
147 | { | ||
148 | pglob->gl_opendir = (void*)fudge_opendir; | ||
149 | pglob->gl_readdir = (void*)fudge_readdir; | ||
150 | pglob->gl_closedir = (void*)fudge_closedir; | ||
151 | pglob->gl_lstat = fudge_lstat; | ||
152 | pglob->gl_stat = fudge_stat; | ||
153 | |||
154 | memset(&cur, 0, sizeof(cur)); | ||
155 | cur.fd_in = fd_in; | ||
156 | cur.fd_out = fd_out; | ||
157 | |||
158 | return(glob(pattern, flags | GLOB_ALTDIRFUNC, (void*)errfunc, | ||
159 | pglob)); | ||
160 | } | ||
diff --git a/sftp-glob.h b/sftp-glob.h new file mode 100644 index 000000000..9e75168ac --- /dev/null +++ b/sftp-glob.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* $OpenBSD: sftp-glob.h,v 1.1 2001/03/13 22:42:54 djm Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2001 Damien Miller. All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions | ||
8 | * are met: | ||
9 | * 1. Redistributions of source code must retain the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer. | ||
11 | * 2. Redistributions in binary form must reproduce the above copyright | ||
12 | * notice, this list of conditions and the following disclaimer in the | ||
13 | * documentation and/or other materials provided with the distribution. | ||
14 | * | ||
15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | */ | ||
26 | |||
27 | /* Remote sftp filename globbing */ | ||
28 | |||
29 | int | ||
30 | remote_glob(int fd_in, int fd_out, const char *pattern, int flags, | ||
31 | const int (*errfunc)(const char *, int), glob_t *pglob); | ||
32 | |||
diff --git a/sftp-int.c b/sftp-int.c index 6f5b3677a..d350e398d 100644 --- a/sftp-int.c +++ b/sftp-int.c | |||
@@ -22,13 +22,13 @@ | |||
22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 22 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | /* XXX: finish implementation of all commands */ | ||
26 | /* XXX: do fnmatch() instead of using raw pathname */ | ||
27 | /* XXX: globbed ls */ | 25 | /* XXX: globbed ls */ |
28 | /* XXX: recursive operations */ | 26 | /* XXX: recursive operations */ |
29 | 27 | ||
30 | #include "includes.h" | 28 | #include "includes.h" |
31 | RCSID("$OpenBSD: sftp-int.c,v 1.26 2001/03/07 10:11:23 djm Exp $"); | 29 | RCSID("$OpenBSD: sftp-int.c,v 1.27 2001/03/13 22:42:54 djm Exp $"); |
30 | |||
31 | #include <glob.h> | ||
32 | 32 | ||
33 | #include "buffer.h" | 33 | #include "buffer.h" |
34 | #include "xmalloc.h" | 34 | #include "xmalloc.h" |
@@ -37,6 +37,7 @@ RCSID("$OpenBSD: sftp-int.c,v 1.26 2001/03/07 10:11:23 djm Exp $"); | |||
37 | 37 | ||
38 | #include "sftp.h" | 38 | #include "sftp.h" |
39 | #include "sftp-common.h" | 39 | #include "sftp-common.h" |
40 | #include "sftp-glob.h" | ||
40 | #include "sftp-client.h" | 41 | #include "sftp-client.h" |
41 | #include "sftp-int.h" | 42 | #include "sftp-int.h" |
42 | 43 | ||
@@ -283,8 +284,6 @@ infer_path(const char *p, char **ifp) | |||
283 | { | 284 | { |
284 | char *cp; | 285 | char *cp; |
285 | 286 | ||
286 | debug("XXX: P = \"%s\"", p); | ||
287 | |||
288 | cp = strrchr(p, '/'); | 287 | cp = strrchr(p, '/'); |
289 | if (cp == NULL) { | 288 | if (cp == NULL) { |
290 | *ifp = xstrdup(p); | 289 | *ifp = xstrdup(p); |
@@ -360,9 +359,6 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg, | |||
360 | /* Try to get second pathname (optional) */ | 359 | /* Try to get second pathname (optional) */ |
361 | if (get_pathname(&cp, path2)) | 360 | if (get_pathname(&cp, path2)) |
362 | return(-1); | 361 | return(-1); |
363 | /* Otherwise try to guess it from first path */ | ||
364 | if (*path2 == NULL && infer_path(*path1, path2)) | ||
365 | return(-1); | ||
366 | break; | 362 | break; |
367 | case I_RENAME: | 363 | case I_RENAME: |
368 | case I_SYMLINK: | 364 | case I_SYMLINK: |
@@ -451,11 +447,12 @@ int | |||
451 | parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | 447 | parse_dispatch_command(int in, int out, const char *cmd, char **pwd) |
452 | { | 448 | { |
453 | char *path1, *path2, *tmp; | 449 | char *path1, *path2, *tmp; |
454 | int pflag, cmdnum; | 450 | int pflag, cmdnum, i; |
455 | unsigned long n_arg; | 451 | unsigned long n_arg; |
456 | Attrib a, *aa; | 452 | Attrib a, *aa; |
457 | char path_buf[MAXPATHLEN]; | 453 | char path_buf[MAXPATHLEN]; |
458 | int err = 0; | 454 | int err = 0; |
455 | glob_t g; | ||
459 | 456 | ||
460 | path1 = path2 = NULL; | 457 | path1 = path2 = NULL; |
461 | cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); | 458 | cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); |
@@ -465,14 +462,63 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
465 | case -1: | 462 | case -1: |
466 | break; | 463 | break; |
467 | case I_GET: | 464 | case I_GET: |
468 | path1 = make_absolute(path1, *pwd); | 465 | memset(&g, 0, sizeof(g)); |
469 | err = do_download(in, out, path1, path2, pflag); | 466 | if (!remote_glob(in, out, path1, 0, NULL, &g)) { |
467 | if (path2) { | ||
468 | /* XXX: target should be directory */ | ||
469 | error("You cannot specify a target when " | ||
470 | "downloading multiple files"); | ||
471 | err = -1; | ||
472 | break; | ||
473 | } | ||
474 | for(i = 0; g.gl_pathv[i]; i++) { | ||
475 | if (!infer_path(g.gl_pathv[i], &path2)) { | ||
476 | printf("Fetching %s\n", g.gl_pathv[i]); | ||
477 | if (do_download(in, out, g.gl_pathv[i], | ||
478 | path2, pflag) == -1) | ||
479 | err = -1; | ||
480 | free(path2); | ||
481 | path2 = NULL; | ||
482 | } else | ||
483 | err = -1; | ||
484 | } | ||
485 | } else { | ||
486 | if (!path2 && infer_path(path1, &path2)) { | ||
487 | err = -1; | ||
488 | break; | ||
489 | } | ||
490 | err = do_download(in, out, path1, path2, pflag); | ||
491 | } | ||
470 | break; | 492 | break; |
471 | case I_PUT: | 493 | case I_PUT: |
472 | path2 = make_absolute(path2, *pwd); | 494 | if (!glob(path1, 0, NULL, &g)) { |
473 | err = do_upload(in, out, path1, path2, pflag); | 495 | if (path2) { |
474 | break; | 496 | error("You cannot specify a target when " |
475 | case I_RENAME: | 497 | "uploading multiple files"); |
498 | err = -1; | ||
499 | break; | ||
500 | } | ||
501 | for(i = 0; g.gl_pathv[i]; i++) { | ||
502 | if (!infer_path(g.gl_pathv[i], &path2)) { | ||
503 | path2 = make_absolute(path2, *pwd); | ||
504 | printf("Uploading %s\n", g.gl_pathv[i]); | ||
505 | if (do_upload(in, out, g.gl_pathv[i], | ||
506 | path2, pflag) == -1) | ||
507 | err = -1; | ||
508 | free(path2); | ||
509 | path2 = NULL; | ||
510 | } else | ||
511 | err = -1; | ||
512 | } | ||
513 | } else { | ||
514 | if (!path2 && infer_path(path1, &path2)) { | ||
515 | err = -1; | ||
516 | break; | ||
517 | } | ||
518 | err = do_upload(in, out, path1, path2, pflag); | ||
519 | } | ||
520 | break; | ||
521 | case I_RENAME: | ||
476 | path1 = make_absolute(path1, *pwd); | 522 | path1 = make_absolute(path1, *pwd); |
477 | path2 = make_absolute(path2, *pwd); | 523 | path2 = make_absolute(path2, *pwd); |
478 | err = do_rename(in, out, path1, path2); | 524 | err = do_rename(in, out, path1, path2); |
@@ -489,7 +535,12 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
489 | break; | 535 | break; |
490 | case I_RM: | 536 | case I_RM: |
491 | path1 = make_absolute(path1, *pwd); | 537 | path1 = make_absolute(path1, *pwd); |
492 | err = do_rm(in, out, path1); | 538 | remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
539 | for(i = 0; g.gl_pathv[i]; i++) { | ||
540 | printf("Removing %s\n", g.gl_pathv[i]); | ||
541 | if (do_rm(in, out, g.gl_pathv[i]) == -1) | ||
542 | err = -1; | ||
543 | } | ||
493 | break; | 544 | break; |
494 | case I_MKDIR: | 545 | case I_MKDIR: |
495 | path1 = make_absolute(path1, *pwd); | 546 | path1 = make_absolute(path1, *pwd); |
@@ -577,33 +628,45 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd) | |||
577 | attrib_clear(&a); | 628 | attrib_clear(&a); |
578 | a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; | 629 | a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
579 | a.perm = n_arg; | 630 | a.perm = n_arg; |
580 | do_setstat(in, out, path1, &a); | 631 | remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
632 | for(i = 0; g.gl_pathv[i]; i++) { | ||
633 | printf("Changing mode on %s\n", g.gl_pathv[i]); | ||
634 | do_setstat(in, out, g.gl_pathv[i], &a); | ||
635 | } | ||
581 | break; | 636 | break; |
582 | case I_CHOWN: | 637 | case I_CHOWN: |
583 | path1 = make_absolute(path1, *pwd); | 638 | path1 = make_absolute(path1, *pwd); |
584 | if (!(aa = do_stat(in, out, path1))) | 639 | remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
585 | break; | 640 | for(i = 0; g.gl_pathv[i]; i++) { |
586 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | 641 | if (!(aa = do_stat(in, out, g.gl_pathv[i]))) |
587 | error("Can't get current ownership of " | 642 | continue; |
588 | "remote file \"%s\"", path1); | 643 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
589 | break; | 644 | error("Can't get current ownership of " |
645 | "remote file \"%s\"", g.gl_pathv[i]); | ||
646 | continue; | ||
647 | } | ||
648 | printf("Changing owner on %s\n", g.gl_pathv[i]); | ||
649 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
650 | aa->uid = n_arg; | ||
651 | do_setstat(in, out, g.gl_pathv[i], aa); | ||
590 | } | 652 | } |
591 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
592 | aa->uid = n_arg; | ||
593 | do_setstat(in, out, path1, aa); | ||
594 | break; | 653 | break; |
595 | case I_CHGRP: | 654 | case I_CHGRP: |
596 | path1 = make_absolute(path1, *pwd); | 655 | path1 = make_absolute(path1, *pwd); |
597 | if (!(aa = do_stat(in, out, path1))) | 656 | remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
598 | break; | 657 | for(i = 0; g.gl_pathv[i]; i++) { |
599 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { | 658 | if (!(aa = do_stat(in, out, g.gl_pathv[i]))) |
600 | error("Can't get current ownership of " | 659 | continue; |
601 | "remote file \"%s\"", path1); | 660 | if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
602 | break; | 661 | error("Can't get current ownership of " |
662 | "remote file \"%s\"", g.gl_pathv[i]); | ||
663 | continue; | ||
664 | } | ||
665 | printf("Changing group on %s\n", g.gl_pathv[i]); | ||
666 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
667 | aa->gid = n_arg; | ||
668 | do_setstat(in, out, g.gl_pathv[i], aa); | ||
603 | } | 669 | } |
604 | aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; | ||
605 | aa->gid = n_arg; | ||
606 | do_setstat(in, out, path1, aa); | ||
607 | break; | 670 | break; |
608 | case I_PWD: | 671 | case I_PWD: |
609 | printf("Remote working directory: %s\n", *pwd); | 672 | printf("Remote working directory: %s\n", *pwd); |