Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.4
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.4 ! djm 32: RCSID("$OpenBSD: sftp-client.c,v 1.3 2001/02/04 15:32:25 stevesk 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);
250: return(0);
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);
334: return(NULL);
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);
341: debug3("Received %i SSH2_FXP_NAME responses", count);
342: for(i = 0; i < count; i++) {
343: char *filename, *longname;
344: Attrib *a;
345:
346: filename = buffer_get_string(&msg, NULL);
347: longname = buffer_get_string(&msg, NULL);
348: a = decode_attrib(&msg);
349:
350: printf("%s\n", longname);
351:
352: xfree(filename);
353: xfree(longname);
354: }
355: }
356:
357: buffer_free(&msg);
358: do_close(fd_in, fd_out, handle, handle_len);
359: xfree(handle);
360:
361: return(0);
362: }
363:
364: int
365: do_rm(int fd_in, int fd_out, char *path)
366: {
367: u_int status, id;
368:
369: debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
370:
1.4 ! djm 371: id = msg_id++;
1.1 djm 372: send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
373: status = get_status(fd_in, id);
374: if (status != SSH2_FX_OK)
375: error("Couldn't delete file: %s", fx2txt(status));
376: return(status);
377: }
378:
379: int
380: do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
381: {
382: u_int status, id;
383:
1.4 ! djm 384: id = msg_id++;
1.1 djm 385: send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
386: strlen(path), a);
387:
388: status = get_status(fd_in, id);
389: if (status != SSH2_FX_OK)
390: error("Couldn't create directory: %s", fx2txt(status));
391:
392: return(status);
393: }
394:
395: int
396: do_rmdir(int fd_in, int fd_out, char *path)
397: {
398: u_int status, id;
399:
1.4 ! djm 400: id = msg_id++;
1.1 djm 401: send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
402:
403: status = get_status(fd_in, id);
404: if (status != SSH2_FX_OK)
405: error("Couldn't remove directory: %s", fx2txt(status));
406:
407: return(status);
408: }
409:
410: Attrib *
411: do_stat(int fd_in, int fd_out, char *path)
412: {
413: u_int id;
414:
1.4 ! djm 415: id = msg_id++;
1.1 djm 416: send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
417: return(get_decode_stat(fd_in, id));
418: }
419:
420: Attrib *
421: do_lstat(int fd_in, int fd_out, char *path)
422: {
423: u_int id;
424:
1.4 ! djm 425: id = msg_id++;
1.1 djm 426: send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
427: return(get_decode_stat(fd_in, id));
428: }
429:
430: Attrib *
431: do_fstat(int fd_in, int fd_out, char *handle,
432: u_int handle_len)
433: {
434: u_int id;
435:
1.4 ! djm 436: id = msg_id++;
1.1 djm 437: send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
438: return(get_decode_stat(fd_in, id));
439: }
440:
441: int
442: do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
443: {
444: u_int status, id;
445:
1.4 ! djm 446: id = msg_id++;
1.1 djm 447: send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
448: strlen(path), a);
449:
450: status = get_status(fd_in, id);
451: if (status != SSH2_FX_OK)
452: error("Couldn't setstat on \"%s\": %s", path,
453: fx2txt(status));
454:
455: return(status);
456: }
457:
458: int
459: do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
460: Attrib *a)
461: {
462: u_int status, id;
463:
1.4 ! djm 464: id = msg_id++;
1.1 djm 465: send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
466: handle_len, a);
467:
468: status = get_status(fd_in, id);
469: if (status != SSH2_FX_OK)
470: error("Couldn't fsetstat: %s", fx2txt(status));
471:
472: return(status);
473: }
474:
475: char *
476: do_realpath(int fd_in, int fd_out, char *path)
477: {
478: Buffer msg;
479: u_int type, expected_id, count, id;
480: char *filename, *longname;
481: Attrib *a;
482:
1.4 ! djm 483: expected_id = id = msg_id++;
1.1 djm 484: send_string_request(fd_out, id, SSH2_FXP_REALPATH, path,
485: strlen(path));
486:
487: buffer_init(&msg);
488:
489: get_msg(fd_in, &msg);
490: type = buffer_get_char(&msg);
491: id = buffer_get_int(&msg);
492:
493: if (id != expected_id)
494: fatal("ID mismatch (%d != %d)", id, expected_id);
495:
496: if (type == SSH2_FXP_STATUS) {
497: u_int status = buffer_get_int(&msg);
498:
499: error("Couldn't canonicalise: %s", fx2txt(status));
500: return(NULL);
501: } else if (type != SSH2_FXP_NAME)
502: fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
503: SSH2_FXP_NAME, type);
504:
505: count = buffer_get_int(&msg);
506: if (count != 1)
507: fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
508:
509: filename = buffer_get_string(&msg, NULL);
510: longname = buffer_get_string(&msg, NULL);
511: a = decode_attrib(&msg);
512:
513: debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
514:
515: xfree(longname);
516:
517: buffer_free(&msg);
518:
519: return(filename);
520: }
521:
522: int
523: do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
524: {
525: Buffer msg;
526: u_int status, id;
527:
528: buffer_init(&msg);
529:
530: /* Send rename request */
1.4 ! djm 531: id = msg_id++;
1.1 djm 532: buffer_put_char(&msg, SSH2_FXP_RENAME);
533: buffer_put_int(&msg, id);
534: buffer_put_cstring(&msg, oldpath);
535: buffer_put_cstring(&msg, newpath);
536: send_msg(fd_out, &msg);
537: debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
538: newpath);
539: buffer_free(&msg);
540:
541: status = get_status(fd_in, id);
542: if (status != SSH2_FX_OK)
543: error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
544: fx2txt(status));
545:
546: return(status);
547: }
548:
549: int
550: do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
551: int pflag)
552: {
553: int local_fd;
554: u_int expected_id, handle_len, mode, type, id;
555: u_int64_t offset;
556: char *handle;
557: Buffer msg;
558: Attrib junk, *a;
559:
560: a = do_stat(fd_in, fd_out, remote_path);
561: if (a == NULL)
562: return(-1);
563:
564: /* XXX: should we preserve set[ug]id? */
565: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
566: mode = S_IWRITE | (a->perm & 0777);
567: else
568: mode = 0666;
569:
570: local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
571: if (local_fd == -1) {
572: error("Couldn't open local file \"%s\" for writing: %s",
573: local_path, strerror(errno));
574: return(errno);
575: }
576:
577: /* Override umask and utimes if asked */
578: if (pflag && fchmod(local_fd, mode) == -1)
579: error("Couldn't set mode on \"%s\": %s", local_path,
580: strerror(errno));
581: if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
582: struct timeval tv;
583:
584: tv.tv_sec = a->atime;
585: tv.tv_usec = a->mtime;
586: if (utimes(local_path, &tv) == -1)
587: error("Can't set times on \"%s\": %s", local_path,
588: strerror(errno));
589: }
590:
591: buffer_init(&msg);
592:
593: /* Send open request */
1.4 ! djm 594: id = msg_id++;
1.1 djm 595: buffer_put_char(&msg, SSH2_FXP_OPEN);
596: buffer_put_int(&msg, id);
597: buffer_put_cstring(&msg, remote_path);
598: buffer_put_int(&msg, SSH2_FXF_READ);
599: attrib_clear(&junk); /* Send empty attributes */
600: encode_attrib(&msg, &junk);
601: send_msg(fd_out, &msg);
602: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
603:
604: handle = get_handle(fd_in, id, &handle_len);
605: if (handle == NULL) {
606: buffer_free(&msg);
607: close(local_fd);
608: return(-1);
609: }
610:
611: /* Read from remote and write to local */
612: offset = 0;
613: for(;;) {
614: u_int len;
615: char *data;
616:
1.4 ! djm 617: id = expected_id = msg_id++;
1.1 djm 618:
619: buffer_clear(&msg);
620: buffer_put_char(&msg, SSH2_FXP_READ);
621: buffer_put_int(&msg, id);
622: buffer_put_string(&msg, handle, handle_len);
623: buffer_put_int64(&msg, offset);
624: buffer_put_int(&msg, COPY_SIZE);
625: send_msg(fd_out, &msg);
626: debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2 deraadt 627: id, (unsigned long long)offset, COPY_SIZE);
1.1 djm 628:
629: buffer_clear(&msg);
630:
631: get_msg(fd_in, &msg);
632: type = buffer_get_char(&msg);
633: id = buffer_get_int(&msg);
634: debug3("Received reply T:%d I:%d", type, id);
635: if (id != expected_id)
636: fatal("ID mismatch (%d != %d)", id, expected_id);
637: if (type == SSH2_FXP_STATUS) {
638: int status = buffer_get_int(&msg);
639:
640: if (status == SSH2_FX_EOF)
641: break;
642: else {
643: error("Couldn't read from remote "
644: "file \"%s\" : %s", remote_path,
645: fx2txt(status));
646: do_close(fd_in, fd_out, handle, handle_len);
647: xfree(handle);
648: close(local_fd);
649: buffer_free(&msg);
650: return(status);
651: }
652: } else if (type != SSH2_FXP_DATA) {
653: fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
654: SSH2_FXP_DATA, type);
655: }
656:
657: data = buffer_get_string(&msg, &len);
658: if (len > COPY_SIZE)
659: fatal("Received more data than asked for %d > %d",
660: len, COPY_SIZE);
661:
1.2 deraadt 662: debug3("In read loop, got %d offset %lld", len,
663: (unsigned long long)offset);
1.1 djm 664: if (atomicio(write, local_fd, data, len) != len) {
665: error("Couldn't write to \"%s\": %s", local_path,
666: strerror(errno));
667: do_close(fd_in, fd_out, handle, handle_len);
668: xfree(handle);
669: close(local_fd);
670: xfree(data);
671: buffer_free(&msg);
672: return(-1);
673: }
674:
675: offset += len;
676: xfree(data);
677: }
678: xfree(handle);
679: buffer_free(&msg);
680: close(local_fd);
681:
682: return(do_close(fd_in, fd_out, handle, handle_len));
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;
696:
697: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
698: error("Couldn't open local file \"%s\" for reading: %s",
699: local_path, strerror(errno));
700: return(-1);
701: }
702: if (fstat(local_fd, &sb) == -1) {
703: error("Couldn't fstat local file \"%s\": %s",
704: local_path, strerror(errno));
705: close(local_fd);
706: return(-1);
707: }
708: stat_to_attrib(&sb, &a);
709:
710: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
711: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
712: a.perm &= 0777;
713: if (!pflag)
714: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
715:
716: buffer_init(&msg);
717:
718: /* Send open request */
1.4 ! djm 719: id = msg_id++;
1.1 djm 720: buffer_put_char(&msg, SSH2_FXP_OPEN);
721: buffer_put_int(&msg, id);
722: buffer_put_cstring(&msg, remote_path);
723: buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
724: encode_attrib(&msg, &a);
725: send_msg(fd_out, &msg);
726: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
727:
728: buffer_clear(&msg);
729:
730: handle = get_handle(fd_in, id, &handle_len);
731: if (handle == NULL) {
732: close(local_fd);
733: buffer_free(&msg);
734: return(-1);
735: }
736:
737: /* Override umask and utimes if asked */
738: if (pflag)
739: do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
740:
741: /* Read from local and write to remote */
742: offset = 0;
743: for(;;) {
744: int len;
745: char data[COPY_SIZE];
746: u_int status;
747:
748: /*
749: * Can't use atomicio here because it returns 0 on EOF, thus losing
750: * the last block of the file
751: */
752: do
753: len = read(local_fd, data, COPY_SIZE);
754: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
755:
756: if (len == -1)
757: fatal("Couldn't read from \"%s\": %s", local_path,
758: strerror(errno));
759: if (len == 0)
760: break;
761:
762: buffer_clear(&msg);
763: buffer_put_char(&msg, SSH2_FXP_WRITE);
764: buffer_put_int(&msg, ++id);
765: buffer_put_string(&msg, handle, handle_len);
766: buffer_put_int64(&msg, offset);
767: buffer_put_string(&msg, data, len);
768: send_msg(fd_out, &msg);
769: debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2 deraadt 770: id, (unsigned long long)offset, len);
1.1 djm 771:
772: status = get_status(fd_in, id);
773: if (status != SSH2_FX_OK) {
774: error("Couldn't write to remote file \"%s\": %s",
775: remote_path, fx2txt(status));
776: do_close(fd_in, fd_out, handle, handle_len);
777: xfree(handle);
778: close(local_fd);
779: return(-1);
780: }
1.2 deraadt 781: debug3("In write loop, got %d offset %llu", len,
782: (unsigned long long)offset);
1.1 djm 783:
784: offset += len;
785: }
786: xfree(handle);
787: buffer_free(&msg);
788:
789: if (close(local_fd) == -1) {
790: error("Couldn't close local file \"%s\": %s", local_path,
791: strerror(errno));
792: do_close(fd_in, fd_out, handle, handle_len);
793: return(-1);
794: }
795:
796: return(do_close(fd_in, fd_out, handle, handle_len));
797: }