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