summaryrefslogtreecommitdiff
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 191ee72e8..7f972e306 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,10 @@
8 - markus@cvs.openbsd.org 2001/03/15 22:07:08 8 - markus@cvs.openbsd.org 2001/03/15 22:07:08
9 [session.c] 9 [session.c]
10 pass Session to do_child + KNF 10 pass Session to do_child + KNF
11 - djm@cvs.openbsd.org 2001/03/16 08:16:18
12 [sftp-client.c sftp-client.h sftp-glob.c sftp-int.c]
13 Revise globbing for get/put to be more shell-like. In particular,
14 "get/put file* directory/" now works. ok markus@
11 15
1220010315 1620010315
13 - OpenBSD CVS Sync 17 - OpenBSD CVS Sync
@@ -4570,4 +4574,4 @@
4570 - Wrote replacements for strlcpy and mkdtemp 4574 - Wrote replacements for strlcpy and mkdtemp
4571 - Released 1.0pre1 4575 - Released 1.0pre1
4572 4576
4573$Id: ChangeLog,v 1.963 2001/03/17 00:32:57 mouring Exp $ 4577$Id: ChangeLog,v 1.964 2001/03/17 00:34:46 mouring Exp $
diff --git a/sftp-client.c b/sftp-client.c
index 87f3053f6..b0007a734 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.13 2001/03/14 08:57:14 markus Exp $"); 32RCSID("$OpenBSD: sftp-client.c,v 1.14 2001/03/16 08:16:17 djm Exp $");
33 33
34#include "ssh.h" 34#include "ssh.h"
35#include "buffer.h" 35#include "buffer.h"
@@ -180,7 +180,7 @@ get_handle(int fd, u_int expected_id, u_int *len)
180} 180}
181 181
182Attrib * 182Attrib *
183get_decode_stat(int fd, u_int expected_id) 183get_decode_stat(int fd, u_int expected_id, int quiet)
184{ 184{
185 Buffer msg; 185 Buffer msg;
186 u_int type, id; 186 u_int type, id;
@@ -198,7 +198,10 @@ get_decode_stat(int fd, u_int expected_id)
198 if (type == SSH2_FXP_STATUS) { 198 if (type == SSH2_FXP_STATUS) {
199 int status = buffer_get_int(&msg); 199 int status = buffer_get_int(&msg);
200 200
201 error("Couldn't stat remote file: %s", fx2txt(status)); 201 if (quiet)
202 debug("Couldn't stat remote file: %s", fx2txt(status));
203 else
204 error("Couldn't stat remote file: %s", fx2txt(status));
202 return(NULL); 205 return(NULL);
203 } else if (type != SSH2_FXP_ATTRS) { 206 } else if (type != SSH2_FXP_ATTRS) {
204 fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d", 207 fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
@@ -455,34 +458,33 @@ do_rmdir(int fd_in, int fd_out, char *path)
455} 458}
456 459
457Attrib * 460Attrib *
458do_stat(int fd_in, int fd_out, char *path) 461do_stat(int fd_in, int fd_out, char *path, int quiet)
459{ 462{
460 u_int id; 463 u_int id;
461 464
462 id = msg_id++; 465 id = msg_id++;
463 send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path)); 466 send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
464 return(get_decode_stat(fd_in, id)); 467 return(get_decode_stat(fd_in, id, quiet));
465} 468}
466 469
467Attrib * 470Attrib *
468do_lstat(int fd_in, int fd_out, char *path) 471do_lstat(int fd_in, int fd_out, char *path, int quiet)
469{ 472{
470 u_int id; 473 u_int id;
471 474
472 id = msg_id++; 475 id = msg_id++;
473 send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path)); 476 send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
474 return(get_decode_stat(fd_in, id)); 477 return(get_decode_stat(fd_in, id, quiet));
475} 478}
476 479
477Attrib * 480Attrib *
478do_fstat(int fd_in, int fd_out, char *handle, 481do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
479 u_int handle_len)
480{ 482{
481 u_int id; 483 u_int id;
482 484
483 id = msg_id++; 485 id = msg_id++;
484 send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len); 486 send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
485 return(get_decode_stat(fd_in, id)); 487 return(get_decode_stat(fd_in, id, quiet));
486} 488}
487 489
488int 490int
@@ -677,7 +679,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
677 Attrib junk, *a; 679 Attrib junk, *a;
678 int status; 680 int status;
679 681
680 a = do_stat(fd_in, fd_out, remote_path); 682 a = do_stat(fd_in, fd_out, remote_path, 0);
681 if (a == NULL) 683 if (a == NULL)
682 return(-1); 684 return(-1);
683 685
@@ -687,11 +689,17 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
687 else 689 else
688 mode = 0666; 690 mode = 0666;
689 691
692 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
693 (a->perm & S_IFDIR)) {
694 error("Cannot download a directory: %s", remote_path);
695 return(-1);
696 }
697
690 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); 698 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
691 if (local_fd == -1) { 699 if (local_fd == -1) {
692 error("Couldn't open local file \"%s\" for writing: %s", 700 error("Couldn't open local file \"%s\" for writing: %s",
693 local_path, strerror(errno)); 701 local_path, strerror(errno));
694 return(errno); 702 return(-1);
695 } 703 }
696 704
697 buffer_init(&msg); 705 buffer_init(&msg);
diff --git a/sftp-client.h b/sftp-client.h
index e7ba02ad6..a935736e3 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.h,v 1.3 2001/03/13 22:42:54 djm Exp $ */ 1/* $OpenBSD: sftp-client.h,v 1.4 2001/03/16 08:16:18 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001 Damien Miller. All rights reserved. 4 * 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);
62int do_rmdir(int fd_in, int fd_out, char *path); 62int do_rmdir(int fd_in, int fd_out, char *path);
63 63
64/* Get file attributes of 'path' (follows symlinks) */ 64/* Get file attributes of 'path' (follows symlinks) */
65Attrib *do_stat(int fd_in, int fd_out, char *path); 65Attrib *do_stat(int fd_in, int fd_out, char *path, int quiet);
66 66
67/* Get file attributes of 'path' (does not follow symlinks) */ 67/* Get file attributes of 'path' (does not follow symlinks) */
68Attrib *do_lstat(int fd_in, int fd_out, char *path); 68Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet);
69 69
70/* Get file attributes of open file 'handle' */ 70/* Get file attributes of open file 'handle' */
71Attrib *do_fstat(int fd_in, int fd_out, char *handle, 71Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len,
72 u_int handle_len); 72 int quiet);
73 73
74/* Set file attributes of 'path' */ 74/* Set file attributes of 'path' */
75int do_setstat(int fd_in, int fd_out, char *path, Attrib *a); 75int do_setstat(int fd_in, int fd_out, char *path, Attrib *a);
diff --git a/sftp-glob.c b/sftp-glob.c
index aec6d2734..79dca00f1 100644
--- a/sftp-glob.c
+++ b/sftp-glob.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: sftp-glob.c,v 1.1 2001/03/13 22:42:54 djm Exp $"); 26RCSID("$OpenBSD: sftp-glob.c,v 1.2 2001/03/16 08:16:18 djm Exp $");
27 27
28#include "ssh.h" 28#include "ssh.h"
29#include "buffer.h" 29#include "buffer.h"
@@ -119,7 +119,7 @@ int fudge_lstat(const char *path, struct stat *st)
119{ 119{
120 Attrib *a; 120 Attrib *a;
121 121
122 if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path))) 122 if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
123 return(-1); 123 return(-1);
124 124
125 attrib_to_stat(a, st); 125 attrib_to_stat(a, st);
@@ -131,7 +131,7 @@ int fudge_stat(const char *path, struct stat *st)
131{ 131{
132 Attrib *a; 132 Attrib *a;
133 133
134 if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path))) 134 if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
135 return(-1); 135 return(-1);
136 136
137 attrib_to_stat(a, st); 137 attrib_to_stat(a, st);
diff --git a/sftp-int.c b/sftp-int.c
index cf86012ea..fdadf23b2 100644
--- a/sftp-int.c
+++ b/sftp-int.c
@@ -26,7 +26,7 @@
26/* XXX: recursive operations */ 26/* XXX: recursive operations */
27 27
28#include "includes.h" 28#include "includes.h"
29RCSID("$OpenBSD: sftp-int.c,v 1.28 2001/03/14 15:15:58 markus Exp $"); 29RCSID("$OpenBSD: sftp-int.c,v 1.29 2001/03/16 08:16:18 djm Exp $");
30 30
31#include "buffer.h" 31#include "buffer.h"
32#include "xmalloc.h" 32#include "xmalloc.h"
@@ -195,18 +195,50 @@ local_do_ls(const char *args)
195} 195}
196 196
197char * 197char *
198path_append(char *p1, char *p2)
199{
200 char *ret;
201
202 ret = xmalloc(strlen(p1) + strlen(p2) + 2);
203 strcpy(ret, p1);
204 strcat(ret, "/");
205 strcat(ret, p2);
206
207 return(ret);
208}
209
210char *
198make_absolute(char *p, char *pwd) 211make_absolute(char *p, char *pwd)
199{ 212{
200 char buf[2048]; 213 char *abs;
201 214
202 /* Derelativise */ 215 /* Derelativise */
203 if (p && p[0] != '/') { 216 if (p && p[0] != '/') {
204 snprintf(buf, sizeof(buf), "%s/%s", pwd, p); 217 abs = path_append(pwd, p);
205 xfree(p); 218 xfree(p);
206 p = xstrdup(buf); 219 return(abs);
220 } else
221 return(p);
222}
223
224int
225infer_path(const char *p, char **ifp)
226{
227 char *cp;
228
229 cp = strrchr(p, '/');
230 if (cp == NULL) {
231 *ifp = xstrdup(p);
232 return(0);
233 }
234
235 if (!cp[1]) {
236 error("Invalid path");
237 return(-1);
207 } 238 }
208 239
209 return(p); 240 *ifp = xstrdup(cp + 1);
241 return(0);
210} 242}
211 243
212int 244int
@@ -281,23 +313,182 @@ get_pathname(const char **cpp, char **path)
281} 313}
282 314
283int 315int
284infer_path(const char *p, char **ifp) 316is_dir(char *path)
285{ 317{
286 char *cp; 318 struct stat sb;
287 319
288 cp = strrchr(p, '/'); 320 /* XXX: report errors? */
289 if (cp == NULL) { 321 if (stat(path, &sb) == -1)
290 *ifp = xstrdup(p);
291 return(0); 322 return(0);
323
324 return(sb.st_mode & S_IFDIR);
325}
326
327int
328remote_is_dir(int in, int out, char *path)
329{
330 Attrib *a;
331
332 /* XXX: report errors? */
333 if ((a = do_stat(in, out, path, 1)) == NULL)
334 return(0);
335 if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
336 return(0);
337 return(a->perm & S_IFDIR);
338}
339
340int
341process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
342{
343 char *abs_src = NULL;
344 char *abs_dst = NULL;
345 char *tmp;
346 glob_t g;
347 int err = 0;
348 int i;
349
350 abs_src = xstrdup(src);
351 abs_src = make_absolute(abs_src, pwd);
352
353 memset(&g, '\0', sizeof(g));
354 debug3("Looking up %s", abs_src);
355 if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
356 error("File \"%s\" not found.", abs_src);
357 err = -1;
358 goto out;
292 } 359 }
293 360
294 if (!cp[1]) { 361 /* Only one match, dst may be file, directory or unspecified */
295 error("Invalid path"); 362 if (g.gl_pathv[0] && g.gl_matchc == 1) {
296 return(-1); 363 if (dst) {
364 /* If directory specified, append filename */
365 if (is_dir(dst)) {
366 if (infer_path(g.gl_pathv[0], &tmp)) {
367 err = 1;
368 goto out;
369 }
370 abs_dst = path_append(dst, tmp);
371 xfree(tmp);
372 } else
373 abs_dst = xstrdup(dst);
374 } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
375 err = -1;
376 goto out;
377 }
378 printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
379 err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
380 goto out;
297 } 381 }
298 382
299 *ifp = xstrdup(cp + 1); 383 /* Multiple matches, dst may be directory or unspecified */
300 return(0); 384 if (dst && !is_dir(dst)) {
385 error("Multiple files match, but \"%s\" is not a directory",
386 dst);
387 err = -1;
388 goto out;
389 }
390
391 for(i = 0; g.gl_pathv[i]; i++) {
392 if (infer_path(g.gl_pathv[i], &tmp)) {
393 err = -1;
394 goto out;
395 }
396 if (dst) {
397 abs_dst = path_append(dst, tmp);
398 xfree(tmp);
399 } else
400 abs_dst = tmp;
401
402 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
403 if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
404 err = -1;
405 xfree(abs_dst);
406 abs_dst = NULL;
407 }
408
409out:
410 xfree(abs_src);
411 if (abs_dst)
412 xfree(abs_dst);
413 globfree(&g);
414 return(err);
415}
416
417int
418process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
419{
420 char *tmp_dst = NULL;
421 char *abs_dst = NULL;
422 char *tmp;
423 glob_t g;
424 int err = 0;
425 int i;
426
427 if (dst) {
428 tmp_dst = xstrdup(dst);
429 tmp_dst = make_absolute(tmp_dst, pwd);
430 }
431
432 memset(&g, '\0', sizeof(g));
433 debug3("Looking up %s", src);
434 if (glob(src, 0, NULL, &g)) {
435 error("File \"%s\" not found.", src);
436 err = -1;
437 goto out;
438 }
439
440 /* Only one match, dst may be file, directory or unspecified */
441 if (g.gl_pathv[0] && g.gl_matchc == 1) {
442 if (tmp_dst) {
443 /* If directory specified, append filename */
444 if (remote_is_dir(in, out, tmp_dst)) {
445 if (infer_path(g.gl_pathv[0], &tmp)) {
446 err = 1;
447 goto out;
448 }
449 abs_dst = path_append(tmp_dst, tmp);
450 xfree(tmp);
451 } else
452 abs_dst = xstrdup(tmp_dst);
453 } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
454 err = -1;
455 goto out;
456 }
457 printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
458 err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
459 goto out;
460 }
461
462 /* Multiple matches, dst may be directory or unspecified */
463 if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
464 error("Multiple files match, but \"%s\" is not a directory",
465 tmp_dst);
466 err = -1;
467 goto out;
468 }
469
470 for(i = 0; g.gl_pathv[i]; i++) {
471 if (infer_path(g.gl_pathv[i], &tmp)) {
472 err = -1;
473 goto out;
474 }
475 if (tmp_dst) {
476 abs_dst = path_append(tmp_dst, tmp);
477 xfree(tmp);
478 } else
479 abs_dst = make_absolute(tmp, pwd);
480
481 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
482 if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
483 err = -1;
484 }
485
486out:
487 if (abs_dst)
488 xfree(abs_dst);
489 if (tmp_dst)
490 xfree(tmp_dst);
491 return(err);
301} 492}
302 493
303int 494int
@@ -459,66 +650,17 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
459 path1 = path2 = NULL; 650 path1 = path2 = NULL;
460 cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); 651 cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
461 652
653 memset(&g, 0, sizeof(g));
654
462 /* Perform command */ 655 /* Perform command */
463 switch (cmdnum) { 656 switch (cmdnum) {
464 case -1: 657 case -1:
465 break; 658 break;
466 case I_GET: 659 case I_GET:
467 memset(&g, 0, sizeof(g)); 660 err = process_get(in, out, path1, path2, *pwd, pflag);
468 if (!remote_glob(in, out, path1, 0, NULL, &g)) {
469 if (path2) {
470 /* XXX: target should be directory */
471 error("You cannot specify a target when "
472 "downloading multiple files");
473 err = -1;
474 break;
475 }
476 for(i = 0; g.gl_pathv[i]; i++) {
477 if (!infer_path(g.gl_pathv[i], &path2)) {
478 printf("Fetching %s\n", g.gl_pathv[i]);
479 if (do_download(in, out, g.gl_pathv[i],
480 path2, pflag) == -1)
481 err = -1;
482 free(path2);
483 path2 = NULL;
484 } else
485 err = -1;
486 }
487 } else {
488 if (!path2 && infer_path(path1, &path2)) {
489 err = -1;
490 break;
491 }
492 err = do_download(in, out, path1, path2, pflag);
493 }
494 break; 661 break;
495 case I_PUT: 662 case I_PUT:
496 if (!glob(path1, 0, NULL, &g)) { 663 err = process_put(in, out, path1, path2, *pwd, pflag);
497 if (path2) {
498 error("You cannot specify a target when "
499 "uploading multiple files");
500 err = -1;
501 break;
502 }
503 for(i = 0; g.gl_pathv[i]; i++) {
504 if (!infer_path(g.gl_pathv[i], &path2)) {
505 path2 = make_absolute(path2, *pwd);
506 printf("Uploading %s\n", g.gl_pathv[i]);
507 if (do_upload(in, out, g.gl_pathv[i],
508 path2, pflag) == -1)
509 err = -1;
510 free(path2);
511 path2 = NULL;
512 } else
513 err = -1;
514 }
515 } else {
516 if (!path2 && infer_path(path1, &path2)) {
517 err = -1;
518 break;
519 }
520 err = do_upload(in, out, path1, path2, pflag);
521 }
522 break; 664 break;
523 case I_RENAME: 665 case I_RENAME:
524 path1 = make_absolute(path1, *pwd); 666 path1 = make_absolute(path1, *pwd);
@@ -561,7 +703,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
561 err = 1; 703 err = 1;
562 break; 704 break;
563 } 705 }
564 if ((aa = do_stat(in, out, tmp)) == NULL) { 706 if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
565 xfree(tmp); 707 xfree(tmp);
566 err = 1; 708 err = 1;
567 break; 709 break;
@@ -592,7 +734,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
592 break; 734 break;
593 xfree(path1); 735 xfree(path1);
594 path1 = tmp; 736 path1 = tmp;
595 if ((aa = do_stat(in, out, path1)) == NULL) 737 if ((aa = do_stat(in, out, path1, 0)) == NULL)
596 break; 738 break;
597 if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 739 if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
598 !S_ISDIR(aa->perm)) { 740 !S_ISDIR(aa->perm)) {
@@ -640,7 +782,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
640 path1 = make_absolute(path1, *pwd); 782 path1 = make_absolute(path1, *pwd);
641 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); 783 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
642 for(i = 0; g.gl_pathv[i]; i++) { 784 for(i = 0; g.gl_pathv[i]; i++) {
643 if (!(aa = do_stat(in, out, g.gl_pathv[i]))) 785 if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
644 continue; 786 continue;
645 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 787 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
646 error("Can't get current ownership of " 788 error("Can't get current ownership of "
@@ -657,7 +799,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
657 path1 = make_absolute(path1, *pwd); 799 path1 = make_absolute(path1, *pwd);
658 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); 800 remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
659 for(i = 0; g.gl_pathv[i]; i++) { 801 for(i = 0; g.gl_pathv[i]; i++) {
660 if (!(aa = do_stat(in, out, g.gl_pathv[i]))) 802 if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
661 continue; 803 continue;
662 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { 804 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
663 error("Can't get current ownership of " 805 error("Can't get current ownership of "
@@ -693,6 +835,8 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
693 fatal("%d is not implemented", cmdnum); 835 fatal("%d is not implemented", cmdnum);
694 } 836 }
695 837
838 if (g.gl_pathc)
839 globfree(&g);
696 if (path1) 840 if (path1)
697 xfree(path1); 841 xfree(path1);
698 if (path2) 842 if (path2)