Annotation of src/usr.bin/ssh/sftp-client.c, Revision 1.5
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.5 ! djm 32: RCSID("$OpenBSD: sftp-client.c,v 1.4 2001/02/06 23:30:28 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);
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;
1.5 ! djm 559: int status;
1.1 djm 560:
561: a = do_stat(fd_in, fd_out, remote_path);
562: if (a == NULL)
563: return(-1);
564:
565: /* XXX: should we preserve set[ug]id? */
566: if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
567: mode = S_IWRITE | (a->perm & 0777);
568: else
569: mode = 0666;
570:
571: local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
572: if (local_fd == -1) {
573: error("Couldn't open local file \"%s\" for writing: %s",
574: local_path, strerror(errno));
575: return(errno);
576: }
577:
578: /* Override umask and utimes if asked */
579: if (pflag && fchmod(local_fd, mode) == -1)
580: error("Couldn't set mode on \"%s\": %s", local_path,
581: strerror(errno));
582: if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
583: struct timeval tv;
584:
585: tv.tv_sec = a->atime;
586: tv.tv_usec = a->mtime;
587: if (utimes(local_path, &tv) == -1)
588: error("Can't set times on \"%s\": %s", local_path,
589: strerror(errno));
590: }
591:
592: buffer_init(&msg);
593:
594: /* Send open request */
1.4 djm 595: id = msg_id++;
1.1 djm 596: buffer_put_char(&msg, SSH2_FXP_OPEN);
597: buffer_put_int(&msg, id);
598: buffer_put_cstring(&msg, remote_path);
599: buffer_put_int(&msg, SSH2_FXF_READ);
600: attrib_clear(&junk); /* Send empty attributes */
601: encode_attrib(&msg, &junk);
602: send_msg(fd_out, &msg);
603: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
604:
605: handle = get_handle(fd_in, id, &handle_len);
606: if (handle == NULL) {
607: buffer_free(&msg);
608: close(local_fd);
609: return(-1);
610: }
611:
612: /* Read from remote and write to local */
613: offset = 0;
614: for(;;) {
615: u_int len;
616: char *data;
617:
1.4 djm 618: id = expected_id = msg_id++;
1.1 djm 619:
620: buffer_clear(&msg);
621: buffer_put_char(&msg, SSH2_FXP_READ);
622: buffer_put_int(&msg, id);
623: buffer_put_string(&msg, handle, handle_len);
624: buffer_put_int64(&msg, offset);
625: buffer_put_int(&msg, COPY_SIZE);
626: send_msg(fd_out, &msg);
627: debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
1.2 deraadt 628: id, (unsigned long long)offset, COPY_SIZE);
1.1 djm 629:
630: buffer_clear(&msg);
631:
632: get_msg(fd_in, &msg);
633: type = buffer_get_char(&msg);
634: id = buffer_get_int(&msg);
635: debug3("Received reply T:%d I:%d", type, id);
636: if (id != expected_id)
637: fatal("ID mismatch (%d != %d)", id, expected_id);
638: if (type == SSH2_FXP_STATUS) {
1.5 ! djm 639: status = buffer_get_int(&msg);
1.1 djm 640:
641: if (status == SSH2_FX_EOF)
642: break;
643: else {
644: error("Couldn't read from remote "
645: "file \"%s\" : %s", remote_path,
646: fx2txt(status));
647: do_close(fd_in, fd_out, handle, handle_len);
1.5 ! djm 648: goto done;
1.1 djm 649: }
650: } else if (type != SSH2_FXP_DATA) {
651: fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
652: SSH2_FXP_DATA, type);
653: }
654:
655: data = buffer_get_string(&msg, &len);
656: if (len > COPY_SIZE)
657: fatal("Received more data than asked for %d > %d",
658: len, COPY_SIZE);
659:
1.2 deraadt 660: debug3("In read loop, got %d offset %lld", len,
661: (unsigned long long)offset);
1.1 djm 662: if (atomicio(write, local_fd, data, len) != len) {
663: error("Couldn't write to \"%s\": %s", local_path,
664: strerror(errno));
665: do_close(fd_in, fd_out, handle, handle_len);
1.5 ! djm 666: status = -1;
1.1 djm 667: xfree(data);
1.5 ! djm 668: goto done;
1.1 djm 669: }
670:
671: offset += len;
672: xfree(data);
673: }
1.5 ! djm 674: status = do_close(fd_in, fd_out, handle, handle_len);
! 675:
! 676: done:
! 677: close(local_fd);
! 678: buffer_free(&msg);
1.1 djm 679: xfree(handle);
1.5 ! djm 680: return status;
1.1 djm 681: }
682:
683: int
684: do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
685: int pflag)
686: {
687: int local_fd;
688: u_int handle_len, id;
689: u_int64_t offset;
690: char *handle;
691: Buffer msg;
692: struct stat sb;
693: Attrib a;
1.5 ! djm 694: int status;
1.1 djm 695:
696: if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
697: error("Couldn't open local file \"%s\" for reading: %s",
698: local_path, strerror(errno));
699: return(-1);
700: }
701: if (fstat(local_fd, &sb) == -1) {
702: error("Couldn't fstat local file \"%s\": %s",
703: local_path, strerror(errno));
704: close(local_fd);
705: return(-1);
706: }
707: stat_to_attrib(&sb, &a);
708:
709: a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
710: a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
711: a.perm &= 0777;
712: if (!pflag)
713: a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
714:
715: buffer_init(&msg);
716:
717: /* Send open request */
1.4 djm 718: id = msg_id++;
1.1 djm 719: buffer_put_char(&msg, SSH2_FXP_OPEN);
720: buffer_put_int(&msg, id);
721: buffer_put_cstring(&msg, remote_path);
722: buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
723: encode_attrib(&msg, &a);
724: send_msg(fd_out, &msg);
725: debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
726:
727: buffer_clear(&msg);
728:
729: handle = get_handle(fd_in, id, &handle_len);
730: if (handle == NULL) {
731: close(local_fd);
732: buffer_free(&msg);
733: return(-1);
734: }
735:
736: /* Override umask and utimes if asked */
737: if (pflag)
738: do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
739:
740: /* Read from local and write to remote */
741: offset = 0;
742: for(;;) {
743: int len;
744: char data[COPY_SIZE];
745:
746: /*
747: * Can't use atomicio here because it returns 0 on EOF, thus losing
748: * the last block of the file
749: */
750: do
751: len = read(local_fd, data, COPY_SIZE);
752: while ((len == -1) && (errno == EINTR || errno == EAGAIN));
753:
754: if (len == -1)
755: fatal("Couldn't read from \"%s\": %s", local_path,
756: strerror(errno));
757: if (len == 0)
758: break;
759:
760: buffer_clear(&msg);
761: buffer_put_char(&msg, SSH2_FXP_WRITE);
762: buffer_put_int(&msg, ++id);
763: buffer_put_string(&msg, handle, handle_len);
764: buffer_put_int64(&msg, offset);
765: buffer_put_string(&msg, data, len);
766: send_msg(fd_out, &msg);
767: debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
1.2 deraadt 768: id, (unsigned long long)offset, len);
1.1 djm 769:
770: status = get_status(fd_in, id);
771: if (status != SSH2_FX_OK) {
772: error("Couldn't write to remote file \"%s\": %s",
773: remote_path, fx2txt(status));
774: do_close(fd_in, fd_out, handle, handle_len);
775: close(local_fd);
1.5 ! djm 776: goto done;
1.1 djm 777: }
1.2 deraadt 778: debug3("In write loop, got %d offset %llu", len,
779: (unsigned long long)offset);
1.1 djm 780:
781: offset += len;
782: }
783:
784: if (close(local_fd) == -1) {
785: error("Couldn't close local file \"%s\": %s", local_path,
786: strerror(errno));
787: do_close(fd_in, fd_out, handle, handle_len);
1.5 ! djm 788: status = -1;
! 789: goto done;
1.1 djm 790: }
791:
1.5 ! djm 792: status = do_close(fd_in, fd_out, handle, handle_len);
! 793:
! 794: done:
! 795: xfree(handle);
! 796: buffer_free(&msg);
! 797: return status;
1.1 djm 798: }
1.5 ! djm 799:
! 800: