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