diff options
Diffstat (limited to 'sftp-int.c')
-rw-r--r-- | sftp-int.c | 288 |
1 files changed, 216 insertions, 72 deletions
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" |
29 | RCSID("$OpenBSD: sftp-int.c,v 1.28 2001/03/14 15:15:58 markus Exp $"); | 29 | RCSID("$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 | ||
197 | char * | 197 | char * |
198 | path_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 | |||
210 | char * | ||
198 | make_absolute(char *p, char *pwd) | 211 | make_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 | |||
224 | int | ||
225 | infer_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 | ||
212 | int | 244 | int |
@@ -281,23 +313,182 @@ get_pathname(const char **cpp, char **path) | |||
281 | } | 313 | } |
282 | 314 | ||
283 | int | 315 | int |
284 | infer_path(const char *p, char **ifp) | 316 | is_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 | |||
327 | int | ||
328 | remote_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 | |||
340 | int | ||
341 | process_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 | |||
409 | out: | ||
410 | xfree(abs_src); | ||
411 | if (abs_dst) | ||
412 | xfree(abs_dst); | ||
413 | globfree(&g); | ||
414 | return(err); | ||
415 | } | ||
416 | |||
417 | int | ||
418 | process_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 | |||
486 | out: | ||
487 | if (abs_dst) | ||
488 | xfree(abs_dst); | ||
489 | if (tmp_dst) | ||
490 | xfree(tmp_dst); | ||
491 | return(err); | ||
301 | } | 492 | } |
302 | 493 | ||
303 | int | 494 | int |
@@ -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) |