]> andersk Git - gssapi-openssh.git/blob - openssh/sftp-client.c
The man2html from jbasney on pkilab2 works whereas the standard one doesn't.
[gssapi-openssh.git] / openssh / 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.18 2001/07/14 15:10:16 stevesk 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
313         for(;;) {
314                 int count;
315
316                 id = expected_id = msg_id++;
317
318                 debug3("Sending SSH2_FXP_READDIR I:%d", id);
319
320                 buffer_clear(&msg);
321                 buffer_put_char(&msg, SSH2_FXP_READDIR);
322                 buffer_put_int(&msg, id);
323                 buffer_put_string(&msg, handle, handle_len);
324                 send_msg(fd_out, &msg);
325
326                 buffer_clear(&msg);
327
328                 get_msg(fd_in, &msg);
329
330                 type = buffer_get_char(&msg);
331                 id = buffer_get_int(&msg);
332
333                 debug3("Received reply T:%d I:%d", type, id);
334
335                 if (id != expected_id)
336                         fatal("ID mismatch (%d != %d)", id, expected_id);
337
338                 if (type == SSH2_FXP_STATUS) {
339                         int status = buffer_get_int(&msg);
340
341                         debug3("Received SSH2_FXP_STATUS %d", status);
342
343                         if (status == SSH2_FX_EOF) {
344                                 break;
345                         } else {
346                                 error("Couldn't read directory: %s",
347                                     fx2txt(status));
348                                 do_close(fd_in, fd_out, handle, handle_len);
349                                 return(status);
350                         }
351                 } else if (type != SSH2_FXP_NAME)
352                         fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
353                             SSH2_FXP_NAME, type);
354
355                 count = buffer_get_int(&msg);
356                 if (count == 0)
357                         break;
358                 debug3("Received %d SSH2_FXP_NAME responses", count);
359                 for(i = 0; i < count; i++) {
360                         char *filename, *longname;
361                         Attrib *a;
362
363                         filename = buffer_get_string(&msg, NULL);
364                         longname = buffer_get_string(&msg, NULL);
365                         a = decode_attrib(&msg);
366
367                         if (printflag)
368                                 printf("%s\n", longname);
369
370                         if (dir) {
371                                 *dir = xrealloc(*dir, sizeof(**dir) *
372                                     (ents + 2));
373                                 (*dir)[ents] = xmalloc(sizeof(***dir));
374                                 (*dir)[ents]->filename = xstrdup(filename);
375                                 (*dir)[ents]->longname = xstrdup(longname);
376                                 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
377                                 (*dir)[++ents] = NULL;
378                         }
379
380                         xfree(filename);
381                         xfree(longname);
382                 }
383         }
384
385         buffer_free(&msg);
386         do_close(fd_in, fd_out, handle, handle_len);
387         xfree(handle);
388
389         return(0);
390 }
391
392 int
393 do_ls(int fd_in, int fd_out, char *path)
394 {
395         return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
396 }
397
398 int
399 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
400 {
401         return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
402 }
403
404 void free_sftp_dirents(SFTP_DIRENT **s)
405 {
406         int i;
407         
408         for(i = 0; s[i]; i++) {
409                 xfree(s[i]->filename);
410                 xfree(s[i]->longname);
411                 xfree(s[i]);
412         }
413         xfree(s);
414 }
415
416 int
417 do_rm(int fd_in, int fd_out, char *path)
418 {
419         u_int status, id;
420
421         debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
422
423         id = msg_id++;
424         send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
425         status = get_status(fd_in, id);
426         if (status != SSH2_FX_OK)
427                 error("Couldn't delete file: %s", fx2txt(status));
428         return(status);
429 }
430
431 int
432 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
433 {
434         u_int status, id;
435
436         id = msg_id++;
437         send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
438             strlen(path), a);
439
440         status = get_status(fd_in, id);
441         if (status != SSH2_FX_OK)
442                 error("Couldn't create directory: %s", fx2txt(status));
443
444         return(status);
445 }
446
447 int
448 do_rmdir(int fd_in, int fd_out, char *path)
449 {
450         u_int status, id;
451
452         id = msg_id++;
453         send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
454
455         status = get_status(fd_in, id);
456         if (status != SSH2_FX_OK)
457                 error("Couldn't remove directory: %s", fx2txt(status));
458
459         return(status);
460 }
461
462 Attrib *
463 do_stat(int fd_in, int fd_out, char *path, int quiet)
464 {
465         u_int id;
466
467         id = msg_id++;
468         send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
469         return(get_decode_stat(fd_in, id, quiet));
470 }
471
472 Attrib *
473 do_lstat(int fd_in, int fd_out, char *path, int quiet)
474 {
475         u_int id;
476
477         id = msg_id++;
478         send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
479         return(get_decode_stat(fd_in, id, quiet));
480 }
481
482 Attrib *
483 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
484 {
485         u_int id;
486
487         id = msg_id++;
488         send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
489         return(get_decode_stat(fd_in, id, quiet));
490 }
491
492 int
493 do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
494 {
495         u_int status, id;
496
497         id = msg_id++;
498         send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
499             strlen(path), a);
500
501         status = get_status(fd_in, id);
502         if (status != SSH2_FX_OK)
503                 error("Couldn't setstat on \"%s\": %s", path,
504                     fx2txt(status));
505
506         return(status);
507 }
508
509 int
510 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
511     Attrib *a)
512 {
513         u_int status, id;
514
515         id = msg_id++;
516         send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
517             handle_len, a);
518
519         status = get_status(fd_in, id);
520         if (status != SSH2_FX_OK)
521                 error("Couldn't fsetstat: %s", fx2txt(status));
522
523         return(status);
524 }
525
526 char *
527 do_realpath(int fd_in, int fd_out, char *path)
528 {
529         Buffer msg;
530         u_int type, expected_id, count, id;
531         char *filename, *longname;
532         Attrib *a;
533
534         expected_id = id = msg_id++;
535         send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
536
537         buffer_init(&msg);
538
539         get_msg(fd_in, &msg);
540         type = buffer_get_char(&msg);
541         id = buffer_get_int(&msg);
542
543         if (id != expected_id)
544                 fatal("ID mismatch (%d != %d)", id, expected_id);
545
546         if (type == SSH2_FXP_STATUS) {
547                 u_int status = buffer_get_int(&msg);
548
549                 error("Couldn't canonicalise: %s", fx2txt(status));
550                 return(NULL);
551         } else if (type != SSH2_FXP_NAME)
552                 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
553                     SSH2_FXP_NAME, type);
554
555         count = buffer_get_int(&msg);
556         if (count != 1)
557                 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
558
559         filename = buffer_get_string(&msg, NULL);
560         longname = buffer_get_string(&msg, NULL);
561         a = decode_attrib(&msg);
562
563         debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
564
565         xfree(longname);
566
567         buffer_free(&msg);
568
569         return(filename);
570 }
571
572 int
573 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
574 {
575         Buffer msg;
576         u_int status, id;
577
578         buffer_init(&msg);
579
580         /* Send rename request */
581         id = msg_id++;
582         buffer_put_char(&msg, SSH2_FXP_RENAME);
583         buffer_put_int(&msg, id);
584         buffer_put_cstring(&msg, oldpath);
585         buffer_put_cstring(&msg, newpath);
586         send_msg(fd_out, &msg);
587         debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
588             newpath);
589         buffer_free(&msg);
590
591         status = get_status(fd_in, id);
592         if (status != SSH2_FX_OK)
593                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
594                     fx2txt(status));
595
596         return(status);
597 }
598
599 int
600 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
601 {
602         Buffer msg;
603         u_int status, id;
604
605         buffer_init(&msg);
606
607         /* Send rename request */
608         id = msg_id++;
609         buffer_put_char(&msg, SSH2_FXP_SYMLINK);
610         buffer_put_int(&msg, id);
611         buffer_put_cstring(&msg, oldpath);
612         buffer_put_cstring(&msg, newpath);
613         send_msg(fd_out, &msg);
614         debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
615             newpath);
616         buffer_free(&msg);
617
618         status = get_status(fd_in, id);
619         if (status != SSH2_FX_OK)
620                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
621                     fx2txt(status));
622
623         return(status);
624 }
625
626 char *
627 do_readlink(int fd_in, int fd_out, char *path)
628 {
629         Buffer msg;
630         u_int type, expected_id, count, id;
631         char *filename, *longname;
632         Attrib *a;
633
634         expected_id = id = msg_id++;
635         send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
636
637         buffer_init(&msg);
638
639         get_msg(fd_in, &msg);
640         type = buffer_get_char(&msg);
641         id = buffer_get_int(&msg);
642
643         if (id != expected_id)
644                 fatal("ID mismatch (%d != %d)", id, expected_id);
645
646         if (type == SSH2_FXP_STATUS) {
647                 u_int status = buffer_get_int(&msg);
648
649                 error("Couldn't readlink: %s", fx2txt(status));
650                 return(NULL);
651         } else if (type != SSH2_FXP_NAME)
652                 fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
653                     SSH2_FXP_NAME, type);
654
655         count = buffer_get_int(&msg);
656         if (count != 1)
657                 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
658
659         filename = buffer_get_string(&msg, NULL);
660         longname = buffer_get_string(&msg, NULL);
661         a = decode_attrib(&msg);
662
663         debug3("SSH_FXP_READLINK %s -> %s", path, filename);
664
665         xfree(longname);
666
667         buffer_free(&msg);
668
669         return(filename);
670 }
671
672 int
673 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
674     int pflag)
675 {
676         int local_fd;
677         u_int expected_id, handle_len, mode, type, id;
678         u_int64_t offset;
679         char *handle;
680         Buffer msg;
681         Attrib junk, *a;
682         int status;
683
684         a = do_stat(fd_in, fd_out, remote_path, 0);
685         if (a == NULL)
686                 return(-1);
687
688         /* XXX: should we preserve set[ug]id? */
689         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
690                 mode = S_IWRITE | (a->perm & 0777);
691         else
692                 mode = 0666;
693
694         if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
695             (a->perm & S_IFDIR)) {
696                 error("Cannot download a directory: %s", remote_path);
697                 return(-1);
698         }
699
700         local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
701         if (local_fd == -1) {
702                 error("Couldn't open local file \"%s\" for writing: %s",
703                     local_path, strerror(errno));
704                 return(-1);
705         }
706
707         buffer_init(&msg);
708
709         /* Send open request */
710         id = msg_id++;
711         buffer_put_char(&msg, SSH2_FXP_OPEN);
712         buffer_put_int(&msg, id);
713         buffer_put_cstring(&msg, remote_path);
714         buffer_put_int(&msg, SSH2_FXF_READ);
715         attrib_clear(&junk); /* Send empty attributes */
716         encode_attrib(&msg, &junk);
717         send_msg(fd_out, &msg);
718         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
719
720         handle = get_handle(fd_in, id, &handle_len);
721         if (handle == NULL) {
722                 buffer_free(&msg);
723                 close(local_fd);
724                 return(-1);
725         }
726
727         /* Read from remote and write to local */
728         offset = 0;
729         for(;;) {
730                 u_int len;
731                 char *data;
732
733                 id = expected_id = msg_id++;
734
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, COPY_SIZE);
741                 send_msg(fd_out, &msg);
742                 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
743                     id, (u_int64_t)offset, COPY_SIZE);
744
745                 buffer_clear(&msg);
746
747                 get_msg(fd_in, &msg);
748                 type = buffer_get_char(&msg);
749                 id = buffer_get_int(&msg);
750                 debug3("Received reply T:%d I:%d", type, id);
751                 if (id != expected_id)
752                         fatal("ID mismatch (%d != %d)", id, expected_id);
753                 if (type == SSH2_FXP_STATUS) {
754                         status = buffer_get_int(&msg);
755
756                         if (status == SSH2_FX_EOF)
757                                 break;
758                         else {
759                                 error("Couldn't read from remote "
760                                     "file \"%s\" : %s", remote_path,
761                                      fx2txt(status));
762                                 do_close(fd_in, fd_out, handle, handle_len);
763                                 goto done;
764                         }
765                 } else if (type != SSH2_FXP_DATA) {
766                         fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
767                             SSH2_FXP_DATA, type);
768                 }
769
770                 data = buffer_get_string(&msg, &len);
771                 if (len > COPY_SIZE)
772                         fatal("Received more data than asked for %d > %d",
773                             len, COPY_SIZE);
774
775                 debug3("In read loop, got %d offset %llu", len,
776                     (u_int64_t)offset);
777                 if (atomicio(write, local_fd, data, len) != len) {
778                         error("Couldn't write to \"%s\": %s", local_path,
779                             strerror(errno));
780                         do_close(fd_in, fd_out, handle, handle_len);
781                         status = -1;
782                         xfree(data);
783                         goto done;
784                 }
785
786                 offset += len;
787                 xfree(data);
788         }
789         status = do_close(fd_in, fd_out, handle, handle_len);
790
791         /* Override umask and utimes if asked */
792 #ifdef HAVE_FCHMOD
793         if (pflag && fchmod(local_fd, mode) == -1)
794 #else 
795         if (pflag && chmod(local_path, mode) == -1)
796 #endif /* HAVE_FCHMOD */
797                 error("Couldn't set mode on \"%s\": %s", local_path,
798                     strerror(errno));
799         if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
800                 struct timeval tv[2];
801                 tv[0].tv_sec = a->atime;
802                 tv[1].tv_sec = a->mtime;
803                 tv[0].tv_usec = tv[1].tv_usec = 0;
804                 if (utimes(local_path, tv) == -1)
805                         error("Can't set times on \"%s\": %s", local_path,
806                             strerror(errno));
807         }
808
809 done:
810         close(local_fd);
811         buffer_free(&msg);
812         xfree(handle);
813         return status;
814 }
815
816 int
817 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
818     int pflag)
819 {
820         int local_fd;
821         u_int handle_len, id;
822         u_int64_t offset;
823         char *handle;
824         Buffer msg;
825         struct stat sb;
826         Attrib a;
827         int status;
828
829         if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
830                 error("Couldn't open local file \"%s\" for reading: %s",
831                     local_path, strerror(errno));
832                 return(-1);
833         }
834         if (fstat(local_fd, &sb) == -1) {
835                 error("Couldn't fstat local file \"%s\": %s",
836                     local_path, strerror(errno));
837                 close(local_fd);
838                 return(-1);
839         }
840         stat_to_attrib(&sb, &a);
841
842         a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
843         a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
844         a.perm &= 0777;
845         if (!pflag)
846                 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
847
848         buffer_init(&msg);
849
850         /* Send open request */
851         id = msg_id++;
852         buffer_put_char(&msg, SSH2_FXP_OPEN);
853         buffer_put_int(&msg, id);
854         buffer_put_cstring(&msg, remote_path);
855         buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
856         encode_attrib(&msg, &a);
857         send_msg(fd_out, &msg);
858         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
859
860         buffer_clear(&msg);
861
862         handle = get_handle(fd_in, id, &handle_len);
863         if (handle == NULL) {
864                 close(local_fd);
865                 buffer_free(&msg);
866                 return(-1);
867         }
868
869         /* Read from local and write to remote */
870         offset = 0;
871         for(;;) {
872                 int len;
873                 char data[COPY_SIZE];
874
875                 /*
876                  * Can't use atomicio here because it returns 0 on EOF, thus losing
877                  * the last block of the file
878                  */
879                 do
880                         len = read(local_fd, data, COPY_SIZE);
881                 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
882
883                 if (len == -1)
884                         fatal("Couldn't read from \"%s\": %s", local_path,
885                             strerror(errno));
886                 if (len == 0)
887                         break;
888
889                 buffer_clear(&msg);
890                 buffer_put_char(&msg, SSH2_FXP_WRITE);
891                 buffer_put_int(&msg, ++id);
892                 buffer_put_string(&msg, handle, handle_len);
893                 buffer_put_int64(&msg, offset);
894                 buffer_put_string(&msg, data, len);
895                 send_msg(fd_out, &msg);
896                 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
897                     id, (u_int64_t)offset, len);
898
899                 status = get_status(fd_in, id);
900                 if (status != SSH2_FX_OK) {
901                         error("Couldn't write to remote file \"%s\": %s",
902                             remote_path, fx2txt(status));
903                         do_close(fd_in, fd_out, handle, handle_len);
904                         close(local_fd);
905                         goto done;
906                 }
907                 debug3("In write loop, got %d offset %llu", len,
908                     (u_int64_t)offset);
909
910                 offset += len;
911         }
912
913         if (close(local_fd) == -1) {
914                 error("Couldn't close local file \"%s\": %s", local_path,
915                     strerror(errno));
916                 do_close(fd_in, fd_out, handle, handle_len);
917                 status = -1;
918                 goto done;
919         }
920
921         /* Override umask and utimes if asked */
922         if (pflag)
923                 do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
924
925         status = do_close(fd_in, fd_out, handle, handle_len);
926
927 done:
928         xfree(handle);
929         buffer_free(&msg);
930         return status;
931 }
932
This page took 0.198644 seconds and 5 git commands to generate.