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