diff options
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 242 |
1 files changed, 162 insertions, 80 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.148 2013/07/25 00:56:52 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.158 2013/11/20 20:54:10 deraadt 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 | * |
@@ -94,6 +94,9 @@ int global_aflag = 0; | |||
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 */ |
95 | int global_pflag = 0; | 95 | int global_pflag = 0; |
96 | 96 | ||
97 | /* When this option is set, transfers will have fsync() called on each file */ | ||
98 | int global_fflag = 0; | ||
99 | |||
97 | /* SIGINT received during command processing */ | 100 | /* SIGINT received during command processing */ |
98 | volatile sig_atomic_t interrupted = 0; | 101 | volatile sig_atomic_t interrupted = 0; |
99 | 102 | ||
@@ -129,32 +132,34 @@ extern char *__progname; | |||
129 | #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) | 132 | #define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT) |
130 | 133 | ||
131 | /* Commands for interactive mode */ | 134 | /* Commands for interactive mode */ |
132 | #define I_CHDIR 1 | 135 | enum sftp_command { |
133 | #define I_CHGRP 2 | 136 | I_CHDIR = 1, |
134 | #define I_CHMOD 3 | 137 | I_CHGRP, |
135 | #define I_CHOWN 4 | 138 | I_CHMOD, |
136 | #define I_DF 24 | 139 | I_CHOWN, |
137 | #define I_GET 5 | 140 | I_DF, |
138 | #define I_HELP 6 | 141 | I_GET, |
139 | #define I_LCHDIR 7 | 142 | I_HELP, |
140 | #define I_LINK 25 | 143 | I_LCHDIR, |
141 | #define I_LLS 8 | 144 | I_LINK, |
142 | #define I_LMKDIR 9 | 145 | I_LLS, |
143 | #define I_LPWD 10 | 146 | I_LMKDIR, |
144 | #define I_LS 11 | 147 | I_LPWD, |
145 | #define I_LUMASK 12 | 148 | I_LS, |
146 | #define I_MKDIR 13 | 149 | I_LUMASK, |
147 | #define I_PUT 14 | 150 | I_MKDIR, |
148 | #define I_PWD 15 | 151 | I_PUT, |
149 | #define I_QUIT 16 | 152 | I_PWD, |
150 | #define I_RENAME 17 | 153 | I_QUIT, |
151 | #define I_RM 18 | 154 | I_RENAME, |
152 | #define I_RMDIR 19 | 155 | I_RM, |
153 | #define I_SHELL 20 | 156 | I_RMDIR, |
154 | #define I_SYMLINK 21 | 157 | I_SHELL, |
155 | #define I_VERSION 22 | 158 | I_SYMLINK, |
156 | #define I_PROGRESS 23 | 159 | I_VERSION, |
157 | #define I_REGET 26 | 160 | I_PROGRESS, |
161 | I_REGET, | ||
162 | }; | ||
158 | 163 | ||
159 | struct CMD { | 164 | struct CMD { |
160 | const char *c; | 165 | const char *c; |
@@ -357,7 +362,7 @@ make_absolute(char *p, char *pwd) | |||
357 | 362 | ||
358 | static int | 363 | static int |
359 | parse_getput_flags(const char *cmd, char **argv, int argc, | 364 | parse_getput_flags(const char *cmd, char **argv, int argc, |
360 | int *aflag, int *pflag, int *rflag) | 365 | int *aflag, int *fflag, int *pflag, int *rflag) |
361 | { | 366 | { |
362 | extern int opterr, optind, optopt, optreset; | 367 | extern int opterr, optind, optopt, optreset; |
363 | int ch; | 368 | int ch; |
@@ -365,12 +370,15 @@ parse_getput_flags(const char *cmd, char **argv, int argc, | |||
365 | optind = optreset = 1; | 370 | optind = optreset = 1; |
366 | opterr = 0; | 371 | opterr = 0; |
367 | 372 | ||
368 | *aflag = *rflag = *pflag = 0; | 373 | *aflag = *fflag = *rflag = *pflag = 0; |
369 | while ((ch = getopt(argc, argv, "aPpRr")) != -1) { | 374 | while ((ch = getopt(argc, argv, "afPpRr")) != -1) { |
370 | switch (ch) { | 375 | switch (ch) { |
371 | case 'a': | 376 | case 'a': |
372 | *aflag = 1; | 377 | *aflag = 1; |
373 | break; | 378 | break; |
379 | case 'f': | ||
380 | *fflag = 1; | ||
381 | break; | ||
374 | case 'p': | 382 | case 'p': |
375 | case 'P': | 383 | case 'P': |
376 | *pflag = 1; | 384 | *pflag = 1; |
@@ -413,6 +421,30 @@ parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) | |||
413 | } | 421 | } |
414 | 422 | ||
415 | static int | 423 | static int |
424 | parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag) | ||
425 | { | ||
426 | extern int opterr, optind, optopt, optreset; | ||
427 | int ch; | ||
428 | |||
429 | optind = optreset = 1; | ||
430 | opterr = 0; | ||
431 | |||
432 | *lflag = 0; | ||
433 | while ((ch = getopt(argc, argv, "l")) != -1) { | ||
434 | switch (ch) { | ||
435 | case 'l': | ||
436 | *lflag = 1; | ||
437 | break; | ||
438 | default: | ||
439 | error("%s: Invalid flag -%c", cmd, optopt); | ||
440 | return -1; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | return optind; | ||
445 | } | ||
446 | |||
447 | static int | ||
416 | parse_ls_flags(char **argv, int argc, int *lflag) | 448 | parse_ls_flags(char **argv, int argc, int *lflag) |
417 | { | 449 | { |
418 | extern int opterr, optind, optopt, optreset; | 450 | extern int opterr, optind, optopt, optreset; |
@@ -493,6 +525,26 @@ parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) | |||
493 | } | 525 | } |
494 | 526 | ||
495 | static int | 527 | static int |
528 | parse_no_flags(const char *cmd, char **argv, int argc) | ||
529 | { | ||
530 | extern int opterr, optind, optopt, optreset; | ||
531 | int ch; | ||
532 | |||
533 | optind = optreset = 1; | ||
534 | opterr = 0; | ||
535 | |||
536 | while ((ch = getopt(argc, argv, "")) != -1) { | ||
537 | switch (ch) { | ||
538 | default: | ||
539 | error("%s: Invalid flag -%c", cmd, optopt); | ||
540 | return -1; | ||
541 | } | ||
542 | } | ||
543 | |||
544 | return optind; | ||
545 | } | ||
546 | |||
547 | static int | ||
496 | is_dir(char *path) | 548 | is_dir(char *path) |
497 | { | 549 | { |
498 | struct stat sb; | 550 | struct stat sb; |
@@ -528,7 +580,7 @@ pathname_is_dir(char *pathname) | |||
528 | 580 | ||
529 | static int | 581 | static int |
530 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | 582 | process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
531 | int pflag, int rflag, int resume) | 583 | int pflag, int rflag, int resume, int fflag) |
532 | { | 584 | { |
533 | char *abs_src = NULL; | 585 | char *abs_src = NULL; |
534 | char *abs_dst = NULL; | 586 | char *abs_dst = NULL; |
@@ -587,11 +639,13 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
587 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); | 639 | printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
588 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 640 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
589 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, | 641 | if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, |
590 | pflag || global_pflag, 1, resume) == -1) | 642 | pflag || global_pflag, 1, resume, |
643 | fflag || global_fflag) == -1) | ||
591 | err = -1; | 644 | err = -1; |
592 | } else { | 645 | } else { |
593 | if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, | 646 | if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, |
594 | pflag || global_pflag, resume) == -1) | 647 | pflag || global_pflag, resume, |
648 | fflag || global_fflag) == -1) | ||
595 | err = -1; | 649 | err = -1; |
596 | } | 650 | } |
597 | free(abs_dst); | 651 | free(abs_dst); |
@@ -606,7 +660,7 @@ out: | |||
606 | 660 | ||
607 | static int | 661 | static int |
608 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | 662 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, |
609 | int pflag, int rflag) | 663 | int pflag, int rflag, int fflag) |
610 | { | 664 | { |
611 | char *tmp_dst = NULL; | 665 | char *tmp_dst = NULL; |
612 | char *abs_dst = NULL; | 666 | char *abs_dst = NULL; |
@@ -647,7 +701,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
647 | error("stat %s: %s", g.gl_pathv[i], strerror(errno)); | 701 | error("stat %s: %s", g.gl_pathv[i], strerror(errno)); |
648 | continue; | 702 | continue; |
649 | } | 703 | } |
650 | 704 | ||
651 | tmp = xstrdup(g.gl_pathv[i]); | 705 | tmp = xstrdup(g.gl_pathv[i]); |
652 | if ((filename = basename(tmp)) == NULL) { | 706 | if ((filename = basename(tmp)) == NULL) { |
653 | error("basename %s: %s", tmp, strerror(errno)); | 707 | error("basename %s: %s", tmp, strerror(errno)); |
@@ -673,11 +727,13 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | |||
673 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); | 727 | printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); |
674 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { | 728 | if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { |
675 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, | 729 | if (upload_dir(conn, g.gl_pathv[i], abs_dst, |
676 | pflag || global_pflag, 1) == -1) | 730 | pflag || global_pflag, 1, |
731 | fflag || global_fflag) == -1) | ||
677 | err = -1; | 732 | err = -1; |
678 | } else { | 733 | } else { |
679 | if (do_upload(conn, g.gl_pathv[i], abs_dst, | 734 | if (do_upload(conn, g.gl_pathv[i], abs_dst, |
680 | pflag || global_pflag) == -1) | 735 | pflag || global_pflag, |
736 | fflag || global_fflag) == -1) | ||
681 | err = -1; | 737 | err = -1; |
682 | } | 738 | } |
683 | } | 739 | } |
@@ -975,7 +1031,7 @@ undo_glob_escape(char *s) | |||
975 | * | 1031 | * |
976 | * If "lastquote" is not NULL, the quoting character used for the last | 1032 | * If "lastquote" is not NULL, the quoting character used for the last |
977 | * argument is placed in *lastquote ("\0", "'" or "\""). | 1033 | * argument is placed in *lastquote ("\0", "'" or "\""). |
978 | * | 1034 | * |
979 | * If "terminated" is not NULL, *terminated will be set to 1 when the | 1035 | * If "terminated" is not NULL, *terminated will be set to 1 when the |
980 | * last argument's quote has been properly terminated or 0 otherwise. | 1036 | * last argument's quote has been properly terminated or 0 otherwise. |
981 | * This parameter is only of use if "sloppy" is set. | 1037 | * This parameter is only of use if "sloppy" is set. |
@@ -1009,7 +1065,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1009 | error("Too many arguments."); | 1065 | error("Too many arguments."); |
1010 | return NULL; | 1066 | return NULL; |
1011 | } | 1067 | } |
1012 | if (isspace(arg[i])) { | 1068 | if (isspace((unsigned char)arg[i])) { |
1013 | if (state == MA_UNQUOTED) { | 1069 | if (state == MA_UNQUOTED) { |
1014 | /* Terminate current argument */ | 1070 | /* Terminate current argument */ |
1015 | argvs[j++] = '\0'; | 1071 | argvs[j++] = '\0'; |
@@ -1024,7 +1080,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1024 | state = q; | 1080 | state = q; |
1025 | if (lastquote != NULL) | 1081 | if (lastquote != NULL) |
1026 | *lastquote = arg[i]; | 1082 | *lastquote = arg[i]; |
1027 | } else if (state == MA_UNQUOTED) | 1083 | } else if (state == MA_UNQUOTED) |
1028 | state = q; | 1084 | state = q; |
1029 | else if (state == q) | 1085 | else if (state == q) |
1030 | state = MA_UNQUOTED; | 1086 | state = MA_UNQUOTED; |
@@ -1130,9 +1186,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, | |||
1130 | } | 1186 | } |
1131 | 1187 | ||
1132 | static int | 1188 | static int |
1133 | parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | 1189 | parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, |
1134 | int *pflag, int *rflag, int *sflag, unsigned long *n_arg, | 1190 | int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, |
1135 | char **path1, char **path2) | 1191 | unsigned long *n_arg, char **path1, char **path2) |
1136 | { | 1192 | { |
1137 | const char *cmd, *cp = *cpp; | 1193 | const char *cmd, *cp = *cpp; |
1138 | char *cp2, **argv; | 1194 | char *cp2, **argv; |
@@ -1144,9 +1200,9 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1144 | cp = cp + strspn(cp, WHITESPACE); | 1200 | cp = cp + strspn(cp, WHITESPACE); |
1145 | 1201 | ||
1146 | /* Check for leading '-' (disable error processing) */ | 1202 | /* Check for leading '-' (disable error processing) */ |
1147 | *iflag = 0; | 1203 | *ignore_errors = 0; |
1148 | if (*cp == '-') { | 1204 | if (*cp == '-') { |
1149 | *iflag = 1; | 1205 | *ignore_errors = 1; |
1150 | cp++; | 1206 | cp++; |
1151 | cp = cp + strspn(cp, WHITESPACE); | 1207 | cp = cp + strspn(cp, WHITESPACE); |
1152 | } | 1208 | } |
@@ -1176,7 +1232,8 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1176 | } | 1232 | } |
1177 | 1233 | ||
1178 | /* Get arguments and parse flags */ | 1234 | /* Get arguments and parse flags */ |
1179 | *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0; | 1235 | *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0; |
1236 | *rflag = *sflag = 0; | ||
1180 | *path1 = *path2 = NULL; | 1237 | *path1 = *path2 = NULL; |
1181 | optidx = 1; | 1238 | optidx = 1; |
1182 | switch (cmdnum) { | 1239 | switch (cmdnum) { |
@@ -1184,7 +1241,7 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1184 | case I_REGET: | 1241 | case I_REGET: |
1185 | case I_PUT: | 1242 | case I_PUT: |
1186 | if ((optidx = parse_getput_flags(cmd, argv, argc, | 1243 | if ((optidx = parse_getput_flags(cmd, argv, argc, |
1187 | aflag, pflag, rflag)) == -1) | 1244 | aflag, fflag, pflag, rflag)) == -1) |
1188 | return -1; | 1245 | return -1; |
1189 | /* Get first pathname (mandatory) */ | 1246 | /* Get first pathname (mandatory) */ |
1190 | if (argc - optidx < 1) { | 1247 | if (argc - optidx < 1) { |
@@ -1208,8 +1265,15 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1208 | case I_LINK: | 1265 | case I_LINK: |
1209 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) | 1266 | if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) |
1210 | return -1; | 1267 | return -1; |
1211 | case I_SYMLINK: | 1268 | goto parse_two_paths; |
1212 | case I_RENAME: | 1269 | case I_RENAME: |
1270 | if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1) | ||
1271 | return -1; | ||
1272 | goto parse_two_paths; | ||
1273 | case I_SYMLINK: | ||
1274 | if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) | ||
1275 | return -1; | ||
1276 | parse_two_paths: | ||
1213 | if (argc - optidx < 2) { | 1277 | if (argc - optidx < 2) { |
1214 | error("You must specify two paths after a %s " | 1278 | error("You must specify two paths after a %s " |
1215 | "command.", cmd); | 1279 | "command.", cmd); |
@@ -1227,6 +1291,8 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1227 | case I_CHDIR: | 1291 | case I_CHDIR: |
1228 | case I_LCHDIR: | 1292 | case I_LCHDIR: |
1229 | case I_LMKDIR: | 1293 | case I_LMKDIR: |
1294 | if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) | ||
1295 | return -1; | ||
1230 | /* Get pathname (mandatory) */ | 1296 | /* Get pathname (mandatory) */ |
1231 | if (argc - optidx < 1) { | 1297 | if (argc - optidx < 1) { |
1232 | error("You must specify a path after a %s command.", | 1298 | error("You must specify a path after a %s command.", |
@@ -1268,6 +1334,8 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1268 | base = 8; | 1334 | base = 8; |
1269 | case I_CHOWN: | 1335 | case I_CHOWN: |
1270 | case I_CHGRP: | 1336 | case I_CHGRP: |
1337 | if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) | ||
1338 | return -1; | ||
1271 | /* Get numeric arg (mandatory) */ | 1339 | /* Get numeric arg (mandatory) */ |
1272 | if (argc - optidx < 1) | 1340 | if (argc - optidx < 1) |
1273 | goto need_num_arg; | 1341 | goto need_num_arg; |
@@ -1298,6 +1366,8 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, | |||
1298 | case I_HELP: | 1366 | case I_HELP: |
1299 | case I_VERSION: | 1367 | case I_VERSION: |
1300 | case I_PROGRESS: | 1368 | case I_PROGRESS: |
1369 | if ((optidx = parse_no_flags(cmd, argv, argc)) == -1) | ||
1370 | return -1; | ||
1301 | break; | 1371 | break; |
1302 | default: | 1372 | default: |
1303 | fatal("Command not implemented"); | 1373 | fatal("Command not implemented"); |
@@ -1312,8 +1382,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1312 | int err_abort) | 1382 | int err_abort) |
1313 | { | 1383 | { |
1314 | char *path1, *path2, *tmp; | 1384 | char *path1, *path2, *tmp; |
1315 | int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; | 1385 | int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0; |
1316 | int rflag = 0, sflag = 0; | 1386 | int lflag = 0, pflag = 0, rflag = 0, sflag = 0; |
1317 | int cmdnum, i; | 1387 | int cmdnum, i; |
1318 | unsigned long n_arg = 0; | 1388 | unsigned long n_arg = 0; |
1319 | Attrib a, *aa; | 1389 | Attrib a, *aa; |
@@ -1322,9 +1392,9 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1322 | glob_t g; | 1392 | glob_t g; |
1323 | 1393 | ||
1324 | path1 = path2 = NULL; | 1394 | path1 = path2 = NULL; |
1325 | cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag, | 1395 | cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag, |
1326 | &rflag, &sflag, &n_arg, &path1, &path2); | 1396 | &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2); |
1327 | if (iflag != 0) | 1397 | if (ignore_errors != 0) |
1328 | err_abort = 0; | 1398 | err_abort = 0; |
1329 | 1399 | ||
1330 | memset(&g, 0, sizeof(g)); | 1400 | memset(&g, 0, sizeof(g)); |
@@ -1343,20 +1413,22 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1343 | /* FALLTHROUGH */ | 1413 | /* FALLTHROUGH */ |
1344 | case I_GET: | 1414 | case I_GET: |
1345 | err = process_get(conn, path1, path2, *pwd, pflag, | 1415 | err = process_get(conn, path1, path2, *pwd, pflag, |
1346 | rflag, aflag); | 1416 | rflag, aflag, fflag); |
1347 | break; | 1417 | break; |
1348 | case I_PUT: | 1418 | case I_PUT: |
1349 | err = process_put(conn, path1, path2, *pwd, pflag, rflag); | 1419 | err = process_put(conn, path1, path2, *pwd, pflag, |
1420 | rflag, fflag); | ||
1350 | break; | 1421 | break; |
1351 | case I_RENAME: | 1422 | case I_RENAME: |
1352 | path1 = make_absolute(path1, *pwd); | 1423 | path1 = make_absolute(path1, *pwd); |
1353 | path2 = make_absolute(path2, *pwd); | 1424 | path2 = make_absolute(path2, *pwd); |
1354 | err = do_rename(conn, path1, path2); | 1425 | err = do_rename(conn, path1, path2, lflag); |
1355 | break; | 1426 | break; |
1356 | case I_SYMLINK: | 1427 | case I_SYMLINK: |
1357 | sflag = 1; | 1428 | sflag = 1; |
1358 | case I_LINK: | 1429 | case I_LINK: |
1359 | path1 = make_absolute(path1, *pwd); | 1430 | if (!sflag) |
1431 | path1 = make_absolute(path1, *pwd); | ||
1360 | path2 = make_absolute(path2, *pwd); | 1432 | path2 = make_absolute(path2, *pwd); |
1361 | err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); | 1433 | err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); |
1362 | break; | 1434 | break; |
@@ -1567,7 +1639,7 @@ complete_display(char **list, u_int len) | |||
1567 | char *tmp; | 1639 | char *tmp; |
1568 | 1640 | ||
1569 | /* Count entries for sort and find longest */ | 1641 | /* Count entries for sort and find longest */ |
1570 | for (y = 0; list[y]; y++) | 1642 | for (y = 0; list[y]; y++) |
1571 | m = MAX(m, strlen(list[y])); | 1643 | m = MAX(m, strlen(list[y])); |
1572 | 1644 | ||
1573 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) | 1645 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1) |
@@ -1612,8 +1684,8 @@ complete_ambiguous(const char *word, char **list, size_t count) | |||
1612 | for (y = 1; list[y]; y++) { | 1684 | for (y = 1; list[y]; y++) { |
1613 | u_int x; | 1685 | u_int x; |
1614 | 1686 | ||
1615 | for (x = 0; x < matchlen; x++) | 1687 | for (x = 0; x < matchlen; x++) |
1616 | if (list[0][x] != list[y][x]) | 1688 | if (list[0][x] != list[y][x]) |
1617 | break; | 1689 | break; |
1618 | 1690 | ||
1619 | matchlen = x; | 1691 | matchlen = x; |
@@ -1625,7 +1697,7 @@ complete_ambiguous(const char *word, char **list, size_t count) | |||
1625 | tmp[matchlen] = '\0'; | 1697 | tmp[matchlen] = '\0'; |
1626 | return tmp; | 1698 | return tmp; |
1627 | } | 1699 | } |
1628 | } | 1700 | } |
1629 | 1701 | ||
1630 | return xstrdup(word); | 1702 | return xstrdup(word); |
1631 | } | 1703 | } |
@@ -1645,12 +1717,12 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1645 | if (cmd == NULL) { | 1717 | if (cmd == NULL) { |
1646 | for (y = 0; cmds[y].c; y++) | 1718 | for (y = 0; cmds[y].c; y++) |
1647 | list[count++] = xstrdup(cmds[y].c); | 1719 | list[count++] = xstrdup(cmds[y].c); |
1648 | 1720 | ||
1649 | list[count] = NULL; | 1721 | list[count] = NULL; |
1650 | complete_display(list, 0); | 1722 | complete_display(list, 0); |
1651 | 1723 | ||
1652 | for (y = 0; list[y] != NULL; y++) | 1724 | for (y = 0; list[y] != NULL; y++) |
1653 | free(list[y]); | 1725 | free(list[y]); |
1654 | free(list); | 1726 | free(list); |
1655 | return count; | 1727 | return count; |
1656 | } | 1728 | } |
@@ -1658,7 +1730,7 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1658 | /* Prepare subset of commands that start with "cmd" */ | 1730 | /* Prepare subset of commands that start with "cmd" */ |
1659 | cmdlen = strlen(cmd); | 1731 | cmdlen = strlen(cmd); |
1660 | for (y = 0; cmds[y].c; y++) { | 1732 | for (y = 0; cmds[y].c; y++) { |
1661 | if (!strncasecmp(cmd, cmds[y].c, cmdlen)) | 1733 | if (!strncasecmp(cmd, cmds[y].c, cmdlen)) |
1662 | list[count++] = xstrdup(cmds[y].c); | 1734 | list[count++] = xstrdup(cmds[y].c); |
1663 | } | 1735 | } |
1664 | list[count] = NULL; | 1736 | list[count] = NULL; |
@@ -1673,8 +1745,8 @@ complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote, | |||
1673 | if (count > 1) | 1745 | if (count > 1) |
1674 | complete_display(list, 0); | 1746 | complete_display(list, 0); |
1675 | 1747 | ||
1676 | for (y = 0; list[y]; y++) | 1748 | for (y = 0; list[y]; y++) |
1677 | free(list[y]); | 1749 | free(list[y]); |
1678 | free(list); | 1750 | free(list); |
1679 | 1751 | ||
1680 | if (tmp != NULL) { | 1752 | if (tmp != NULL) { |
@@ -1714,7 +1786,7 @@ complete_is_remote(char *cmd) { | |||
1714 | return -1; | 1786 | return -1; |
1715 | 1787 | ||
1716 | for (i = 0; cmds[i].c; i++) { | 1788 | for (i = 0; cmds[i].c; i++) { |
1717 | if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) | 1789 | if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c))) |
1718 | return cmds[i].t; | 1790 | return cmds[i].t; |
1719 | } | 1791 | } |
1720 | 1792 | ||
@@ -1731,7 +1803,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1731 | u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; | 1803 | u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs; |
1732 | int clen; | 1804 | int clen; |
1733 | const LineInfo *lf; | 1805 | const LineInfo *lf; |
1734 | 1806 | ||
1735 | /* Glob from "file" location */ | 1807 | /* Glob from "file" location */ |
1736 | if (file == NULL) | 1808 | if (file == NULL) |
1737 | tmp = xstrdup("*"); | 1809 | tmp = xstrdup("*"); |
@@ -1745,9 +1817,9 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1745 | if (remote != LOCAL) { | 1817 | if (remote != LOCAL) { |
1746 | tmp = make_absolute(tmp, remote_path); | 1818 | tmp = make_absolute(tmp, remote_path); |
1747 | remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); | 1819 | remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); |
1748 | } else | 1820 | } else |
1749 | glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); | 1821 | glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g); |
1750 | 1822 | ||
1751 | /* Determine length of pwd so we can trim completion display */ | 1823 | /* Determine length of pwd so we can trim completion display */ |
1752 | for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { | 1824 | for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) { |
1753 | /* Terminate counting on first unescaped glob metacharacter */ | 1825 | /* Terminate counting on first unescaped glob metacharacter */ |
@@ -1763,7 +1835,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1763 | } | 1835 | } |
1764 | free(tmp); | 1836 | free(tmp); |
1765 | 1837 | ||
1766 | if (g.gl_matchc == 0) | 1838 | if (g.gl_matchc == 0) |
1767 | goto out; | 1839 | goto out; |
1768 | 1840 | ||
1769 | if (g.gl_matchc > 1) | 1841 | if (g.gl_matchc > 1) |
@@ -1796,7 +1868,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1796 | 1868 | ||
1797 | if (tmplen > (filelen - cesc)) { | 1869 | if (tmplen > (filelen - cesc)) { |
1798 | tmp2 = tmp + filelen - cesc; | 1870 | tmp2 = tmp + filelen - cesc; |
1799 | len = strlen(tmp2); | 1871 | len = strlen(tmp2); |
1800 | /* quote argument on way out */ | 1872 | /* quote argument on way out */ |
1801 | for (i = 0; i < len; i += clen) { | 1873 | for (i = 0; i < len; i += clen) { |
1802 | if ((clen = mblen(tmp2 + i, len - i)) < 0 || | 1874 | if ((clen = mblen(tmp2 + i, len - i)) < 0 || |
@@ -1852,7 +1924,7 @@ complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path, | |||
1852 | static unsigned char | 1924 | static unsigned char |
1853 | complete(EditLine *el, int ch) | 1925 | complete(EditLine *el, int ch) |
1854 | { | 1926 | { |
1855 | char **argv, *line, quote; | 1927 | char **argv, *line, quote; |
1856 | int argc, carg; | 1928 | int argc, carg; |
1857 | u_int cursor, len, terminated, ret = CC_ERROR; | 1929 | u_int cursor, len, terminated, ret = CC_ERROR; |
1858 | const LineInfo *lf; | 1930 | const LineInfo *lf; |
@@ -1891,7 +1963,7 @@ complete(EditLine *el, int ch) | |||
1891 | } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { | 1963 | } else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ') { |
1892 | /* Handle the command parsing */ | 1964 | /* Handle the command parsing */ |
1893 | if (complete_cmd_parse(el, argv[0], argc == carg, | 1965 | if (complete_cmd_parse(el, argv[0], argc == carg, |
1894 | quote, terminated) != 0) | 1966 | quote, terminated) != 0) |
1895 | ret = CC_REDISPLAY; | 1967 | ret = CC_REDISPLAY; |
1896 | } else if (carg >= 1) { | 1968 | } else if (carg >= 1) { |
1897 | /* Handle file parsing */ | 1969 | /* Handle file parsing */ |
@@ -1904,11 +1976,11 @@ complete(EditLine *el, int ch) | |||
1904 | if (remote != 0 && | 1976 | if (remote != 0 && |
1905 | complete_match(el, complete_ctx->conn, | 1977 | complete_match(el, complete_ctx->conn, |
1906 | *complete_ctx->remote_pathp, filematch, | 1978 | *complete_ctx->remote_pathp, filematch, |
1907 | remote, carg == argc, quote, terminated) != 0) | 1979 | remote, carg == argc, quote, terminated) != 0) |
1908 | ret = CC_REDISPLAY; | 1980 | ret = CC_REDISPLAY; |
1909 | } | 1981 | } |
1910 | 1982 | ||
1911 | free(line); | 1983 | free(line); |
1912 | return ret; | 1984 | return ret; |
1913 | } | 1985 | } |
1914 | #endif /* USE_LIBEDIT */ | 1986 | #endif /* USE_LIBEDIT */ |
@@ -1942,12 +2014,19 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) | |||
1942 | el_source(el, NULL); | 2014 | el_source(el, NULL); |
1943 | 2015 | ||
1944 | /* Tab Completion */ | 2016 | /* Tab Completion */ |
1945 | el_set(el, EL_ADDFN, "ftp-complete", | 2017 | el_set(el, EL_ADDFN, "ftp-complete", |
1946 | "Context sensitive argument completion", complete); | 2018 | "Context sensitive argument completion", complete); |
1947 | complete_ctx.conn = conn; | 2019 | complete_ctx.conn = conn; |
1948 | complete_ctx.remote_pathp = &remote_path; | 2020 | complete_ctx.remote_pathp = &remote_path; |
1949 | el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); | 2021 | el_set(el, EL_CLIENTDATA, (void*)&complete_ctx); |
1950 | el_set(el, EL_BIND, "^I", "ftp-complete", NULL); | 2022 | el_set(el, EL_BIND, "^I", "ftp-complete", NULL); |
2023 | /* enable ctrl-left-arrow and ctrl-right-arrow */ | ||
2024 | el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL); | ||
2025 | el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL); | ||
2026 | el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL); | ||
2027 | el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL); | ||
2028 | /* make ^w match ksh behaviour */ | ||
2029 | el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL); | ||
1951 | } | 2030 | } |
1952 | #endif /* USE_LIBEDIT */ | 2031 | #endif /* USE_LIBEDIT */ |
1953 | 2032 | ||
@@ -2116,7 +2195,7 @@ usage(void) | |||
2116 | extern char *__progname; | 2195 | extern char *__progname; |
2117 | 2196 | ||
2118 | fprintf(stderr, | 2197 | fprintf(stderr, |
2119 | "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" | 2198 | "usage: %s [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" |
2120 | " [-D sftp_server_path] [-F ssh_config] " | 2199 | " [-D sftp_server_path] [-F ssh_config] " |
2121 | "[-i identity_file] [-l limit]\n" | 2200 | "[-i identity_file] [-l limit]\n" |
2122 | " [-o ssh_option] [-P port] [-R num_requests] " | 2201 | " [-o ssh_option] [-P port] [-R num_requests] " |
@@ -2164,7 +2243,7 @@ main(int argc, char **argv) | |||
2164 | infile = stdin; | 2243 | infile = stdin; |
2165 | 2244 | ||
2166 | while ((ch = getopt(argc, argv, | 2245 | while ((ch = getopt(argc, argv, |
2167 | "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { | 2246 | "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { |
2168 | switch (ch) { | 2247 | switch (ch) { |
2169 | /* Passed through to ssh(1) */ | 2248 | /* Passed through to ssh(1) */ |
2170 | case '4': | 2249 | case '4': |
@@ -2224,6 +2303,9 @@ main(int argc, char **argv) | |||
2224 | quiet = batchmode = 1; | 2303 | quiet = batchmode = 1; |
2225 | addargs(&args, "-obatchmode yes"); | 2304 | addargs(&args, "-obatchmode yes"); |
2226 | break; | 2305 | break; |
2306 | case 'f': | ||
2307 | global_fflag = 1; | ||
2308 | break; | ||
2227 | case 'p': | 2309 | case 'p': |
2228 | global_pflag = 1; | 2310 | global_pflag = 1; |
2229 | break; | 2311 | break; |