diff options
Diffstat (limited to 'sftp-int.c')
-rw-r--r-- | sftp-int.c | 217 |
1 files changed, 87 insertions, 130 deletions
diff --git a/sftp-int.c b/sftp-int.c index 94299aa43..6987de9a3 100644 --- a/sftp-int.c +++ b/sftp-int.c | |||
@@ -25,7 +25,7 @@ | |||
25 | /* XXX: recursive operations */ | 25 | /* XXX: recursive operations */ |
26 | 26 | ||
27 | #include "includes.h" | 27 | #include "includes.h" |
28 | RCSID("$OpenBSD: sftp-int.c,v 1.62 2003/08/25 08:13:09 fgsch Exp $"); | 28 | RCSID("$OpenBSD: sftp-int.c,v 1.57 2003/03/05 22:33:43 markus Exp $"); |
29 | 29 | ||
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
@@ -53,10 +53,6 @@ int showprogress = 1; | |||
53 | /* Seperators for interactive commands */ | 53 | /* Seperators for interactive commands */ |
54 | #define WHITESPACE " \t\r\n" | 54 | #define WHITESPACE " \t\r\n" |
55 | 55 | ||
56 | /* Define what type of ls view (0 - multi-column) */ | ||
57 | #define LONG_VIEW 1 /* Full view ala ls -l */ | ||
58 | #define SHORT_VIEW 2 /* Single row view ala ls -1 */ | ||
59 | |||
60 | /* Commands for interactive mode */ | 56 | /* Commands for interactive mode */ |
61 | #define I_CHDIR 1 | 57 | #define I_CHDIR 1 |
62 | #define I_CHGRP 2 | 58 | #define I_CHGRP 2 |
@@ -311,10 +307,7 @@ parse_ls_flags(const char **cpp, int *lflag) | |||
311 | for(; strchr(WHITESPACE, *cp) == NULL; cp++) { | 307 | for(; strchr(WHITESPACE, *cp) == NULL; cp++) { |
312 | switch (*cp) { | 308 | switch (*cp) { |
313 | case 'l': | 309 | case 'l': |
314 | *lflag = LONG_VIEW; | 310 | *lflag = 1; |
315 | break; | ||
316 | case '1': | ||
317 | *lflag = SHORT_VIEW; | ||
318 | break; | 311 | break; |
319 | default: | 312 | default: |
320 | error("Invalid flag -%c", *cp); | 313 | error("Invalid flag -%c", *cp); |
@@ -332,7 +325,7 @@ get_pathname(const char **cpp, char **path) | |||
332 | { | 325 | { |
333 | const char *cp = *cpp, *end; | 326 | const char *cp = *cpp, *end; |
334 | char quot; | 327 | char quot; |
335 | int i, j; | 328 | int i; |
336 | 329 | ||
337 | cp += strspn(cp, WHITESPACE); | 330 | cp += strspn(cp, WHITESPACE); |
338 | if (!*cp) { | 331 | if (!*cp) { |
@@ -341,54 +334,37 @@ get_pathname(const char **cpp, char **path) | |||
341 | return (0); | 334 | return (0); |
342 | } | 335 | } |
343 | 336 | ||
344 | *path = xmalloc(strlen(cp) + 1); | ||
345 | |||
346 | /* Check for quoted filenames */ | 337 | /* Check for quoted filenames */ |
347 | if (*cp == '\"' || *cp == '\'') { | 338 | if (*cp == '\"' || *cp == '\'') { |
348 | quot = *cp++; | 339 | quot = *cp++; |
349 | 340 | ||
350 | /* Search for terminating quote, unescape some chars */ | 341 | end = strchr(cp, quot); |
351 | for (i = j = 0; i <= strlen(cp); i++) { | 342 | if (end == NULL) { |
352 | if (cp[i] == quot) { /* Found quote */ | 343 | error("Unterminated quote"); |
353 | (*path)[j] = '\0'; | 344 | goto fail; |
354 | break; | ||
355 | } | ||
356 | if (cp[i] == '\0') { /* End of string */ | ||
357 | error("Unterminated quote"); | ||
358 | goto fail; | ||
359 | } | ||
360 | if (cp[i] == '\\') { /* Escaped characters */ | ||
361 | i++; | ||
362 | if (cp[i] != '\'' && cp[i] != '\"' && | ||
363 | cp[i] != '\\') { | ||
364 | error("Bad escaped character '\%c'", | ||
365 | cp[i]); | ||
366 | goto fail; | ||
367 | } | ||
368 | } | ||
369 | (*path)[j++] = cp[i]; | ||
370 | } | 345 | } |
371 | 346 | if (cp == end) { | |
372 | if (j == 0) { | ||
373 | error("Empty quotes"); | 347 | error("Empty quotes"); |
374 | goto fail; | 348 | goto fail; |
375 | } | 349 | } |
376 | *cpp = cp + i + strspn(cp + i, WHITESPACE); | 350 | *cpp = end + 1 + strspn(end + 1, WHITESPACE); |
377 | } else { | 351 | } else { |
378 | /* Read to end of filename */ | 352 | /* Read to end of filename */ |
379 | end = strpbrk(cp, WHITESPACE); | 353 | end = strpbrk(cp, WHITESPACE); |
380 | if (end == NULL) | 354 | if (end == NULL) |
381 | end = strchr(cp, '\0'); | 355 | end = strchr(cp, '\0'); |
382 | *cpp = end + strspn(end, WHITESPACE); | 356 | *cpp = end + strspn(end, WHITESPACE); |
383 | |||
384 | memcpy(*path, cp, end - cp); | ||
385 | (*path)[end - cp] = '\0'; | ||
386 | } | 357 | } |
387 | return (0); | 358 | |
359 | i = end - cp; | ||
360 | |||
361 | *path = xmalloc(i + 1); | ||
362 | memcpy(*path, cp, i); | ||
363 | (*path)[i] = '\0'; | ||
364 | return(0); | ||
388 | 365 | ||
389 | fail: | 366 | fail: |
390 | xfree(*path); | 367 | *path = NULL; |
391 | *path = NULL; | ||
392 | return (-1); | 368 | return (-1); |
393 | } | 369 | } |
394 | 370 | ||
@@ -449,8 +425,29 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
449 | goto out; | 425 | goto out; |
450 | } | 426 | } |
451 | 427 | ||
452 | /* If multiple matches, dst must be a directory or unspecified */ | 428 | /* Only one match, dst may be file, directory or unspecified */ |
453 | if (g.gl_matchc > 1 && dst && !is_dir(dst)) { | 429 | if (g.gl_pathv[0] && g.gl_matchc == 1) { |
430 | if (dst) { | ||
431 | /* If directory specified, append filename */ | ||
432 | if (is_dir(dst)) { | ||
433 | if (infer_path(g.gl_pathv[0], &tmp)) { | ||
434 | err = 1; | ||
435 | goto out; | ||
436 | } | ||
437 | abs_dst = path_append(dst, tmp); | ||
438 | xfree(tmp); | ||
439 | } else | ||
440 | abs_dst = xstrdup(dst); | ||
441 | } else if (infer_path(g.gl_pathv[0], &abs_dst)) { | ||
442 | err = -1; | ||
443 | goto out; | ||
444 | } | ||
445 | err = do_download(conn, g.gl_pathv[0], abs_dst, pflag); | ||
446 | goto out; | ||
447 | } | ||
448 | |||
449 | /* Multiple matches, dst may be directory or unspecified */ | ||
450 | if (dst && !is_dir(dst)) { | ||
454 | error("Multiple files match, but \"%s\" is not a directory", | 451 | error("Multiple files match, but \"%s\" is not a directory", |
455 | dst); | 452 | dst); |
456 | err = -1; | 453 | err = -1; |
@@ -462,19 +459,7 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
462 | err = -1; | 459 | err = -1; |
463 | goto out; | 460 | goto out; |
464 | } | 461 | } |
465 | 462 | if (dst) { | |
466 | if (g.gl_matchc == 1 && dst) { | ||
467 | /* If directory specified, append filename */ | ||
468 | if (is_dir(dst)) { | ||
469 | if (infer_path(g.gl_pathv[0], &tmp)) { | ||
470 | err = 1; | ||
471 | goto out; | ||
472 | } | ||
473 | abs_dst = path_append(dst, tmp); | ||
474 | xfree(tmp); | ||
475 | } else | ||
476 | abs_dst = xstrdup(dst); | ||
477 | } else if (dst) { | ||
478 | abs_dst = path_append(dst, tmp); | 463 | abs_dst = path_append(dst, tmp); |
479 | xfree(tmp); | 464 | xfree(tmp); |
480 | } else | 465 | } else |
@@ -518,8 +503,38 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
518 | goto out; | 503 | goto out; |
519 | } | 504 | } |
520 | 505 | ||
521 | /* If multiple matches, dst may be directory or unspecified */ | 506 | /* Only one match, dst may be file, directory or unspecified */ |
522 | if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) { | 507 | if (g.gl_pathv[0] && g.gl_matchc == 1) { |
508 | if (!is_reg(g.gl_pathv[0])) { | ||
509 | error("Can't upload %s: not a regular file", | ||
510 | g.gl_pathv[0]); | ||
511 | err = 1; | ||
512 | goto out; | ||
513 | } | ||
514 | if (tmp_dst) { | ||
515 | /* If directory specified, append filename */ | ||
516 | if (remote_is_dir(conn, tmp_dst)) { | ||
517 | if (infer_path(g.gl_pathv[0], &tmp)) { | ||
518 | err = 1; | ||
519 | goto out; | ||
520 | } | ||
521 | abs_dst = path_append(tmp_dst, tmp); | ||
522 | xfree(tmp); | ||
523 | } else | ||
524 | abs_dst = xstrdup(tmp_dst); | ||
525 | } else { | ||
526 | if (infer_path(g.gl_pathv[0], &abs_dst)) { | ||
527 | err = -1; | ||
528 | goto out; | ||
529 | } | ||
530 | abs_dst = make_absolute(abs_dst, pwd); | ||
531 | } | ||
532 | err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag); | ||
533 | goto out; | ||
534 | } | ||
535 | |||
536 | /* Multiple matches, dst may be directory or unspecified */ | ||
537 | if (tmp_dst && !remote_is_dir(conn, tmp_dst)) { | ||
523 | error("Multiple files match, but \"%s\" is not a directory", | 538 | error("Multiple files match, but \"%s\" is not a directory", |
524 | tmp_dst); | 539 | tmp_dst); |
525 | err = -1; | 540 | err = -1; |
@@ -536,20 +551,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag) | |||
536 | err = -1; | 551 | err = -1; |
537 | goto out; | 552 | goto out; |
538 | } | 553 | } |
539 | 554 | if (tmp_dst) { | |
540 | if (g.gl_matchc == 1 && tmp_dst) { | ||
541 | /* If directory specified, append filename */ | ||
542 | if (remote_is_dir(conn, tmp_dst)) { | ||
543 | if (infer_path(g.gl_pathv[0], &tmp)) { | ||
544 | err = 1; | ||
545 | goto out; | ||
546 | } | ||
547 | abs_dst = path_append(tmp_dst, tmp); | ||
548 | xfree(tmp); | ||
549 | } else | ||
550 | abs_dst = xstrdup(tmp_dst); | ||
551 | |||
552 | } else if (tmp_dst) { | ||
553 | abs_dst = path_append(tmp_dst, tmp); | 555 | abs_dst = path_append(tmp_dst, tmp); |
554 | xfree(tmp); | 556 | xfree(tmp); |
555 | } else | 557 | } else |
@@ -565,7 +567,6 @@ out: | |||
565 | xfree(abs_dst); | 567 | xfree(abs_dst); |
566 | if (tmp_dst) | 568 | if (tmp_dst) |
567 | xfree(tmp_dst); | 569 | xfree(tmp_dst); |
568 | globfree(&g); | ||
569 | return(err); | 570 | return(err); |
570 | } | 571 | } |
571 | 572 | ||
@@ -582,27 +583,15 @@ sdirent_comp(const void *aa, const void *bb) | |||
582 | static int | 583 | static int |
583 | do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | 584 | do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) |
584 | { | 585 | { |
585 | int n, c = 1, colspace = 0, columns = 1; | 586 | int n; |
586 | SFTP_DIRENT **d; | 587 | SFTP_DIRENT **d; |
587 | 588 | ||
588 | if ((n = do_readdir(conn, path, &d)) != 0) | 589 | if ((n = do_readdir(conn, path, &d)) != 0) |
589 | return (n); | 590 | return (n); |
590 | 591 | ||
591 | if (!(lflag & SHORT_VIEW)) { | 592 | /* Count entries for sort */ |
592 | int m = 0, width = 80; | 593 | for (n = 0; d[n] != NULL; n++) |
593 | struct winsize ws; | 594 | ; |
594 | |||
595 | /* Count entries for sort and find longest filename */ | ||
596 | for (n = 0; d[n] != NULL; n++) | ||
597 | m = MAX(m, strlen(d[n]->filename)); | ||
598 | |||
599 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) | ||
600 | width = ws.ws_col; | ||
601 | |||
602 | columns = width / (m + 2); | ||
603 | columns = MAX(columns, 1); | ||
604 | colspace = width / columns; | ||
605 | } | ||
606 | 595 | ||
607 | qsort(d, n, sizeof(*d), sdirent_comp); | 596 | qsort(d, n, sizeof(*d), sdirent_comp); |
608 | 597 | ||
@@ -613,7 +602,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
613 | fname = path_strip(tmp, strip_path); | 602 | fname = path_strip(tmp, strip_path); |
614 | xfree(tmp); | 603 | xfree(tmp); |
615 | 604 | ||
616 | if (lflag & LONG_VIEW) { | 605 | if (lflag) { |
617 | char *lname; | 606 | char *lname; |
618 | struct stat sb; | 607 | struct stat sb; |
619 | 608 | ||
@@ -623,20 +612,13 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag) | |||
623 | printf("%s\n", lname); | 612 | printf("%s\n", lname); |
624 | xfree(lname); | 613 | xfree(lname); |
625 | } else { | 614 | } else { |
626 | printf("%-*s", colspace, fname); | 615 | /* XXX - multicolumn display would be nice here */ |
627 | if (c >= columns) { | 616 | printf("%s\n", fname); |
628 | printf("\n"); | ||
629 | c = 1; | ||
630 | } else | ||
631 | c++; | ||
632 | } | 617 | } |
633 | 618 | ||
634 | xfree(fname); | 619 | xfree(fname); |
635 | } | 620 | } |
636 | 621 | ||
637 | if (!(lflag & LONG_VIEW) && (c != 1)) | ||
638 | printf("\n"); | ||
639 | |||
640 | free_sftp_dirents(d); | 622 | free_sftp_dirents(d); |
641 | return (0); | 623 | return (0); |
642 | } | 624 | } |
@@ -647,8 +629,9 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
647 | int lflag) | 629 | int lflag) |
648 | { | 630 | { |
649 | glob_t g; | 631 | glob_t g; |
650 | int i, c = 1, colspace = 0, columns = 1; | 632 | int i; |
651 | Attrib *a; | 633 | Attrib *a; |
634 | struct stat sb; | ||
652 | 635 | ||
653 | memset(&g, 0, sizeof(g)); | 636 | memset(&g, 0, sizeof(g)); |
654 | 637 | ||
@@ -675,31 +658,12 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
675 | } | 658 | } |
676 | } | 659 | } |
677 | 660 | ||
678 | if (!(lflag & SHORT_VIEW)) { | ||
679 | int m = 0, width = 80; | ||
680 | struct winsize ws; | ||
681 | |||
682 | /* Count entries for sort and find longest filename */ | ||
683 | for (i = 0; g.gl_pathv[i]; i++) | ||
684 | m = MAX(m, strlen(g.gl_pathv[i])); | ||
685 | |||
686 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) | ||
687 | width = ws.ws_col; | ||
688 | |||
689 | columns = width / (m + 2); | ||
690 | columns = MAX(columns, 1); | ||
691 | colspace = width / columns; | ||
692 | } | ||
693 | |||
694 | for (i = 0; g.gl_pathv[i]; i++) { | 661 | for (i = 0; g.gl_pathv[i]; i++) { |
695 | char *fname; | 662 | char *fname, *lname; |
696 | 663 | ||
697 | fname = path_strip(g.gl_pathv[i], strip_path); | 664 | fname = path_strip(g.gl_pathv[i], strip_path); |
698 | 665 | ||
699 | if (lflag & LONG_VIEW) { | 666 | if (lflag) { |
700 | char *lname; | ||
701 | struct stat sb; | ||
702 | |||
703 | /* | 667 | /* |
704 | * XXX: this is slow - 1 roundtrip per path | 668 | * XXX: this is slow - 1 roundtrip per path |
705 | * A solution to this is to fork glob() and | 669 | * A solution to this is to fork glob() and |
@@ -715,19 +679,12 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
715 | printf("%s\n", lname); | 679 | printf("%s\n", lname); |
716 | xfree(lname); | 680 | xfree(lname); |
717 | } else { | 681 | } else { |
718 | printf("%-*s", colspace, fname); | 682 | /* XXX - multicolumn display would be nice here */ |
719 | if (c >= columns) { | 683 | printf("%s\n", fname); |
720 | printf("\n"); | ||
721 | c = 1; | ||
722 | } else | ||
723 | c++; | ||
724 | } | 684 | } |
725 | xfree(fname); | 685 | xfree(fname); |
726 | } | 686 | } |
727 | 687 | ||
728 | if (!(lflag & LONG_VIEW) && (c != 1)) | ||
729 | printf("\n"); | ||
730 | |||
731 | if (g.gl_pathc) | 688 | if (g.gl_pathc) |
732 | globfree(&g); | 689 | globfree(&g); |
733 | 690 | ||