Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.18
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.18 ! stevesk 32: RCSID("$OpenBSD: sftp-client.c,v 1.17 2001/06/23 15:12:20 itojun Exp $");
1.1 djm 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:
1.4 djm 49: /* Message ID */
50: static u_int msg_id = 1;
51:
1.17 itojun 52: static void
1.1 djm 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:
1.17 itojun 71: static void
1.1 djm 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);
1.15 djm 78: if (len == 0)
79: fatal("Connection closed");
80: else if (len == -1)
1.1 djm 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)));
1.15 djm 89: if (len == 0)
90: fatal("Connection closed");
91: else if (len == -1)
1.1 djm 92: fatal("Couldn't read packet: %s", strerror(errno));
93:
94: msg_len -= len;
95: buffer_append(m, buf, len);
96: }
97: }
98:
1.17 itojun 99: static void
1.1 djm 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:
1.17 itojun 114: static void
1.1 djm 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:
1.17 itojun 130: static u_int
1.1 djm 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:
1.17 itojun 155: static char *
1.1 djm 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:
1.17 itojun 184: static Attrib *
1.14 djm 185: get_decode_stat(int fd, u_int expected_id, int quiet)
1.1 djm 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:
1.14 djm 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));
1.1 djm 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:
1.3 stevesk 233: /* Expecting a VERSION reply */
1.1 djm 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);
1.11 djm 255:
256: return(version);
1.1 djm 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:
1.4 djm 267: id = msg_id++;
1.1 djm 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:
1.12 djm 283:
1.17 itojun 284: static int
1.16 markus 285: do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
1.12 djm 286: SFTP_DIRENT ***dir)
1.1 djm 287: {
288: Buffer msg;
1.13 markus 289: u_int type, id, handle_len, i, expected_id, ents = 0;
1.1 djm 290: char *handle;
291:
1.4 djm 292: id = msg_id++;
1.1 djm 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:
1.12 djm 306: if (dir) {
307: ents = 0;
308: *dir = xmalloc(sizeof(**dir));
309: (*dir)[0] = NULL;
310: }
311:
312:
1.1 djm 313: for(;;) {
314: int count;
315:
1.4 djm 316: id = expected_id = msg_id++;
1.1 djm 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);
1.9 djm 349: return(status);
1.1 djm 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);
1.7 markus 356: if (count == 0)
357: break;
1.8 stevesk 358: debug3("Received %d SSH2_FXP_NAME responses", count);
1.1 djm 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:
1.12 djm 367: if (printflag)
368: printf("%s\n", longname);
369:
370: if (dir) {
1.16 markus 371: *dir = xrealloc(*dir, sizeof(**dir) *
1.12 djm 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: }
1.1 djm 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
1.12 djm 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
1.1 djm 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:
1.4 djm 423: id = msg_id++;
1.1 djm 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:
1.4 djm 436: id = msg_id++;
1.1 djm 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:
1.4 djm 452: id = msg_id++;
1.1 djm 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 *
1.14 djm 463: do_stat(int fd_in, int fd_out, char *path, int quiet)
1.1 djm 464: {
465: u_int id;
466:
1.4 djm 467: id = msg_id++;
1.1 djm 468: send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
1.14 djm 469: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 470: }
471:
472: Attrib *
1.14 djm 473: do_lstat(int fd_in, int fd_out, char *path, int quiet)
1.1 djm 474: {
475: u_int id;
476:
1.4 djm 477: id = msg_id++;
1.1 djm 478: send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
1.14 djm 479: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 480: }
481:
482: Attrib *
1.14 djm 483: do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
1.1 djm 484: {
485: u_int id;
486:
1.4 djm 487: id = msg_id++;
1.1 djm 488: send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
1.14 djm 489: return(get_decode_stat(fd_in, id, quiet));
1.1 djm 490: }
491:
492: int
493: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
494: {
495: u_int status, id;
496:
1.4 djm 497: id = msg_id++;
1.1 djm 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:
1.4 djm 515: id = msg_id++;
1.1 djm 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:
1.4 djm 534: expected_id = id = msg_id++;
1.11 djm 535: send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
1.1 djm 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 */
1.4 djm 581: id = msg_id++;
1.1 djm 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);
1.11 djm 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);
1.1 djm 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;
1.5 djm 682: int status;
1.1 djm 683:
1.14 djm 684: a = do_stat(fd_in, fd_out, remote_path, 0);
1.1 djm 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:
1.14 djm 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:
1.1 djm 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));
1.14 djm 704: return(-1);
1.1 djm 705: }
706:
707: buffer_init(&msg);
708:
709: /* Send open request */
1.4 djm 710: id = msg_id++;
1.1 djm 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:
1.4 djm 733: id = expected_id = msg_id++;
1.1 djm 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",
1.2 deraadt 743: id, (unsigned long long)offset, COPY_SIZE);
1.1 djm 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) {
1.5 djm 754: status = buffer_get_int(&msg);
1.1 djm 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);
1.5 djm 763: goto done;
1.1 djm 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:
1.6 itojun 775: debug3("In read loop, got %d offset %llu", len,
1.2 deraadt 776: (unsigned long long)offset);
1.1 djm 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);
1.5 djm 781: status = -1;
1.1 djm 782: xfree(data);
1.5 djm 783: goto done;
1.1 djm 784: }
785:
786: offset += len;
787: xfree(data);
788: }
1.5 djm 789: status = do_close(fd_in, fd_out, handle, handle_len);
790:
1.10 djm 791: /* Override umask and utimes if asked */
792: if (pflag && fchmod(local_fd, mode) == -1)
793: error("Couldn't set mode on \"%s\": %s", local_path,
794: strerror(errno));
795: if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
796: struct timeval tv[2];
797: tv[0].tv_sec = a->atime;
798: tv[1].tv_sec = a->mtime;
799: tv[0].tv_usec = tv[1].tv_usec = 0;
800: if (utimes(local_path, tv) == -1)
801: error("Can't set times on \"%s\": %s", local_path,
802: strerror(errno));
803: }
804:
1.5 djm 805: done:
806: close(local_fd);
807: buffer_free(&msg);
1.1 djm 808: xfree(handle);
1.5 djm 809: return status;
1.1 djm 810: }
811:
812: int
813: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
814: int pflag)
815: {
816: int local_fd;
817: u_int handle_len, id;
818: u_int64_t offset;
819: char *handle;
820: Buffer msg;
821: struct stat sb;
822: Attrib a;
1.5 djm 823: int status;
1.1 djm 824:
825: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
826: error("Couldn't open local file \"%s\" for reading: %s",
827: local_path, strerror(errno));
828: return(-1);
829: }
830: if (fstat(local_fd, &sb) == -1) {
831: error("Couldn't fstat local file \"%s\": %s",
832: local_path, strerror(errno));
833: close(local_fd);
834: return(-1);
835: }
836: stat_to_attrib(&sb, &a);
837:
838: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
839: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
840: a.perm &= 0777;
841: if (!pflag)
842: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
843:
844: buffer_init(&msg);
845:
846: /* Send open request */
1.4 djm 847: id = msg_id++;
1.1 djm 848: buffer_put_char(&msg, SSH2_FXP_OPEN);
849: buffer_put_int(&msg, id);
850: buffer_put_cstring(&msg, remote_path);
851: buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
852: encode_attrib(&msg, &a);
853: send_msg(fd_out, &msg);
854: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
855:
856: buffer_clear(&msg);
857:
858: handle = get_handle(fd_in, id, &handle_len);
859: if (handle == NULL) {
860: close(local_fd);
861: buffer_free(&msg);
862: return(-1);
863: }
864:
865: /* Read from local and write to remote */
866: offset = 0;
867: for(;;) {
868: int len;
869: char data[COPY_SIZE];
870:
871: /*
872: * Can't use atomicio here because it returns 0 on EOF, thus losing
873: * the last block of the file
874: */
875: do
876: len = read(local_fd, data, COPY_SIZE);
877: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
878:
879: if (len == -1)
880: fatal("Couldn't read from \"%s\": %s", local_path,
881: strerror(errno));
882: if (len == 0)
883: break;
884:
885: buffer_clear(&msg);
886: buffer_put_char(&msg, SSH2_FXP_WRITE);
887: buffer_put_int(&msg, ++id);
888: buffer_put_string(&msg, handle, handle_len);
889: buffer_put_int64(&msg, offset);
890: buffer_put_string(&msg, data, len);
891: send_msg(fd_out, &msg);
892: debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2 deraadt 893: id, (unsigned long long)offset, len);
1.1 djm 894:
895: status = get_status(fd_in, id);
896: if (status != SSH2_FX_OK) {
897: error("Couldn't write to remote file \"%s\": %s",
898: remote_path, fx2txt(status));
899: do_close(fd_in, fd_out, handle, handle_len);
900: close(local_fd);
1.5 djm 901: goto done;
1.1 djm 902: }
1.2 deraadt 903: debug3("In write loop, got %d offset %llu", len,
904: (unsigned long long)offset);
1.1 djm 905:
906: offset += len;
907: }
908:
909: if (close(local_fd) == -1) {
910: error("Couldn't close local file \"%s\": %s", local_path,
911: strerror(errno));
912: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 913: status = -1;
914: goto done;
1.1 djm 915: }
916:
1.10 djm 917: /* Override umask and utimes if asked */
918: if (pflag)
919: do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
920:
1.5 djm 921: status = do_close(fd_in, fd_out, handle, handle_len);
922:
923: done:
924: xfree(handle);
925: buffer_free(&msg);
926: return status;
1.1 djm 927: }
1.12 djm 928: