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