Merge from vendor branch GDB:
[dragonfly.git] / crypto / openssh-4 / sftp-client.c
1 /*
2  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 /* XXX: memleaks */
18 /* XXX: signed vs unsigned */
19 /* XXX: remove all logging, only return status codes */
20 /* XXX: copy between two remote sites */
21
22 #include "includes.h"
23 RCSID("$OpenBSD: sftp-client.c,v 1.57 2005/07/27 10:39:03 dtucker Exp $");
24
25 #include "openbsd-compat/sys-queue.h"
26
27 #include "buffer.h"
28 #include "bufaux.h"
29 #include "getput.h"
30 #include "xmalloc.h"
31 #include "log.h"
32 #include "atomicio.h"
33 #include "progressmeter.h"
34
35 #include "sftp.h"
36 #include "sftp-common.h"
37 #include "sftp-client.h"
38
39 extern volatile sig_atomic_t interrupted;
40 extern int showprogress;
41
42 /* Minimum amount of data to read at at time */
43 #define MIN_READ_SIZE   512
44
45 /* Maximum packet size */
46 #define MAX_MSG_LENGTH  (256 * 1024)
47
48 struct sftp_conn {
49         int fd_in;
50         int fd_out;
51         u_int transfer_buflen;
52         u_int num_requests;
53         u_int version;
54         u_int msg_id;
55 };
56
57 static void
58 send_msg(int fd, Buffer *m)
59 {
60         u_char mlen[4];
61
62         if (buffer_len(m) > MAX_MSG_LENGTH)
63                 fatal("Outbound message too long %u", buffer_len(m));
64
65         /* Send length first */
66         PUT_32BIT(mlen, buffer_len(m));
67         if (atomicio(vwrite, fd, mlen, sizeof(mlen)) != sizeof(mlen))
68                 fatal("Couldn't send packet: %s", strerror(errno));
69
70         if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) != buffer_len(m))
71                 fatal("Couldn't send packet: %s", strerror(errno));
72
73         buffer_clear(m);
74 }
75
76 static void
77 get_msg(int fd, Buffer *m)
78 {
79         u_int msg_len;
80
81         buffer_append_space(m, 4);
82         if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
83                 if (errno == EPIPE)
84                         fatal("Connection closed");
85                 else
86                         fatal("Couldn't read packet: %s", strerror(errno));
87         }
88
89         msg_len = buffer_get_int(m);
90         if (msg_len > MAX_MSG_LENGTH)
91                 fatal("Received message too long %u", msg_len);
92
93         buffer_append_space(m, msg_len);
94         if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
95                 if (errno == EPIPE)
96                         fatal("Connection closed");
97                 else
98                         fatal("Read packet: %s", strerror(errno));
99         }
100 }
101
102 static void
103 send_string_request(int fd, u_int id, u_int code, char *s,
104     u_int len)
105 {
106         Buffer msg;
107
108         buffer_init(&msg);
109         buffer_put_char(&msg, code);
110         buffer_put_int(&msg, id);
111         buffer_put_string(&msg, s, len);
112         send_msg(fd, &msg);
113         debug3("Sent message fd %d T:%u I:%u", fd, code, id);
114         buffer_free(&msg);
115 }
116
117 static void
118 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
119     u_int len, Attrib *a)
120 {
121         Buffer msg;
122
123         buffer_init(&msg);
124         buffer_put_char(&msg, code);
125         buffer_put_int(&msg, id);
126         buffer_put_string(&msg, s, len);
127         encode_attrib(&msg, a);
128         send_msg(fd, &msg);
129         debug3("Sent message fd %d T:%u I:%u", fd, code, id);
130         buffer_free(&msg);
131 }
132
133 static u_int
134 get_status(int fd, u_int expected_id)
135 {
136         Buffer msg;
137         u_int type, id, status;
138
139         buffer_init(&msg);
140         get_msg(fd, &msg);
141         type = buffer_get_char(&msg);
142         id = buffer_get_int(&msg);
143
144         if (id != expected_id)
145                 fatal("ID mismatch (%u != %u)", id, expected_id);
146         if (type != SSH2_FXP_STATUS)
147                 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
148                     SSH2_FXP_STATUS, type);
149
150         status = buffer_get_int(&msg);
151         buffer_free(&msg);
152
153         debug3("SSH2_FXP_STATUS %u", status);
154
155         return(status);
156 }
157
158 static char *
159 get_handle(int fd, u_int expected_id, u_int *len)
160 {
161         Buffer msg;
162         u_int type, id;
163         char *handle;
164
165         buffer_init(&msg);
166         get_msg(fd, &msg);
167         type = buffer_get_char(&msg);
168         id = buffer_get_int(&msg);
169
170         if (id != expected_id)
171                 fatal("ID mismatch (%u != %u)", id, expected_id);
172         if (type == SSH2_FXP_STATUS) {
173                 int status = buffer_get_int(&msg);
174
175                 error("Couldn't get handle: %s", fx2txt(status));
176                 buffer_free(&msg);
177                 return(NULL);
178         } else if (type != SSH2_FXP_HANDLE)
179                 fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
180                     SSH2_FXP_HANDLE, type);
181
182         handle = buffer_get_string(&msg, len);
183         buffer_free(&msg);
184
185         return(handle);
186 }
187
188 static Attrib *
189 get_decode_stat(int fd, u_int expected_id, int quiet)
190 {
191         Buffer msg;
192         u_int type, id;
193         Attrib *a;
194
195         buffer_init(&msg);
196         get_msg(fd, &msg);
197
198         type = buffer_get_char(&msg);
199         id = buffer_get_int(&msg);
200
201         debug3("Received stat reply T:%u I:%u", type, id);
202         if (id != expected_id)
203                 fatal("ID mismatch (%u != %u)", id, expected_id);
204         if (type == SSH2_FXP_STATUS) {
205                 int status = buffer_get_int(&msg);
206
207                 if (quiet)
208                         debug("Couldn't stat remote file: %s", fx2txt(status));
209                 else
210                         error("Couldn't stat remote file: %s", fx2txt(status));
211                 buffer_free(&msg);
212                 return(NULL);
213         } else if (type != SSH2_FXP_ATTRS) {
214                 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
215                     SSH2_FXP_ATTRS, type);
216         }
217         a = decode_attrib(&msg);
218         buffer_free(&msg);
219
220         return(a);
221 }
222
223 struct sftp_conn *
224 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
225 {
226         u_int type;
227         int version;
228         Buffer msg;
229         struct sftp_conn *ret;
230
231         buffer_init(&msg);
232         buffer_put_char(&msg, SSH2_FXP_INIT);
233         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
234         send_msg(fd_out, &msg);
235
236         buffer_clear(&msg);
237
238         get_msg(fd_in, &msg);
239
240         /* Expecting a VERSION reply */
241         if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
242                 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
243                     type);
244                 buffer_free(&msg);
245                 return(NULL);
246         }
247         version = buffer_get_int(&msg);
248
249         debug2("Remote version: %d", version);
250
251         /* Check for extensions */
252         while (buffer_len(&msg) > 0) {
253                 char *name = buffer_get_string(&msg, NULL);
254                 char *value = buffer_get_string(&msg, NULL);
255
256                 debug2("Init extension: \"%s\"", name);
257                 xfree(name);
258                 xfree(value);
259         }
260
261         buffer_free(&msg);
262
263         ret = xmalloc(sizeof(*ret));
264         ret->fd_in = fd_in;
265         ret->fd_out = fd_out;
266         ret->transfer_buflen = transfer_buflen;
267         ret->num_requests = num_requests;
268         ret->version = version;
269         ret->msg_id = 1;
270
271         /* Some filexfer v.0 servers don't support large packets */
272         if (version == 0)
273                 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
274
275         return(ret);
276 }
277
278 u_int
279 sftp_proto_version(struct sftp_conn *conn)
280 {
281         return(conn->version);
282 }
283
284 int
285 do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
286 {
287         u_int id, status;
288         Buffer msg;
289
290         buffer_init(&msg);
291
292         id = conn->msg_id++;
293         buffer_put_char(&msg, SSH2_FXP_CLOSE);
294         buffer_put_int(&msg, id);
295         buffer_put_string(&msg, handle, handle_len);
296         send_msg(conn->fd_out, &msg);
297         debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
298
299         status = get_status(conn->fd_in, id);
300         if (status != SSH2_FX_OK)
301                 error("Couldn't close file: %s", fx2txt(status));
302
303         buffer_free(&msg);
304
305         return(status);
306 }
307
308
309 static int
310 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
311     SFTP_DIRENT ***dir)
312 {
313         Buffer msg;
314         u_int count, type, id, handle_len, i, expected_id, ents = 0;
315         char *handle;
316
317         id = conn->msg_id++;
318
319         buffer_init(&msg);
320         buffer_put_char(&msg, SSH2_FXP_OPENDIR);
321         buffer_put_int(&msg, id);
322         buffer_put_cstring(&msg, path);
323         send_msg(conn->fd_out, &msg);
324
325         buffer_clear(&msg);
326
327         handle = get_handle(conn->fd_in, id, &handle_len);
328         if (handle == NULL)
329                 return(-1);
330
331         if (dir) {
332                 ents = 0;
333                 *dir = xmalloc(sizeof(**dir));
334                 (*dir)[0] = NULL;
335         }
336
337         for (; !interrupted;) {
338                 id = expected_id = conn->msg_id++;
339
340                 debug3("Sending SSH2_FXP_READDIR I:%u", id);
341
342                 buffer_clear(&msg);
343                 buffer_put_char(&msg, SSH2_FXP_READDIR);
344                 buffer_put_int(&msg, id);
345                 buffer_put_string(&msg, handle, handle_len);
346                 send_msg(conn->fd_out, &msg);
347
348                 buffer_clear(&msg);
349
350                 get_msg(conn->fd_in, &msg);
351
352                 type = buffer_get_char(&msg);
353                 id = buffer_get_int(&msg);
354
355                 debug3("Received reply T:%u I:%u", type, id);
356
357                 if (id != expected_id)
358                         fatal("ID mismatch (%u != %u)", id, expected_id);
359
360                 if (type == SSH2_FXP_STATUS) {
361                         int status = buffer_get_int(&msg);
362
363                         debug3("Received SSH2_FXP_STATUS %d", status);
364
365                         if (status == SSH2_FX_EOF) {
366                                 break;
367                         } else {
368                                 error("Couldn't read directory: %s",
369                                     fx2txt(status));
370                                 do_close(conn, handle, handle_len);
371                                 xfree(handle);
372                                 return(status);
373                         }
374                 } else if (type != SSH2_FXP_NAME)
375                         fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
376                             SSH2_FXP_NAME, type);
377
378                 count = buffer_get_int(&msg);
379                 if (count == 0)
380                         break;
381                 debug3("Received %d SSH2_FXP_NAME responses", count);
382                 for (i = 0; i < count; i++) {
383                         char *filename, *longname;
384                         Attrib *a;
385
386                         filename = buffer_get_string(&msg, NULL);
387                         longname = buffer_get_string(&msg, NULL);
388                         a = decode_attrib(&msg);
389
390                         if (printflag)
391                                 printf("%s\n", longname);
392
393                         if (dir) {
394                                 *dir = xrealloc(*dir, sizeof(**dir) *
395                                     (ents + 2));
396                                 (*dir)[ents] = xmalloc(sizeof(***dir));
397                                 (*dir)[ents]->filename = xstrdup(filename);
398                                 (*dir)[ents]->longname = xstrdup(longname);
399                                 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
400                                 (*dir)[++ents] = NULL;
401                         }
402
403                         xfree(filename);
404                         xfree(longname);
405                 }
406         }
407
408         buffer_free(&msg);
409         do_close(conn, handle, handle_len);
410         xfree(handle);
411
412         /* Don't return partial matches on interrupt */
413         if (interrupted && dir != NULL && *dir != NULL) {
414                 free_sftp_dirents(*dir);
415                 *dir = xmalloc(sizeof(**dir));
416                 **dir = NULL;
417         }
418
419         return(0);
420 }
421
422 int
423 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
424 {
425         return(do_lsreaddir(conn, path, 0, dir));
426 }
427
428 void free_sftp_dirents(SFTP_DIRENT **s)
429 {
430         int i;
431
432         for (i = 0; s[i]; i++) {
433                 xfree(s[i]->filename);
434                 xfree(s[i]->longname);
435                 xfree(s[i]);
436         }
437         xfree(s);
438 }
439
440 int
441 do_rm(struct sftp_conn *conn, char *path)
442 {
443         u_int status, id;
444
445         debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
446
447         id = conn->msg_id++;
448         send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,
449             strlen(path));
450         status = get_status(conn->fd_in, id);
451         if (status != SSH2_FX_OK)
452                 error("Couldn't delete file: %s", fx2txt(status));
453         return(status);
454 }
455
456 int
457 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)
458 {
459         u_int status, id;
460
461         id = conn->msg_id++;
462         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
463             strlen(path), a);
464
465         status = get_status(conn->fd_in, id);
466         if (status != SSH2_FX_OK)
467                 error("Couldn't create directory: %s", fx2txt(status));
468
469         return(status);
470 }
471
472 int
473 do_rmdir(struct sftp_conn *conn, char *path)
474 {
475         u_int status, id;
476
477         id = conn->msg_id++;
478         send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,
479             strlen(path));
480
481         status = get_status(conn->fd_in, id);
482         if (status != SSH2_FX_OK)
483                 error("Couldn't remove directory: %s", fx2txt(status));
484
485         return(status);
486 }
487
488 Attrib *
489 do_stat(struct sftp_conn *conn, char *path, int quiet)
490 {
491         u_int id;
492
493         id = conn->msg_id++;
494
495         send_string_request(conn->fd_out, id,
496             conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
497             path, strlen(path));
498
499         return(get_decode_stat(conn->fd_in, id, quiet));
500 }
501
502 Attrib *
503 do_lstat(struct sftp_conn *conn, char *path, int quiet)
504 {
505         u_int id;
506
507         if (conn->version == 0) {
508                 if (quiet)
509                         debug("Server version does not support lstat operation");
510                 else
511                         logit("Server version does not support lstat operation");
512                 return(do_stat(conn, path, quiet));
513         }
514
515         id = conn->msg_id++;
516         send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,
517             strlen(path));
518
519         return(get_decode_stat(conn->fd_in, id, quiet));
520 }
521
522 Attrib *
523 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
524 {
525         u_int id;
526
527         id = conn->msg_id++;
528         send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,
529             handle_len);
530
531         return(get_decode_stat(conn->fd_in, id, quiet));
532 }
533
534 int
535 do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
536 {
537         u_int status, id;
538
539         id = conn->msg_id++;
540         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,
541             strlen(path), a);
542
543         status = get_status(conn->fd_in, id);
544         if (status != SSH2_FX_OK)
545                 error("Couldn't setstat on \"%s\": %s", path,
546                     fx2txt(status));
547
548         return(status);
549 }
550
551 int
552 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
553     Attrib *a)
554 {
555         u_int status, id;
556
557         id = conn->msg_id++;
558         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,
559             handle_len, a);
560
561         status = get_status(conn->fd_in, id);
562         if (status != SSH2_FX_OK)
563                 error("Couldn't fsetstat: %s", fx2txt(status));
564
565         return(status);
566 }
567
568 char *
569 do_realpath(struct sftp_conn *conn, char *path)
570 {
571         Buffer msg;
572         u_int type, expected_id, count, id;
573         char *filename, *longname;
574         Attrib *a;
575
576         expected_id = id = conn->msg_id++;
577         send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,
578             strlen(path));
579
580         buffer_init(&msg);
581
582         get_msg(conn->fd_in, &msg);
583         type = buffer_get_char(&msg);
584         id = buffer_get_int(&msg);
585
586         if (id != expected_id)
587                 fatal("ID mismatch (%u != %u)", id, expected_id);
588
589         if (type == SSH2_FXP_STATUS) {
590                 u_int status = buffer_get_int(&msg);
591
592                 error("Couldn't canonicalise: %s", fx2txt(status));
593                 return(NULL);
594         } else if (type != SSH2_FXP_NAME)
595                 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
596                     SSH2_FXP_NAME, type);
597
598         count = buffer_get_int(&msg);
599         if (count != 1)
600                 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
601
602         filename = buffer_get_string(&msg, NULL);
603         longname = buffer_get_string(&msg, NULL);
604         a = decode_attrib(&msg);
605
606         debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
607
608         xfree(longname);
609
610         buffer_free(&msg);
611
612         return(filename);
613 }
614
615 int
616 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
617 {
618         Buffer msg;
619         u_int status, id;
620
621         buffer_init(&msg);
622
623         /* Send rename request */
624         id = conn->msg_id++;
625         buffer_put_char(&msg, SSH2_FXP_RENAME);
626         buffer_put_int(&msg, id);
627         buffer_put_cstring(&msg, oldpath);
628         buffer_put_cstring(&msg, newpath);
629         send_msg(conn->fd_out, &msg);
630         debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
631             newpath);
632         buffer_free(&msg);
633
634         status = get_status(conn->fd_in, id);
635         if (status != SSH2_FX_OK)
636                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
637                     newpath, fx2txt(status));
638
639         return(status);
640 }
641
642 int
643 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
644 {
645         Buffer msg;
646         u_int status, id;
647
648         if (conn->version < 3) {
649                 error("This server does not support the symlink operation");
650                 return(SSH2_FX_OP_UNSUPPORTED);
651         }
652
653         buffer_init(&msg);
654
655         /* Send symlink request */
656         id = conn->msg_id++;
657         buffer_put_char(&msg, SSH2_FXP_SYMLINK);
658         buffer_put_int(&msg, id);
659         buffer_put_cstring(&msg, oldpath);
660         buffer_put_cstring(&msg, newpath);
661         send_msg(conn->fd_out, &msg);
662         debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
663             newpath);
664         buffer_free(&msg);
665
666         status = get_status(conn->fd_in, id);
667         if (status != SSH2_FX_OK)
668                 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
669                     newpath, fx2txt(status));
670
671         return(status);
672 }
673
674 char *
675 do_readlink(struct sftp_conn *conn, char *path)
676 {
677         Buffer msg;
678         u_int type, expected_id, count, id;
679         char *filename, *longname;
680         Attrib *a;
681
682         expected_id = id = conn->msg_id++;
683         send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,
684             strlen(path));
685
686         buffer_init(&msg);
687
688         get_msg(conn->fd_in, &msg);
689         type = buffer_get_char(&msg);
690         id = buffer_get_int(&msg);
691
692         if (id != expected_id)
693                 fatal("ID mismatch (%u != %u)", id, expected_id);
694
695         if (type == SSH2_FXP_STATUS) {
696                 u_int status = buffer_get_int(&msg);
697
698                 error("Couldn't readlink: %s", fx2txt(status));
699                 return(NULL);
700         } else if (type != SSH2_FXP_NAME)
701                 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
702                     SSH2_FXP_NAME, type);
703
704         count = buffer_get_int(&msg);
705         if (count != 1)
706                 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
707
708         filename = buffer_get_string(&msg, NULL);
709         longname = buffer_get_string(&msg, NULL);
710         a = decode_attrib(&msg);
711
712         debug3("SSH_FXP_READLINK %s -> %s", path, filename);
713
714         xfree(longname);
715
716         buffer_free(&msg);
717
718         return(filename);
719 }
720
721 static void
722 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
723     char *handle, u_int handle_len)
724 {
725         Buffer msg;
726
727         buffer_init(&msg);
728         buffer_clear(&msg);
729         buffer_put_char(&msg, SSH2_FXP_READ);
730         buffer_put_int(&msg, id);
731         buffer_put_string(&msg, handle, handle_len);
732         buffer_put_int64(&msg, offset);
733         buffer_put_int(&msg, len);
734         send_msg(fd_out, &msg);
735         buffer_free(&msg);
736 }
737
738 int
739 do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
740     int pflag)
741 {
742         Attrib junk, *a;
743         Buffer msg;
744         char *handle;
745         int local_fd, status = 0, write_error;
746         int read_error, write_errno;
747         u_int64_t offset, size;
748         u_int handle_len, mode, type, id, buflen, num_req, max_req;
749         off_t progress_counter;
750         struct request {
751                 u_int id;
752                 u_int len;
753                 u_int64_t offset;
754                 TAILQ_ENTRY(request) tq;
755         };
756         TAILQ_HEAD(reqhead, request) requests;
757         struct request *req;
758
759         TAILQ_INIT(&requests);
760
761         a = do_stat(conn, remote_path, 0);
762         if (a == NULL)
763                 return(-1);
764
765         /* XXX: should we preserve set[ug]id? */
766         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
767                 mode = a->perm & 0777;
768         else
769                 mode = 0666;
770
771         if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
772             (!S_ISREG(a->perm))) {
773                 error("Cannot download non-regular file: %s", remote_path);
774                 return(-1);
775         }
776
777         if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
778                 size = a->size;
779         else
780                 size = 0;
781
782         buflen = conn->transfer_buflen;
783         buffer_init(&msg);
784
785         /* Send open request */
786         id = conn->msg_id++;
787         buffer_put_char(&msg, SSH2_FXP_OPEN);
788         buffer_put_int(&msg, id);
789         buffer_put_cstring(&msg, remote_path);
790         buffer_put_int(&msg, SSH2_FXF_READ);
791         attrib_clear(&junk); /* Send empty attributes */
792         encode_attrib(&msg, &junk);
793         send_msg(conn->fd_out, &msg);
794         debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
795
796         handle = get_handle(conn->fd_in, id, &handle_len);
797         if (handle == NULL) {
798                 buffer_free(&msg);
799                 return(-1);
800         }
801
802         local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
803             mode | S_IWRITE);
804         if (local_fd == -1) {
805                 error("Couldn't open local file \"%s\" for writing: %s",
806                     local_path, strerror(errno));
807                 buffer_free(&msg);
808                 xfree(handle);
809                 return(-1);
810         }
811
812         /* Read from remote and write to local */
813         write_error = read_error = write_errno = num_req = offset = 0;
814         max_req = 1;
815         progress_counter = 0;
816
817         if (showprogress && size != 0)
818                 start_progress_meter(remote_path, size, &progress_counter);
819
820         while (num_req > 0 || max_req > 0) {
821                 char *data;
822                 u_int len;
823
824                 /*
825                  * Simulate EOF on interrupt: stop sending new requests and
826                  * allow outstanding requests to drain gracefully
827                  */
828                 if (interrupted) {
829                         if (num_req == 0) /* If we haven't started yet... */
830                                 break;
831                         max_req = 0;
832                 }
833
834                 /* Send some more requests */
835                 while (num_req < max_req) {
836                         debug3("Request range %llu -> %llu (%d/%d)",
837                             (unsigned long long)offset,
838                             (unsigned long long)offset + buflen - 1,
839                             num_req, max_req);
840                         req = xmalloc(sizeof(*req));
841                         req->id = conn->msg_id++;
842                         req->len = buflen;
843                         req->offset = offset;
844                         offset += buflen;
845                         num_req++;
846                         TAILQ_INSERT_TAIL(&requests, req, tq);
847                         send_read_request(conn->fd_out, req->id, req->offset,
848                             req->len, handle, handle_len);
849                 }
850
851                 buffer_clear(&msg);
852                 get_msg(conn->fd_in, &msg);
853                 type = buffer_get_char(&msg);
854                 id = buffer_get_int(&msg);
855                 debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
856
857                 /* Find the request in our queue */
858                 for (req = TAILQ_FIRST(&requests);
859                     req != NULL && req->id != id;
860                     req = TAILQ_NEXT(req, tq))
861                         ;
862                 if (req == NULL)
863                         fatal("Unexpected reply %u", id);
864
865                 switch (type) {
866                 case SSH2_FXP_STATUS:
867                         status = buffer_get_int(&msg);
868                         if (status != SSH2_FX_EOF)
869                                 read_error = 1;
870                         max_req = 0;
871                         TAILQ_REMOVE(&requests, req, tq);
872                         xfree(req);
873                         num_req--;
874                         break;
875                 case SSH2_FXP_DATA:
876                         data = buffer_get_string(&msg, &len);
877                         debug3("Received data %llu -> %llu",
878                             (unsigned long long)req->offset,
879                             (unsigned long long)req->offset + len - 1);
880                         if (len > req->len)
881                                 fatal("Received more data than asked for "
882                                     "%u > %u", len, req->len);
883                         if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
884                             atomicio(vwrite, local_fd, data, len) != len) &&
885                             !write_error) {
886                                 write_errno = errno;
887                                 write_error = 1;
888                                 max_req = 0;
889                         }
890                         progress_counter += len;
891                         xfree(data);
892
893                         if (len == req->len) {
894                                 TAILQ_REMOVE(&requests, req, tq);
895                                 xfree(req);
896                                 num_req--;
897                         } else {
898                                 /* Resend the request for the missing data */
899                                 debug3("Short data block, re-requesting "
900                                     "%llu -> %llu (%2d)",
901                                     (unsigned long long)req->offset + len,
902                                     (unsigned long long)req->offset +
903                                     req->len - 1, num_req);
904                                 req->id = conn->msg_id++;
905                                 req->len -= len;
906                                 req->offset += len;
907                                 send_read_request(conn->fd_out, req->id,
908                                     req->offset, req->len, handle, handle_len);
909                                 /* Reduce the request size */
910                                 if (len < buflen)
911                                         buflen = MAX(MIN_READ_SIZE, len);
912                         }
913                         if (max_req > 0) { /* max_req = 0 iff EOF received */
914                                 if (size > 0 && offset > size) {
915                                         /* Only one request at a time
916                                          * after the expected EOF */
917                                         debug3("Finish at %llu (%2d)",
918                                             (unsigned long long)offset,
919                                             num_req);
920                                         max_req = 1;
921                                 } else if (max_req <= conn->num_requests) {
922                                         ++max_req;
923                                 }
924                         }
925                         break;
926                 default:
927                         fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
928                             SSH2_FXP_DATA, type);
929                 }
930         }
931
932         if (showprogress && size)
933                 stop_progress_meter();
934
935         /* Sanity check */
936         if (TAILQ_FIRST(&requests) != NULL)
937                 fatal("Transfer complete, but requests still in queue");
938
939         if (read_error) {
940                 error("Couldn't read from remote file \"%s\" : %s",
941                     remote_path, fx2txt(status));
942                 do_close(conn, handle, handle_len);
943         } else if (write_error) {
944                 error("Couldn't write to \"%s\": %s", local_path,
945                     strerror(write_errno));
946                 status = -1;
947                 do_close(conn, handle, handle_len);
948         } else {
949                 status = do_close(conn, handle, handle_len);
950
951                 /* Override umask and utimes if asked */
952 #ifdef HAVE_FCHMOD
953                 if (pflag && fchmod(local_fd, mode) == -1)
954 #else
955                 if (pflag && chmod(local_path, mode) == -1)
956 #endif /* HAVE_FCHMOD */
957                         error("Couldn't set mode on \"%s\": %s", local_path,
958                             strerror(errno));
959                 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
960                         struct timeval tv[2];
961                         tv[0].tv_sec = a->atime;
962                         tv[1].tv_sec = a->mtime;
963                         tv[0].tv_usec = tv[1].tv_usec = 0;
964                         if (utimes(local_path, tv) == -1)
965                                 error("Can't set times on \"%s\": %s",
966                                     local_path, strerror(errno));
967                 }
968         }
969         close(local_fd);
970         buffer_free(&msg);
971         xfree(handle);
972
973         return(status);
974 }
975
976 int
977 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
978     int pflag)
979 {
980         int local_fd, status;
981         u_int handle_len, id, type;
982         u_int64_t offset;
983         char *handle, *data;
984         Buffer msg;
985         struct stat sb;
986         Attrib a;
987         u_int32_t startid;
988         u_int32_t ackid;
989         struct outstanding_ack {
990                 u_int id;
991                 u_int len;
992                 u_int64_t offset;
993                 TAILQ_ENTRY(outstanding_ack) tq;
994         };
995         TAILQ_HEAD(ackhead, outstanding_ack) acks;
996         struct outstanding_ack *ack = NULL;
997
998         TAILQ_INIT(&acks);
999
1000         if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1001                 error("Couldn't open local file \"%s\" for reading: %s",
1002                     local_path, strerror(errno));
1003                 return(-1);
1004         }
1005         if (fstat(local_fd, &sb) == -1) {
1006                 error("Couldn't fstat local file \"%s\": %s",
1007                     local_path, strerror(errno));
1008                 close(local_fd);
1009                 return(-1);
1010         }
1011         if (!S_ISREG(sb.st_mode)) {
1012                 error("%s is not a regular file", local_path);
1013                 close(local_fd);
1014                 return(-1);
1015         }
1016         stat_to_attrib(&sb, &a);
1017
1018         a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1019         a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1020         a.perm &= 0777;
1021         if (!pflag)
1022                 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1023
1024         buffer_init(&msg);
1025
1026         /* Send open request */
1027         id = conn->msg_id++;
1028         buffer_put_char(&msg, SSH2_FXP_OPEN);
1029         buffer_put_int(&msg, id);
1030         buffer_put_cstring(&msg, remote_path);
1031         buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1032         encode_attrib(&msg, &a);
1033         send_msg(conn->fd_out, &msg);
1034         debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1035
1036         buffer_clear(&msg);
1037
1038         handle = get_handle(conn->fd_in, id, &handle_len);
1039         if (handle == NULL) {
1040                 close(local_fd);
1041                 buffer_free(&msg);
1042                 return(-1);
1043         }
1044
1045         startid = ackid = id + 1;
1046         data = xmalloc(conn->transfer_buflen);
1047
1048         /* Read from local and write to remote */
1049         offset = 0;
1050         if (showprogress)
1051                 start_progress_meter(local_path, sb.st_size, &offset);
1052
1053         for (;;) {
1054                 int len;
1055
1056                 /*
1057                  * Can't use atomicio here because it returns 0 on EOF,
1058                  * thus losing the last block of the file.
1059                  * Simulate an EOF on interrupt, allowing ACKs from the
1060                  * server to drain.
1061                  */
1062                 if (interrupted)
1063                         len = 0;
1064                 else do
1065                         len = read(local_fd, data, conn->transfer_buflen);
1066                 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1067
1068                 if (len == -1)
1069                         fatal("Couldn't read from \"%s\": %s", local_path,
1070                             strerror(errno));
1071
1072                 if (len != 0) {
1073                         ack = xmalloc(sizeof(*ack));
1074                         ack->id = ++id;
1075                         ack->offset = offset;
1076                         ack->len = len;
1077                         TAILQ_INSERT_TAIL(&acks, ack, tq);
1078
1079                         buffer_clear(&msg);
1080                         buffer_put_char(&msg, SSH2_FXP_WRITE);
1081                         buffer_put_int(&msg, ack->id);
1082                         buffer_put_string(&msg, handle, handle_len);
1083                         buffer_put_int64(&msg, offset);
1084                         buffer_put_string(&msg, data, len);
1085                         send_msg(conn->fd_out, &msg);
1086                         debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1087                             id, (unsigned long long)offset, len);
1088                 } else if (TAILQ_FIRST(&acks) == NULL)
1089                         break;
1090
1091                 if (ack == NULL)
1092                         fatal("Unexpected ACK %u", id);
1093
1094                 if (id == startid || len == 0 ||
1095                     id - ackid >= conn->num_requests) {
1096                         u_int r_id;
1097
1098                         buffer_clear(&msg);
1099                         get_msg(conn->fd_in, &msg);
1100                         type = buffer_get_char(&msg);
1101                         r_id = buffer_get_int(&msg);
1102
1103                         if (type != SSH2_FXP_STATUS)
1104                                 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1105                                     "got %d", SSH2_FXP_STATUS, type);
1106
1107                         status = buffer_get_int(&msg);
1108                         debug3("SSH2_FXP_STATUS %d", status);
1109
1110                         /* Find the request in our queue */
1111                         for (ack = TAILQ_FIRST(&acks);
1112                             ack != NULL && ack->id != r_id;
1113                             ack = TAILQ_NEXT(ack, tq))
1114                                 ;
1115                         if (ack == NULL)
1116                                 fatal("Can't find request for ID %u", r_id);
1117                         TAILQ_REMOVE(&acks, ack, tq);
1118
1119                         if (status != SSH2_FX_OK) {
1120                                 error("Couldn't write to remote file \"%s\": %s",
1121                                     remote_path, fx2txt(status));
1122                                 do_close(conn, handle, handle_len);
1123                                 close(local_fd);
1124                                 xfree(data);
1125                                 xfree(ack);
1126                                 goto done;
1127                         }
1128                         debug3("In write loop, ack for %u %u bytes at %llu",
1129                             ack->id, ack->len, (unsigned long long)ack->offset);
1130                         ++ackid;
1131                         xfree(ack);
1132                 }
1133                 offset += len;
1134         }
1135         if (showprogress)
1136                 stop_progress_meter();
1137         xfree(data);
1138
1139         if (close(local_fd) == -1) {
1140                 error("Couldn't close local file \"%s\": %s", local_path,
1141                     strerror(errno));
1142                 do_close(conn, handle, handle_len);
1143                 status = -1;
1144                 goto done;
1145         }
1146
1147         /* Override umask and utimes if asked */
1148         if (pflag)
1149                 do_fsetstat(conn, handle, handle_len, &a);
1150
1151         status = do_close(conn, handle, handle_len);
1152
1153 done:
1154         xfree(handle);
1155         buffer_free(&msg);
1156         return(status);
1157 }