diff options
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 66 |
1 files changed, 41 insertions, 25 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.158 2013/11/20 20:54:10 deraadt Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.164 2014/07/09 01:45:10 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -88,7 +88,7 @@ int showprogress = 1; | |||
88 | /* When this option is set, we always recursively download/upload directories */ | 88 | /* When this option is set, we always recursively download/upload directories */ |
89 | int global_rflag = 0; | 89 | int global_rflag = 0; |
90 | 90 | ||
91 | /* When this option is set, we resume download if possible */ | 91 | /* When this option is set, we resume download or upload if possible */ |
92 | int global_aflag = 0; | 92 | int global_aflag = 0; |
93 | 93 | ||
94 | /* When this option is set, the file transfers will always preserve times */ | 94 | /* When this option is set, the file transfers will always preserve times */ |
@@ -151,14 +151,15 @@ enum sftp_command { | |||
151 | I_PUT, | 151 | I_PUT, |
152 | I_PWD, | 152 | I_PWD, |
153 | I_QUIT, | 153 | I_QUIT, |
154 | I_REGET, | ||
154 | I_RENAME, | 155 | I_RENAME, |
156 | I_REPUT, | ||
155 | I_RM, | 157 | I_RM, |
156 | I_RMDIR, | 158 | I_RMDIR, |
157 | I_SHELL, | 159 | I_SHELL, |
158 | I_SYMLINK, | 160 | I_SYMLINK, |
159 | I_VERSION, | 161 | I_VERSION, |
160 | I_PROGRESS, | 162 | I_PROGRESS, |
161 | I_REGET, | ||
162 | }; | 163 | }; |
163 | 164 | ||
164 | struct CMD { | 165 | struct CMD { |
@@ -201,6 +202,7 @@ static const struct CMD cmds[] = { | |||
201 | { "quit", I_QUIT, NOARGS }, | 202 | { "quit", I_QUIT, NOARGS }, |
202 | { "reget", I_REGET, REMOTE }, | 203 | { "reget", I_REGET, REMOTE }, |
203 | { "rename", I_RENAME, REMOTE }, | 204 | { "rename", I_RENAME, REMOTE }, |
205 | { "reput", I_REPUT, LOCAL }, | ||
204 | { "rm", I_RM, REMOTE }, | 206 | { "rm", I_RM, REMOTE }, |
205 | { "rmdir", I_RMDIR, REMOTE }, | 207 | { "rmdir", I_RMDIR, REMOTE }, |
206 | { "symlink", I_SYMLINK, REMOTE }, | 208 | { "symlink", I_SYMLINK, REMOTE }, |
@@ -250,6 +252,7 @@ help(void) | |||
250 | "exit Quit sftp\n" | 252 | "exit Quit sftp\n" |
251 | "get [-Ppr] remote [local] Download file\n" | 253 | "get [-Ppr] remote [local] Download file\n" |
252 | "reget remote [local] Resume download file\n" | 254 | "reget remote [local] Resume download file\n" |
255 | "reput [local] remote Resume upload file\n" | ||
253 | "help Display this help text\n" | 256 | "help Display this help text\n" |
254 | "lcd path Change local directory to 'path'\n" | 257 | "lcd path Change local directory to 'path'\n" |
255 | "lls [ls-options [path]] Display local directory listing\n" | 258 | "lls [ls-options [path]] Display local directory listing\n" |
@@ -586,15 +589,19 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
586 | char *abs_dst = NULL; | 589 | char *abs_dst = NULL; |
587 | glob_t g; | 590 | glob_t g; |
588 | char *filename, *tmp=NULL; | 591 | char *filename, *tmp=NULL; |
589 | int i, err = 0; | 592 | int i, r, err = 0; |
590 | 593 | ||
591 | abs_src = xstrdup(src); | 594 | abs_src = xstrdup(src); |
592 | abs_src = make_absolute(abs_src, pwd); | 595 | abs_src = make_absolute(abs_src, pwd); |
593 | memset(&g, 0, sizeof(g)); | 596 | memset(&g, 0, sizeof(g)); |
594 | 597 | ||
595 | debug3("Looking up %s", abs_src); | 598 | debug3("Looking up %s", abs_src); |
596 | if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) { | 599 | if ((r = remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) != 0) { |
597 | error("File \"%s\" not found.", abs_src); | 600 | if (r == GLOB_NOSPACE) { |
601 | error("Too many matches for \"%s\".", abs_src); | ||
602 | } else { | ||
603 | error("File \"%s\" not found.", abs_src); | ||
604 | } | ||
598 | err = -1; | 605 | err = -1; |
599 | goto out; | 606 | goto out; |
600 | } | 607 | } |
@@ -660,7 +667,7 @@ out: | |||
660 | 667 | ||
661 | static int | 668 | static int |
662 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | 669 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
663 | int pflag, int rflag, int fflag) | 670 | int pflag, int rflag, int resume, int fflag) |
664 | { | 671 | { |
665 | char *tmp_dst = NULL; | 672 | char *tmp_dst = NULL; |
666 | char *abs_dst = NULL; | 673 | char *abs_dst = NULL; |
@@ -723,16 +730,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
723 | } | 730 | } |
724 | free(tmp); | 731 | free(tmp); |
725 | 732 | ||
726 | if (!quiet) | 733 | resume |= global_aflag; |
734 | if (!quiet && resume) | ||
735 | printf("Resuming upload of %s to %s\n", g.gl_pathv[i], | ||
736 | abs_dst); | ||
737 | else if (!quiet && !resume) | ||
727 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | 738 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); |
728 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 739 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
729 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, | 740 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
730 | pflag || global_pflag, 1, | 741 | pflag || global_pflag, 1, resume, |
731 | fflag || global_fflag) == -1) | 742 | fflag || global_fflag) == -1) |
732 | err = -1; | 743 | err = -1; |
733 | } else { | 744 | } else { |
734 | if (do_upload(conn, g.gl_pathv[i], abs_dst, | 745 | if (do_upload(conn, g.gl_pathv[i], abs_dst, |
735 | pflag || global_pflag, | 746 | pflag || global_pflag, resume, |
736 | fflag || global_fflag) == -1) | 747 | fflag || global_fflag) == -1) |
737 | err = -1; | 748 | err = -1; |
738 | } | 749 | } |
@@ -855,19 +866,23 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
855 | { | 866 | { |
856 | char *fname, *lname; | 867 | char *fname, *lname; |
857 | glob_t g; | 868 | glob_t g; |
858 | int err; | 869 | int err, r; |
859 | struct winsize ws; | 870 | struct winsize ws; |
860 | u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; | 871 | u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; |
861 | 872 | ||
862 | memset(&g, 0, sizeof(g)); | 873 | memset(&g, 0, sizeof(g)); |
863 | 874 | ||
864 | if (remote_glob(conn, path, | 875 | if ((r = remote_glob(conn, path, |
865 | GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, | 876 | GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT, |
866 | NULL, &g) || | 877 | NULL, &g)) != 0 || |
867 | (g.gl_pathc && !g.gl_matchc)) { | 878 | (g.gl_pathc && !g.gl_matchc)) { |
868 | if (g.gl_pathc) | 879 | if (g.gl_pathc) |
869 | globfree(&g); | 880 | globfree(&g); |
870 | error("Can't ls: \"%s\" not found", path); | 881 | if (r == GLOB_NOSPACE) { |
882 | error("Can't ls: Too many matches for \"%s\"", path); | ||
883 | } else { | ||
884 | error("Can't ls: \"%s\" not found", path); | ||
885 | } | ||
871 | return -1; | 886 | return -1; |
872 | } | 887 | } |
873 | 888 | ||
@@ -1186,8 +1201,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1186 | } | 1201 | } |
1187 | 1202 | ||
1188 | static int | 1203 | static int |
1189 | parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, | 1204 | parse_args(const char **cpp, int *ignore_errors, int *aflag, |
1190 | int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, | 1205 | int *fflag, int *hflag, int *iflag, int *lflag, int *pflag, |
1206 | int *rflag, int *sflag, | ||
1191 | unsigned long *n_arg, char **path1, char **path2) | 1207 | unsigned long *n_arg, char **path1, char **path2) |
1192 | { | 1208 | { |
1193 | const char *cmd, *cp = *cpp; | 1209 | const char *cmd, *cp = *cpp; |
@@ -1239,6 +1255,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, | |||
1239 | switch (cmdnum) { | 1255 | switch (cmdnum) { |
1240 | case I_GET: | 1256 | case I_GET: |
1241 | case I_REGET: | 1257 | case I_REGET: |
1258 | case I_REPUT: | ||
1242 | case I_PUT: | 1259 | case I_PUT: |
1243 | if ((optidx = parse_getput_flags(cmd, argv, argc, | 1260 | if ((optidx = parse_getput_flags(cmd, argv, argc, |
1244 | aflag, fflag, pflag, rflag)) == -1) | 1261 | aflag, fflag, pflag, rflag)) == -1) |
@@ -1256,11 +1273,6 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, | |||
1256 | /* Destination is not globbed */ | 1273 | /* Destination is not globbed */ |
1257 | undo_glob_escape(*path2); | 1274 | undo_glob_escape(*path2); |
1258 | } | 1275 | } |
1259 | if (*aflag && cmdnum == I_PUT) { | ||
1260 | /* XXX implement resume for uploads */ | ||
1261 | error("Resume is not supported for uploads"); | ||
1262 | return -1; | ||
1263 | } | ||
1264 | break; | 1276 | break; |
1265 | case I_LINK: | 1277 | case I_LINK: |
1266 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) | 1278 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) |
@@ -1382,7 +1394,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1382 | int err_abort) | 1394 | int err_abort) |
1383 | { | 1395 | { |
1384 | char *path1, *path2, *tmp; | 1396 | char *path1, *path2, *tmp; |
1385 | int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0; | 1397 | int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, |
1398 | iflag = 0; | ||
1386 | int lflag = 0, pflag = 0, rflag = 0, sflag = 0; | 1399 | int lflag = 0, pflag = 0, rflag = 0, sflag = 0; |
1387 | int cmdnum, i; | 1400 | int cmdnum, i; |
1388 | unsigned long n_arg = 0; | 1401 | unsigned long n_arg = 0; |
@@ -1415,9 +1428,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1415 | err = process_get(conn, path1, path2, *pwd, pflag, | 1428 | err = process_get(conn, path1, path2, *pwd, pflag, |
1416 | rflag, aflag, fflag); | 1429 | rflag, aflag, fflag); |
1417 | break; | 1430 | break; |
1431 | case I_REPUT: | ||
1432 | aflag = 1; | ||
1433 | /* FALLTHROUGH */ | ||
1418 | case I_PUT: | 1434 | case I_PUT: |
1419 | err = process_put(conn, path1, path2, *pwd, pflag, | 1435 | err = process_put(conn, path1, path2, *pwd, pflag, |
1420 | rflag, fflag); | 1436 | rflag, aflag, fflag); |
1421 | break; | 1437 | break; |
1422 | case I_RENAME: | 1438 | case I_RENAME: |
1423 | path1 = make_absolute(path1, *pwd); | 1439 | path1 = make_absolute(path1, *pwd); |
@@ -1834,6 +1850,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1834 | pwdlen = tmplen + 1; /* track last seen '/' */ | 1850 | pwdlen = tmplen + 1; /* track last seen '/' */ |
1835 | } | 1851 | } |
1836 | free(tmp); | 1852 | free(tmp); |
1853 | tmp = NULL; | ||
1837 | 1854 | ||
1838 | if (g.gl_matchc == 0) | 1855 | if (g.gl_matchc == 0) |
1839 | goto out; | 1856 | goto out; |
@@ -1841,7 +1858,6 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1841 | if (g.gl_matchc > 1) | 1858 | if (g.gl_matchc > 1) |
1842 | complete_display(g.gl_pathv, pwdlen); | 1859 | complete_display(g.gl_pathv, pwdlen); |
1843 | 1860 | ||
1844 | tmp = NULL; | ||
1845 | /* Don't try to extend globs */ | 1861 | /* Don't try to extend globs */ |
1846 | if (file == NULL || hadglob) | 1862 | if (file == NULL || hadglob) |
1847 | goto out; | 1863 | goto out; |
@@ -1904,7 +1920,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1904 | lf = el_line(el); | 1920 | lf = el_line(el); |
1905 | if (g.gl_matchc == 1) { | 1921 | if (g.gl_matchc == 1) { |
1906 | i = 0; | 1922 | i = 0; |
1907 | if (!terminated) | 1923 | if (!terminated && quote != '\0') |
1908 | ins[i++] = quote; | 1924 | ins[i++] = quote; |
1909 | if (*(lf->cursor - 1) != '/' && | 1925 | if (*(lf->cursor - 1) != '/' && |
1910 | (lastarg || *(lf->cursor) != ' ')) | 1926 | (lastarg || *(lf->cursor) != ' ')) |