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