sftp-client.c revision 240075
1/* $OpenBSD: sftp-client.c,v 1.97 2012/07/02 12:13:26 dtucker 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	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 = 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				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] = xmalloc(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			xfree(filename);
556			xfree(longname);
557		}
558	}
559
560	buffer_free(&msg);
561	do_close(conn, handle, handle_len);
562	xfree(handle);
563
564	/* Don't return partial matches on interrupt */
565	if (interrupted && dir != NULL && *dir != NULL) {
566		free_sftp_dirents(*dir);
567		*dir = xmalloc(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		xfree(s[i]->filename);
586		xfree(s[i]->longname);
587		xfree(s[i]);
588	}
589	xfree(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	xfree(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	xfree(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)
992{
993	Attrib junk;
994	Buffer msg;
995	char *handle;
996	int local_fd, status = 0, write_error;
997	int read_error, write_errno;
998	u_int64_t offset, size;
999	u_int handle_len, mode, type, id, buflen, num_req, max_req;
1000	off_t progress_counter;
1001	struct request {
1002		u_int id;
1003		u_int len;
1004		u_int64_t offset;
1005		TAILQ_ENTRY(request) tq;
1006	};
1007	TAILQ_HEAD(reqhead, request) requests;
1008	struct request *req;
1009
1010	TAILQ_INIT(&requests);
1011
1012	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1013		return -1;
1014
1015	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1016	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1017		mode = a->perm & 0777;
1018	else
1019		mode = 0666;
1020
1021	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1022	    (!S_ISREG(a->perm))) {
1023		error("Cannot download non-regular file: %s", remote_path);
1024		return(-1);
1025	}
1026
1027	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1028		size = a->size;
1029	else
1030		size = 0;
1031
1032	buflen = conn->transfer_buflen;
1033	buffer_init(&msg);
1034
1035	/* Send open request */
1036	id = conn->msg_id++;
1037	buffer_put_char(&msg, SSH2_FXP_OPEN);
1038	buffer_put_int(&msg, id);
1039	buffer_put_cstring(&msg, remote_path);
1040	buffer_put_int(&msg, SSH2_FXF_READ);
1041	attrib_clear(&junk); /* Send empty attributes */
1042	encode_attrib(&msg, &junk);
1043	send_msg(conn, &msg);
1044	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1045
1046	handle = get_handle(conn, id, &handle_len,
1047	    "remote open(\"%s\")", remote_path);
1048	if (handle == NULL) {
1049		buffer_free(&msg);
1050		return(-1);
1051	}
1052
1053	local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
1054	    mode | S_IWRITE);
1055	if (local_fd == -1) {
1056		error("Couldn't open local file \"%s\" for writing: %s",
1057		    local_path, strerror(errno));
1058		do_close(conn, handle, handle_len);
1059		buffer_free(&msg);
1060		xfree(handle);
1061		return(-1);
1062	}
1063
1064	/* Read from remote and write to local */
1065	write_error = read_error = write_errno = num_req = offset = 0;
1066	max_req = 1;
1067	progress_counter = 0;
1068
1069	if (showprogress && size != 0)
1070		start_progress_meter(remote_path, size, &progress_counter);
1071
1072	while (num_req > 0 || max_req > 0) {
1073		char *data;
1074		u_int len;
1075
1076		/*
1077		 * Simulate EOF on interrupt: stop sending new requests and
1078		 * allow outstanding requests to drain gracefully
1079		 */
1080		if (interrupted) {
1081			if (num_req == 0) /* If we haven't started yet... */
1082				break;
1083			max_req = 0;
1084		}
1085
1086		/* Send some more requests */
1087		while (num_req < max_req) {
1088			debug3("Request range %llu -> %llu (%d/%d)",
1089			    (unsigned long long)offset,
1090			    (unsigned long long)offset + buflen - 1,
1091			    num_req, max_req);
1092			req = xmalloc(sizeof(*req));
1093			req->id = conn->msg_id++;
1094			req->len = buflen;
1095			req->offset = offset;
1096			offset += buflen;
1097			num_req++;
1098			TAILQ_INSERT_TAIL(&requests, req, tq);
1099			send_read_request(conn, req->id, req->offset,
1100			    req->len, handle, handle_len);
1101		}
1102
1103		buffer_clear(&msg);
1104		get_msg(conn, &msg);
1105		type = buffer_get_char(&msg);
1106		id = buffer_get_int(&msg);
1107		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1108
1109		/* Find the request in our queue */
1110		for (req = TAILQ_FIRST(&requests);
1111		    req != NULL && req->id != id;
1112		    req = TAILQ_NEXT(req, tq))
1113			;
1114		if (req == NULL)
1115			fatal("Unexpected reply %u", id);
1116
1117		switch (type) {
1118		case SSH2_FXP_STATUS:
1119			status = buffer_get_int(&msg);
1120			if (status != SSH2_FX_EOF)
1121				read_error = 1;
1122			max_req = 0;
1123			TAILQ_REMOVE(&requests, req, tq);
1124			xfree(req);
1125			num_req--;
1126			break;
1127		case SSH2_FXP_DATA:
1128			data = buffer_get_string(&msg, &len);
1129			debug3("Received data %llu -> %llu",
1130			    (unsigned long long)req->offset,
1131			    (unsigned long long)req->offset + len - 1);
1132			if (len > req->len)
1133				fatal("Received more data than asked for "
1134				    "%u > %u", len, req->len);
1135			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1136			    atomicio(vwrite, local_fd, data, len) != len) &&
1137			    !write_error) {
1138				write_errno = errno;
1139				write_error = 1;
1140				max_req = 0;
1141			}
1142			progress_counter += len;
1143			xfree(data);
1144
1145			if (len == req->len) {
1146				TAILQ_REMOVE(&requests, req, tq);
1147				xfree(req);
1148				num_req--;
1149			} else {
1150				/* Resend the request for the missing data */
1151				debug3("Short data block, re-requesting "
1152				    "%llu -> %llu (%2d)",
1153				    (unsigned long long)req->offset + len,
1154				    (unsigned long long)req->offset +
1155				    req->len - 1, num_req);
1156				req->id = conn->msg_id++;
1157				req->len -= len;
1158				req->offset += len;
1159				send_read_request(conn, req->id,
1160				    req->offset, req->len, handle, handle_len);
1161				/* Reduce the request size */
1162				if (len < buflen)
1163					buflen = MAX(MIN_READ_SIZE, len);
1164			}
1165			if (max_req > 0) { /* max_req = 0 iff EOF received */
1166				if (size > 0 && offset > size) {
1167					/* Only one request at a time
1168					 * after the expected EOF */
1169					debug3("Finish at %llu (%2d)",
1170					    (unsigned long long)offset,
1171					    num_req);
1172					max_req = 1;
1173				} else if (max_req <= conn->num_requests) {
1174					++max_req;
1175				}
1176			}
1177			break;
1178		default:
1179			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1180			    SSH2_FXP_DATA, type);
1181		}
1182	}
1183
1184	if (showprogress && size)
1185		stop_progress_meter();
1186
1187	/* Sanity check */
1188	if (TAILQ_FIRST(&requests) != NULL)
1189		fatal("Transfer complete, but requests still in queue");
1190
1191	if (read_error) {
1192		error("Couldn't read from remote file \"%s\" : %s",
1193		    remote_path, fx2txt(status));
1194		do_close(conn, handle, handle_len);
1195	} else if (write_error) {
1196		error("Couldn't write to \"%s\": %s", local_path,
1197		    strerror(write_errno));
1198		status = -1;
1199		do_close(conn, handle, handle_len);
1200	} else {
1201		status = do_close(conn, handle, handle_len);
1202
1203		/* Override umask and utimes if asked */
1204#ifdef HAVE_FCHMOD
1205		if (pflag && fchmod(local_fd, mode) == -1)
1206#else
1207		if (pflag && chmod(local_path, mode) == -1)
1208#endif /* HAVE_FCHMOD */
1209			error("Couldn't set mode on \"%s\": %s", local_path,
1210			    strerror(errno));
1211		if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1212			struct timeval tv[2];
1213			tv[0].tv_sec = a->atime;
1214			tv[1].tv_sec = a->mtime;
1215			tv[0].tv_usec = tv[1].tv_usec = 0;
1216			if (utimes(local_path, tv) == -1)
1217				error("Can't set times on \"%s\": %s",
1218				    local_path, strerror(errno));
1219		}
1220	}
1221	close(local_fd);
1222	buffer_free(&msg);
1223	xfree(handle);
1224
1225	return(status);
1226}
1227
1228static int
1229download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1230    Attrib *dirattrib, int pflag, int printflag, int depth)
1231{
1232	int i, ret = 0;
1233	SFTP_DIRENT **dir_entries;
1234	char *filename, *new_src, *new_dst;
1235	mode_t mode = 0777;
1236
1237	if (depth >= MAX_DIR_DEPTH) {
1238		error("Maximum directory depth exceeded: %d levels", depth);
1239		return -1;
1240	}
1241
1242	if (dirattrib == NULL &&
1243	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1244		error("Unable to stat remote directory \"%s\"", src);
1245		return -1;
1246	}
1247	if (!S_ISDIR(dirattrib->perm)) {
1248		error("\"%s\" is not a directory", src);
1249		return -1;
1250	}
1251	if (printflag)
1252		printf("Retrieving %s\n", src);
1253
1254	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1255		mode = dirattrib->perm & 01777;
1256	else {
1257		debug("Server did not send permissions for "
1258		    "directory \"%s\"", dst);
1259	}
1260
1261	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1262		error("mkdir %s: %s", dst, strerror(errno));
1263		return -1;
1264	}
1265
1266	if (do_readdir(conn, src, &dir_entries) == -1) {
1267		error("%s: Failed to get directory contents", src);
1268		return -1;
1269	}
1270
1271	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1272		filename = dir_entries[i]->filename;
1273
1274		new_dst = path_append(dst, filename);
1275		new_src = path_append(src, filename);
1276
1277		if (S_ISDIR(dir_entries[i]->a.perm)) {
1278			if (strcmp(filename, ".") == 0 ||
1279			    strcmp(filename, "..") == 0)
1280				continue;
1281			if (download_dir_internal(conn, new_src, new_dst,
1282			    &(dir_entries[i]->a), pflag, printflag,
1283			    depth + 1) == -1)
1284				ret = -1;
1285		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1286			if (do_download(conn, new_src, new_dst,
1287			    &(dir_entries[i]->a), pflag) == -1) {
1288				error("Download of file %s to %s failed",
1289				    new_src, new_dst);
1290				ret = -1;
1291			}
1292		} else
1293			logit("%s: not a regular file\n", new_src);
1294
1295		xfree(new_dst);
1296		xfree(new_src);
1297	}
1298
1299	if (pflag) {
1300		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1301			struct timeval tv[2];
1302			tv[0].tv_sec = dirattrib->atime;
1303			tv[1].tv_sec = dirattrib->mtime;
1304			tv[0].tv_usec = tv[1].tv_usec = 0;
1305			if (utimes(dst, tv) == -1)
1306				error("Can't set times on \"%s\": %s",
1307				    dst, strerror(errno));
1308		} else
1309			debug("Server did not send times for directory "
1310			    "\"%s\"", dst);
1311	}
1312
1313	free_sftp_dirents(dir_entries);
1314
1315	return ret;
1316}
1317
1318int
1319download_dir(struct sftp_conn *conn, char *src, char *dst,
1320    Attrib *dirattrib, int pflag, int printflag)
1321{
1322	char *src_canon;
1323	int ret;
1324
1325	if ((src_canon = do_realpath(conn, src)) == NULL) {
1326		error("Unable to canonicalise path \"%s\"", src);
1327		return -1;
1328	}
1329
1330	ret = download_dir_internal(conn, src_canon, dst,
1331	    dirattrib, pflag, printflag, 0);
1332	xfree(src_canon);
1333	return ret;
1334}
1335
1336int
1337do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1338    int pflag)
1339{
1340	int local_fd;
1341	int status = SSH2_FX_OK;
1342	u_int handle_len, id, type;
1343	off_t offset;
1344	char *handle, *data;
1345	Buffer msg;
1346	struct stat sb;
1347	Attrib a;
1348	u_int32_t startid;
1349	u_int32_t ackid;
1350	struct outstanding_ack {
1351		u_int id;
1352		u_int len;
1353		off_t offset;
1354		TAILQ_ENTRY(outstanding_ack) tq;
1355	};
1356	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1357	struct outstanding_ack *ack = NULL;
1358
1359	TAILQ_INIT(&acks);
1360
1361	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1362		error("Couldn't open local file \"%s\" for reading: %s",
1363		    local_path, strerror(errno));
1364		return(-1);
1365	}
1366	if (fstat(local_fd, &sb) == -1) {
1367		error("Couldn't fstat local file \"%s\": %s",
1368		    local_path, strerror(errno));
1369		close(local_fd);
1370		return(-1);
1371	}
1372	if (!S_ISREG(sb.st_mode)) {
1373		error("%s is not a regular file", local_path);
1374		close(local_fd);
1375		return(-1);
1376	}
1377	stat_to_attrib(&sb, &a);
1378
1379	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1380	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1381	a.perm &= 0777;
1382	if (!pflag)
1383		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1384
1385	buffer_init(&msg);
1386
1387	/* Send open request */
1388	id = conn->msg_id++;
1389	buffer_put_char(&msg, SSH2_FXP_OPEN);
1390	buffer_put_int(&msg, id);
1391	buffer_put_cstring(&msg, remote_path);
1392	buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1393	encode_attrib(&msg, &a);
1394	send_msg(conn, &msg);
1395	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1396
1397	buffer_clear(&msg);
1398
1399	handle = get_handle(conn, id, &handle_len,
1400	    "remote open(\"%s\")", remote_path);
1401	if (handle == NULL) {
1402		close(local_fd);
1403		buffer_free(&msg);
1404		return -1;
1405	}
1406
1407	startid = ackid = id + 1;
1408	data = xmalloc(conn->transfer_buflen);
1409
1410	/* Read from local and write to remote */
1411	offset = 0;
1412	if (showprogress)
1413		start_progress_meter(local_path, sb.st_size, &offset);
1414
1415	for (;;) {
1416		int len;
1417
1418		/*
1419		 * Can't use atomicio here because it returns 0 on EOF,
1420		 * thus losing the last block of the file.
1421		 * Simulate an EOF on interrupt, allowing ACKs from the
1422		 * server to drain.
1423		 */
1424		if (interrupted || status != SSH2_FX_OK)
1425			len = 0;
1426		else do
1427			len = read(local_fd, data, conn->transfer_buflen);
1428		while ((len == -1) &&
1429		    (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
1430
1431		if (len == -1)
1432			fatal("Couldn't read from \"%s\": %s", local_path,
1433			    strerror(errno));
1434
1435		if (len != 0) {
1436			ack = xmalloc(sizeof(*ack));
1437			ack->id = ++id;
1438			ack->offset = offset;
1439			ack->len = len;
1440			TAILQ_INSERT_TAIL(&acks, ack, tq);
1441
1442			buffer_clear(&msg);
1443			buffer_put_char(&msg, SSH2_FXP_WRITE);
1444			buffer_put_int(&msg, ack->id);
1445			buffer_put_string(&msg, handle, handle_len);
1446			buffer_put_int64(&msg, offset);
1447			buffer_put_string(&msg, data, len);
1448			send_msg(conn, &msg);
1449			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1450			    id, (unsigned long long)offset, len);
1451		} else if (TAILQ_FIRST(&acks) == NULL)
1452			break;
1453
1454		if (ack == NULL)
1455			fatal("Unexpected ACK %u", id);
1456
1457		if (id == startid || len == 0 ||
1458		    id - ackid >= conn->num_requests) {
1459			u_int r_id;
1460
1461			buffer_clear(&msg);
1462			get_msg(conn, &msg);
1463			type = buffer_get_char(&msg);
1464			r_id = buffer_get_int(&msg);
1465
1466			if (type != SSH2_FXP_STATUS)
1467				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1468				    "got %d", SSH2_FXP_STATUS, type);
1469
1470			status = buffer_get_int(&msg);
1471			debug3("SSH2_FXP_STATUS %d", status);
1472
1473			/* Find the request in our queue */
1474			for (ack = TAILQ_FIRST(&acks);
1475			    ack != NULL && ack->id != r_id;
1476			    ack = TAILQ_NEXT(ack, tq))
1477				;
1478			if (ack == NULL)
1479				fatal("Can't find request for ID %u", r_id);
1480			TAILQ_REMOVE(&acks, ack, tq);
1481			debug3("In write loop, ack for %u %u bytes at %lld",
1482			    ack->id, ack->len, (long long)ack->offset);
1483			++ackid;
1484			xfree(ack);
1485		}
1486		offset += len;
1487		if (offset < 0)
1488			fatal("%s: offset < 0", __func__);
1489	}
1490	buffer_free(&msg);
1491
1492	if (showprogress)
1493		stop_progress_meter();
1494	xfree(data);
1495
1496	if (status != SSH2_FX_OK) {
1497		error("Couldn't write to remote file \"%s\": %s",
1498		    remote_path, fx2txt(status));
1499		status = -1;
1500	}
1501
1502	if (close(local_fd) == -1) {
1503		error("Couldn't close local file \"%s\": %s", local_path,
1504		    strerror(errno));
1505		status = -1;
1506	}
1507
1508	/* Override umask and utimes if asked */
1509	if (pflag)
1510		do_fsetstat(conn, handle, handle_len, &a);
1511
1512	if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1513		status = -1;
1514	xfree(handle);
1515
1516	return status;
1517}
1518
1519static int
1520upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1521    int pflag, int printflag, int depth)
1522{
1523	int ret = 0, status;
1524	DIR *dirp;
1525	struct dirent *dp;
1526	char *filename, *new_src, *new_dst;
1527	struct stat sb;
1528	Attrib a;
1529
1530	if (depth >= MAX_DIR_DEPTH) {
1531		error("Maximum directory depth exceeded: %d levels", depth);
1532		return -1;
1533	}
1534
1535	if (stat(src, &sb) == -1) {
1536		error("Couldn't stat directory \"%s\": %s",
1537		    src, strerror(errno));
1538		return -1;
1539	}
1540	if (!S_ISDIR(sb.st_mode)) {
1541		error("\"%s\" is not a directory", src);
1542		return -1;
1543	}
1544	if (printflag)
1545		printf("Entering %s\n", src);
1546
1547	attrib_clear(&a);
1548	stat_to_attrib(&sb, &a);
1549	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1550	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1551	a.perm &= 01777;
1552	if (!pflag)
1553		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1554
1555	status = do_mkdir(conn, dst, &a, 0);
1556	/*
1557	 * we lack a portable status for errno EEXIST,
1558	 * so if we get a SSH2_FX_FAILURE back we must check
1559	 * if it was created successfully.
1560	 */
1561	if (status != SSH2_FX_OK) {
1562		if (status != SSH2_FX_FAILURE)
1563			return -1;
1564		if (do_stat(conn, dst, 0) == NULL)
1565			return -1;
1566	}
1567
1568	if ((dirp = opendir(src)) == NULL) {
1569		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1570		return -1;
1571	}
1572
1573	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1574		if (dp->d_ino == 0)
1575			continue;
1576		filename = dp->d_name;
1577		new_dst = path_append(dst, filename);
1578		new_src = path_append(src, filename);
1579
1580		if (lstat(new_src, &sb) == -1) {
1581			logit("%s: lstat failed: %s", filename,
1582			    strerror(errno));
1583			ret = -1;
1584		} else if (S_ISDIR(sb.st_mode)) {
1585			if (strcmp(filename, ".") == 0 ||
1586			    strcmp(filename, "..") == 0)
1587				continue;
1588
1589			if (upload_dir_internal(conn, new_src, new_dst,
1590			    pflag, printflag, depth + 1) == -1)
1591				ret = -1;
1592		} else if (S_ISREG(sb.st_mode)) {
1593			if (do_upload(conn, new_src, new_dst, pflag) == -1) {
1594				error("Uploading of file %s to %s failed!",
1595				    new_src, new_dst);
1596				ret = -1;
1597			}
1598		} else
1599			logit("%s: not a regular file\n", filename);
1600		xfree(new_dst);
1601		xfree(new_src);
1602	}
1603
1604	do_setstat(conn, dst, &a);
1605
1606	(void) closedir(dirp);
1607	return ret;
1608}
1609
1610int
1611upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
1612    int pflag)
1613{
1614	char *dst_canon;
1615	int ret;
1616
1617	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1618		error("Unable to canonicalise path \"%s\"", dst);
1619		return -1;
1620	}
1621
1622	ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
1623	xfree(dst_canon);
1624	return ret;
1625}
1626
1627char *
1628path_append(char *p1, char *p2)
1629{
1630	char *ret;
1631	size_t len = strlen(p1) + strlen(p2) + 2;
1632
1633	ret = xmalloc(len);
1634	strlcpy(ret, p1, len);
1635	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1636		strlcat(ret, "/", len);
1637	strlcat(ret, p2, len);
1638
1639	return(ret);
1640}
1641
1642