sftp-client.c revision 76259
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"
32RCSID("$OpenBSD: sftp-client.c,v 1.16 2001/04/05 10:42:52 markus Exp $");
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
51/* Message ID */
52static u_int msg_id = 1;
53
54void
55send_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
73void
74get_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 == 0)
81		fatal("Connection closed");
82	else if (len == -1)
83		fatal("Couldn't read packet: %s", strerror(errno));
84
85	msg_len = GET_32BIT(buf);
86	if (msg_len > 256 * 1024)
87		fatal("Received message too long %d", msg_len);
88
89	while (msg_len) {
90		len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf)));
91		if (len == 0)
92			fatal("Connection closed");
93		else if (len == -1)
94			fatal("Couldn't read packet: %s", strerror(errno));
95
96		msg_len -= len;
97		buffer_append(m, buf, len);
98	}
99}
100
101void
102send_string_request(int fd, u_int id, u_int code, char *s,
103    u_int len)
104{
105	Buffer msg;
106
107	buffer_init(&msg);
108	buffer_put_char(&msg, code);
109	buffer_put_int(&msg, id);
110	buffer_put_string(&msg, s, len);
111	send_msg(fd, &msg);
112	debug3("Sent message fd %d T:%d I:%d", fd, code, id);
113	buffer_free(&msg);
114}
115
116void
117send_string_attrs_request(int fd, u_int id, u_int code, char *s,
118    u_int len, Attrib *a)
119{
120	Buffer msg;
121
122	buffer_init(&msg);
123	buffer_put_char(&msg, code);
124	buffer_put_int(&msg, id);
125	buffer_put_string(&msg, s, len);
126	encode_attrib(&msg, a);
127	send_msg(fd, &msg);
128	debug3("Sent message fd %d T:%d I:%d", fd, code, id);
129	buffer_free(&msg);
130}
131
132u_int
133get_status(int fd, int expected_id)
134{
135	Buffer msg;
136	u_int type, id, status;
137
138	buffer_init(&msg);
139	get_msg(fd, &msg);
140	type = buffer_get_char(&msg);
141	id = buffer_get_int(&msg);
142
143	if (id != expected_id)
144		fatal("ID mismatch (%d != %d)", id, expected_id);
145	if (type != SSH2_FXP_STATUS)
146		fatal("Expected SSH2_FXP_STATUS(%d) packet, got %d",
147		    SSH2_FXP_STATUS, type);
148
149	status = buffer_get_int(&msg);
150	buffer_free(&msg);
151
152	debug3("SSH2_FXP_STATUS %d", status);
153
154	return(status);
155}
156
157char *
158get_handle(int fd, u_int expected_id, u_int *len)
159{
160	Buffer msg;
161	u_int type, id;
162	char *handle;
163
164	buffer_init(&msg);
165	get_msg(fd, &msg);
166	type = buffer_get_char(&msg);
167	id = buffer_get_int(&msg);
168
169	if (id != expected_id)
170		fatal("ID mismatch (%d != %d)", id, expected_id);
171	if (type == SSH2_FXP_STATUS) {
172		int status = buffer_get_int(&msg);
173
174		error("Couldn't get handle: %s", fx2txt(status));
175		return(NULL);
176	} else if (type != SSH2_FXP_HANDLE)
177		fatal("Expected SSH2_FXP_HANDLE(%d) packet, got %d",
178		    SSH2_FXP_HANDLE, type);
179
180	handle = buffer_get_string(&msg, len);
181	buffer_free(&msg);
182
183	return(handle);
184}
185
186Attrib *
187get_decode_stat(int fd, u_int expected_id, int quiet)
188{
189	Buffer msg;
190	u_int type, id;
191	Attrib *a;
192
193	buffer_init(&msg);
194	get_msg(fd, &msg);
195
196	type = buffer_get_char(&msg);
197	id = buffer_get_int(&msg);
198
199	debug3("Received stat reply T:%d I:%d", type, id);
200	if (id != expected_id)
201		fatal("ID mismatch (%d != %d)", id, expected_id);
202	if (type == SSH2_FXP_STATUS) {
203		int status = buffer_get_int(&msg);
204
205		if (quiet)
206			debug("Couldn't stat remote file: %s", fx2txt(status));
207		else
208			error("Couldn't stat remote file: %s", fx2txt(status));
209		return(NULL);
210	} else if (type != SSH2_FXP_ATTRS) {
211		fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
212		    SSH2_FXP_ATTRS, type);
213	}
214	a = decode_attrib(&msg);
215	buffer_free(&msg);
216
217	return(a);
218}
219
220int
221do_init(int fd_in, int fd_out)
222{
223	int type, version;
224	Buffer msg;
225
226	buffer_init(&msg);
227	buffer_put_char(&msg, SSH2_FXP_INIT);
228	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
229	send_msg(fd_out, &msg);
230
231	buffer_clear(&msg);
232
233	get_msg(fd_in, &msg);
234
235	/* Expecting a VERSION reply */
236	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
237		error("Invalid packet back from SSH2_FXP_INIT (type %d)",
238		    type);
239		buffer_free(&msg);
240		return(-1);
241	}
242	version = buffer_get_int(&msg);
243
244	debug2("Remote version: %d", version);
245
246	/* Check for extensions */
247	while (buffer_len(&msg) > 0) {
248		char *name = buffer_get_string(&msg, NULL);
249		char *value = buffer_get_string(&msg, NULL);
250
251		debug2("Init extension: \"%s\"", name);
252		xfree(name);
253		xfree(value);
254	}
255
256	buffer_free(&msg);
257
258	return(version);
259}
260
261int
262do_close(int fd_in, int fd_out, char *handle, u_int handle_len)
263{
264	u_int id, status;
265	Buffer msg;
266
267	buffer_init(&msg);
268
269	id = msg_id++;
270	buffer_put_char(&msg, SSH2_FXP_CLOSE);
271	buffer_put_int(&msg, id);
272	buffer_put_string(&msg, handle, handle_len);
273	send_msg(fd_out, &msg);
274	debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
275
276	status = get_status(fd_in, id);
277	if (status != SSH2_FX_OK)
278		error("Couldn't close file: %s", fx2txt(status));
279
280	buffer_free(&msg);
281
282	return(status);
283}
284
285
286int
287do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,
288    SFTP_DIRENT ***dir)
289{
290	Buffer msg;
291	u_int type, id, handle_len, i, expected_id, ents = 0;
292	char *handle;
293
294	id = msg_id++;
295
296	buffer_init(&msg);
297	buffer_put_char(&msg, SSH2_FXP_OPENDIR);
298	buffer_put_int(&msg, id);
299	buffer_put_cstring(&msg, path);
300	send_msg(fd_out, &msg);
301
302	buffer_clear(&msg);
303
304	handle = get_handle(fd_in, id, &handle_len);
305	if (handle == NULL)
306		return(-1);
307
308	if (dir) {
309		ents = 0;
310		*dir = xmalloc(sizeof(**dir));
311		(*dir)[0] = NULL;
312	}
313
314
315	for(;;) {
316		int count;
317
318		id = expected_id = msg_id++;
319
320		debug3("Sending SSH2_FXP_READDIR I:%d", id);
321
322		buffer_clear(&msg);
323		buffer_put_char(&msg, SSH2_FXP_READDIR);
324		buffer_put_int(&msg, id);
325		buffer_put_string(&msg, handle, handle_len);
326		send_msg(fd_out, &msg);
327
328		buffer_clear(&msg);
329
330		get_msg(fd_in, &msg);
331
332		type = buffer_get_char(&msg);
333		id = buffer_get_int(&msg);
334
335		debug3("Received reply T:%d I:%d", type, id);
336
337		if (id != expected_id)
338			fatal("ID mismatch (%d != %d)", id, expected_id);
339
340		if (type == SSH2_FXP_STATUS) {
341			int status = buffer_get_int(&msg);
342
343			debug3("Received SSH2_FXP_STATUS %d", status);
344
345			if (status == SSH2_FX_EOF) {
346				break;
347			} else {
348				error("Couldn't read directory: %s",
349				    fx2txt(status));
350				do_close(fd_in, fd_out, handle, handle_len);
351				return(status);
352			}
353		} else if (type != SSH2_FXP_NAME)
354			fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
355			    SSH2_FXP_NAME, type);
356
357		count = buffer_get_int(&msg);
358		if (count == 0)
359			break;
360		debug3("Received %d SSH2_FXP_NAME responses", count);
361		for(i = 0; i < count; i++) {
362			char *filename, *longname;
363			Attrib *a;
364
365			filename = buffer_get_string(&msg, NULL);
366			longname = buffer_get_string(&msg, NULL);
367			a = decode_attrib(&msg);
368
369			if (printflag)
370				printf("%s\n", longname);
371
372			if (dir) {
373				*dir = xrealloc(*dir, sizeof(**dir) *
374				    (ents + 2));
375				(*dir)[ents] = xmalloc(sizeof(***dir));
376				(*dir)[ents]->filename = xstrdup(filename);
377				(*dir)[ents]->longname = xstrdup(longname);
378				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
379				(*dir)[++ents] = NULL;
380			}
381
382			xfree(filename);
383			xfree(longname);
384		}
385	}
386
387	buffer_free(&msg);
388	do_close(fd_in, fd_out, handle, handle_len);
389	xfree(handle);
390
391	return(0);
392}
393
394int
395do_ls(int fd_in, int fd_out, char *path)
396{
397	return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
398}
399
400int
401do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
402{
403	return(do_lsreaddir(fd_in, fd_out, path, 0, dir));
404}
405
406void free_sftp_dirents(SFTP_DIRENT **s)
407{
408	int i;
409
410	for(i = 0; s[i]; i++) {
411		xfree(s[i]->filename);
412		xfree(s[i]->longname);
413		xfree(s[i]);
414	}
415	xfree(s);
416}
417
418int
419do_rm(int fd_in, int fd_out, char *path)
420{
421	u_int status, id;
422
423	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
424
425	id = msg_id++;
426	send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));
427	status = get_status(fd_in, id);
428	if (status != SSH2_FX_OK)
429		error("Couldn't delete file: %s", fx2txt(status));
430	return(status);
431}
432
433int
434do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
435{
436	u_int status, id;
437
438	id = msg_id++;
439	send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
440	    strlen(path), a);
441
442	status = get_status(fd_in, id);
443	if (status != SSH2_FX_OK)
444		error("Couldn't create directory: %s", fx2txt(status));
445
446	return(status);
447}
448
449int
450do_rmdir(int fd_in, int fd_out, char *path)
451{
452	u_int status, id;
453
454	id = msg_id++;
455	send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
456
457	status = get_status(fd_in, id);
458	if (status != SSH2_FX_OK)
459		error("Couldn't remove directory: %s", fx2txt(status));
460
461	return(status);
462}
463
464Attrib *
465do_stat(int fd_in, int fd_out, char *path, int quiet)
466{
467	u_int id;
468
469	id = msg_id++;
470	send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
471	return(get_decode_stat(fd_in, id, quiet));
472}
473
474Attrib *
475do_lstat(int fd_in, int fd_out, char *path, int quiet)
476{
477	u_int id;
478
479	id = msg_id++;
480	send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
481	return(get_decode_stat(fd_in, id, quiet));
482}
483
484Attrib *
485do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
486{
487	u_int id;
488
489	id = msg_id++;
490	send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
491	return(get_decode_stat(fd_in, id, quiet));
492}
493
494int
495do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
496{
497	u_int status, id;
498
499	id = msg_id++;
500	send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
501	    strlen(path), a);
502
503	status = get_status(fd_in, id);
504	if (status != SSH2_FX_OK)
505		error("Couldn't setstat on \"%s\": %s", path,
506		    fx2txt(status));
507
508	return(status);
509}
510
511int
512do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
513    Attrib *a)
514{
515	u_int status, id;
516
517	id = msg_id++;
518	send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
519	    handle_len, a);
520
521	status = get_status(fd_in, id);
522	if (status != SSH2_FX_OK)
523		error("Couldn't fsetstat: %s", fx2txt(status));
524
525	return(status);
526}
527
528char *
529do_realpath(int fd_in, int fd_out, char *path)
530{
531	Buffer msg;
532	u_int type, expected_id, count, id;
533	char *filename, *longname;
534	Attrib *a;
535
536	expected_id = id = msg_id++;
537	send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
538
539	buffer_init(&msg);
540
541	get_msg(fd_in, &msg);
542	type = buffer_get_char(&msg);
543	id = buffer_get_int(&msg);
544
545	if (id != expected_id)
546		fatal("ID mismatch (%d != %d)", id, expected_id);
547
548	if (type == SSH2_FXP_STATUS) {
549		u_int status = buffer_get_int(&msg);
550
551		error("Couldn't canonicalise: %s", fx2txt(status));
552		return(NULL);
553	} else if (type != SSH2_FXP_NAME)
554		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
555		    SSH2_FXP_NAME, type);
556
557	count = buffer_get_int(&msg);
558	if (count != 1)
559		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
560
561	filename = buffer_get_string(&msg, NULL);
562	longname = buffer_get_string(&msg, NULL);
563	a = decode_attrib(&msg);
564
565	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
566
567	xfree(longname);
568
569	buffer_free(&msg);
570
571	return(filename);
572}
573
574int
575do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
576{
577	Buffer msg;
578	u_int status, id;
579
580	buffer_init(&msg);
581
582	/* Send rename request */
583	id = msg_id++;
584	buffer_put_char(&msg, SSH2_FXP_RENAME);
585	buffer_put_int(&msg, id);
586	buffer_put_cstring(&msg, oldpath);
587	buffer_put_cstring(&msg, newpath);
588	send_msg(fd_out, &msg);
589	debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
590	    newpath);
591	buffer_free(&msg);
592
593	status = get_status(fd_in, id);
594	if (status != SSH2_FX_OK)
595		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
596		    fx2txt(status));
597
598	return(status);
599}
600
601int
602do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)
603{
604	Buffer msg;
605	u_int status, id;
606
607	buffer_init(&msg);
608
609	/* Send rename request */
610	id = msg_id++;
611	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
612	buffer_put_int(&msg, id);
613	buffer_put_cstring(&msg, oldpath);
614	buffer_put_cstring(&msg, newpath);
615	send_msg(fd_out, &msg);
616	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
617	    newpath);
618	buffer_free(&msg);
619
620	status = get_status(fd_in, id);
621	if (status != SSH2_FX_OK)
622		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
623		    fx2txt(status));
624
625	return(status);
626}
627
628char *
629do_readlink(int fd_in, int fd_out, char *path)
630{
631	Buffer msg;
632	u_int type, expected_id, count, id;
633	char *filename, *longname;
634	Attrib *a;
635
636	expected_id = id = msg_id++;
637	send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
638
639	buffer_init(&msg);
640
641	get_msg(fd_in, &msg);
642	type = buffer_get_char(&msg);
643	id = buffer_get_int(&msg);
644
645	if (id != expected_id)
646		fatal("ID mismatch (%d != %d)", id, expected_id);
647
648	if (type == SSH2_FXP_STATUS) {
649		u_int status = buffer_get_int(&msg);
650
651		error("Couldn't readlink: %s", fx2txt(status));
652		return(NULL);
653	} else if (type != SSH2_FXP_NAME)
654		fatal("Expected SSH2_FXP_NAME(%d) packet, got %d",
655		    SSH2_FXP_NAME, type);
656
657	count = buffer_get_int(&msg);
658	if (count != 1)
659		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
660
661	filename = buffer_get_string(&msg, NULL);
662	longname = buffer_get_string(&msg, NULL);
663	a = decode_attrib(&msg);
664
665	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
666
667	xfree(longname);
668
669	buffer_free(&msg);
670
671	return(filename);
672}
673
674int
675do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
676    int pflag)
677{
678	int local_fd;
679	u_int expected_id, handle_len, mode, type, id;
680	u_int64_t offset;
681	char *handle;
682	Buffer msg;
683	Attrib junk, *a;
684	int status;
685
686	a = do_stat(fd_in, fd_out, remote_path, 0);
687	if (a == NULL)
688		return(-1);
689
690	/* XXX: should we preserve set[ug]id? */
691	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
692		mode = S_IWRITE | (a->perm & 0777);
693	else
694		mode = 0666;
695
696	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
697	    (a->perm & S_IFDIR)) {
698		error("Cannot download a directory: %s", remote_path);
699		return(-1);
700	}
701
702	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
703	if (local_fd == -1) {
704		error("Couldn't open local file \"%s\" for writing: %s",
705		    local_path, strerror(errno));
706		return(-1);
707	}
708
709	buffer_init(&msg);
710
711	/* Send open request */
712	id = msg_id++;
713	buffer_put_char(&msg, SSH2_FXP_OPEN);
714	buffer_put_int(&msg, id);
715	buffer_put_cstring(&msg, remote_path);
716	buffer_put_int(&msg, SSH2_FXF_READ);
717	attrib_clear(&junk); /* Send empty attributes */
718	encode_attrib(&msg, &junk);
719	send_msg(fd_out, &msg);
720	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
721
722	handle = get_handle(fd_in, id, &handle_len);
723	if (handle == NULL) {
724		buffer_free(&msg);
725		close(local_fd);
726		return(-1);
727	}
728
729	/* Read from remote and write to local */
730	offset = 0;
731	for(;;) {
732		u_int len;
733		char *data;
734
735		id = expected_id = msg_id++;
736
737		buffer_clear(&msg);
738		buffer_put_char(&msg, SSH2_FXP_READ);
739		buffer_put_int(&msg, id);
740		buffer_put_string(&msg, handle, handle_len);
741		buffer_put_int64(&msg, offset);
742		buffer_put_int(&msg, COPY_SIZE);
743		send_msg(fd_out, &msg);
744		debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",
745		    id, (unsigned long long)offset, COPY_SIZE);
746
747		buffer_clear(&msg);
748
749		get_msg(fd_in, &msg);
750		type = buffer_get_char(&msg);
751		id = buffer_get_int(&msg);
752		debug3("Received reply T:%d I:%d", type, id);
753		if (id != expected_id)
754			fatal("ID mismatch (%d != %d)", id, expected_id);
755		if (type == SSH2_FXP_STATUS) {
756			status = buffer_get_int(&msg);
757
758			if (status == SSH2_FX_EOF)
759				break;
760			else {
761				error("Couldn't read from remote "
762				    "file \"%s\" : %s", remote_path,
763				     fx2txt(status));
764				do_close(fd_in, fd_out, handle, handle_len);
765				goto done;
766			}
767		} else if (type != SSH2_FXP_DATA) {
768			fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
769			    SSH2_FXP_DATA, type);
770		}
771
772		data = buffer_get_string(&msg, &len);
773		if (len > COPY_SIZE)
774			fatal("Received more data than asked for %d > %d",
775			    len, COPY_SIZE);
776
777		debug3("In read loop, got %d offset %llu", len,
778		    (unsigned long long)offset);
779		if (atomicio(write, local_fd, data, len) != len) {
780			error("Couldn't write to \"%s\": %s", local_path,
781			    strerror(errno));
782			do_close(fd_in, fd_out, handle, handle_len);
783			status = -1;
784			xfree(data);
785			goto done;
786		}
787
788		offset += len;
789		xfree(data);
790	}
791	status = do_close(fd_in, fd_out, handle, handle_len);
792
793	/* Override umask and utimes if asked */
794	if (pflag && fchmod(local_fd, mode) == -1)
795		error("Couldn't set mode on \"%s\": %s", local_path,
796		    strerror(errno));
797	if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
798		struct timeval tv[2];
799		tv[0].tv_sec = a->atime;
800		tv[1].tv_sec = a->mtime;
801		tv[0].tv_usec = tv[1].tv_usec = 0;
802		if (utimes(local_path, tv) == -1)
803			error("Can't set times on \"%s\": %s", local_path,
804			    strerror(errno));
805	}
806
807done:
808	close(local_fd);
809	buffer_free(&msg);
810	xfree(handle);
811	return status;
812}
813
814int
815do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
816    int pflag)
817{
818	int local_fd;
819	u_int handle_len, id;
820	u_int64_t offset;
821	char *handle;
822	Buffer msg;
823	struct stat sb;
824	Attrib a;
825	int status;
826
827	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
828		error("Couldn't open local file \"%s\" for reading: %s",
829		    local_path, strerror(errno));
830		return(-1);
831	}
832	if (fstat(local_fd, &sb) == -1) {
833		error("Couldn't fstat local file \"%s\": %s",
834		    local_path, strerror(errno));
835		close(local_fd);
836		return(-1);
837	}
838	stat_to_attrib(&sb, &a);
839
840	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
841	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
842	a.perm &= 0777;
843	if (!pflag)
844		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
845
846	buffer_init(&msg);
847
848	/* Send open request */
849	id = msg_id++;
850	buffer_put_char(&msg, SSH2_FXP_OPEN);
851	buffer_put_int(&msg, id);
852	buffer_put_cstring(&msg, remote_path);
853	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
854	encode_attrib(&msg, &a);
855	send_msg(fd_out, &msg);
856	debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
857
858	buffer_clear(&msg);
859
860	handle = get_handle(fd_in, id, &handle_len);
861	if (handle == NULL) {
862		close(local_fd);
863		buffer_free(&msg);
864		return(-1);
865	}
866
867	/* Read from local and write to remote */
868	offset = 0;
869	for(;;) {
870		int len;
871		char data[COPY_SIZE];
872
873		/*
874		 * Can't use atomicio here because it returns 0 on EOF, thus losing
875		 * the last block of the file
876		 */
877		do
878			len = read(local_fd, data, COPY_SIZE);
879		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
880
881		if (len == -1)
882			fatal("Couldn't read from \"%s\": %s", local_path,
883			    strerror(errno));
884		if (len == 0)
885			break;
886
887		buffer_clear(&msg);
888		buffer_put_char(&msg, SSH2_FXP_WRITE);
889		buffer_put_int(&msg, ++id);
890		buffer_put_string(&msg, handle, handle_len);
891		buffer_put_int64(&msg, offset);
892		buffer_put_string(&msg, data, len);
893		send_msg(fd_out, &msg);
894		debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
895		    id, (unsigned long long)offset, len);
896
897		status = get_status(fd_in, id);
898		if (status != SSH2_FX_OK) {
899			error("Couldn't write to remote file \"%s\": %s",
900			    remote_path, fx2txt(status));
901			do_close(fd_in, fd_out, handle, handle_len);
902			close(local_fd);
903			goto done;
904		}
905		debug3("In write loop, got %d offset %llu", len,
906		    (unsigned long long)offset);
907
908		offset += len;
909	}
910
911	if (close(local_fd) == -1) {
912		error("Couldn't close local file \"%s\": %s", local_path,
913		    strerror(errno));
914		do_close(fd_in, fd_out, handle, handle_len);
915		status = -1;
916		goto done;
917	}
918
919	/* Override umask and utimes if asked */
920	if (pflag)
921		do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
922
923	status = do_close(fd_in, fd_out, handle, handle_len);
924
925done:
926	xfree(handle);
927	buffer_free(&msg);
928	return status;
929}
930
931