summaryrefslogtreecommitdiff
path: root/sftp.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-07-25 11:56:52 +1000
committerDamien Miller <djm@mindrot.org>2013-07-25 11:56:52 +1000
commit0d032419ee6e1968fc1cb187af63bf3b77b506ea (patch)
treece2788365040e9ea188bd60c8bec87d410814017 /sftp.c
parent98e27dcf581647b5bbe9780e8f59685d942d8ea3 (diff)
- djm@cvs.openbsd.org 2013/07/25 00:56:52
[sftp-client.c sftp-client.h sftp.1 sftp.c] sftp support for resuming partial downloads; patch mostly by Loganaden Velvindron/AfriNIC with some tweaks by me; feedback and ok dtucker@
Diffstat (limited to 'sftp.c')
-rw-r--r--sftp.c76
1 files changed, 50 insertions, 26 deletions
diff --git a/sftp.c b/sftp.c
index f0daaefa4..969328de4 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp.c,v 1.147 2013/07/12 00:20:00 djm Exp $ */ 1/* $OpenBSD: sftp.c,v 1.148 2013/07/25 00:56:52 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,6 +88,9 @@ 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 */
89int global_rflag = 0; 89int global_rflag = 0;
90 90
91/* When this option is set, we resume download if possible */
92int global_aflag = 0;
93
91/* 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 */
92int global_pflag = 0; 95int global_pflag = 0;
93 96
@@ -151,6 +154,7 @@ extern char *__progname;
151#define I_SYMLINK 21 154#define I_SYMLINK 21
152#define I_VERSION 22 155#define I_VERSION 22
153#define I_PROGRESS 23 156#define I_PROGRESS 23
157#define I_REGET 26
154 158
155struct CMD { 159struct CMD {
156 const char *c; 160 const char *c;
@@ -190,6 +194,7 @@ static const struct CMD cmds[] = {
190 { "put", I_PUT, LOCAL }, 194 { "put", I_PUT, LOCAL },
191 { "pwd", I_PWD, REMOTE }, 195 { "pwd", I_PWD, REMOTE },
192 { "quit", I_QUIT, NOARGS }, 196 { "quit", I_QUIT, NOARGS },
197 { "reget", I_REGET, REMOTE },
193 { "rename", I_RENAME, REMOTE }, 198 { "rename", I_RENAME, REMOTE },
194 { "rm", I_RM, REMOTE }, 199 { "rm", I_RM, REMOTE },
195 { "rmdir", I_RMDIR, REMOTE }, 200 { "rmdir", I_RMDIR, REMOTE },
@@ -239,6 +244,7 @@ help(void)
239 " filesystem containing 'path'\n" 244 " filesystem containing 'path'\n"
240 "exit Quit sftp\n" 245 "exit Quit sftp\n"
241 "get [-Ppr] remote [local] Download file\n" 246 "get [-Ppr] remote [local] Download file\n"
247 "reget remote [local] Resume download file\n"
242 "help Display this help text\n" 248 "help Display this help text\n"
243 "lcd path Change local directory to 'path'\n" 249 "lcd path Change local directory to 'path'\n"
244 "lls [ls-options [path]] Display local directory listing\n" 250 "lls [ls-options [path]] Display local directory listing\n"
@@ -350,8 +356,8 @@ make_absolute(char *p, char *pwd)
350} 356}
351 357
352static int 358static int
353parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, 359parse_getput_flags(const char *cmd, char **argv, int argc,
354 int *rflag) 360 int *aflag, int *pflag, int *rflag)
355{ 361{
356 extern int opterr, optind, optopt, optreset; 362 extern int opterr, optind, optopt, optreset;
357 int ch; 363 int ch;
@@ -359,9 +365,12 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
359 optind = optreset = 1; 365 optind = optreset = 1;
360 opterr = 0; 366 opterr = 0;
361 367
362 *rflag = *pflag = 0; 368 *aflag = *rflag = *pflag = 0;
363 while ((ch = getopt(argc, argv, "PpRr")) != -1) { 369 while ((ch = getopt(argc, argv, "aPpRr")) != -1) {
364 switch (ch) { 370 switch (ch) {
371 case 'a':
372 *aflag = 1;
373 break;
365 case 'p': 374 case 'p':
366 case 'P': 375 case 'P':
367 *pflag = 1; 376 *pflag = 1;
@@ -519,7 +528,7 @@ pathname_is_dir(char *pathname)
519 528
520static int 529static int
521process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, 530process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
522 int pflag, int rflag) 531 int pflag, int rflag, int resume)
523{ 532{
524 char *abs_src = NULL; 533 char *abs_src = NULL;
525 char *abs_dst = NULL; 534 char *abs_dst = NULL;
@@ -571,15 +580,18 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
571 } 580 }
572 free(tmp); 581 free(tmp);
573 582
574 if (!quiet) 583 resume |= global_aflag;
584 if (!quiet && resume)
585 printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst);
586 else if (!quiet && !resume)
575 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); 587 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
576 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 588 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
577 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, 589 if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
578 pflag || global_pflag, 1) == -1) 590 pflag || global_pflag, 1, resume) == -1)
579 err = -1; 591 err = -1;
580 } else { 592 } else {
581 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, 593 if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
582 pflag || global_pflag) == -1) 594 pflag || global_pflag, resume) == -1)
583 err = -1; 595 err = -1;
584 } 596 }
585 free(abs_dst); 597 free(abs_dst);
@@ -1118,8 +1130,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1118} 1130}
1119 1131
1120static int 1132static int
1121parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, 1133parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
1122 int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) 1134 int *pflag, int *rflag, int *sflag, unsigned long *n_arg,
1135 char **path1, char **path2)
1123{ 1136{
1124 const char *cmd, *cp = *cpp; 1137 const char *cmd, *cp = *cpp;
1125 char *cp2, **argv; 1138 char *cp2, **argv;
@@ -1163,14 +1176,15 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1163 } 1176 }
1164 1177
1165 /* Get arguments and parse flags */ 1178 /* Get arguments and parse flags */
1166 *lflag = *pflag = *rflag = *hflag = *n_arg = 0; 1179 *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0;
1167 *path1 = *path2 = NULL; 1180 *path1 = *path2 = NULL;
1168 optidx = 1; 1181 optidx = 1;
1169 switch (cmdnum) { 1182 switch (cmdnum) {
1170 case I_GET: 1183 case I_GET:
1184 case I_REGET:
1171 case I_PUT: 1185 case I_PUT:
1172 if ((optidx = parse_getput_flags(cmd, argv, argc, 1186 if ((optidx = parse_getput_flags(cmd, argv, argc,
1173 pflag, rflag)) == -1) 1187 aflag, pflag, rflag)) == -1)
1174 return -1; 1188 return -1;
1175 /* Get first pathname (mandatory) */ 1189 /* Get first pathname (mandatory) */
1176 if (argc - optidx < 1) { 1190 if (argc - optidx < 1) {
@@ -1185,6 +1199,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1185 /* Destination is not globbed */ 1199 /* Destination is not globbed */
1186 undo_glob_escape(*path2); 1200 undo_glob_escape(*path2);
1187 } 1201 }
1202 if (*aflag && cmdnum == I_PUT) {
1203 /* XXX implement resume for uploads */
1204 error("Resume is not supported for uploads");
1205 return -1;
1206 }
1188 break; 1207 break;
1189 case I_LINK: 1208 case I_LINK:
1190 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) 1209 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
@@ -1293,7 +1312,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1293 int err_abort) 1312 int err_abort)
1294{ 1313{
1295 char *path1, *path2, *tmp; 1314 char *path1, *path2, *tmp;
1296 int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0; 1315 int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0;
1316 int rflag = 0, sflag = 0;
1297 int cmdnum, i; 1317 int cmdnum, i;
1298 unsigned long n_arg = 0; 1318 unsigned long n_arg = 0;
1299 Attrib a, *aa; 1319 Attrib a, *aa;
@@ -1302,9 +1322,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1302 glob_t g; 1322 glob_t g;
1303 1323
1304 path1 = path2 = NULL; 1324 path1 = path2 = NULL;
1305 cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, 1325 cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag,
1306 &sflag, &n_arg, &path1, &path2); 1326 &rflag, &sflag, &n_arg, &path1, &path2);
1307
1308 if (iflag != 0) 1327 if (iflag != 0)
1309 err_abort = 0; 1328 err_abort = 0;
1310 1329
@@ -1319,8 +1338,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1319 /* Unrecognized command */ 1338 /* Unrecognized command */
1320 err = -1; 1339 err = -1;
1321 break; 1340 break;
1341 case I_REGET:
1342 aflag = 1;
1343 /* FALLTHROUGH */
1322 case I_GET: 1344 case I_GET:
1323 err = process_get(conn, path1, path2, *pwd, pflag, rflag); 1345 err = process_get(conn, path1, path2, *pwd, pflag,
1346 rflag, aflag);
1324 break; 1347 break;
1325 case I_PUT: 1348 case I_PUT:
1326 err = process_put(conn, path1, path2, *pwd, pflag, rflag); 1349 err = process_put(conn, path1, path2, *pwd, pflag, rflag);
@@ -1949,12 +1972,10 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1949 } 1972 }
1950 } else { 1973 } else {
1951 /* XXX this is wrong wrt quoting */ 1974 /* XXX this is wrong wrt quoting */
1952 if (file2 == NULL) 1975 snprintf(cmd, sizeof cmd, "get%s %s%s%s",
1953 snprintf(cmd, sizeof cmd, "get %s", dir); 1976 global_aflag ? " -a" : "", dir,
1954 else 1977 file2 == NULL ? "" : " ",
1955 snprintf(cmd, sizeof cmd, "get %s %s", dir, 1978 file2 == NULL ? "" : file2);
1956 file2);
1957
1958 err = parse_dispatch_command(conn, cmd, 1979 err = parse_dispatch_command(conn, cmd,
1959 &remote_path, 1); 1980 &remote_path, 1);
1960 free(dir); 1981 free(dir);
@@ -2143,7 +2164,7 @@ main(int argc, char **argv)
2143 infile = stdin; 2164 infile = stdin;
2144 2165
2145 while ((ch = getopt(argc, argv, 2166 while ((ch = getopt(argc, argv,
2146 "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { 2167 "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2147 switch (ch) { 2168 switch (ch) {
2148 /* Passed through to ssh(1) */ 2169 /* Passed through to ssh(1) */
2149 case '4': 2170 case '4':
@@ -2183,6 +2204,9 @@ main(int argc, char **argv)
2183 case '2': 2204 case '2':
2184 sshver = 2; 2205 sshver = 2;
2185 break; 2206 break;
2207 case 'a':
2208 global_aflag = 1;
2209 break;
2186 case 'B': 2210 case 'B':
2187 copy_buffer_len = strtol(optarg, &cp, 10); 2211 copy_buffer_len = strtol(optarg, &cp, 10);
2188 if (copy_buffer_len == 0 || *cp != '\0') 2212 if (copy_buffer_len == 0 || *cp != '\0')