summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2001-03-14 10:27:09 +1100
committerDamien Miller <djm@mindrot.org>2001-03-14 10:27:09 +1100
commit4870afd7c73a605778794378915eab0c26e8c353 (patch)
tree76d93d5002452636a8884c83ba0aba2f6c0a3f58
parent056ddf7af3504a688c34f2daf50bcd20abfef3ba (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--ChangeLog5
-rw-r--r--Makefile.in6
-rw-r--r--sftp-client.c53
-rw-r--r--sftp-client.h16
-rw-r--r--sftp-glob.c160
-rw-r--r--sftp-glob.h32
-rw-r--r--sftp-int.c133
7 files changed, 361 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index 13e1f3606..99ed4d03d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
720010313 1020010313
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
3prefix=@prefix@ 3prefix=@prefix@
4exec_prefix=@exec_prefix@ 4exec_prefix=@exec_prefix@
@@ -116,8 +116,8 @@ ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a log.o ssh-keyscan.o
116sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o log.o sftp-server.o 116sftp-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
119sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-int.o sftp-common.o 119sftp$(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
123logintest: logintest.o $(LIBCOMPAT) libssh.a log.o loginrec.o 123logintest: 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"
32RCSID("$OpenBSD: sftp-client.c,v 1.11 2001/03/07 10:11:22 djm Exp $"); 32RCSID("$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
278int 279int
279do_ls(int fd_in, int fd_out, char *path) 280do_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
367int 387int
388do_ls(int fd_in, int fd_out, char *path)
389{
390 return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
391}
392
393int
394do_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
399void 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
411int
368do_rm(int fd_in, int fd_out, char *path) 412do_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
29typedef struct SFTP_DIRENT SFTP_DIRENT;
30
31struct 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 */
39int do_ls(int fd_in, int fd_out, char *path); 47int do_ls(int fd_in, int fd_out, char *path);
40 48
49/* Read contents of 'path' to NULL-terminated array 'dir' */
50int 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) */
53void free_sftp_dirents(SFTP_DIRENT **s);
54
41/* Delete file 'path' */ 55/* Delete file 'path' */
42int do_rm(int fd_in, int fd_out, char *path); 56int 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"
26RCSID("$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
44struct SFTP_OPENDIR {
45 SFTP_DIRENT **dir;
46 int offset;
47};
48
49static struct {
50 int fd_in;
51 int fd_out;
52} cur;
53
54void *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
68struct 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
96void fudge_closedir(struct SFTP_OPENDIR *od)
97{
98 free_sftp_dirents(od->dir);
99 free(od);
100}
101
102void 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
120int 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
132int 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
144int
145remote_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
29int
30remote_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"
31RCSID("$OpenBSD: sftp-int.c,v 1.26 2001/03/07 10:11:23 djm Exp $"); 29RCSID("$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
451parse_dispatch_command(int in, int out, const char *cmd, char **pwd) 447parse_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);