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