Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.11.2.1
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.2.1! jason 250: return(0);
1.1 djm 251: }
252:
253: int
254: do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
255: {
256: u_int id, status;
257: Buffer msg;
258:
259: buffer_init(&msg);
260:
1.4 djm 261: id = msg_id++;
1.1 djm 262: buffer_put_char(&msg, SSH2_FXP_CLOSE);
263: buffer_put_int(&msg, id);
264: buffer_put_string(&msg, handle, handle_len);
265: send_msg(fd_out, &msg);
266: debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
267:
268: status = get_status(fd_in, id);
269: if (status != SSH2_FX_OK)
270: error("Couldn't close file: %s", fx2txt(status));
271:
272: buffer_free(&msg);
273:
274: return(status);
275: }
276:
277: int
278: do_ls(int fd_in, int fd_out, char *path)
279: {
280: Buffer msg;
281: u_int type, id, handle_len, i, expected_id;
282: char *handle;
283:
1.4 djm 284: id = msg_id++;
1.1 djm 285:
286: buffer_init(&msg);
287: buffer_put_char(&msg, SSH2_FXP_OPENDIR);
288: buffer_put_int(&msg, id);
289: buffer_put_cstring(&msg, path);
290: send_msg(fd_out, &msg);
291:
292: buffer_clear(&msg);
293:
294: handle = get_handle(fd_in, id, &handle_len);
295: if (handle == NULL)
296: return(-1);
297:
298: for(;;) {
299: int count;
300:
1.4 djm 301: id = expected_id = msg_id++;
1.1 djm 302:
303: debug3("Sending SSH2_FXP_READDIR I:%d", id);
304:
305: buffer_clear(&msg);
306: buffer_put_char(&msg, SSH2_FXP_READDIR);
307: buffer_put_int(&msg, id);
308: buffer_put_string(&msg, handle, handle_len);
309: send_msg(fd_out, &msg);
310:
311: buffer_clear(&msg);
312:
313: get_msg(fd_in, &msg);
314:
315: type = buffer_get_char(&msg);
316: id = buffer_get_int(&msg);
317:
318: debug3("Received reply T:%d I:%d", type, id);
319:
320: if (id != expected_id)
321: fatal("ID mismatch (%d != %d)", id, expected_id);
322:
323: if (type == SSH2_FXP_STATUS) {
324: int status = buffer_get_int(&msg);
325:
326: debug3("Received SSH2_FXP_STATUS %d", status);
327:
328: if (status == SSH2_FX_EOF) {
329: break;
330: } else {
331: error("Couldn't read directory: %s",
332: fx2txt(status));
333: do_close(fd_in, fd_out, handle, handle_len);
1.9 djm 334: return(status);
1.1 djm 335: }
336: } else if (type != SSH2_FXP_NAME)
337: fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
338: SSH2_FXP_NAME, type);
339:
340: count = buffer_get_int(&msg);
1.7 markus 341: if (count == 0)
342: break;
1.8 stevesk 343: debug3("Received %d SSH2_FXP_NAME responses", count);
1.1 djm 344: for(i = 0; i < count; i++) {
345: char *filename, *longname;
346: Attrib *a;
347:
348: filename = buffer_get_string(&msg, NULL);
349: longname = buffer_get_string(&msg, NULL);
350: a = decode_attrib(&msg);
351:
352: printf("%s\n", longname);
353:
354: xfree(filename);
355: xfree(longname);
356: }
357: }
358:
359: buffer_free(&msg);
360: do_close(fd_in, fd_out, handle, handle_len);
361: xfree(handle);
362:
363: return(0);
364: }
365:
366: int
367: do_rm(int fd_in, int fd_out, char *path)
368: {
369: u_int status, id;
370:
371: debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
372:
1.4 djm 373: id = msg_id++;
1.1 djm 374: send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
375: status = get_status(fd_in, id);
376: if (status != SSH2_FX_OK)
377: error("Couldn't delete file: %s", fx2txt(status));
378: return(status);
379: }
380:
381: int
382: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
383: {
384: u_int status, id;
385:
1.4 djm 386: id = msg_id++;
1.1 djm 387: send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
388: strlen(path), a);
389:
390: status = get_status(fd_in, id);
391: if (status != SSH2_FX_OK)
392: error("Couldn't create directory: %s", fx2txt(status));
393:
394: return(status);
395: }
396:
397: int
398: do_rmdir(int fd_in, int fd_out, char *path)
399: {
400: u_int status, id;
401:
1.4 djm 402: id = msg_id++;
1.1 djm 403: send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
404:
405: status = get_status(fd_in, id);
406: if (status != SSH2_FX_OK)
407: error("Couldn't remove directory: %s", fx2txt(status));
408:
409: return(status);
410: }
411:
412: Attrib *
413: do_stat(int fd_in, int fd_out, char *path)
414: {
415: u_int id;
416:
1.4 djm 417: id = msg_id++;
1.1 djm 418: send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
419: return(get_decode_stat(fd_in, id));
420: }
421:
422: Attrib *
423: do_lstat(int fd_in, int fd_out, char *path)
424: {
425: u_int id;
426:
1.4 djm 427: id = msg_id++;
1.1 djm 428: send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
429: return(get_decode_stat(fd_in, id));
430: }
431:
432: Attrib *
433: do_fstat(int fd_in, int fd_out, char *handle,
434: u_int handle_len)
435: {
436: u_int id;
437:
1.4 djm 438: id = msg_id++;
1.1 djm 439: send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
440: return(get_decode_stat(fd_in, id));
441: }
442:
443: int
444: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
445: {
446: u_int status, id;
447:
1.4 djm 448: id = msg_id++;
1.1 djm 449: send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
450: strlen(path), a);
451:
452: status = get_status(fd_in, id);
453: if (status != SSH2_FX_OK)
454: error("Couldn't setstat on \"%s\": %s", path,
455: fx2txt(status));
456:
457: return(status);
458: }
459:
460: int
461: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
462: Attrib *a)
463: {
464: u_int status, id;
465:
1.4 djm 466: id = msg_id++;
1.1 djm 467: send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
468: handle_len, a);
469:
470: status = get_status(fd_in, id);
471: if (status != SSH2_FX_OK)
472: error("Couldn't fsetstat: %s", fx2txt(status));
473:
474: return(status);
475: }
476:
477: char *
478: do_realpath(int fd_in, int fd_out, char *path)
479: {
480: Buffer msg;
481: u_int type, expected_id, count, id;
482: char *filename, *longname;
483: Attrib *a;
484:
1.4 djm 485: expected_id = id = msg_id++;
1.11.2.1! jason 486: send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
! 487: 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);
549: }
550:
551: int
552: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
553: int pflag)
554: {
555: int local_fd;
556: u_int expected_id, handle_len, mode, type, id;
557: u_int64_t offset;
558: char *handle;
559: Buffer msg;
560: Attrib junk, *a;
1.5 djm 561: int status;
1.1 djm 562:
563: a = do_stat(fd_in, fd_out, remote_path);
564: if (a == NULL)
565: return(-1);
566:
567: /* XXX: should we preserve set[ug]id? */
568: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
569: mode = S_IWRITE | (a->perm & 0777);
570: else
571: mode = 0666;
572:
573: local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
574: if (local_fd == -1) {
575: error("Couldn't open local file \"%s\" for writing: %s",
576: local_path, strerror(errno));
577: return(errno);
578: }
579:
580: buffer_init(&msg);
581:
582: /* Send open request */
1.4 djm 583: id = msg_id++;
1.1 djm 584: buffer_put_char(&msg, SSH2_FXP_OPEN);
585: buffer_put_int(&msg, id);
586: buffer_put_cstring(&msg, remote_path);
587: buffer_put_int(&msg, SSH2_FXF_READ);
588: attrib_clear(&junk); /* Send empty attributes */
589: encode_attrib(&msg, &junk);
590: send_msg(fd_out, &msg);
591: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
592:
593: handle = get_handle(fd_in, id, &handle_len);
594: if (handle == NULL) {
595: buffer_free(&msg);
596: close(local_fd);
597: return(-1);
598: }
599:
600: /* Read from remote and write to local */
601: offset = 0;
602: for(;;) {
603: u_int len;
604: char *data;
605:
1.4 djm 606: id = expected_id = msg_id++;
1.1 djm 607:
608: buffer_clear(&msg);
609: buffer_put_char(&msg, SSH2_FXP_READ);
610: buffer_put_int(&msg, id);
611: buffer_put_string(&msg, handle, handle_len);
612: buffer_put_int64(&msg, offset);
613: buffer_put_int(&msg, COPY_SIZE);
614: send_msg(fd_out, &msg);
615: debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2 deraadt 616: id, (unsigned long long)offset, COPY_SIZE);
1.1 djm 617:
618: buffer_clear(&msg);
619:
620: get_msg(fd_in, &msg);
621: type = buffer_get_char(&msg);
622: id = buffer_get_int(&msg);
623: debug3("Received reply T:%d I:%d", type, id);
624: if (id != expected_id)
625: fatal("ID mismatch (%d != %d)", id, expected_id);
626: if (type == SSH2_FXP_STATUS) {
1.5 djm 627: status = buffer_get_int(&msg);
1.1 djm 628:
629: if (status == SSH2_FX_EOF)
630: break;
631: else {
632: error("Couldn't read from remote "
633: "file \"%s\" : %s", remote_path,
634: fx2txt(status));
635: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 636: goto done;
1.1 djm 637: }
638: } else if (type != SSH2_FXP_DATA) {
639: fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
640: SSH2_FXP_DATA, type);
641: }
642:
643: data = buffer_get_string(&msg, &len);
644: if (len > COPY_SIZE)
645: fatal("Received more data than asked for %d > %d",
646: len, COPY_SIZE);
647:
1.6 itojun 648: debug3("In read loop, got %d offset %llu", len,
1.2 deraadt 649: (unsigned long long)offset);
1.1 djm 650: if (atomicio(write, local_fd, data, len) != len) {
651: error("Couldn't write to \"%s\": %s", local_path,
652: strerror(errno));
653: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 654: status = -1;
1.1 djm 655: xfree(data);
1.5 djm 656: goto done;
1.1 djm 657: }
658:
659: offset += len;
660: xfree(data);
661: }
1.5 djm 662: status = do_close(fd_in, fd_out, handle, handle_len);
663:
1.10 djm 664: /* Override umask and utimes if asked */
665: if (pflag && fchmod(local_fd, mode) == -1)
666: error("Couldn't set mode on \"%s\": %s", local_path,
667: strerror(errno));
668: if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
669: struct timeval tv[2];
670: tv[0].tv_sec = a->atime;
671: tv[1].tv_sec = a->mtime;
672: tv[0].tv_usec = tv[1].tv_usec = 0;
673: if (utimes(local_path, tv) == -1)
674: error("Can't set times on \"%s\": %s", local_path,
675: strerror(errno));
676: }
677:
1.5 djm 678: done:
679: close(local_fd);
680: buffer_free(&msg);
1.1 djm 681: xfree(handle);
1.5 djm 682: return status;
1.1 djm 683: }
684:
685: int
686: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
687: int pflag)
688: {
689: int local_fd;
690: u_int handle_len, id;
691: u_int64_t offset;
692: char *handle;
693: Buffer msg;
694: struct stat sb;
695: Attrib a;
1.5 djm 696: int status;
1.1 djm 697:
698: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
699: error("Couldn't open local file \"%s\" for reading: %s",
700: local_path, strerror(errno));
701: return(-1);
702: }
703: if (fstat(local_fd, &sb) == -1) {
704: error("Couldn't fstat local file \"%s\": %s",
705: local_path, strerror(errno));
706: close(local_fd);
707: return(-1);
708: }
709: stat_to_attrib(&sb, &a);
710:
711: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
712: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
713: a.perm &= 0777;
714: if (!pflag)
715: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
716:
717: buffer_init(&msg);
718:
719: /* Send open request */
1.4 djm 720: id = msg_id++;
1.1 djm 721: buffer_put_char(&msg, SSH2_FXP_OPEN);
722: buffer_put_int(&msg, id);
723: buffer_put_cstring(&msg, remote_path);
724: buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
725: encode_attrib(&msg, &a);
726: send_msg(fd_out, &msg);
727: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
728:
729: buffer_clear(&msg);
730:
731: handle = get_handle(fd_in, id, &handle_len);
732: if (handle == NULL) {
733: close(local_fd);
734: buffer_free(&msg);
735: return(-1);
736: }
737:
738: /* Read from local and write to remote */
739: offset = 0;
740: for(;;) {
741: int len;
742: char data[COPY_SIZE];
743:
744: /*
745: * Can't use atomicio here because it returns 0 on EOF, thus losing
746: * the last block of the file
747: */
748: do
749: len = read(local_fd, data, COPY_SIZE);
750: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
751:
752: if (len == -1)
753: fatal("Couldn't read from \"%s\": %s", local_path,
754: strerror(errno));
755: if (len == 0)
756: break;
757:
758: buffer_clear(&msg);
759: buffer_put_char(&msg, SSH2_FXP_WRITE);
760: buffer_put_int(&msg, ++id);
761: buffer_put_string(&msg, handle, handle_len);
762: buffer_put_int64(&msg, offset);
763: buffer_put_string(&msg, data, len);
764: send_msg(fd_out, &msg);
765: debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2 deraadt 766: id, (unsigned long long)offset, len);
1.1 djm 767:
768: status = get_status(fd_in, id);
769: if (status != SSH2_FX_OK) {
770: error("Couldn't write to remote file \"%s\": %s",
771: remote_path, fx2txt(status));
772: do_close(fd_in, fd_out, handle, handle_len);
773: close(local_fd);
1.5 djm 774: goto done;
1.1 djm 775: }
1.2 deraadt 776: debug3("In write loop, got %d offset %llu", len,
777: (unsigned long long)offset);
1.1 djm 778:
779: offset += len;
780: }
781:
782: if (close(local_fd) == -1) {
783: error("Couldn't close local file \"%s\": %s", local_path,
784: strerror(errno));
785: do_close(fd_in, fd_out, handle, handle_len);
1.5 djm 786: status = -1;
787: goto done;
1.1 djm 788: }
789:
1.10 djm 790: /* Override umask and utimes if asked */
791: if (pflag)
792: do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
793:
1.5 djm 794: status = do_close(fd_in, fd_out, handle, handle_len);
795:
796: done:
797: xfree(handle);
798: buffer_free(&msg);
799: return status;
1.1 djm 800: }