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