1/* $OpenBSD: sftp-client.c,v 1.108 2013/11/08 00:39:15 djm Exp $ */
2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* XXX: memleaks */
19/* XXX: signed vs unsigned */
20/* XXX: remove all logging, only return status codes */
21/* XXX: copy between two remote sites */
22
23#include "includes.h"
24
25#include <sys/types.h>
26#include <sys/param.h>
27#ifdef HAVE_SYS_STATVFS_H
28#include <sys/statvfs.h>
29#endif
30#include "openbsd-compat/sys-queue.h"
31#ifdef HAVE_SYS_STAT_H
32# include <sys/stat.h>
33#endif
34#ifdef HAVE_SYS_TIME_H
35# include <sys/time.h>
36#endif
37#include <sys/uio.h>
38
39#include <dirent.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <signal.h>
43#include <stdarg.h>
44#include <stdio.h>
45#include <string.h>
46#include <unistd.h>
47
48#include "xmalloc.h"
49#include "buffer.h"
50#include "log.h"
51#include "atomicio.h"
52#include "progressmeter.h"
53#include "misc.h"
54
55#include "sftp.h"
56#include "sftp-common.h"
57#include "sftp-client.h"
58
59extern volatile sig_atomic_t interrupted;
60extern int showprogress;
61
62/* Minimum amount of data to read at a time */
63#define MIN_READ_SIZE	512
64
65/* Maximum depth to descend in directory trees */
66#define MAX_DIR_DEPTH 64
67
68struct sftp_conn {
69	int fd_in;
70	int fd_out;
71	u_int transfer_buflen;
72	u_int num_requests;
73	u_int version;
74	u_int msg_id;
75#define SFTP_EXT_POSIX_RENAME	0x00000001
76#define SFTP_EXT_STATVFS	0x00000002
77#define SFTP_EXT_FSTATVFS	0x00000004
78#define SFTP_EXT_HARDLINK	0x00000008
79	u_int exts;
80	u_int64_t limit_kbps;
81	struct bwlimit bwlimit_in, bwlimit_out;
82};
83
84static char *
85get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
86    const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
87
88/* ARGSUSED */
89static int
90sftpio(void *_bwlimit, size_t amount)
91{
92	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
93
94	bandwidth_limit(bwlimit, amount);
95	return 0;
96}
97
98static void
99send_msg(struct sftp_conn *conn, Buffer *m)
100{
101	u_char mlen[4];
102	struct iovec iov[2];
103
104	if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
105		fatal("Outbound message too long %u", buffer_len(m));
106
107	/* Send length first */
108	put_u32(mlen, buffer_len(m));
109	iov[0].iov_base = mlen;
110	iov[0].iov_len = sizeof(mlen);
111	iov[1].iov_base = buffer_ptr(m);
112	iov[1].iov_len = buffer_len(m);
113
114	if (atomiciov6(writev, conn->fd_out, iov, 2,
115	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
116	    buffer_len(m) + sizeof(mlen))
117		fatal("Couldn't send packet: %s", strerror(errno));
118
119	buffer_clear(m);
120}
121
122static void
123get_msg(struct sftp_conn *conn, Buffer *m)
124{
125	u_int msg_len;
126
127	buffer_append_space(m, 4);
128	if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4,
129	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
130		if (errno == EPIPE)
131			fatal("Connection closed");
132		else
133			fatal("Couldn't read packet: %s", strerror(errno));
134	}
135
136	msg_len = buffer_get_int(m);
137	if (msg_len > SFTP_MAX_MSG_LENGTH)
138		fatal("Received message too long %u", msg_len);
139
140	buffer_append_space(m, msg_len);
141	if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len,
142	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
143	    != msg_len) {
144		if (errno == EPIPE)
145			fatal("Connection closed");
146		else
147			fatal("Read packet: %s", strerror(errno));
148	}
149}
150
151static void
152send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s,
153    u_int len)
154{
155	Buffer msg;
156
157	buffer_init(&msg);
158	buffer_put_char(&msg, code);
159	buffer_put_int(&msg, id);
160	buffer_put_string(&msg, s, len);
161	send_msg(conn, &msg);
162	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
163	buffer_free(&msg);
164}
165
166static void
167send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
168    char *s, u_int len, Attrib *a)
169{
170	Buffer msg;
171
172	buffer_init(&msg);
173	buffer_put_char(&msg, code);
174	buffer_put_int(&msg, id);
175	buffer_put_string(&msg, s, len);
176	encode_attrib(&msg, a);
177	send_msg(conn, &msg);
178	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
179	buffer_free(&msg);
180}
181
182static u_int
183get_status(struct sftp_conn *conn, u_int expected_id)
184{
185	Buffer msg;
186	u_int type, id, status;
187
188	buffer_init(&msg);
189	get_msg(conn, &msg);
190	type = buffer_get_char(&msg);
191	id = buffer_get_int(&msg);
192
193	if (id != expected_id)
194		fatal("ID mismatch (%u != %u)", id, expected_id);
195	if (type != SSH2_FXP_STATUS)
196		fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
197		    SSH2_FXP_STATUS, type);
198
199	status = buffer_get_int(&msg);
200	buffer_free(&msg);
201
202	debug3("SSH2_FXP_STATUS %u", status);
203
204	return status;
205}
206
207static char *
208get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
209    const char *errfmt, ...)
210{
211	Buffer msg;
212	u_int type, id;
213	char *handle, errmsg[256];
214	va_list args;
215	int status;
216
217	va_start(args, errfmt);
218	if (errfmt != NULL)
219		vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
220	va_end(args);
221
222	buffer_init(&msg);
223	get_msg(conn, &msg);
224	type = buffer_get_char(&msg);
225	id = buffer_get_int(&msg);
226
227	if (id != expected_id)
228		fatal("%s: ID mismatch (%u != %u)",
229		    errfmt == NULL ? __func__ : errmsg, id, expected_id);
230	if (type == SSH2_FXP_STATUS) {
231		status = buffer_get_int(&msg);
232		if (errfmt != NULL)
233			error("%s: %s", errmsg, fx2txt(status));
234		buffer_free(&msg);
235		return(NULL);
236	} else if (type != SSH2_FXP_HANDLE)
237		fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
238		    errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
239
240	handle = buffer_get_string(&msg, len);
241	buffer_free(&msg);
242
243	return(handle);
244}
245
246static Attrib *
247get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
248{
249	Buffer msg;
250	u_int type, id;
251	Attrib *a;
252
253	buffer_init(&msg);
254	get_msg(conn, &msg);
255
256	type = buffer_get_char(&msg);
257	id = buffer_get_int(&msg);
258
259	debug3("Received stat reply T:%u I:%u", type, id);
260	if (id != expected_id)
261		fatal("ID mismatch (%u != %u)", id, expected_id);
262	if (type == SSH2_FXP_STATUS) {
263		int status = buffer_get_int(&msg);
264
265		if (quiet)
266			debug("Couldn't stat remote file: %s", fx2txt(status));
267		else
268			error("Couldn't stat remote file: %s", fx2txt(status));
269		buffer_free(&msg);
270		return(NULL);
271	} else if (type != SSH2_FXP_ATTRS) {
272		fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
273		    SSH2_FXP_ATTRS, type);
274	}
275	a = decode_attrib(&msg);
276	buffer_free(&msg);
277
278	return(a);
279}
280
281static int
282get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
283    u_int expected_id, int quiet)
284{
285	Buffer msg;
286	u_int type, id, flag;
287
288	buffer_init(&msg);
289	get_msg(conn, &msg);
290
291	type = buffer_get_char(&msg);
292	id = buffer_get_int(&msg);
293
294	debug3("Received statvfs reply T:%u I:%u", type, id);
295	if (id != expected_id)
296		fatal("ID mismatch (%u != %u)", id, expected_id);
297	if (type == SSH2_FXP_STATUS) {
298		int status = buffer_get_int(&msg);
299
300		if (quiet)
301			debug("Couldn't statvfs: %s", fx2txt(status));
302		else
303			error("Couldn't statvfs: %s", fx2txt(status));
304		buffer_free(&msg);
305		return -1;
306	} else if (type != SSH2_FXP_EXTENDED_REPLY) {
307		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
308		    SSH2_FXP_EXTENDED_REPLY, type);
309	}
310
311	bzero(st, sizeof(*st));
312	st->f_bsize = buffer_get_int64(&msg);
313	st->f_frsize = buffer_get_int64(&msg);
314	st->f_blocks = buffer_get_int64(&msg);
315	st->f_bfree = buffer_get_int64(&msg);
316	st->f_bavail = buffer_get_int64(&msg);
317	st->f_files = buffer_get_int64(&msg);
318	st->f_ffree = buffer_get_int64(&msg);
319	st->f_favail = buffer_get_int64(&msg);
320	st->f_fsid = buffer_get_int64(&msg);
321	flag = buffer_get_int64(&msg);
322	st->f_namemax = buffer_get_int64(&msg);
323
324	st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
325	st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
326
327	buffer_free(&msg);
328
329	return 0;
330}
331
332struct sftp_conn *
333do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
334    u_int64_t limit_kbps)
335{
336	u_int type;
337	Buffer msg;
338	struct sftp_conn *ret;
339
340	ret = xmalloc(sizeof(*ret));
341	ret->fd_in = fd_in;
342	ret->fd_out = fd_out;
343	ret->transfer_buflen = transfer_buflen;
344	ret->num_requests = num_requests;
345	ret->exts = 0;
346	ret->limit_kbps = 0;
347
348	buffer_init(&msg);
349	buffer_put_char(&msg, SSH2_FXP_INIT);
350	buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
351	send_msg(ret, &msg);
352
353	buffer_clear(&msg);
354
355	get_msg(ret, &msg);
356
357	/* Expecting a VERSION reply */
358	if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
359		error("Invalid packet back from SSH2_FXP_INIT (type %u)",
360		    type);
361		buffer_free(&msg);
362		return(NULL);
363	}
364	ret->version = buffer_get_int(&msg);
365
366	debug2("Remote version: %u", ret->version);
367
368	/* Check for extensions */
369	while (buffer_len(&msg) > 0) {
370		char *name = buffer_get_string(&msg, NULL);
371		char *value = buffer_get_string(&msg, NULL);
372		int known = 0;
373
374		if (strcmp(name, "posix-rename@openssh.com") == 0 &&
375		    strcmp(value, "1") == 0) {
376			ret->exts |= SFTP_EXT_POSIX_RENAME;
377			known = 1;
378		} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
379		    strcmp(value, "2") == 0) {
380			ret->exts |= SFTP_EXT_STATVFS;
381			known = 1;
382		} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
383		    strcmp(value, "2") == 0) {
384			ret->exts |= SFTP_EXT_FSTATVFS;
385			known = 1;
386		} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
387		    strcmp(value, "1") == 0) {
388			ret->exts |= SFTP_EXT_HARDLINK;
389			known = 1;
390		}
391		if (known) {
392			debug2("Server supports extension \"%s\" revision %s",
393			    name, value);
394		} else {
395			debug2("Unrecognised server extension \"%s\"", name);
396		}
397		free(name);
398		free(value);
399	}
400
401	buffer_free(&msg);
402
403	/* Some filexfer v.0 servers don't support large packets */
404	if (ret->version == 0)
405		ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
406
407	ret->limit_kbps = limit_kbps;
408	if (ret->limit_kbps > 0) {
409		bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
410		    ret->transfer_buflen);
411		bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
412		    ret->transfer_buflen);
413	}
414
415	return ret;
416}
417
418u_int
419sftp_proto_version(struct sftp_conn *conn)
420{
421	return conn->version;
422}
423
424int
425do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
426{
427	u_int id, status;
428	Buffer msg;
429
430	buffer_init(&msg);
431
432	id = conn->msg_id++;
433	buffer_put_char(&msg, SSH2_FXP_CLOSE);
434	buffer_put_int(&msg, id);
435	buffer_put_string(&msg, handle, handle_len);
436	send_msg(conn, &msg);
437	debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
438
439	status = get_status(conn, id);
440	if (status != SSH2_FX_OK)
441		error("Couldn't close file: %s", fx2txt(status));
442
443	buffer_free(&msg);
444
445	return status;
446}
447
448
449static int
450do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
451    SFTP_DIRENT ***dir)
452{
453	Buffer msg;
454	u_int count, type, id, handle_len, i, expected_id, ents = 0;
455	char *handle;
456
457	id = conn->msg_id++;
458
459	buffer_init(&msg);
460	buffer_put_char(&msg, SSH2_FXP_OPENDIR);
461	buffer_put_int(&msg, id);
462	buffer_put_cstring(&msg, path);
463	send_msg(conn, &msg);
464
465	handle = get_handle(conn, id, &handle_len,
466	    "remote readdir(\"%s\")", path);
467	if (handle == NULL) {
468		buffer_free(&msg);
469		return -1;
470	}
471
472	if (dir) {
473		ents = 0;
474		*dir = xcalloc(1, sizeof(**dir));
475		(*dir)[0] = NULL;
476	}
477
478	for (; !interrupted;) {
479		id = expected_id = conn->msg_id++;
480
481		debug3("Sending SSH2_FXP_READDIR I:%u", id);
482
483		buffer_clear(&msg);
484		buffer_put_char(&msg, SSH2_FXP_READDIR);
485		buffer_put_int(&msg, id);
486		buffer_put_string(&msg, handle, handle_len);
487		send_msg(conn, &msg);
488
489		buffer_clear(&msg);
490
491		get_msg(conn, &msg);
492
493		type = buffer_get_char(&msg);
494		id = buffer_get_int(&msg);
495
496		debug3("Received reply T:%u I:%u", type, id);
497
498		if (id != expected_id)
499			fatal("ID mismatch (%u != %u)", id, expected_id);
500
501		if (type == SSH2_FXP_STATUS) {
502			int status = buffer_get_int(&msg);
503
504			debug3("Received SSH2_FXP_STATUS %d", status);
505
506			if (status == SSH2_FX_EOF) {
507				break;
508			} else {
509				error("Couldn't read directory: %s",
510				    fx2txt(status));
511				do_close(conn, handle, handle_len);
512				free(handle);
513				buffer_free(&msg);
514				return(status);
515			}
516		} else if (type != SSH2_FXP_NAME)
517			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
518			    SSH2_FXP_NAME, type);
519
520		count = buffer_get_int(&msg);
521		if (count == 0)
522			break;
523		debug3("Received %d SSH2_FXP_NAME responses", count);
524		for (i = 0; i < count; i++) {
525			char *filename, *longname;
526			Attrib *a;
527
528			filename = buffer_get_string(&msg, NULL);
529			longname = buffer_get_string(&msg, NULL);
530			a = decode_attrib(&msg);
531
532			if (printflag)
533				printf("%s\n", longname);
534
535			/*
536			 * Directory entries should never contain '/'
537			 * These can be used to attack recursive ops
538			 * (e.g. send '../../../../etc/passwd')
539			 */
540			if (strchr(filename, '/') != NULL) {
541				error("Server sent suspect path \"%s\" "
542				    "during readdir of \"%s\"", filename, path);
543				goto next;
544			}
545
546			if (dir) {
547				*dir = xrealloc(*dir, ents + 2, sizeof(**dir));
548				(*dir)[ents] = xcalloc(1, sizeof(***dir));
549				(*dir)[ents]->filename = xstrdup(filename);
550				(*dir)[ents]->longname = xstrdup(longname);
551				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
552				(*dir)[++ents] = NULL;
553			}
554 next:
555			free(filename);
556			free(longname);
557		}
558	}
559
560	buffer_free(&msg);
561	do_close(conn, handle, handle_len);
562	free(handle);
563
564	/* Don't return partial matches on interrupt */
565	if (interrupted && dir != NULL && *dir != NULL) {
566		free_sftp_dirents(*dir);
567		*dir = xcalloc(1, sizeof(**dir));
568		**dir = NULL;
569	}
570
571	return 0;
572}
573
574int
575do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
576{
577	return(do_lsreaddir(conn, path, 0, dir));
578}
579
580void free_sftp_dirents(SFTP_DIRENT **s)
581{
582	int i;
583
584	for (i = 0; s[i]; i++) {
585		free(s[i]->filename);
586		free(s[i]->longname);
587		free(s[i]);
588	}
589	free(s);
590}
591
592int
593do_rm(struct sftp_conn *conn, char *path)
594{
595	u_int status, id;
596
597	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
598
599	id = conn->msg_id++;
600	send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
601	status = get_status(conn, id);
602	if (status != SSH2_FX_OK)
603		error("Couldn't delete file: %s", fx2txt(status));
604	return(status);
605}
606
607int
608do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
609{
610	u_int status, id;
611
612	id = conn->msg_id++;
613	send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
614	    strlen(path), a);
615
616	status = get_status(conn, id);
617	if (status != SSH2_FX_OK && printflag)
618		error("Couldn't create directory: %s", fx2txt(status));
619
620	return(status);
621}
622
623int
624do_rmdir(struct sftp_conn *conn, char *path)
625{
626	u_int status, id;
627
628	id = conn->msg_id++;
629	send_string_request(conn, id, SSH2_FXP_RMDIR, path,
630	    strlen(path));
631
632	status = get_status(conn, id);
633	if (status != SSH2_FX_OK)
634		error("Couldn't remove directory: %s", fx2txt(status));
635
636	return(status);
637}
638
639Attrib *
640do_stat(struct sftp_conn *conn, char *path, int quiet)
641{
642	u_int id;
643
644	id = conn->msg_id++;
645
646	send_string_request(conn, id,
647	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
648	    path, strlen(path));
649
650	return(get_decode_stat(conn, id, quiet));
651}
652
653Attrib *
654do_lstat(struct sftp_conn *conn, char *path, int quiet)
655{
656	u_int id;
657
658	if (conn->version == 0) {
659		if (quiet)
660			debug("Server version does not support lstat operation");
661		else
662			logit("Server version does not support lstat operation");
663		return(do_stat(conn, path, quiet));
664	}
665
666	id = conn->msg_id++;
667	send_string_request(conn, id, SSH2_FXP_LSTAT, path,
668	    strlen(path));
669
670	return(get_decode_stat(conn, id, quiet));
671}
672
673#ifdef notyet
674Attrib *
675do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
676{
677	u_int id;
678
679	id = conn->msg_id++;
680	send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
681	    handle_len);
682
683	return(get_decode_stat(conn, id, quiet));
684}
685#endif
686
687int
688do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
689{
690	u_int status, id;
691
692	id = conn->msg_id++;
693	send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
694	    strlen(path), a);
695
696	status = get_status(conn, id);
697	if (status != SSH2_FX_OK)
698		error("Couldn't setstat on \"%s\": %s", path,
699		    fx2txt(status));
700
701	return(status);
702}
703
704int
705do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
706    Attrib *a)
707{
708	u_int status, id;
709
710	id = conn->msg_id++;
711	send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
712	    handle_len, a);
713
714	status = get_status(conn, id);
715	if (status != SSH2_FX_OK)
716		error("Couldn't fsetstat: %s", fx2txt(status));
717
718	return(status);
719}
720
721char *
722do_realpath(struct sftp_conn *conn, char *path)
723{
724	Buffer msg;
725	u_int type, expected_id, count, id;
726	char *filename, *longname;
727	Attrib *a;
728
729	expected_id = id = conn->msg_id++;
730	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
731	    strlen(path));
732
733	buffer_init(&msg);
734
735	get_msg(conn, &msg);
736	type = buffer_get_char(&msg);
737	id = buffer_get_int(&msg);
738
739	if (id != expected_id)
740		fatal("ID mismatch (%u != %u)", id, expected_id);
741
742	if (type == SSH2_FXP_STATUS) {
743		u_int status = buffer_get_int(&msg);
744
745		error("Couldn't canonicalise: %s", fx2txt(status));
746		buffer_free(&msg);
747		return NULL;
748	} else if (type != SSH2_FXP_NAME)
749		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
750		    SSH2_FXP_NAME, type);
751
752	count = buffer_get_int(&msg);
753	if (count != 1)
754		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
755
756	filename = buffer_get_string(&msg, NULL);
757	longname = buffer_get_string(&msg, NULL);
758	a = decode_attrib(&msg);
759
760	debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
761	    (unsigned long)a->size);
762
763	free(longname);
764
765	buffer_free(&msg);
766
767	return(filename);
768}
769
770int
771do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
772{
773	Buffer msg;
774	u_int status, id;
775
776	buffer_init(&msg);
777
778	/* Send rename request */
779	id = conn->msg_id++;
780	if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
781		buffer_put_char(&msg, SSH2_FXP_EXTENDED);
782		buffer_put_int(&msg, id);
783		buffer_put_cstring(&msg, "posix-rename@openssh.com");
784	} else {
785		buffer_put_char(&msg, SSH2_FXP_RENAME);
786		buffer_put_int(&msg, id);
787	}
788	buffer_put_cstring(&msg, oldpath);
789	buffer_put_cstring(&msg, newpath);
790	send_msg(conn, &msg);
791	debug3("Sent message %s \"%s\" -> \"%s\"",
792	    (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
793	    "SSH2_FXP_RENAME", oldpath, newpath);
794	buffer_free(&msg);
795
796	status = get_status(conn, id);
797	if (status != SSH2_FX_OK)
798		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
799		    newpath, fx2txt(status));
800
801	return(status);
802}
803
804int
805do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
806{
807	Buffer msg;
808	u_int status, id;
809
810	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
811		error("Server does not support hardlink@openssh.com extension");
812		return -1;
813	}
814
815	buffer_init(&msg);
816
817	/* Send link request */
818	id = conn->msg_id++;
819	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
820	buffer_put_int(&msg, id);
821	buffer_put_cstring(&msg, "hardlink@openssh.com");
822	buffer_put_cstring(&msg, oldpath);
823	buffer_put_cstring(&msg, newpath);
824	send_msg(conn, &msg);
825	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
826	       oldpath, newpath);
827	buffer_free(&msg);
828
829	status = get_status(conn, id);
830	if (status != SSH2_FX_OK)
831		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
832		    newpath, fx2txt(status));
833
834	return(status);
835}
836
837int
838do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
839{
840	Buffer msg;
841	u_int status, id;
842
843	if (conn->version < 3) {
844		error("This server does not support the symlink operation");
845		return(SSH2_FX_OP_UNSUPPORTED);
846	}
847
848	buffer_init(&msg);
849
850	/* Send symlink request */
851	id = conn->msg_id++;
852	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
853	buffer_put_int(&msg, id);
854	buffer_put_cstring(&msg, oldpath);
855	buffer_put_cstring(&msg, newpath);
856	send_msg(conn, &msg);
857	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
858	    newpath);
859	buffer_free(&msg);
860
861	status = get_status(conn, id);
862	if (status != SSH2_FX_OK)
863		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
864		    newpath, fx2txt(status));
865
866	return(status);
867}
868
869#ifdef notyet
870char *
871do_readlink(struct sftp_conn *conn, char *path)
872{
873	Buffer msg;
874	u_int type, expected_id, count, id;
875	char *filename, *longname;
876	Attrib *a;
877
878	expected_id = id = conn->msg_id++;
879	send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
880
881	buffer_init(&msg);
882
883	get_msg(conn, &msg);
884	type = buffer_get_char(&msg);
885	id = buffer_get_int(&msg);
886
887	if (id != expected_id)
888		fatal("ID mismatch (%u != %u)", id, expected_id);
889
890	if (type == SSH2_FXP_STATUS) {
891		u_int status = buffer_get_int(&msg);
892
893		error("Couldn't readlink: %s", fx2txt(status));
894		buffer_free(&msg);
895		return(NULL);
896	} else if (type != SSH2_FXP_NAME)
897		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
898		    SSH2_FXP_NAME, type);
899
900	count = buffer_get_int(&msg);
901	if (count != 1)
902		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
903
904	filename = buffer_get_string(&msg, NULL);
905	longname = buffer_get_string(&msg, NULL);
906	a = decode_attrib(&msg);
907
908	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
909
910	free(longname);
911
912	buffer_free(&msg);
913
914	return(filename);
915}
916#endif
917
918int
919do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
920    int quiet)
921{
922	Buffer msg;
923	u_int id;
924
925	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
926		error("Server does not support statvfs@openssh.com extension");
927		return -1;
928	}
929
930	id = conn->msg_id++;
931
932	buffer_init(&msg);
933	buffer_clear(&msg);
934	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
935	buffer_put_int(&msg, id);
936	buffer_put_cstring(&msg, "statvfs@openssh.com");
937	buffer_put_cstring(&msg, path);
938	send_msg(conn, &msg);
939	buffer_free(&msg);
940
941	return get_decode_statvfs(conn, st, id, quiet);
942}
943
944#ifdef notyet
945int
946do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
947    struct sftp_statvfs *st, int quiet)
948{
949	Buffer msg;
950	u_int id;
951
952	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
953		error("Server does not support fstatvfs@openssh.com extension");
954		return -1;
955	}
956
957	id = conn->msg_id++;
958
959	buffer_init(&msg);
960	buffer_clear(&msg);
961	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
962	buffer_put_int(&msg, id);
963	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
964	buffer_put_string(&msg, handle, handle_len);
965	send_msg(conn, &msg);
966	buffer_free(&msg);
967
968	return get_decode_statvfs(conn, st, id, quiet);
969}
970#endif
971
972static void
973send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
974    u_int len, char *handle, u_int handle_len)
975{
976	Buffer msg;
977
978	buffer_init(&msg);
979	buffer_clear(&msg);
980	buffer_put_char(&msg, SSH2_FXP_READ);
981	buffer_put_int(&msg, id);
982	buffer_put_string(&msg, handle, handle_len);
983	buffer_put_int64(&msg, offset);
984	buffer_put_int(&msg, len);
985	send_msg(conn, &msg);
986	buffer_free(&msg);
987}
988
989int
990do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
991    Attrib *a, int pflag, int resume)
992{
993	Attrib junk;
994	Buffer msg;
995	char *handle;
996	int local_fd = -1, status = 0, write_error;
997	int read_error, write_errno, reordered = 0;
998	u_int64_t offset = 0, size, highwater;
999	u_int handle_len, mode, type, id, buflen, num_req, max_req;
1000	off_t progress_counter;
1001	struct stat st;
1002	struct request {
1003		u_int id;
1004		u_int len;
1005		u_int64_t offset;
1006		TAILQ_ENTRY(request) tq;
1007	};
1008	TAILQ_HEAD(reqhead, request) requests;
1009	struct request *req;
1010
1011	TAILQ_INIT(&requests);
1012
1013	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1014		return -1;
1015
1016	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1017	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1018		mode = a->perm & 0777;
1019	else
1020		mode = 0666;
1021
1022	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1023	    (!S_ISREG(a->perm))) {
1024		error("Cannot download non-regular file: %s", remote_path);
1025		return(-1);
1026	}
1027
1028	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1029		size = a->size;
1030	else
1031		size = 0;
1032
1033	buflen = conn->transfer_buflen;
1034	buffer_init(&msg);
1035
1036	/* Send open request */
1037	id = conn->msg_id++;
1038	buffer_put_char(&msg, SSH2_FXP_OPEN);
1039	buffer_put_int(&msg, id);
1040	buffer_put_cstring(&msg, remote_path);
1041	buffer_put_int(&msg, SSH2_FXF_READ);
1042	attrib_clear(&junk); /* Send empty attributes */
1043	encode_attrib(&msg, &junk);
1044	send_msg(conn, &msg);
1045	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1046
1047	handle = get_handle(conn, id, &handle_len,
1048	    "remote open(\"%s\")", remote_path);
1049	if (handle == NULL) {
1050		buffer_free(&msg);
1051		return(-1);
1052	}
1053
1054	local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? 0 : O_TRUNC),
1055	    mode | S_IWUSR);
1056	if (local_fd == -1) {
1057		error("Couldn't open local file \"%s\" for writing: %s",
1058		    local_path, strerror(errno));
1059		goto fail;
1060	}
1061	offset = highwater = 0;
1062	if (resume) {
1063		if (fstat(local_fd, &st) == -1) {
1064			error("Unable to stat local file \"%s\": %s",
1065			    local_path, strerror(errno));
1066			goto fail;
1067		}
1068		if ((size_t)st.st_size > size) {
1069			error("Unable to resume download of \"%s\": "
1070			    "local file is larger than remote", local_path);
1071 fail:
1072			do_close(conn, handle, handle_len);
1073			buffer_free(&msg);
1074			free(handle);
1075			return -1;
1076		}
1077		offset = highwater = st.st_size;
1078	}
1079
1080	/* Read from remote and write to local */
1081	write_error = read_error = write_errno = num_req = 0;
1082	max_req = 1;
1083	progress_counter = offset;
1084
1085	if (showprogress && size != 0)
1086		start_progress_meter(remote_path, size, &progress_counter);
1087
1088	while (num_req > 0 || max_req > 0) {
1089		char *data;
1090		u_int len;
1091
1092		/*
1093		 * Simulate EOF on interrupt: stop sending new requests and
1094		 * allow outstanding requests to drain gracefully
1095		 */
1096		if (interrupted) {
1097			if (num_req == 0) /* If we haven't started yet... */
1098				break;
1099			max_req = 0;
1100		}
1101
1102		/* Send some more requests */
1103		while (num_req < max_req) {
1104			debug3("Request range %llu -> %llu (%d/%d)",
1105			    (unsigned long long)offset,
1106			    (unsigned long long)offset + buflen - 1,
1107			    num_req, max_req);
1108			req = xcalloc(1, sizeof(*req));
1109			req->id = conn->msg_id++;
1110			req->len = buflen;
1111			req->offset = offset;
1112			offset += buflen;
1113			num_req++;
1114			TAILQ_INSERT_TAIL(&requests, req, tq);
1115			send_read_request(conn, req->id, req->offset,
1116			    req->len, handle, handle_len);
1117		}
1118
1119		buffer_clear(&msg);
1120		get_msg(conn, &msg);
1121		type = buffer_get_char(&msg);
1122		id = buffer_get_int(&msg);
1123		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1124
1125		/* Find the request in our queue */
1126		for (req = TAILQ_FIRST(&requests);
1127		    req != NULL && req->id != id;
1128		    req = TAILQ_NEXT(req, tq))
1129			;
1130		if (req == NULL)
1131			fatal("Unexpected reply %u", id);
1132
1133		switch (type) {
1134		case SSH2_FXP_STATUS:
1135			status = buffer_get_int(&msg);
1136			if (status != SSH2_FX_EOF)
1137				read_error = 1;
1138			max_req = 0;
1139			TAILQ_REMOVE(&requests, req, tq);
1140			free(req);
1141			num_req--;
1142			break;
1143		case SSH2_FXP_DATA:
1144			data = buffer_get_string(&msg, &len);
1145			debug3("Received data %llu -> %llu",
1146			    (unsigned long long)req->offset,
1147			    (unsigned long long)req->offset + len - 1);
1148			if (len > req->len)
1149				fatal("Received more data than asked for "
1150				    "%u > %u", len, req->len);
1151			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1152			    atomicio(vwrite, local_fd, data, len) != len) &&
1153			    !write_error) {
1154				write_errno = errno;
1155				write_error = 1;
1156				max_req = 0;
1157			}
1158			else if (!reordered && req->offset <= highwater)
1159				highwater = req->offset + len;
1160			else if (!reordered && req->offset > highwater)
1161				reordered = 1;
1162			progress_counter += len;
1163			free(data);
1164
1165			if (len == req->len) {
1166				TAILQ_REMOVE(&requests, req, tq);
1167				free(req);
1168				num_req--;
1169			} else {
1170				/* Resend the request for the missing data */
1171				debug3("Short data block, re-requesting "
1172				    "%llu -> %llu (%2d)",
1173				    (unsigned long long)req->offset + len,
1174				    (unsigned long long)req->offset +
1175				    req->len - 1, num_req);
1176				req->id = conn->msg_id++;
1177				req->len -= len;
1178				req->offset += len;
1179				send_read_request(conn, req->id,
1180				    req->offset, req->len, handle, handle_len);
1181				/* Reduce the request size */
1182				if (len < buflen)
1183					buflen = MAX(MIN_READ_SIZE, len);
1184			}
1185			if (max_req > 0) { /* max_req = 0 iff EOF received */
1186				if (size > 0 && offset > size) {
1187					/* Only one request at a time
1188					 * after the expected EOF */
1189					debug3("Finish at %llu (%2d)",
1190					    (unsigned long long)offset,
1191					    num_req);
1192					max_req = 1;
1193				} else if (max_req <= conn->num_requests) {
1194					++max_req;
1195				}
1196			}
1197			break;
1198		default:
1199			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1200			    SSH2_FXP_DATA, type);
1201		}
1202	}
1203
1204	if (showprogress && size)
1205		stop_progress_meter();
1206
1207	/* Sanity check */
1208	if (TAILQ_FIRST(&requests) != NULL)
1209		fatal("Transfer complete, but requests still in queue");
1210	/* Truncate at highest contiguous point to avoid holes on interrupt */
1211	if (read_error || write_error || interrupted) {
1212		if (reordered && resume) {
1213			error("Unable to resume download of \"%s\": "
1214			    "server reordered requests", local_path);
1215		}
1216		debug("truncating at %llu", (unsigned long long)highwater);
1217		ftruncate(local_fd, highwater);
1218	}
1219	if (read_error) {
1220		error("Couldn't read from remote file \"%s\" : %s",
1221		    remote_path, fx2txt(status));
1222		do_close(conn, handle, handle_len);
1223	} else if (write_error) {
1224		error("Couldn't write to \"%s\": %s", local_path,
1225		    strerror(write_errno));
1226		status = -1;
1227		do_close(conn, handle, handle_len);
1228	} else {
1229		status = do_close(conn, handle, handle_len);
1230		if (interrupted)
1231			status = -1;
1232		/* Override umask and utimes if asked */
1233#ifdef HAVE_FCHMOD
1234		if (pflag && fchmod(local_fd, mode) == -1)
1235#else
1236		if (pflag && chmod(local_path, mode) == -1)
1237#endif /* HAVE_FCHMOD */
1238			error("Couldn't set mode on \"%s\": %s", local_path,
1239			    strerror(errno));
1240		if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1241			struct timeval tv[2];
1242			tv[0].tv_sec = a->atime;
1243			tv[1].tv_sec = a->mtime;
1244			tv[0].tv_usec = tv[1].tv_usec = 0;
1245			if (utimes(local_path, tv) == -1)
1246				error("Can't set times on \"%s\": %s",
1247				    local_path, strerror(errno));
1248		}
1249	}
1250	close(local_fd);
1251	buffer_free(&msg);
1252	free(handle);
1253
1254	return(status);
1255}
1256
1257static int
1258download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1259    Attrib *dirattrib, int pflag, int printflag, int depth, int resume)
1260{
1261	int i, ret = 0;
1262	SFTP_DIRENT **dir_entries;
1263	char *filename, *new_src, *new_dst;
1264	mode_t mode = 0777;
1265
1266	if (depth >= MAX_DIR_DEPTH) {
1267		error("Maximum directory depth exceeded: %d levels", depth);
1268		return -1;
1269	}
1270
1271	if (dirattrib == NULL &&
1272	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1273		error("Unable to stat remote directory \"%s\"", src);
1274		return -1;
1275	}
1276	if (!S_ISDIR(dirattrib->perm)) {
1277		error("\"%s\" is not a directory", src);
1278		return -1;
1279	}
1280	if (printflag)
1281		printf("Retrieving %s\n", src);
1282
1283	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1284		mode = dirattrib->perm & 01777;
1285	else {
1286		debug("Server did not send permissions for "
1287		    "directory \"%s\"", dst);
1288	}
1289
1290	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1291		error("mkdir %s: %s", dst, strerror(errno));
1292		return -1;
1293	}
1294
1295	if (do_readdir(conn, src, &dir_entries) == -1) {
1296		error("%s: Failed to get directory contents", src);
1297		return -1;
1298	}
1299
1300	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1301		filename = dir_entries[i]->filename;
1302
1303		new_dst = path_append(dst, filename);
1304		new_src = path_append(src, filename);
1305
1306		if (S_ISDIR(dir_entries[i]->a.perm)) {
1307			if (strcmp(filename, ".") == 0 ||
1308			    strcmp(filename, "..") == 0)
1309				continue;
1310			if (download_dir_internal(conn, new_src, new_dst,
1311			    &(dir_entries[i]->a), pflag, printflag,
1312			    depth + 1, resume) == -1)
1313				ret = -1;
1314		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1315			if (do_download(conn, new_src, new_dst,
1316			    &(dir_entries[i]->a), pflag, resume) == -1) {
1317				error("Download of file %s to %s failed",
1318				    new_src, new_dst);
1319				ret = -1;
1320			}
1321		} else
1322			logit("%s: not a regular file\n", new_src);
1323
1324		free(new_dst);
1325		free(new_src);
1326	}
1327
1328	if (pflag) {
1329		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1330			struct timeval tv[2];
1331			tv[0].tv_sec = dirattrib->atime;
1332			tv[1].tv_sec = dirattrib->mtime;
1333			tv[0].tv_usec = tv[1].tv_usec = 0;
1334			if (utimes(dst, tv) == -1)
1335				error("Can't set times on \"%s\": %s",
1336				    dst, strerror(errno));
1337		} else
1338			debug("Server did not send times for directory "
1339			    "\"%s\"", dst);
1340	}
1341
1342	free_sftp_dirents(dir_entries);
1343
1344	return ret;
1345}
1346
1347int
1348download_dir(struct sftp_conn *conn, char *src, char *dst,
1349    Attrib *dirattrib, int pflag, int printflag, int resume)
1350{
1351	char *src_canon;
1352	int ret;
1353
1354	if ((src_canon = do_realpath(conn, src)) == NULL) {
1355		error("Unable to canonicalise path \"%s\"", src);
1356		return -1;
1357	}
1358
1359	ret = download_dir_internal(conn, src_canon, dst,
1360	    dirattrib, pflag, printflag, 0, resume);
1361	free(src_canon);
1362	return ret;
1363}
1364
1365int
1366do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1367    int pflag)
1368{
1369	int local_fd;
1370	int status = SSH2_FX_OK;
1371	u_int handle_len, id, type;
1372	off_t offset, progress_counter;
1373	char *handle, *data;
1374	Buffer msg;
1375	struct stat sb;
1376	Attrib a;
1377	u_int32_t startid;
1378	u_int32_t ackid;
1379	struct outstanding_ack {
1380		u_int id;
1381		u_int len;
1382		off_t offset;
1383		TAILQ_ENTRY(outstanding_ack) tq;
1384	};
1385	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1386	struct outstanding_ack *ack = NULL;
1387
1388	TAILQ_INIT(&acks);
1389
1390	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1391		error("Couldn't open local file \"%s\" for reading: %s",
1392		    local_path, strerror(errno));
1393		return(-1);
1394	}
1395	if (fstat(local_fd, &sb) == -1) {
1396		error("Couldn't fstat local file \"%s\": %s",
1397		    local_path, strerror(errno));
1398		close(local_fd);
1399		return(-1);
1400	}
1401	if (!S_ISREG(sb.st_mode)) {
1402		error("%s is not a regular file", local_path);
1403		close(local_fd);
1404		return(-1);
1405	}
1406	stat_to_attrib(&sb, &a);
1407
1408	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1409	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1410	a.perm &= 0777;
1411	if (!pflag)
1412		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1413
1414	buffer_init(&msg);
1415
1416	/* Send open request */
1417	id = conn->msg_id++;
1418	buffer_put_char(&msg, SSH2_FXP_OPEN);
1419	buffer_put_int(&msg, id);
1420	buffer_put_cstring(&msg, remote_path);
1421	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1422	encode_attrib(&msg, &a);
1423	send_msg(conn, &msg);
1424	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1425
1426	buffer_clear(&msg);
1427
1428	handle = get_handle(conn, id, &handle_len,
1429	    "remote open(\"%s\")", remote_path);
1430	if (handle == NULL) {
1431		close(local_fd);
1432		buffer_free(&msg);
1433		return -1;
1434	}
1435
1436	startid = ackid = id + 1;
1437	data = xmalloc(conn->transfer_buflen);
1438
1439	/* Read from local and write to remote */
1440	offset = progress_counter = 0;
1441	if (showprogress)
1442		start_progress_meter(local_path, sb.st_size,
1443		    &progress_counter);
1444
1445	for (;;) {
1446		int len;
1447
1448		/*
1449		 * Can't use atomicio here because it returns 0 on EOF,
1450		 * thus losing the last block of the file.
1451		 * Simulate an EOF on interrupt, allowing ACKs from the
1452		 * server to drain.
1453		 */
1454		if (interrupted || status != SSH2_FX_OK)
1455			len = 0;
1456		else do
1457			len = read(local_fd, data, conn->transfer_buflen);
1458		while ((len == -1) &&
1459		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
1460
1461		if (len == -1)
1462			fatal("Couldn't read from \"%s\": %s", local_path,
1463			    strerror(errno));
1464
1465		if (len != 0) {
1466			ack = xcalloc(1, sizeof(*ack));
1467			ack->id = ++id;
1468			ack->offset = offset;
1469			ack->len = len;
1470			TAILQ_INSERT_TAIL(&acks, ack, tq);
1471
1472			buffer_clear(&msg);
1473			buffer_put_char(&msg, SSH2_FXP_WRITE);
1474			buffer_put_int(&msg, ack->id);
1475			buffer_put_string(&msg, handle, handle_len);
1476			buffer_put_int64(&msg, offset);
1477			buffer_put_string(&msg, data, len);
1478			send_msg(conn, &msg);
1479			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1480			    id, (unsigned long long)offset, len);
1481		} else if (TAILQ_FIRST(&acks) == NULL)
1482			break;
1483
1484		if (ack == NULL)
1485			fatal("Unexpected ACK %u", id);
1486
1487		if (id == startid || len == 0 ||
1488		    id - ackid >= conn->num_requests) {
1489			u_int r_id;
1490
1491			buffer_clear(&msg);
1492			get_msg(conn, &msg);
1493			type = buffer_get_char(&msg);
1494			r_id = buffer_get_int(&msg);
1495
1496			if (type != SSH2_FXP_STATUS)
1497				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1498				    "got %d", SSH2_FXP_STATUS, type);
1499
1500			status = buffer_get_int(&msg);
1501			debug3("SSH2_FXP_STATUS %d", status);
1502
1503			/* Find the request in our queue */
1504			for (ack = TAILQ_FIRST(&acks);
1505			    ack != NULL && ack->id != r_id;
1506			    ack = TAILQ_NEXT(ack, tq))
1507				;
1508			if (ack == NULL)
1509				fatal("Can't find request for ID %u", r_id);
1510			TAILQ_REMOVE(&acks, ack, tq);
1511			debug3("In write loop, ack for %u %u bytes at %lld",
1512			    ack->id, ack->len, (long long)ack->offset);
1513			++ackid;
1514			progress_counter += ack->len;
1515			free(ack);
1516		}
1517		offset += len;
1518		if (offset < 0)
1519			fatal("%s: offset < 0", __func__);
1520	}
1521	buffer_free(&msg);
1522
1523	if (showprogress)
1524		stop_progress_meter();
1525	free(data);
1526
1527	if (status != SSH2_FX_OK) {
1528		error("Couldn't write to remote file \"%s\": %s",
1529		    remote_path, fx2txt(status));
1530		status = -1;
1531	}
1532
1533	if (close(local_fd) == -1) {
1534		error("Couldn't close local file \"%s\": %s", local_path,
1535		    strerror(errno));
1536		status = -1;
1537	}
1538
1539	/* Override umask and utimes if asked */
1540	if (pflag)
1541		do_fsetstat(conn, handle, handle_len, &a);
1542
1543	if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1544		status = -1;
1545	free(handle);
1546
1547	return status;
1548}
1549
1550static int
1551upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1552    int pflag, int printflag, int depth)
1553{
1554	int ret = 0, status;
1555	DIR *dirp;
1556	struct dirent *dp;
1557	char *filename, *new_src, *new_dst;
1558	struct stat sb;
1559	Attrib a;
1560
1561	if (depth >= MAX_DIR_DEPTH) {
1562		error("Maximum directory depth exceeded: %d levels", depth);
1563		return -1;
1564	}
1565
1566	if (stat(src, &sb) == -1) {
1567		error("Couldn't stat directory \"%s\": %s",
1568		    src, strerror(errno));
1569		return -1;
1570	}
1571	if (!S_ISDIR(sb.st_mode)) {
1572		error("\"%s\" is not a directory", src);
1573		return -1;
1574	}
1575	if (printflag)
1576		printf("Entering %s\n", src);
1577
1578	attrib_clear(&a);
1579	stat_to_attrib(&sb, &a);
1580	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1581	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1582	a.perm &= 01777;
1583	if (!pflag)
1584		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1585
1586	status = do_mkdir(conn, dst, &a, 0);
1587	/*
1588	 * we lack a portable status for errno EEXIST,
1589	 * so if we get a SSH2_FX_FAILURE back we must check
1590	 * if it was created successfully.
1591	 */
1592	if (status != SSH2_FX_OK) {
1593		if (status != SSH2_FX_FAILURE)
1594			return -1;
1595		if (do_stat(conn, dst, 0) == NULL)
1596			return -1;
1597	}
1598
1599	if ((dirp = opendir(src)) == NULL) {
1600		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1601		return -1;
1602	}
1603
1604	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1605		if (dp->d_ino == 0)
1606			continue;
1607		filename = dp->d_name;
1608		new_dst = path_append(dst, filename);
1609		new_src = path_append(src, filename);
1610
1611		if (lstat(new_src, &sb) == -1) {
1612			logit("%s: lstat failed: %s", filename,
1613			    strerror(errno));
1614			ret = -1;
1615		} else if (S_ISDIR(sb.st_mode)) {
1616			if (strcmp(filename, ".") == 0 ||
1617			    strcmp(filename, "..") == 0)
1618				continue;
1619
1620			if (upload_dir_internal(conn, new_src, new_dst,
1621			    pflag, printflag, depth + 1) == -1)
1622				ret = -1;
1623		} else if (S_ISREG(sb.st_mode)) {
1624			if (do_upload(conn, new_src, new_dst, pflag) == -1) {
1625				error("Uploading of file %s to %s failed!",
1626				    new_src, new_dst);
1627				ret = -1;
1628			}
1629		} else
1630			logit("%s: not a regular file\n", filename);
1631		free(new_dst);
1632		free(new_src);
1633	}
1634
1635	do_setstat(conn, dst, &a);
1636
1637	(void) closedir(dirp);
1638	return ret;
1639}
1640
1641int
1642upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
1643    int pflag)
1644{
1645	char *dst_canon;
1646	int ret;
1647
1648	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1649		error("Unable to canonicalise path \"%s\"", dst);
1650		return -1;
1651	}
1652
1653	ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
1654	free(dst_canon);
1655	return ret;
1656}
1657
1658char *
1659path_append(char *p1, char *p2)
1660{
1661	char *ret;
1662	size_t len = strlen(p1) + strlen(p2) + 2;
1663
1664	ret = xmalloc(len);
1665	strlcpy(ret, p1, len);
1666	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1667		strlcat(ret, "/", len);
1668	strlcat(ret, p2, len);
1669
1670	return(ret);
1671}
1672
1673