sftp-client.c revision 221420
1/* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 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		xfree(name);
398		xfree(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	buffer_clear(&msg);
466
467	handle = get_handle(conn, id, &handle_len,
468	    "remote readdir(\"%s\")", path);
469	if (handle == NULL)
470		return -1;
471
472	if (dir) {
473		ents = 0;
474		*dir = xmalloc(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				xfree(handle);
513				return(status);
514			}
515		} else if (type != SSH2_FXP_NAME)
516			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
517			    SSH2_FXP_NAME, type);
518
519		count = buffer_get_int(&msg);
520		if (count == 0)
521			break;
522		debug3("Received %d SSH2_FXP_NAME responses", count);
523		for (i = 0; i < count; i++) {
524			char *filename, *longname;
525			Attrib *a;
526
527			filename = buffer_get_string(&msg, NULL);
528			longname = buffer_get_string(&msg, NULL);
529			a = decode_attrib(&msg);
530
531			if (printflag)
532				printf("%s\n", longname);
533
534			/*
535			 * Directory entries should never contain '/'
536			 * These can be used to attack recursive ops
537			 * (e.g. send '../../../../etc/passwd')
538			 */
539			if (strchr(filename, '/') != NULL) {
540				error("Server sent suspect path \"%s\" "
541				    "during readdir of \"%s\"", filename, path);
542				goto next;
543			}
544
545			if (dir) {
546				*dir = xrealloc(*dir, ents + 2, sizeof(**dir));
547				(*dir)[ents] = xmalloc(sizeof(***dir));
548				(*dir)[ents]->filename = xstrdup(filename);
549				(*dir)[ents]->longname = xstrdup(longname);
550				memcpy(&(*dir)[ents]->a, a, sizeof(*a));
551				(*dir)[++ents] = NULL;
552			}
553 next:
554			xfree(filename);
555			xfree(longname);
556		}
557	}
558
559	buffer_free(&msg);
560	do_close(conn, handle, handle_len);
561	xfree(handle);
562
563	/* Don't return partial matches on interrupt */
564	if (interrupted && dir != NULL && *dir != NULL) {
565		free_sftp_dirents(*dir);
566		*dir = xmalloc(sizeof(**dir));
567		**dir = NULL;
568	}
569
570	return 0;
571}
572
573int
574do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
575{
576	return(do_lsreaddir(conn, path, 0, dir));
577}
578
579void free_sftp_dirents(SFTP_DIRENT **s)
580{
581	int i;
582
583	for (i = 0; s[i]; i++) {
584		xfree(s[i]->filename);
585		xfree(s[i]->longname);
586		xfree(s[i]);
587	}
588	xfree(s);
589}
590
591int
592do_rm(struct sftp_conn *conn, char *path)
593{
594	u_int status, id;
595
596	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
597
598	id = conn->msg_id++;
599	send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
600	status = get_status(conn, id);
601	if (status != SSH2_FX_OK)
602		error("Couldn't delete file: %s", fx2txt(status));
603	return(status);
604}
605
606int
607do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag)
608{
609	u_int status, id;
610
611	id = conn->msg_id++;
612	send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
613	    strlen(path), a);
614
615	status = get_status(conn, id);
616	if (status != SSH2_FX_OK && printflag)
617		error("Couldn't create directory: %s", fx2txt(status));
618
619	return(status);
620}
621
622int
623do_rmdir(struct sftp_conn *conn, char *path)
624{
625	u_int status, id;
626
627	id = conn->msg_id++;
628	send_string_request(conn, id, SSH2_FXP_RMDIR, path,
629	    strlen(path));
630
631	status = get_status(conn, id);
632	if (status != SSH2_FX_OK)
633		error("Couldn't remove directory: %s", fx2txt(status));
634
635	return(status);
636}
637
638Attrib *
639do_stat(struct sftp_conn *conn, char *path, int quiet)
640{
641	u_int id;
642
643	id = conn->msg_id++;
644
645	send_string_request(conn, id,
646	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
647	    path, strlen(path));
648
649	return(get_decode_stat(conn, id, quiet));
650}
651
652Attrib *
653do_lstat(struct sftp_conn *conn, char *path, int quiet)
654{
655	u_int id;
656
657	if (conn->version == 0) {
658		if (quiet)
659			debug("Server version does not support lstat operation");
660		else
661			logit("Server version does not support lstat operation");
662		return(do_stat(conn, path, quiet));
663	}
664
665	id = conn->msg_id++;
666	send_string_request(conn, id, SSH2_FXP_LSTAT, path,
667	    strlen(path));
668
669	return(get_decode_stat(conn, id, quiet));
670}
671
672#ifdef notyet
673Attrib *
674do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
675{
676	u_int id;
677
678	id = conn->msg_id++;
679	send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
680	    handle_len);
681
682	return(get_decode_stat(conn, id, quiet));
683}
684#endif
685
686int
687do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
688{
689	u_int status, id;
690
691	id = conn->msg_id++;
692	send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
693	    strlen(path), a);
694
695	status = get_status(conn, id);
696	if (status != SSH2_FX_OK)
697		error("Couldn't setstat on \"%s\": %s", path,
698		    fx2txt(status));
699
700	return(status);
701}
702
703int
704do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
705    Attrib *a)
706{
707	u_int status, id;
708
709	id = conn->msg_id++;
710	send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
711	    handle_len, a);
712
713	status = get_status(conn, id);
714	if (status != SSH2_FX_OK)
715		error("Couldn't fsetstat: %s", fx2txt(status));
716
717	return(status);
718}
719
720char *
721do_realpath(struct sftp_conn *conn, char *path)
722{
723	Buffer msg;
724	u_int type, expected_id, count, id;
725	char *filename, *longname;
726	Attrib *a;
727
728	expected_id = id = conn->msg_id++;
729	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
730	    strlen(path));
731
732	buffer_init(&msg);
733
734	get_msg(conn, &msg);
735	type = buffer_get_char(&msg);
736	id = buffer_get_int(&msg);
737
738	if (id != expected_id)
739		fatal("ID mismatch (%u != %u)", id, expected_id);
740
741	if (type == SSH2_FXP_STATUS) {
742		u_int status = buffer_get_int(&msg);
743
744		error("Couldn't canonicalise: %s", fx2txt(status));
745		buffer_free(&msg);
746		return NULL;
747	} else if (type != SSH2_FXP_NAME)
748		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
749		    SSH2_FXP_NAME, type);
750
751	count = buffer_get_int(&msg);
752	if (count != 1)
753		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
754
755	filename = buffer_get_string(&msg, NULL);
756	longname = buffer_get_string(&msg, NULL);
757	a = decode_attrib(&msg);
758
759	debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
760
761	xfree(longname);
762
763	buffer_free(&msg);
764
765	return(filename);
766}
767
768int
769do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
770{
771	Buffer msg;
772	u_int status, id;
773
774	buffer_init(&msg);
775
776	/* Send rename request */
777	id = conn->msg_id++;
778	if ((conn->exts & SFTP_EXT_POSIX_RENAME)) {
779		buffer_put_char(&msg, SSH2_FXP_EXTENDED);
780		buffer_put_int(&msg, id);
781		buffer_put_cstring(&msg, "posix-rename@openssh.com");
782	} else {
783		buffer_put_char(&msg, SSH2_FXP_RENAME);
784		buffer_put_int(&msg, id);
785	}
786	buffer_put_cstring(&msg, oldpath);
787	buffer_put_cstring(&msg, newpath);
788	send_msg(conn, &msg);
789	debug3("Sent message %s \"%s\" -> \"%s\"",
790	    (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" :
791	    "SSH2_FXP_RENAME", oldpath, newpath);
792	buffer_free(&msg);
793
794	status = get_status(conn, id);
795	if (status != SSH2_FX_OK)
796		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
797		    newpath, fx2txt(status));
798
799	return(status);
800}
801
802int
803do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
804{
805	Buffer msg;
806	u_int status, id;
807
808	buffer_init(&msg);
809
810	/* Send link request */
811	id = conn->msg_id++;
812	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
813		error("Server does not support hardlink@openssh.com extension");
814		return -1;
815	}
816
817	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
818	buffer_put_int(&msg, id);
819	buffer_put_cstring(&msg, "hardlink@openssh.com");
820	buffer_put_cstring(&msg, oldpath);
821	buffer_put_cstring(&msg, newpath);
822	send_msg(conn, &msg);
823	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
824	       oldpath, newpath);
825	buffer_free(&msg);
826
827	status = get_status(conn, id);
828	if (status != SSH2_FX_OK)
829		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
830		    newpath, fx2txt(status));
831
832	return(status);
833}
834
835int
836do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
837{
838	Buffer msg;
839	u_int status, id;
840
841	if (conn->version < 3) {
842		error("This server does not support the symlink operation");
843		return(SSH2_FX_OP_UNSUPPORTED);
844	}
845
846	buffer_init(&msg);
847
848	/* Send symlink request */
849	id = conn->msg_id++;
850	buffer_put_char(&msg, SSH2_FXP_SYMLINK);
851	buffer_put_int(&msg, id);
852	buffer_put_cstring(&msg, oldpath);
853	buffer_put_cstring(&msg, newpath);
854	send_msg(conn, &msg);
855	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
856	    newpath);
857	buffer_free(&msg);
858
859	status = get_status(conn, id);
860	if (status != SSH2_FX_OK)
861		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
862		    newpath, fx2txt(status));
863
864	return(status);
865}
866
867#ifdef notyet
868char *
869do_readlink(struct sftp_conn *conn, char *path)
870{
871	Buffer msg;
872	u_int type, expected_id, count, id;
873	char *filename, *longname;
874	Attrib *a;
875
876	expected_id = id = conn->msg_id++;
877	send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
878
879	buffer_init(&msg);
880
881	get_msg(conn, &msg);
882	type = buffer_get_char(&msg);
883	id = buffer_get_int(&msg);
884
885	if (id != expected_id)
886		fatal("ID mismatch (%u != %u)", id, expected_id);
887
888	if (type == SSH2_FXP_STATUS) {
889		u_int status = buffer_get_int(&msg);
890
891		error("Couldn't readlink: %s", fx2txt(status));
892		return(NULL);
893	} else if (type != SSH2_FXP_NAME)
894		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
895		    SSH2_FXP_NAME, type);
896
897	count = buffer_get_int(&msg);
898	if (count != 1)
899		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
900
901	filename = buffer_get_string(&msg, NULL);
902	longname = buffer_get_string(&msg, NULL);
903	a = decode_attrib(&msg);
904
905	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
906
907	xfree(longname);
908
909	buffer_free(&msg);
910
911	return(filename);
912}
913#endif
914
915int
916do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
917    int quiet)
918{
919	Buffer msg;
920	u_int id;
921
922	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
923		error("Server does not support statvfs@openssh.com extension");
924		return -1;
925	}
926
927	id = conn->msg_id++;
928
929	buffer_init(&msg);
930	buffer_clear(&msg);
931	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
932	buffer_put_int(&msg, id);
933	buffer_put_cstring(&msg, "statvfs@openssh.com");
934	buffer_put_cstring(&msg, path);
935	send_msg(conn, &msg);
936	buffer_free(&msg);
937
938	return get_decode_statvfs(conn, st, id, quiet);
939}
940
941#ifdef notyet
942int
943do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
944    struct sftp_statvfs *st, int quiet)
945{
946	Buffer msg;
947	u_int id;
948
949	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
950		error("Server does not support fstatvfs@openssh.com extension");
951		return -1;
952	}
953
954	id = conn->msg_id++;
955
956	buffer_init(&msg);
957	buffer_clear(&msg);
958	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
959	buffer_put_int(&msg, id);
960	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
961	buffer_put_string(&msg, handle, handle_len);
962	send_msg(conn, &msg);
963	buffer_free(&msg);
964
965	return get_decode_statvfs(conn, st, id, quiet);
966}
967#endif
968
969static void
970send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
971    u_int len, char *handle, u_int handle_len)
972{
973	Buffer msg;
974
975	buffer_init(&msg);
976	buffer_clear(&msg);
977	buffer_put_char(&msg, SSH2_FXP_READ);
978	buffer_put_int(&msg, id);
979	buffer_put_string(&msg, handle, handle_len);
980	buffer_put_int64(&msg, offset);
981	buffer_put_int(&msg, len);
982	send_msg(conn, &msg);
983	buffer_free(&msg);
984}
985
986int
987do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
988    Attrib *a, int pflag)
989{
990	Attrib junk;
991	Buffer msg;
992	char *handle;
993	int local_fd, status = 0, write_error;
994	int read_error, write_errno;
995	u_int64_t offset, size;
996	u_int handle_len, mode, type, id, buflen, num_req, max_req;
997	off_t progress_counter;
998	struct request {
999		u_int id;
1000		u_int len;
1001		u_int64_t offset;
1002		TAILQ_ENTRY(request) tq;
1003	};
1004	TAILQ_HEAD(reqhead, request) requests;
1005	struct request *req;
1006
1007	TAILQ_INIT(&requests);
1008
1009	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1010		return -1;
1011
1012	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1013	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1014		mode = a->perm & 0777;
1015	else
1016		mode = 0666;
1017
1018	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1019	    (!S_ISREG(a->perm))) {
1020		error("Cannot download non-regular file: %s", remote_path);
1021		return(-1);
1022	}
1023
1024	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1025		size = a->size;
1026	else
1027		size = 0;
1028
1029	buflen = conn->transfer_buflen;
1030	buffer_init(&msg);
1031
1032	/* Send open request */
1033	id = conn->msg_id++;
1034	buffer_put_char(&msg, SSH2_FXP_OPEN);
1035	buffer_put_int(&msg, id);
1036	buffer_put_cstring(&msg, remote_path);
1037	buffer_put_int(&msg, SSH2_FXF_READ);
1038	attrib_clear(&junk); /* Send empty attributes */
1039	encode_attrib(&msg, &junk);
1040	send_msg(conn, &msg);
1041	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1042
1043	handle = get_handle(conn, id, &handle_len,
1044	    "remote open(\"%s\")", remote_path);
1045	if (handle == NULL) {
1046		buffer_free(&msg);
1047		return(-1);
1048	}
1049
1050	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
1051	    mode | S_IWRITE);
1052	if (local_fd == -1) {
1053		error("Couldn't open local file \"%s\" for writing: %s",
1054		    local_path, strerror(errno));
1055		do_close(conn, handle, handle_len);
1056		buffer_free(&msg);
1057		xfree(handle);
1058		return(-1);
1059	}
1060
1061	/* Read from remote and write to local */
1062	write_error = read_error = write_errno = num_req = offset = 0;
1063	max_req = 1;
1064	progress_counter = 0;
1065
1066	if (showprogress && size != 0)
1067		start_progress_meter(remote_path, size, &progress_counter);
1068
1069	while (num_req > 0 || max_req > 0) {
1070		char *data;
1071		u_int len;
1072
1073		/*
1074		 * Simulate EOF on interrupt: stop sending new requests and
1075		 * allow outstanding requests to drain gracefully
1076		 */
1077		if (interrupted) {
1078			if (num_req == 0) /* If we haven't started yet... */
1079				break;
1080			max_req = 0;
1081		}
1082
1083		/* Send some more requests */
1084		while (num_req < max_req) {
1085			debug3("Request range %llu -> %llu (%d/%d)",
1086			    (unsigned long long)offset,
1087			    (unsigned long long)offset + buflen - 1,
1088			    num_req, max_req);
1089			req = xmalloc(sizeof(*req));
1090			req->id = conn->msg_id++;
1091			req->len = buflen;
1092			req->offset = offset;
1093			offset += buflen;
1094			num_req++;
1095			TAILQ_INSERT_TAIL(&requests, req, tq);
1096			send_read_request(conn, req->id, req->offset,
1097			    req->len, handle, handle_len);
1098		}
1099
1100		buffer_clear(&msg);
1101		get_msg(conn, &msg);
1102		type = buffer_get_char(&msg);
1103		id = buffer_get_int(&msg);
1104		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1105
1106		/* Find the request in our queue */
1107		for (req = TAILQ_FIRST(&requests);
1108		    req != NULL && req->id != id;
1109		    req = TAILQ_NEXT(req, tq))
1110			;
1111		if (req == NULL)
1112			fatal("Unexpected reply %u", id);
1113
1114		switch (type) {
1115		case SSH2_FXP_STATUS:
1116			status = buffer_get_int(&msg);
1117			if (status != SSH2_FX_EOF)
1118				read_error = 1;
1119			max_req = 0;
1120			TAILQ_REMOVE(&requests, req, tq);
1121			xfree(req);
1122			num_req--;
1123			break;
1124		case SSH2_FXP_DATA:
1125			data = buffer_get_string(&msg, &len);
1126			debug3("Received data %llu -> %llu",
1127			    (unsigned long long)req->offset,
1128			    (unsigned long long)req->offset + len - 1);
1129			if (len > req->len)
1130				fatal("Received more data than asked for "
1131				    "%u > %u", len, req->len);
1132			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1133			    atomicio(vwrite, local_fd, data, len) != len) &&
1134			    !write_error) {
1135				write_errno = errno;
1136				write_error = 1;
1137				max_req = 0;
1138			}
1139			progress_counter += len;
1140			xfree(data);
1141
1142			if (len == req->len) {
1143				TAILQ_REMOVE(&requests, req, tq);
1144				xfree(req);
1145				num_req--;
1146			} else {
1147				/* Resend the request for the missing data */
1148				debug3("Short data block, re-requesting "
1149				    "%llu -> %llu (%2d)",
1150				    (unsigned long long)req->offset + len,
1151				    (unsigned long long)req->offset +
1152				    req->len - 1, num_req);
1153				req->id = conn->msg_id++;
1154				req->len -= len;
1155				req->offset += len;
1156				send_read_request(conn, req->id,
1157				    req->offset, req->len, handle, handle_len);
1158				/* Reduce the request size */
1159				if (len < buflen)
1160					buflen = MAX(MIN_READ_SIZE, len);
1161			}
1162			if (max_req > 0) { /* max_req = 0 iff EOF received */
1163				if (size > 0 && offset > size) {
1164					/* Only one request at a time
1165					 * after the expected EOF */
1166					debug3("Finish at %llu (%2d)",
1167					    (unsigned long long)offset,
1168					    num_req);
1169					max_req = 1;
1170				} else if (max_req <= conn->num_requests) {
1171					++max_req;
1172				}
1173			}
1174			break;
1175		default:
1176			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1177			    SSH2_FXP_DATA, type);
1178		}
1179	}
1180
1181	if (showprogress && size)
1182		stop_progress_meter();
1183
1184	/* Sanity check */
1185	if (TAILQ_FIRST(&requests) != NULL)
1186		fatal("Transfer complete, but requests still in queue");
1187
1188	if (read_error) {
1189		error("Couldn't read from remote file \"%s\" : %s",
1190		    remote_path, fx2txt(status));
1191		do_close(conn, handle, handle_len);
1192	} else if (write_error) {
1193		error("Couldn't write to \"%s\": %s", local_path,
1194		    strerror(write_errno));
1195		status = -1;
1196		do_close(conn, handle, handle_len);
1197	} else {
1198		status = do_close(conn, handle, handle_len);
1199
1200		/* Override umask and utimes if asked */
1201#ifdef HAVE_FCHMOD
1202		if (pflag && fchmod(local_fd, mode) == -1)
1203#else
1204		if (pflag && chmod(local_path, mode) == -1)
1205#endif /* HAVE_FCHMOD */
1206			error("Couldn't set mode on \"%s\": %s", local_path,
1207			    strerror(errno));
1208		if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1209			struct timeval tv[2];
1210			tv[0].tv_sec = a->atime;
1211			tv[1].tv_sec = a->mtime;
1212			tv[0].tv_usec = tv[1].tv_usec = 0;
1213			if (utimes(local_path, tv) == -1)
1214				error("Can't set times on \"%s\": %s",
1215				    local_path, strerror(errno));
1216		}
1217	}
1218	close(local_fd);
1219	buffer_free(&msg);
1220	xfree(handle);
1221
1222	return(status);
1223}
1224
1225static int
1226download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1227    Attrib *dirattrib, int pflag, int printflag, int depth)
1228{
1229	int i, ret = 0;
1230	SFTP_DIRENT **dir_entries;
1231	char *filename, *new_src, *new_dst;
1232	mode_t mode = 0777;
1233
1234	if (depth >= MAX_DIR_DEPTH) {
1235		error("Maximum directory depth exceeded: %d levels", depth);
1236		return -1;
1237	}
1238
1239	if (dirattrib == NULL &&
1240	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1241		error("Unable to stat remote directory \"%s\"", src);
1242		return -1;
1243	}
1244	if (!S_ISDIR(dirattrib->perm)) {
1245		error("\"%s\" is not a directory", src);
1246		return -1;
1247	}
1248	if (printflag)
1249		printf("Retrieving %s\n", src);
1250
1251	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1252		mode = dirattrib->perm & 01777;
1253	else {
1254		debug("Server did not send permissions for "
1255		    "directory \"%s\"", dst);
1256	}
1257
1258	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1259		error("mkdir %s: %s", dst, strerror(errno));
1260		return -1;
1261	}
1262
1263	if (do_readdir(conn, src, &dir_entries) == -1) {
1264		error("%s: Failed to get directory contents", src);
1265		return -1;
1266	}
1267
1268	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1269		filename = dir_entries[i]->filename;
1270
1271		new_dst = path_append(dst, filename);
1272		new_src = path_append(src, filename);
1273
1274		if (S_ISDIR(dir_entries[i]->a.perm)) {
1275			if (strcmp(filename, ".") == 0 ||
1276			    strcmp(filename, "..") == 0)
1277				continue;
1278			if (download_dir_internal(conn, new_src, new_dst,
1279			    &(dir_entries[i]->a), pflag, printflag,
1280			    depth + 1) == -1)
1281				ret = -1;
1282		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1283			if (do_download(conn, new_src, new_dst,
1284			    &(dir_entries[i]->a), pflag) == -1) {
1285				error("Download of file %s to %s failed",
1286				    new_src, new_dst);
1287				ret = -1;
1288			}
1289		} else
1290			logit("%s: not a regular file\n", new_src);
1291
1292		xfree(new_dst);
1293		xfree(new_src);
1294	}
1295
1296	if (pflag) {
1297		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1298			struct timeval tv[2];
1299			tv[0].tv_sec = dirattrib->atime;
1300			tv[1].tv_sec = dirattrib->mtime;
1301			tv[0].tv_usec = tv[1].tv_usec = 0;
1302			if (utimes(dst, tv) == -1)
1303				error("Can't set times on \"%s\": %s",
1304				    dst, strerror(errno));
1305		} else
1306			debug("Server did not send times for directory "
1307			    "\"%s\"", dst);
1308	}
1309
1310	free_sftp_dirents(dir_entries);
1311
1312	return ret;
1313}
1314
1315int
1316download_dir(struct sftp_conn *conn, char *src, char *dst,
1317    Attrib *dirattrib, int pflag, int printflag)
1318{
1319	char *src_canon;
1320	int ret;
1321
1322	if ((src_canon = do_realpath(conn, src)) == NULL) {
1323		error("Unable to canonicalise path \"%s\"", src);
1324		return -1;
1325	}
1326
1327	ret = download_dir_internal(conn, src_canon, dst,
1328	    dirattrib, pflag, printflag, 0);
1329	xfree(src_canon);
1330	return ret;
1331}
1332
1333int
1334do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1335    int pflag)
1336{
1337	int local_fd;
1338	int status = SSH2_FX_OK;
1339	u_int handle_len, id, type;
1340	off_t offset;
1341	char *handle, *data;
1342	Buffer msg;
1343	struct stat sb;
1344	Attrib a;
1345	u_int32_t startid;
1346	u_int32_t ackid;
1347	struct outstanding_ack {
1348		u_int id;
1349		u_int len;
1350		off_t offset;
1351		TAILQ_ENTRY(outstanding_ack) tq;
1352	};
1353	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1354	struct outstanding_ack *ack = NULL;
1355
1356	TAILQ_INIT(&acks);
1357
1358	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1359		error("Couldn't open local file \"%s\" for reading: %s",
1360		    local_path, strerror(errno));
1361		return(-1);
1362	}
1363	if (fstat(local_fd, &sb) == -1) {
1364		error("Couldn't fstat local file \"%s\": %s",
1365		    local_path, strerror(errno));
1366		close(local_fd);
1367		return(-1);
1368	}
1369	if (!S_ISREG(sb.st_mode)) {
1370		error("%s is not a regular file", local_path);
1371		close(local_fd);
1372		return(-1);
1373	}
1374	stat_to_attrib(&sb, &a);
1375
1376	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1377	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1378	a.perm &= 0777;
1379	if (!pflag)
1380		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1381
1382	buffer_init(&msg);
1383
1384	/* Send open request */
1385	id = conn->msg_id++;
1386	buffer_put_char(&msg, SSH2_FXP_OPEN);
1387	buffer_put_int(&msg, id);
1388	buffer_put_cstring(&msg, remote_path);
1389	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1390	encode_attrib(&msg, &a);
1391	send_msg(conn, &msg);
1392	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1393
1394	buffer_clear(&msg);
1395
1396	handle = get_handle(conn, id, &handle_len,
1397	    "remote open(\"%s\")", remote_path);
1398	if (handle == NULL) {
1399		close(local_fd);
1400		buffer_free(&msg);
1401		return -1;
1402	}
1403
1404	startid = ackid = id + 1;
1405	data = xmalloc(conn->transfer_buflen);
1406
1407	/* Read from local and write to remote */
1408	offset = 0;
1409	if (showprogress)
1410		start_progress_meter(local_path, sb.st_size, &offset);
1411
1412	for (;;) {
1413		int len;
1414
1415		/*
1416		 * Can't use atomicio here because it returns 0 on EOF,
1417		 * thus losing the last block of the file.
1418		 * Simulate an EOF on interrupt, allowing ACKs from the
1419		 * server to drain.
1420		 */
1421		if (interrupted || status != SSH2_FX_OK)
1422			len = 0;
1423		else do
1424			len = read(local_fd, data, conn->transfer_buflen);
1425		while ((len == -1) &&
1426		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
1427
1428		if (len == -1)
1429			fatal("Couldn't read from \"%s\": %s", local_path,
1430			    strerror(errno));
1431
1432		if (len != 0) {
1433			ack = xmalloc(sizeof(*ack));
1434			ack->id = ++id;
1435			ack->offset = offset;
1436			ack->len = len;
1437			TAILQ_INSERT_TAIL(&acks, ack, tq);
1438
1439			buffer_clear(&msg);
1440			buffer_put_char(&msg, SSH2_FXP_WRITE);
1441			buffer_put_int(&msg, ack->id);
1442			buffer_put_string(&msg, handle, handle_len);
1443			buffer_put_int64(&msg, offset);
1444			buffer_put_string(&msg, data, len);
1445			send_msg(conn, &msg);
1446			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1447			    id, (unsigned long long)offset, len);
1448		} else if (TAILQ_FIRST(&acks) == NULL)
1449			break;
1450
1451		if (ack == NULL)
1452			fatal("Unexpected ACK %u", id);
1453
1454		if (id == startid || len == 0 ||
1455		    id - ackid >= conn->num_requests) {
1456			u_int r_id;
1457
1458			buffer_clear(&msg);
1459			get_msg(conn, &msg);
1460			type = buffer_get_char(&msg);
1461			r_id = buffer_get_int(&msg);
1462
1463			if (type != SSH2_FXP_STATUS)
1464				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1465				    "got %d", SSH2_FXP_STATUS, type);
1466
1467			status = buffer_get_int(&msg);
1468			debug3("SSH2_FXP_STATUS %d", status);
1469
1470			/* Find the request in our queue */
1471			for (ack = TAILQ_FIRST(&acks);
1472			    ack != NULL && ack->id != r_id;
1473			    ack = TAILQ_NEXT(ack, tq))
1474				;
1475			if (ack == NULL)
1476				fatal("Can't find request for ID %u", r_id);
1477			TAILQ_REMOVE(&acks, ack, tq);
1478			debug3("In write loop, ack for %u %u bytes at %lld",
1479			    ack->id, ack->len, (long long)ack->offset);
1480			++ackid;
1481			xfree(ack);
1482		}
1483		offset += len;
1484		if (offset < 0)
1485			fatal("%s: offset < 0", __func__);
1486	}
1487	buffer_free(&msg);
1488
1489	if (showprogress)
1490		stop_progress_meter();
1491	xfree(data);
1492
1493	if (status != SSH2_FX_OK) {
1494		error("Couldn't write to remote file \"%s\": %s",
1495		    remote_path, fx2txt(status));
1496		status = -1;
1497	}
1498
1499	if (close(local_fd) == -1) {
1500		error("Couldn't close local file \"%s\": %s", local_path,
1501		    strerror(errno));
1502		status = -1;
1503	}
1504
1505	/* Override umask and utimes if asked */
1506	if (pflag)
1507		do_fsetstat(conn, handle, handle_len, &a);
1508
1509	if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1510		status = -1;
1511	xfree(handle);
1512
1513	return status;
1514}
1515
1516static int
1517upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1518    int pflag, int printflag, int depth)
1519{
1520	int ret = 0, status;
1521	DIR *dirp;
1522	struct dirent *dp;
1523	char *filename, *new_src, *new_dst;
1524	struct stat sb;
1525	Attrib a;
1526
1527	if (depth >= MAX_DIR_DEPTH) {
1528		error("Maximum directory depth exceeded: %d levels", depth);
1529		return -1;
1530	}
1531
1532	if (stat(src, &sb) == -1) {
1533		error("Couldn't stat directory \"%s\": %s",
1534		    src, strerror(errno));
1535		return -1;
1536	}
1537	if (!S_ISDIR(sb.st_mode)) {
1538		error("\"%s\" is not a directory", src);
1539		return -1;
1540	}
1541	if (printflag)
1542		printf("Entering %s\n", src);
1543
1544	attrib_clear(&a);
1545	stat_to_attrib(&sb, &a);
1546	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1547	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1548	a.perm &= 01777;
1549	if (!pflag)
1550		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1551
1552	status = do_mkdir(conn, dst, &a, 0);
1553	/*
1554	 * we lack a portable status for errno EEXIST,
1555	 * so if we get a SSH2_FX_FAILURE back we must check
1556	 * if it was created successfully.
1557	 */
1558	if (status != SSH2_FX_OK) {
1559		if (status != SSH2_FX_FAILURE)
1560			return -1;
1561		if (do_stat(conn, dst, 0) == NULL)
1562			return -1;
1563	}
1564
1565	if ((dirp = opendir(src)) == NULL) {
1566		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1567		return -1;
1568	}
1569
1570	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1571		if (dp->d_ino == 0)
1572			continue;
1573		filename = dp->d_name;
1574		new_dst = path_append(dst, filename);
1575		new_src = path_append(src, filename);
1576
1577		if (lstat(new_src, &sb) == -1) {
1578			logit("%s: lstat failed: %s", filename,
1579			    strerror(errno));
1580			ret = -1;
1581		} else if (S_ISDIR(sb.st_mode)) {
1582			if (strcmp(filename, ".") == 0 ||
1583			    strcmp(filename, "..") == 0)
1584				continue;
1585
1586			if (upload_dir_internal(conn, new_src, new_dst,
1587			    pflag, printflag, depth + 1) == -1)
1588				ret = -1;
1589		} else if (S_ISREG(sb.st_mode)) {
1590			if (do_upload(conn, new_src, new_dst, pflag) == -1) {
1591				error("Uploading of file %s to %s failed!",
1592				    new_src, new_dst);
1593				ret = -1;
1594			}
1595		} else
1596			logit("%s: not a regular file\n", filename);
1597		xfree(new_dst);
1598		xfree(new_src);
1599	}
1600
1601	do_setstat(conn, dst, &a);
1602
1603	(void) closedir(dirp);
1604	return ret;
1605}
1606
1607int
1608upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
1609    int pflag)
1610{
1611	char *dst_canon;
1612	int ret;
1613
1614	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1615		error("Unable to canonicalise path \"%s\"", dst);
1616		return -1;
1617	}
1618
1619	ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
1620	xfree(dst_canon);
1621	return ret;
1622}
1623
1624char *
1625path_append(char *p1, char *p2)
1626{
1627	char *ret;
1628	size_t len = strlen(p1) + strlen(p2) + 2;
1629
1630	ret = xmalloc(len);
1631	strlcpy(ret, p1, len);
1632	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1633		strlcat(ret, "/", len);
1634	strlcat(ret, p2, len);
1635
1636	return(ret);
1637}
1638
1639