]> andersk Git - openssh.git/blob - sftp-client.c
- markus@cvs.openbsd.org 2002/02/03 17:55:55
[openssh.git] / sftp-client.c
1 /*
2  * Copyright (c) 2001 Damien Miller.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 /* XXX: memleaks */
26 /* XXX: signed vs unsigned */
27 /* XXX: redesign to allow concurrent overlapped operations */
28 /* XXX: we use fatal too much, error may be more appropriate in places */
29 /* XXX: copy between two remote sites */
30
31 #include "includes.h"
32 RCSID("$OpenBSD: sftp-client.c,v 1.19 2001/12/19 07:18:56 deraadt Exp $");
33
34 #include "buffer.h"
35 #include "bufaux.h"
36 #include "getput.h"
37 #include "xmalloc.h"
38 #include "log.h"
39 #include "atomicio.h"
40
41 #include "sftp.h"
42 #include "sftp-common.h"
43 #include "sftp-client.h"
44
45 /* How much data to read/write at at time during copies */
46 /* XXX: what should this be? */
47 #define COPY_SIZE       8192
48
49 /* Message ID */
50 static u_int msg_id = 1;
51
52 static void
53 send_msg(int fd, Buffer *m)
54 {
55         int mlen = buffer_len(m);
56         int len;
57         Buffer oqueue;
58
59         buffer_init(&oqueue);
60         buffer_put_int(&oqueue, mlen);
61         buffer_append(&oqueue, buffer_ptr(m), mlen);
62         buffer_consume(m, mlen);
63
64         len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue));
65         if (len <= 0)
66                 fatal("Couldn't send packet: %s", strerror(errno));
67
68         buffer_free(&oqueue);
69 }
70
71 static void
72 get_msg(int fd, Buffer *m)
73 {
74         u_int len, msg_len;
75         unsigned char buf[4096];
76
77         len = atomicio(read, fd, buf, 4);
78         if (len == 0)
79                 fatal("Connection closed");
80         else if (len == -1)
81                 fatal("Couldn't read packet: %s", strerror(errno));
82
83         msg_len = GET_32BIT(buf);
84         if (msg_len > 256 * 1024)
85                 fatal("Received message too long %d", msg_len);
86
87         while (msg_len) {
88                 len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
89                 if (len == 0)
90                         fatal("Connection closed");
91                 else if (len == -1)
92                         fatal("Couldn't read packet: %s", strerror(errno));
93
94                 msg_len -= len;
95                 buffer_append(m, buf, len);
96         }
97 }
98
99 static void
100 send_string_request(int fd, u_int id, u_int code, char *s,
101     u_int len)
102 {
103         Buffer msg;
104
105         buffer_init(&msg);
106         buffer_put_char(&msg, code);
107         buffer_put_int(&msg, id);
108         buffer_put_string(&msg, s, len);
109         send_msg(fd, &msg);
110         debug3("Sent message fd %d T:%d I:%d", fd, code, id);
111         buffer_free(&msg);
112 }
113
114 static void
115 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
116     u_int len, Attrib *a)
117 {
118         Buffer msg;
119
120         buffer_init(&msg);
121         buffer_put_char(&msg, code);
122         buffer_put_int(&msg, id);
123         buffer_put_string(&msg, s, len);
124         encode_attrib(&msg, a);
125         send_msg(fd, &msg);
126         debug3("Sent message fd %d T:%d I:%d", fd, code, id);
127         buffer_free(&msg);
128 }
129
130 static u_int
131 get_status(int fd, int expected_id)
132 {
133         Buffer msg;
134         u_int type, id, status;
135
136         buffer_init(&msg);
137         get_msg(fd, &msg);
138         type = buffer_get_char(&msg);
139         id = buffer_get_int(&msg);
140
141         if (id != expected_id)
142                 fatal("ID mismatch (%d != %d)", id, expected_id);
143         if (type != SSH2_FXP_STATUS)
144                 fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
145                     SSH2_FXP_STATUS, type);
146
147         status = buffer_get_int(&msg);
148         buffer_free(&msg);
149
150         debug3("SSH2_FXP_STATUS %d", status);
151
152         return(status);
153 }
154
155 static char *
156 get_handle(int fd, u_int expected_id, u_int *len)
157 {
158         Buffer msg;
159         u_int type, id;
160         char *handle;
161
162         buffer_init(&msg);
163         get_msg(fd, &msg);
164         type = buffer_get_char(&msg);
165         id = buffer_get_int(&msg);
166
167         if (id != expected_id)
168                 fatal("ID mismatch (%d != %d)", id, expected_id);
169         if (type == SSH2_FXP_STATUS) {
170                 int status = buffer_get_int(&msg);
171
172                 error("Couldn't get handle: %s", fx2txt(status));
173                 return(NULL);
174         } else if (type != SSH2_FXP_HANDLE)
175                 fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
176                     SSH2_FXP_HANDLE, type);
177
178         handle = buffer_get_string(&msg, len);
179         buffer_free(&msg);
180
181         return(handle);
182 }
183
184 static Attrib *
185 get_decode_stat(int fd, u_int expected_id, int quiet)
186 {
187         Buffer msg;
188         u_int type, id;
189         Attrib *a;
190
191         buffer_init(&msg);
192         get_msg(fd, &msg);
193
194         type = buffer_get_char(&msg);
195         id = buffer_get_int(&msg);
196
197         debug3("Received stat reply T:%d I:%d", type, id);
198         if (id != expected_id)
199                 fatal("ID mismatch (%d != %d)", id, expected_id);
200         if (type == SSH2_FXP_STATUS) {
201                 int status = buffer_get_int(&msg);
202
203                 if (quiet)
204                         debug("Couldn't stat remote file: %s", fx2txt(status));
205                 else
206                         error("Couldn't stat remote file: %s", fx2txt(status));
207                 return(NULL);
208         } else if (type != SSH2_FXP_ATTRS) {
209                 fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
210                     SSH2_FXP_ATTRS, type);
211         }
212         a = decode_attrib(&msg);
213         buffer_free(&msg);
214
215         return(a);
216 }
217
218 int
219 do_init(int fd_in, int fd_out)
220 {
221         int type, version;
222         Buffer msg;
223
224         buffer_init(&msg);
225         buffer_put_char(&msg, SSH2_FXP_INIT);
226         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
227         send_msg(fd_out, &msg);
228
229         buffer_clear(&msg);
230
231         get_msg(fd_in, &msg);
232
233         /* Expecting a VERSION reply */
234         if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
235                 error("Invalid packet back from SSH2_FXP_INIT (type %d)",
236                     type);
237                 buffer_free(&msg);
238                 return(-1);
239         }
240         version = buffer_get_int(&msg);
241
242         debug2("Remote version: %d", version);
243
244         /* Check for extensions */
245         while (buffer_len(&msg) > 0) {
246                 char *name = buffer_get_string(&msg, NULL);
247                 char *value = buffer_get_string(&msg, NULL);
248
249                 debug2("Init extension: \"%s\"", name);
250                 xfree(name);
251                 xfree(value);
252         }
253
254         buffer_free(&msg);
255
256         return(version);
257 }
258
259 int
260 do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
261 {
262         u_int id, status;
263         Buffer msg;
264
265         buffer_init(&msg);
266
267         id = msg_id++;
268         buffer_put_char(&msg, SSH2_FXP_CLOSE);
269         buffer_put_int(&msg, id);
270         buffer_put_string(&msg, handle, handle_len);
271         send_msg(fd_out, &msg);
272         debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
273
274         status = get_status(fd_in, id);
275         if (status != SSH2_FX_OK)
276                 error("Couldn't close file: %s", fx2txt(status));
277
278         buffer_free(&msg);
279
280         return(status);
281 }
282
283
284 static int
285 do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
286     SFTP_DIRENT ***dir)
287 {
288         Buffer msg;
289         u_int type, id, handle_len, i, expected_id, ents = 0;
290         char *handle;
291
292         id = msg_id++;
293
294         buffer_init(&msg);
295         buffer_put_char(&msg, SSH2_FXP_OPENDIR);
296         buffer_put_int(&msg, id);
297         buffer_put_cstring(&msg, path);
298         send_msg(fd_out, &msg);
299
300         buffer_clear(&msg);
301
302         handle = get_handle(fd_in, id, &handle_len);
303         if (handle == NULL)
304                 return(-1);
305
306         if (dir) {
307                 ents = 0;
308                 *dir = xmalloc(sizeof(**dir));
309                 (*dir)[0] = NULL;
310         }
311
312         for (;;) {
313                 int count;
314
315                 id = expected_id = msg_id++;
316
317                 debug3("Sending SSH2_FXP_READDIR I:%d", id);
318
319                 buffer_clear(&msg);
320                 buffer_put_char(&msg, SSH2_FXP_READDIR);
321                 buffer_put_int(&msg, id);
322                 buffer_put_string(&msg, handle, handle_len);
323                 send_msg(fd_out, &msg);
324
325                 buffer_clear(&msg);
326
327                 get_msg(fd_in, &msg);
328
329                 type = buffer_get_char(&msg);
330                 id = buffer_get_int(&msg);
331
332                 debug3("Received reply T:%d I:%d", type, id);
333
334                 if (id != expected_id)
335                         fatal("ID mismatch (%d != %d)", id, expected_id);
336
337                 if (type == SSH2_FXP_STATUS) {
338                         int status = buffer_get_int(&msg);
339
340                         debug3("Received SSH2_FXP_STATUS %d", status);
341
342                         if (status == SSH2_FX_EOF) {
343                                 break;
344                         } else {
345                                 error("Couldn't read directory: %s",
346                                     fx2txt(status));
347                                 do_close(fd_in, fd_out, handle, handle_len);
348                                 return(status);
349                         }
350                 } else if (type != SSH2_FXP_NAME)
351                         fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
352                             SSH2_FXP_NAME, type);
353
354                 count = buffer_get_int(&msg);
355                 if (count == 0)
356                         break;
357                 debug3("Received %d SSH2_FXP_NAME responses", count);
358                 for (i = 0; i < count; i++) {
359                         char *filename, *longname;
360                         Attrib *a;
361
362                         filename = buffer_get_string(&msg, NULL);
363                         longname = buffer_get_string(&msg, NULL);
364                         a = decode_attrib(&msg);
365
366                         if (printflag)
367                                 printf("%s\n", longname);
368
369                         if (dir) {
370                                 *dir = xrealloc(*dir, sizeof(**dir) *
371                                     (ents + 2));
372                                 (*dir)[ents] = xmalloc(sizeof(***dir));
373                                 (*dir)[ents]->filename = xstrdup(filename);
374                                 (*dir)[ents]->longname = xstrdup(longname);
375                                 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
376                                 (*dir)[++ents] = NULL;
377                         }
378
379                         xfree(filename);
380                         xfree(longname);
381                 }
382         }
383
384         buffer_free(&msg);
385         do_close(fd_in, fd_out, handle, handle_len);
386         xfree(handle);
387
388         return(0);
389 }
390
391 int
392 do_ls(int fd_in, int fd_out, char *path)
393 {
394         return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
395 }
396
397 int
398 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
399 {
400         return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
401 }
402
403 void free_sftp_dirents(SFTP_DIRENT **s)
404 {
405         int i;
406
407         for (i = 0; s[i]; i++) {
408                 xfree(s[i]->filename);
409                 xfree(s[i]->longname);
410                 xfree(s[i]);
411         }
412         xfree(s);
413 }
414
415 int
416 do_rm(int fd_in, int fd_out, char *path)
417 {
418         u_int status, id;
419
420         debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
421
422         id = msg_id++;
423         send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
424         status = get_status(fd_in, id);
425         if (status != SSH2_FX_OK)
426                 error("Couldn't delete file: %s", fx2txt(status));
427         return(status);
428 }
429
430 int
431 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
432 {
433         u_int status, id;
434
435         id = msg_id++;
436         send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
437             strlen(path), a);
438
439         status = get_status(fd_in, id);
440         if (status != SSH2_FX_OK)
441                 error("Couldn't create directory: %s", fx2txt(status));
442
443         return(status);
444 }
445
446 int
447 do_rmdir(int fd_in, int fd_out, char *path)
448 {
449         u_int status, id;
450
451         id = msg_id++;
452         send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
453
454         status = get_status(fd_in, id);
455         if (status != SSH2_FX_OK)
456                 error("Couldn't remove directory: %s", fx2txt(status));
457
458         return(status);
459 }
460
461 Attrib *
462 do_stat(int fd_in, int fd_out, char *path, int quiet)
463 {
464         u_int id;
465
466         id = msg_id++;
467         send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
468         return(get_decode_stat(fd_in, id, quiet));
469 }
470
471 Attrib *
472 do_lstat(int fd_in, int fd_out, char *path, int quiet)
473 {
474         u_int id;
475
476         id = msg_id++;
477         send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
478         return(get_decode_stat(fd_in, id, quiet));
479 }
480
481 Attrib *
482 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
483 {
484         u_int id;
485
486         id = msg_id++;
487         send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
488         return(get_decode_stat(fd_in, id, quiet));
489 }
490
491 int
492 do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
493 {
494         u_int status, id;
495
496         id = msg_id++;
497         send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
498             strlen(path), a);
499
500         status = get_status(fd_in, id);
501         if (status != SSH2_FX_OK)
502                 error("Couldn't setstat on \"%s\": %s", path,
503                     fx2txt(status));
504
505         return(status);
506 }
507
508 int
509 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
510     Attrib *a)
511 {
512         u_int status, id;
513
514         id = msg_id++;
515         send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
516             handle_len, a);
517
518         status = get_status(fd_in, id);
519         if (status != SSH2_FX_OK)
520                 error("Couldn't fsetstat: %s", fx2txt(status));
521
522         return(status);
523 }
524
525 char *
526 do_realpath(int fd_in, int fd_out, char *path)
527 {
528         Buffer msg;
529         u_int type, expected_id, count, id;
530         char *filename, *longname;
531         Attrib *a;
532
533         expected_id = id = msg_id++;
534         send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
535
536         buffer_init(&msg);
537
538         get_msg(fd_in, &msg);
539         type = buffer_get_char(&msg);
540         id = buffer_get_int(&msg);
541
542         if (id != expected_id)
543                 fatal("ID mismatch (%d != %d)", id, expected_id);
544
545         if (type == SSH2_FXP_STATUS) {
546                 u_int status = buffer_get_int(&msg);
547
548                 error("Couldn't canonicalise: %s", fx2txt(status));
549                 return(NULL);
550         } else if (type != SSH2_FXP_NAME)
551                 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
552                     SSH2_FXP_NAME, type);
553
554         count = buffer_get_int(&msg);
555         if (count != 1)
556                 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
557
558         filename = buffer_get_string(&msg, NULL);
559         longname = buffer_get_string(&msg, NULL);
560         a = decode_attrib(&msg);
561
562         debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
563
564         xfree(longname);
565
566         buffer_free(&msg);
567
568         return(filename);
569 }
570
571 int
572 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
573 {
574         Buffer msg;
575         u_int status, id;
576
577         buffer_init(&msg);
578
579         /* Send rename request */
580         id = msg_id++;
581         buffer_put_char(&msg, SSH2_FXP_RENAME);
582         buffer_put_int(&msg, id);
583         buffer_put_cstring(&msg, oldpath);
584         buffer_put_cstring(&msg, newpath);
585         send_msg(fd_out, &msg);
586         debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
587             newpath);
588         buffer_free(&msg);
589
590         status = get_status(fd_in, id);
591         if (status != SSH2_FX_OK)
592                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
593                     fx2txt(status));
594
595         return(status);
596 }
597
598 int
599 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
600 {
601         Buffer msg;
602         u_int status, id;
603
604         buffer_init(&msg);
605
606         /* Send rename request */
607         id = msg_id++;
608         buffer_put_char(&msg, SSH2_FXP_SYMLINK);
609         buffer_put_int(&msg, id);
610         buffer_put_cstring(&msg, oldpath);
611         buffer_put_cstring(&msg, newpath);
612         send_msg(fd_out, &msg);
613         debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
614             newpath);
615         buffer_free(&msg);
616
617         status = get_status(fd_in, id);
618         if (status != SSH2_FX_OK)
619                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
620                     fx2txt(status));
621
622         return(status);
623 }
624
625 char *
626 do_readlink(int fd_in, int fd_out, char *path)
627 {
628         Buffer msg;
629         u_int type, expected_id, count, id;
630         char *filename, *longname;
631         Attrib *a;
632
633         expected_id = id = msg_id++;
634         send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
635
636         buffer_init(&msg);
637
638         get_msg(fd_in, &msg);
639         type = buffer_get_char(&msg);
640         id = buffer_get_int(&msg);
641
642         if (id != expected_id)
643                 fatal("ID mismatch (%d != %d)", id, expected_id);
644
645         if (type == SSH2_FXP_STATUS) {
646                 u_int status = buffer_get_int(&msg);
647
648                 error("Couldn't readlink: %s", fx2txt(status));
649                 return(NULL);
650         } else if (type != SSH2_FXP_NAME)
651                 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
652                     SSH2_FXP_NAME, type);
653
654         count = buffer_get_int(&msg);
655         if (count != 1)
656                 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
657
658         filename = buffer_get_string(&msg, NULL);
659         longname = buffer_get_string(&msg, NULL);
660         a = decode_attrib(&msg);
661
662         debug3("SSH_FXP_READLINK %s -> %s", path, filename);
663
664         xfree(longname);
665
666         buffer_free(&msg);
667
668         return(filename);
669 }
670
671 int
672 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
673     int pflag)
674 {
675         int local_fd;
676         u_int expected_id, handle_len, mode, type, id;
677         u_int64_t offset;
678         char *handle;
679         Buffer msg;
680         Attrib junk, *a;
681         int status;
682
683         a = do_stat(fd_in, fd_out, remote_path, 0);
684         if (a == NULL)
685                 return(-1);
686
687         /* XXX: should we preserve set[ug]id? */
688         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
689                 mode = S_IWRITE | (a->perm & 0777);
690         else
691                 mode = 0666;
692
693         if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
694             (a->perm & S_IFDIR)) {
695                 error("Cannot download a directory: %s", remote_path);
696                 return(-1);
697         }
698
699         local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
700         if (local_fd == -1) {
701                 error("Couldn't open local file \"%s\" for writing: %s",
702                     local_path, strerror(errno));
703                 return(-1);
704         }
705
706         buffer_init(&msg);
707
708         /* Send open request */
709         id = msg_id++;
710         buffer_put_char(&msg, SSH2_FXP_OPEN);
711         buffer_put_int(&msg, id);
712         buffer_put_cstring(&msg, remote_path);
713         buffer_put_int(&msg, SSH2_FXF_READ);
714         attrib_clear(&junk); /* Send empty attributes */
715         encode_attrib(&msg, &junk);
716         send_msg(fd_out, &msg);
717         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
718
719         handle = get_handle(fd_in, id, &handle_len);
720         if (handle == NULL) {
721                 buffer_free(&msg);
722                 close(local_fd);
723                 return(-1);
724         }
725
726         /* Read from remote and write to local */
727         offset = 0;
728         for (;;) {
729                 u_int len;
730                 char *data;
731
732                 id = expected_id = msg_id++;
733
734                 buffer_clear(&msg);
735                 buffer_put_char(&msg, SSH2_FXP_READ);
736                 buffer_put_int(&msg, id);
737                 buffer_put_string(&msg, handle, handle_len);
738                 buffer_put_int64(&msg, offset);
739                 buffer_put_int(&msg, COPY_SIZE);
740                 send_msg(fd_out, &msg);
741                 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
742                     id, (u_int64_t)offset, COPY_SIZE);
743
744                 buffer_clear(&msg);
745
746                 get_msg(fd_in, &msg);
747                 type = buffer_get_char(&msg);
748                 id = buffer_get_int(&msg);
749                 debug3("Received reply T:%d I:%d", type, id);
750                 if (id != expected_id)
751                         fatal("ID mismatch (%d != %d)", id, expected_id);
752                 if (type == SSH2_FXP_STATUS) {
753                         status = buffer_get_int(&msg);
754
755                         if (status == SSH2_FX_EOF)
756                                 break;
757                         else {
758                                 error("Couldn't read from remote "
759                                     "file \"%s\" : %s", remote_path,
760                                     fx2txt(status));
761                                 do_close(fd_in, fd_out, handle, handle_len);
762                                 goto done;
763                         }
764                 } else if (type != SSH2_FXP_DATA) {
765                         fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
766                             SSH2_FXP_DATA, type);
767                 }
768
769                 data = buffer_get_string(&msg, &len);
770                 if (len > COPY_SIZE)
771                         fatal("Received more data than asked for %d > %d",
772                             len, COPY_SIZE);
773
774                 debug3("In read loop, got %d offset %llu", len,
775                     (u_int64_t)offset);
776                 if (atomicio(write, local_fd, data, len) != len) {
777                         error("Couldn't write to \"%s\": %s", local_path,
778                             strerror(errno));
779                         do_close(fd_in, fd_out, handle, handle_len);
780                         status = -1;
781                         xfree(data);
782                         goto done;
783                 }
784
785                 offset += len;
786                 xfree(data);
787         }
788         status = do_close(fd_in, fd_out, handle, handle_len);
789
790         /* Override umask and utimes if asked */
791 #ifdef HAVE_FCHMOD
792         if (pflag && fchmod(local_fd, mode) == -1)
793 #else 
794         if (pflag && chmod(local_path, mode) == -1)
795 #endif /* HAVE_FCHMOD */
796                 error("Couldn't set mode on \"%s\": %s", local_path,
797                     strerror(errno));
798         if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
799                 struct timeval tv[2];
800                 tv[0].tv_sec = a->atime;
801                 tv[1].tv_sec = a->mtime;
802                 tv[0].tv_usec = tv[1].tv_usec = 0;
803                 if (utimes(local_path, tv) == -1)
804                         error("Can't set times on \"%s\": %s", local_path,
805                             strerror(errno));
806         }
807
808 done:
809         close(local_fd);
810         buffer_free(&msg);
811         xfree(handle);
812         return status;
813 }
814
815 int
816 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
817     int pflag)
818 {
819         int local_fd;
820         u_int handle_len, id;
821         u_int64_t offset;
822         char *handle;
823         Buffer msg;
824         struct stat sb;
825         Attrib a;
826         int status;
827
828         if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
829                 error("Couldn't open local file \"%s\" for reading: %s",
830                     local_path, strerror(errno));
831                 return(-1);
832         }
833         if (fstat(local_fd, &sb) == -1) {
834                 error("Couldn't fstat local file \"%s\": %s",
835                     local_path, strerror(errno));
836                 close(local_fd);
837                 return(-1);
838         }
839         stat_to_attrib(&sb, &a);
840
841         a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
842         a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
843         a.perm &= 0777;
844         if (!pflag)
845                 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
846
847         buffer_init(&msg);
848
849         /* Send open request */
850         id = msg_id++;
851         buffer_put_char(&msg, SSH2_FXP_OPEN);
852         buffer_put_int(&msg, id);
853         buffer_put_cstring(&msg, remote_path);
854         buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
855         encode_attrib(&msg, &a);
856         send_msg(fd_out, &msg);
857         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
858
859         buffer_clear(&msg);
860
861         handle = get_handle(fd_in, id, &handle_len);
862         if (handle == NULL) {
863                 close(local_fd);
864                 buffer_free(&msg);
865                 return(-1);
866         }
867
868         /* Read from local and write to remote */
869         offset = 0;
870         for (;;) {
871                 int len;
872                 char data[COPY_SIZE];
873
874                 /*
875                  * Can't use atomicio here because it returns 0 on EOF, thus losing
876                  * the last block of the file
877                  */
878                 do
879                         len = read(local_fd, data, COPY_SIZE);
880                 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
881
882                 if (len == -1)
883                         fatal("Couldn't read from \"%s\": %s", local_path,
884                             strerror(errno));
885                 if (len == 0)
886                         break;
887
888                 buffer_clear(&msg);
889                 buffer_put_char(&msg, SSH2_FXP_WRITE);
890                 buffer_put_int(&msg, ++id);
891                 buffer_put_string(&msg, handle, handle_len);
892                 buffer_put_int64(&msg, offset);
893                 buffer_put_string(&msg, data, len);
894                 send_msg(fd_out, &msg);
895                 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
896                     id, (u_int64_t)offset, len);
897
898                 status = get_status(fd_in, id);
899                 if (status != SSH2_FX_OK) {
900                         error("Couldn't write to remote file \"%s\": %s",
901                             remote_path, fx2txt(status));
902                         do_close(fd_in, fd_out, handle, handle_len);
903                         close(local_fd);
904                         goto done;
905                 }
906                 debug3("In write loop, got %d offset %llu", len,
907                     (u_int64_t)offset);
908
909                 offset += len;
910         }
911
912         if (close(local_fd) == -1) {
913                 error("Couldn't close local file \"%s\": %s", local_path,
914                     strerror(errno));
915                 do_close(fd_in, fd_out, handle, handle_len);
916                 status = -1;
917                 goto done;
918         }
919
920         /* Override umask and utimes if asked */
921         if (pflag)
922                 do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
923
924         status = do_close(fd_in, fd_out, handle, handle_len);
925
926 done:
927         xfree(handle);
928         buffer_free(&msg);
929         return status;
930 }
931
This page took 0.751063 seconds and 5 git commands to generate.