xref: /netbsd-src/crypto/external/bsd/openssh/dist/sftp-client.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /*	$NetBSD: sftp-client.c,v 1.16 2016/08/02 13:45:12 christos Exp $	*/
2 /* $OpenBSD: sftp-client.c,v 1.124 2016/05/25 23:48:45 schwarze Exp $ */
3 /*
4  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* XXX: memleaks */
20 /* XXX: signed vs unsigned */
21 /* XXX: remove all logging, only return status codes */
22 /* XXX: copy between two remote sites */
23 
24 #include "includes.h"
25 __RCSID("$NetBSD: sftp-client.c,v 1.16 2016/08/02 13:45:12 christos Exp $");
26 #include <sys/param.h>	/* MIN MAX */
27 #include <sys/types.h>
28 #include <sys/poll.h>
29 #include <sys/queue.h>
30 #include <sys/stat.h>
31 #include <sys/time.h>
32 #include <sys/statvfs.h>
33 #include <sys/uio.h>
34 
35 #include <dirent.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 
45 #include "xmalloc.h"
46 #include "ssherr.h"
47 #include "sshbuf.h"
48 #include "log.h"
49 #include "atomicio.h"
50 #include "progressmeter.h"
51 #include "misc.h"
52 #include "utf8.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, *handle;
516 	int status = SSH2_FX_FAILURE;
517 	int r;
518 
519 	if (dir)
520 		*dir = NULL;
521 
522 	id = conn->msg_id++;
523 
524 	if ((msg = sshbuf_new()) == NULL)
525 		fatal("%s: sshbuf_new failed", __func__);
526 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPENDIR)) != 0 ||
527 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
528 	    (r = sshbuf_put_cstring(msg, path)) != 0)
529 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
530 	send_msg(conn, msg);
531 
532 	handle = get_handle(conn, id, &handle_len,
533 	    "remote readdir(\"%s\")", path);
534 	if (handle == NULL) {
535 		sshbuf_free(msg);
536 		return -1;
537 	}
538 
539 	if (dir) {
540 		ents = 0;
541 		*dir = xcalloc(1, sizeof(**dir));
542 		(*dir)[0] = NULL;
543 	}
544 
545 	for (; !interrupted;) {
546 		id = expected_id = conn->msg_id++;
547 
548 		debug3("Sending SSH2_FXP_READDIR I:%u", id);
549 
550 		sshbuf_reset(msg);
551 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_READDIR)) != 0 ||
552 		    (r = sshbuf_put_u32(msg, id)) != 0 ||
553 		    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
554 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
555 		send_msg(conn, msg);
556 
557 		sshbuf_reset(msg);
558 
559 		get_msg(conn, msg);
560 
561 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
562 		    (r = sshbuf_get_u32(msg, &id)) != 0)
563 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
564 
565 		debug3("Received reply T:%u I:%u", type, id);
566 
567 		if (id != expected_id)
568 			fatal("ID mismatch (%u != %u)", id, expected_id);
569 
570 		if (type == SSH2_FXP_STATUS) {
571 			u_int rstatus;
572 
573 			if ((r = sshbuf_get_u32(msg, &rstatus)) != 0)
574 				fatal("%s: buffer error: %s",
575 				    __func__, ssh_err(r));
576 			debug3("Received SSH2_FXP_STATUS %d", rstatus);
577 			if (rstatus == SSH2_FX_EOF)
578 				break;
579 			error("Couldn't read directory: %s", fx2txt(rstatus));
580 			goto out;
581 		} else if (type != SSH2_FXP_NAME)
582 			fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
583 			    SSH2_FXP_NAME, type);
584 
585 		if ((r = sshbuf_get_u32(msg, &count)) != 0)
586 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
587 		if (count == 0)
588 			break;
589 		debug3("Received %d SSH2_FXP_NAME responses", count);
590 		for (i = 0; i < count; i++) {
591 			char *filename, *longname;
592 			Attrib a;
593 
594 			if ((r = sshbuf_get_cstring(msg, &filename,
595 			    NULL)) != 0 ||
596 			    (r = sshbuf_get_cstring(msg, &longname,
597 			    NULL)) != 0)
598 				fatal("%s: buffer error: %s",
599 				    __func__, ssh_err(r));
600 			if ((r = decode_attrib(msg, &a)) != 0) {
601 				error("%s: couldn't decode attrib: %s",
602 				    __func__, ssh_err(r));
603 				free(filename);
604 				free(longname);
605 				sshbuf_free(msg);
606 				return -1;
607 			}
608 
609 			if (print_flag)
610 				mprintf("%s\n", longname);
611 
612 			/*
613 			 * Directory entries should never contain '/'
614 			 * These can be used to attack recursive ops
615 			 * (e.g. send '../../../../etc/passwd')
616 			 */
617 			if (strchr(filename, '/') != NULL) {
618 				error("Server sent suspect path \"%s\" "
619 				    "during readdir of \"%s\"", filename, path);
620 			} else if (dir) {
621 				*dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
622 				(*dir)[ents] = xcalloc(1, sizeof(***dir));
623 				(*dir)[ents]->filename = xstrdup(filename);
624 				(*dir)[ents]->longname = xstrdup(longname);
625 				memcpy(&(*dir)[ents]->a, &a, sizeof(a));
626 				(*dir)[++ents] = NULL;
627 			}
628 			free(filename);
629 			free(longname);
630 		}
631 	}
632 	status = 0;
633 
634  out:
635 	sshbuf_free(msg);
636 	do_close(conn, handle, handle_len);
637 	free(handle);
638 
639 	if (status != 0 && dir != NULL) {
640 		/* Don't return results on error */
641 		free_sftp_dirents(*dir);
642 		*dir = NULL;
643 	} else if (interrupted && dir != NULL && *dir != NULL) {
644 		/* Don't return partial matches on interrupt */
645 		free_sftp_dirents(*dir);
646 		*dir = xcalloc(1, sizeof(**dir));
647 		**dir = NULL;
648 	}
649 
650 	return status;
651 }
652 
653 int
654 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
655 {
656 	return(do_lsreaddir(conn, path, 0, dir));
657 }
658 
659 void free_sftp_dirents(SFTP_DIRENT **s)
660 {
661 	int i;
662 
663 	if (s == NULL)
664 		return;
665 	for (i = 0; s[i]; i++) {
666 		free(s[i]->filename);
667 		free(s[i]->longname);
668 		free(s[i]);
669 	}
670 	free(s);
671 }
672 
673 int
674 do_rm(struct sftp_conn *conn, const char *path)
675 {
676 	u_int status, id;
677 
678 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
679 
680 	id = conn->msg_id++;
681 	send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
682 	status = get_status(conn, id);
683 	if (status != SSH2_FX_OK)
684 		error("Couldn't delete file: %s", fx2txt(status));
685 	return status == SSH2_FX_OK ? 0 : -1;
686 }
687 
688 int
689 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
690 {
691 	u_int status, id;
692 
693 	id = conn->msg_id++;
694 	send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
695 	    strlen(path), a);
696 
697 	status = get_status(conn, id);
698 	if (status != SSH2_FX_OK && print_flag)
699 		error("Couldn't create directory: %s", fx2txt(status));
700 
701 	return status == SSH2_FX_OK ? 0 : -1;
702 }
703 
704 int
705 do_rmdir(struct sftp_conn *conn, const char *path)
706 {
707 	u_int status, id;
708 
709 	id = conn->msg_id++;
710 	send_string_request(conn, id, SSH2_FXP_RMDIR, path,
711 	    strlen(path));
712 
713 	status = get_status(conn, id);
714 	if (status != SSH2_FX_OK)
715 		error("Couldn't remove directory: %s", fx2txt(status));
716 
717 	return status == SSH2_FX_OK ? 0 : -1;
718 }
719 
720 Attrib *
721 do_stat(struct sftp_conn *conn, const char *path, int quiet)
722 {
723 	u_int id;
724 
725 	id = conn->msg_id++;
726 
727 	send_string_request(conn, id,
728 	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
729 	    path, strlen(path));
730 
731 	return(get_decode_stat(conn, id, quiet));
732 }
733 
734 Attrib *
735 do_lstat(struct sftp_conn *conn, const char *path, int quiet)
736 {
737 	u_int id;
738 
739 	if (conn->version == 0) {
740 		if (quiet)
741 			debug("Server version does not support lstat operation");
742 		else
743 			logit("Server version does not support lstat operation");
744 		return(do_stat(conn, path, quiet));
745 	}
746 
747 	id = conn->msg_id++;
748 	send_string_request(conn, id, SSH2_FXP_LSTAT, path,
749 	    strlen(path));
750 
751 	return(get_decode_stat(conn, id, quiet));
752 }
753 
754 #ifdef notyet
755 Attrib *
756 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
757     int quiet)
758 {
759 	u_int id;
760 
761 	id = conn->msg_id++;
762 	send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
763 	    handle_len);
764 
765 	return(get_decode_stat(conn, id, quiet));
766 }
767 #endif
768 
769 int
770 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
771 {
772 	u_int status, id;
773 
774 	id = conn->msg_id++;
775 	send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
776 	    strlen(path), a);
777 
778 	status = get_status(conn, id);
779 	if (status != SSH2_FX_OK)
780 		error("Couldn't setstat on \"%s\": %s", path,
781 		    fx2txt(status));
782 
783 	return status == SSH2_FX_OK ? 0 : -1;
784 }
785 
786 int
787 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
788     Attrib *a)
789 {
790 	u_int status, id;
791 
792 	id = conn->msg_id++;
793 	send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
794 	    handle_len, a);
795 
796 	status = get_status(conn, id);
797 	if (status != SSH2_FX_OK)
798 		error("Couldn't fsetstat: %s", fx2txt(status));
799 
800 	return status == SSH2_FX_OK ? 0 : -1;
801 }
802 
803 char *
804 do_realpath(struct sftp_conn *conn, const char *path)
805 {
806 	struct sshbuf *msg;
807 	u_int expected_id, count, id;
808 	char *filename, *longname;
809 	Attrib a;
810 	u_char type;
811 	int r;
812 
813 	expected_id = id = conn->msg_id++;
814 	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
815 	    strlen(path));
816 
817 	if ((msg = sshbuf_new()) == NULL)
818 		fatal("%s: sshbuf_new failed", __func__);
819 
820 	get_msg(conn, msg);
821 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
822 	    (r = sshbuf_get_u32(msg, &id)) != 0)
823 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
824 
825 	if (id != expected_id)
826 		fatal("ID mismatch (%u != %u)", id, expected_id);
827 
828 	if (type == SSH2_FXP_STATUS) {
829 		u_int status;
830 
831 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
832 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
833 		error("Couldn't canonicalize: %s", fx2txt(status));
834 		sshbuf_free(msg);
835 		return NULL;
836 	} else if (type != SSH2_FXP_NAME)
837 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
838 		    SSH2_FXP_NAME, type);
839 
840 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
841 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
842 	if (count != 1)
843 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
844 
845 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
846 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
847 	    (r = decode_attrib(msg, &a)) != 0)
848 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
849 
850 	debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
851 	    (unsigned long)a.size);
852 
853 	free(longname);
854 
855 	sshbuf_free(msg);
856 
857 	return(filename);
858 }
859 
860 int
861 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
862     int force_legacy)
863 {
864 	struct sshbuf *msg;
865 	u_int status, id;
866 	int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
867 
868 	if ((msg = sshbuf_new()) == NULL)
869 		fatal("%s: sshbuf_new failed", __func__);
870 
871 	/* Send rename request */
872 	id = conn->msg_id++;
873 	if (use_ext) {
874 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
875 		    (r = sshbuf_put_u32(msg, id)) != 0 ||
876 		    (r = sshbuf_put_cstring(msg,
877 		    "posix-rename@openssh.com")) != 0)
878 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
879 	} else {
880 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
881 		    (r = sshbuf_put_u32(msg, id)) != 0)
882 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
883 	}
884 	if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
885 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
886 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
887 	send_msg(conn, msg);
888 	debug3("Sent message %s \"%s\" -> \"%s\"",
889 	    use_ext ? "posix-rename@openssh.com" :
890 	    "SSH2_FXP_RENAME", oldpath, newpath);
891 	sshbuf_free(msg);
892 
893 	status = get_status(conn, id);
894 	if (status != SSH2_FX_OK)
895 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
896 		    newpath, fx2txt(status));
897 
898 	return status == SSH2_FX_OK ? 0 : -1;
899 }
900 
901 int
902 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
903 {
904 	struct sshbuf *msg;
905 	u_int status, id;
906 	int r;
907 
908 	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
909 		error("Server does not support hardlink@openssh.com extension");
910 		return -1;
911 	}
912 
913 	if ((msg = sshbuf_new()) == NULL)
914 		fatal("%s: sshbuf_new failed", __func__);
915 
916 	/* Send link request */
917 	id = conn->msg_id++;
918 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
919 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
920 	    (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
921 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
922 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
923 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
924 	send_msg(conn, msg);
925 	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
926 	       oldpath, newpath);
927 	sshbuf_free(msg);
928 
929 	status = get_status(conn, id);
930 	if (status != SSH2_FX_OK)
931 		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
932 		    newpath, fx2txt(status));
933 
934 	return status == SSH2_FX_OK ? 0 : -1;
935 }
936 
937 int
938 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
939 {
940 	struct sshbuf *msg;
941 	u_int status, id;
942 	int r;
943 
944 	if (conn->version < 3) {
945 		error("This server does not support the symlink operation");
946 		return(SSH2_FX_OP_UNSUPPORTED);
947 	}
948 
949 	if ((msg = sshbuf_new()) == NULL)
950 		fatal("%s: sshbuf_new failed", __func__);
951 
952 	/* Send symlink request */
953 	id = conn->msg_id++;
954 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
955 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
956 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
957 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
958 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
959 	send_msg(conn, msg);
960 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
961 	    newpath);
962 	sshbuf_free(msg);
963 
964 	status = get_status(conn, id);
965 	if (status != SSH2_FX_OK)
966 		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
967 		    newpath, fx2txt(status));
968 
969 	return status == SSH2_FX_OK ? 0 : -1;
970 }
971 
972 int
973 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
974 {
975 	struct sshbuf *msg;
976 	u_int status, id;
977 	int r;
978 
979 	/* Silently return if the extension is not supported */
980 	if ((conn->exts & SFTP_EXT_FSYNC) == 0)
981 		return -1;
982 
983 	/* Send fsync request */
984 	if ((msg = sshbuf_new()) == NULL)
985 		fatal("%s: sshbuf_new failed", __func__);
986 	id = conn->msg_id++;
987 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
988 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
989 	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
990 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
991 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
992 	send_msg(conn, msg);
993 	debug3("Sent message fsync@openssh.com I:%u", id);
994 	sshbuf_free(msg);
995 
996 	status = get_status(conn, id);
997 	if (status != SSH2_FX_OK)
998 		error("Couldn't sync file: %s", fx2txt(status));
999 
1000 	return status;
1001 }
1002 
1003 #ifdef notyet
1004 char *
1005 do_readlink(struct sftp_conn *conn, const char *path)
1006 {
1007 	struct sshbuf *msg;
1008 	u_int expected_id, count, id;
1009 	char *filename, *longname;
1010 	Attrib a;
1011 	u_char type;
1012 	int r;
1013 
1014 	expected_id = id = conn->msg_id++;
1015 	send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
1016 
1017 	if ((msg = sshbuf_new()) == NULL)
1018 		fatal("%s: sshbuf_new failed", __func__);
1019 
1020 	get_msg(conn, msg);
1021 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1022 	    (r = sshbuf_get_u32(msg, &id)) != 0)
1023 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1024 
1025 	if (id != expected_id)
1026 		fatal("ID mismatch (%u != %u)", id, expected_id);
1027 
1028 	if (type == SSH2_FXP_STATUS) {
1029 		u_int status;
1030 
1031 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
1032 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1033 		error("Couldn't readlink: %s", fx2txt(status));
1034 		sshbuf_free(msg);
1035 		return(NULL);
1036 	} else if (type != SSH2_FXP_NAME)
1037 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1038 		    SSH2_FXP_NAME, type);
1039 
1040 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
1041 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1042 	if (count != 1)
1043 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
1044 
1045 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1046 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1047 	    (r = decode_attrib(msg, &a)) != 0)
1048 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1049 
1050 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
1051 
1052 	free(longname);
1053 
1054 	sshbuf_free(msg);
1055 
1056 	return filename;
1057 }
1058 #endif
1059 
1060 int
1061 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
1062     int quiet)
1063 {
1064 	struct sshbuf *msg;
1065 	u_int id;
1066 	int r;
1067 
1068 	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
1069 		error("Server does not support statvfs@openssh.com extension");
1070 		return -1;
1071 	}
1072 
1073 	id = conn->msg_id++;
1074 
1075 	if ((msg = sshbuf_new()) == NULL)
1076 		fatal("%s: sshbuf_new failed", __func__);
1077 	sshbuf_reset(msg);
1078 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1079 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1080 	    (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1081 	    (r = sshbuf_put_cstring(msg, path)) != 0)
1082 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1083 	send_msg(conn, msg);
1084 	sshbuf_free(msg);
1085 
1086 	return get_decode_statvfs(conn, st, id, quiet);
1087 }
1088 
1089 #ifdef notyet
1090 int
1091 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1092     struct sftp_statvfs *st, int quiet)
1093 {
1094 	struct sshbuf *msg;
1095 	u_int id;
1096 
1097 	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
1098 		error("Server does not support fstatvfs@openssh.com extension");
1099 		return -1;
1100 	}
1101 
1102 	id = conn->msg_id++;
1103 
1104 	if ((msg = sshbuf_new()) == NULL)
1105 		fatal("%s: sshbuf_new failed", __func__);
1106 	sshbuf_reset(msg);
1107 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1108 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1109 	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1110 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1111 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1112 	send_msg(conn, msg);
1113 	sshbuf_free(msg);
1114 
1115 	return get_decode_statvfs(conn, st, id, quiet);
1116 }
1117 #endif
1118 
1119 static void
1120 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1121     u_int len, const u_char *handle, u_int handle_len)
1122 {
1123 	struct sshbuf *msg;
1124 	int r;
1125 
1126 	if ((msg = sshbuf_new()) == NULL)
1127 		fatal("%s: sshbuf_new failed", __func__);
1128 	sshbuf_reset(msg);
1129 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1130 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1131 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1132 	    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1133 	    (r = sshbuf_put_u32(msg, len)) != 0)
1134 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1135 	send_msg(conn, msg);
1136 	sshbuf_free(msg);
1137 }
1138 
1139 int
1140 do_download(struct sftp_conn *conn, const char *remote_path,
1141     const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1142     int fsync_flag)
1143 {
1144 	Attrib junk;
1145 	struct sshbuf *msg;
1146 	u_char *handle;
1147 	int local_fd = -1, write_error;
1148 	int read_error, write_errno, reordered = 0, r;
1149 	u_int64_t offset = 0, size, highwater;
1150 	u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1151 	off_t progress_counter;
1152 	size_t handle_len;
1153 	struct stat st;
1154 	struct request {
1155 		u_int id;
1156 		size_t len;
1157 		u_int64_t offset;
1158 		TAILQ_ENTRY(request) tq;
1159 	};
1160 	TAILQ_HEAD(reqhead, request) requests;
1161 	struct request *req;
1162 	u_char type;
1163 
1164 	status = -1;
1165 	TAILQ_INIT(&requests);
1166 
1167 	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1168 		return -1;
1169 
1170 	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1171 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1172 		mode = a->perm & 0777;
1173 	else
1174 		mode = 0666;
1175 
1176 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1177 	    (!S_ISREG(a->perm))) {
1178 		error("Cannot download non-regular file: %s", remote_path);
1179 		return(-1);
1180 	}
1181 
1182 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1183 		size = a->size;
1184 	else
1185 		size = 0;
1186 
1187 	buflen = conn->transfer_buflen;
1188 	if ((msg = sshbuf_new()) == NULL)
1189 		fatal("%s: sshbuf_new failed", __func__);
1190 
1191 	attrib_clear(&junk); /* Send empty attributes */
1192 
1193 	/* Send open request */
1194 	id = conn->msg_id++;
1195 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1196 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1197 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1198 	    (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1199 	    (r = encode_attrib(msg, &junk)) != 0)
1200 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1201 	send_msg(conn, msg);
1202 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1203 
1204 	handle = get_handle(conn, id, &handle_len,
1205 	    "remote open(\"%s\")", remote_path);
1206 	if (handle == NULL) {
1207 		sshbuf_free(msg);
1208 		return(-1);
1209 	}
1210 
1211 	local_fd = open(local_path,
1212 	    O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
1213 	if (local_fd == -1) {
1214 		error("Couldn't open local file \"%s\" for writing: %s",
1215 		    local_path, strerror(errno));
1216 		goto fail;
1217 	}
1218 	offset = highwater = 0;
1219 	if (resume_flag) {
1220 		if (fstat(local_fd, &st) == -1) {
1221 			error("Unable to stat local file \"%s\": %s",
1222 			    local_path, strerror(errno));
1223 			goto fail;
1224 		}
1225 		if (st.st_size < 0) {
1226 			error("\"%s\" has negative size", local_path);
1227 			goto fail;
1228 		}
1229 		if ((u_int64_t)st.st_size > size) {
1230 			error("Unable to resume download of \"%s\": "
1231 			    "local file is larger than remote", local_path);
1232  fail:
1233 			do_close(conn, handle, handle_len);
1234 			sshbuf_free(msg);
1235 			free(handle);
1236 			if (local_fd != -1)
1237 				close(local_fd);
1238 			return -1;
1239 		}
1240 		offset = highwater = st.st_size;
1241 	}
1242 
1243 	/* Read from remote and write to local */
1244 	write_error = read_error = write_errno = num_req = 0;
1245 	max_req = 1;
1246 	progress_counter = offset;
1247 
1248 	if (showprogress && size != 0)
1249 		start_progress_meter(remote_path, size, &progress_counter);
1250 
1251 	while (num_req > 0 || max_req > 0) {
1252 		u_char *data;
1253 		size_t len;
1254 
1255 		/*
1256 		 * Simulate EOF on interrupt: stop sending new requests and
1257 		 * allow outstanding requests to drain gracefully
1258 		 */
1259 		if (interrupted) {
1260 			if (num_req == 0) /* If we haven't started yet... */
1261 				break;
1262 			max_req = 0;
1263 		}
1264 
1265 		/* Send some more requests */
1266 		while (num_req < max_req) {
1267 			debug3("Request range %llu -> %llu (%d/%d)",
1268 			    (unsigned long long)offset,
1269 			    (unsigned long long)offset + buflen - 1,
1270 			    num_req, max_req);
1271 			req = xcalloc(1, sizeof(*req));
1272 			req->id = conn->msg_id++;
1273 			req->len = buflen;
1274 			req->offset = offset;
1275 			offset += buflen;
1276 			num_req++;
1277 			TAILQ_INSERT_TAIL(&requests, req, tq);
1278 			send_read_request(conn, req->id, req->offset,
1279 			    req->len, handle, handle_len);
1280 		}
1281 
1282 		sshbuf_reset(msg);
1283 		get_msg(conn, msg);
1284 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1285 		    (r = sshbuf_get_u32(msg, &id)) != 0)
1286 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1287 		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1288 
1289 		/* Find the request in our queue */
1290 		for (req = TAILQ_FIRST(&requests);
1291 		    req != NULL && req->id != id;
1292 		    req = TAILQ_NEXT(req, tq))
1293 			;
1294 		if (req == NULL)
1295 			fatal("Unexpected reply %u", id);
1296 
1297 		switch (type) {
1298 		case SSH2_FXP_STATUS:
1299 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1300 				fatal("%s: buffer error: %s",
1301 				    __func__, ssh_err(r));
1302 			if (status != SSH2_FX_EOF)
1303 				read_error = 1;
1304 			max_req = 0;
1305 			TAILQ_REMOVE(&requests, req, tq);
1306 			free(req);
1307 			num_req--;
1308 			break;
1309 		case SSH2_FXP_DATA:
1310 			if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1311 				fatal("%s: buffer error: %s",
1312 				    __func__, ssh_err(r));
1313 			debug3("Received data %llu -> %llu",
1314 			    (unsigned long long)req->offset,
1315 			    (unsigned long long)req->offset + len - 1);
1316 			if (len > req->len)
1317 				fatal("Received more data than asked for "
1318 				    "%zu > %zu", len, req->len);
1319 			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1320 			    atomicio(vwrite, local_fd, data, len) != len) &&
1321 			    !write_error) {
1322 				write_errno = errno;
1323 				write_error = 1;
1324 				max_req = 0;
1325 			}
1326 			else if (!reordered && req->offset <= highwater)
1327 				highwater = req->offset + len;
1328 			else if (!reordered && req->offset > highwater)
1329 				reordered = 1;
1330 			progress_counter += len;
1331 			free(data);
1332 
1333 			if (len == req->len) {
1334 				TAILQ_REMOVE(&requests, req, tq);
1335 				free(req);
1336 				num_req--;
1337 			} else {
1338 				/* Resend the request for the missing data */
1339 				debug3("Short data block, re-requesting "
1340 				    "%llu -> %llu (%2d)",
1341 				    (unsigned long long)req->offset + len,
1342 				    (unsigned long long)req->offset +
1343 				    req->len - 1, num_req);
1344 				req->id = conn->msg_id++;
1345 				req->len -= len;
1346 				req->offset += len;
1347 				send_read_request(conn, req->id,
1348 				    req->offset, req->len, handle, handle_len);
1349 				/* Reduce the request size */
1350 				if (len < buflen)
1351 					buflen = MAX(MIN_READ_SIZE, len);
1352 			}
1353 			if (max_req > 0) { /* max_req = 0 iff EOF received */
1354 				if (size > 0 && offset > size) {
1355 					/* Only one request at a time
1356 					 * after the expected EOF */
1357 					debug3("Finish at %llu (%2d)",
1358 					    (unsigned long long)offset,
1359 					    num_req);
1360 					max_req = 1;
1361 				} else if (max_req <= conn->num_requests) {
1362 					++max_req;
1363 				}
1364 			}
1365 			break;
1366 		default:
1367 			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1368 			    SSH2_FXP_DATA, type);
1369 		}
1370 	}
1371 
1372 	if (showprogress && size)
1373 		stop_progress_meter();
1374 
1375 	/* Sanity check */
1376 	if (TAILQ_FIRST(&requests) != NULL)
1377 		fatal("Transfer complete, but requests still in queue");
1378 	/* Truncate at highest contiguous point to avoid holes on interrupt */
1379 	if (read_error || write_error || interrupted) {
1380 		if (reordered && resume_flag) {
1381 			error("Unable to resume download of \"%s\": "
1382 			    "server reordered requests", local_path);
1383 		}
1384 		debug("truncating at %llu", (unsigned long long)highwater);
1385 		if (ftruncate(local_fd, highwater) == -1)
1386 			error("ftruncate \"%s\": %s", local_path,
1387 			    strerror(errno));
1388 	}
1389 	if (read_error) {
1390 		error("Couldn't read from remote file \"%s\" : %s",
1391 		    remote_path, fx2txt(status));
1392 		status = -1;
1393 		do_close(conn, handle, handle_len);
1394 	} else if (write_error) {
1395 		error("Couldn't write to \"%s\": %s", local_path,
1396 		    strerror(write_errno));
1397 		status = SSH2_FX_FAILURE;
1398 		do_close(conn, handle, handle_len);
1399 	} else {
1400 		if (do_close(conn, handle, handle_len) != 0 || interrupted)
1401 			status = SSH2_FX_FAILURE;
1402 		else
1403 			status = SSH2_FX_OK;
1404 		/* Override umask and utimes if asked */
1405 		if (preserve_flag && fchmod(local_fd, mode) == -1)
1406 			error("Couldn't set mode on \"%s\": %s", local_path,
1407 			    strerror(errno));
1408 		if (preserve_flag &&
1409 		    (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1410 			struct timeval tv[2];
1411 			tv[0].tv_sec = a->atime;
1412 			tv[1].tv_sec = a->mtime;
1413 			tv[0].tv_usec = tv[1].tv_usec = 0;
1414 			if (utimes(local_path, tv) == -1)
1415 				error("Can't set times on \"%s\": %s",
1416 				    local_path, strerror(errno));
1417 		}
1418 		if (fsync_flag) {
1419 			debug("syncing \"%s\"", local_path);
1420 			if (fsync(local_fd) == -1)
1421 				error("Couldn't sync file \"%s\": %s",
1422 				    local_path, strerror(errno));
1423 		}
1424 	}
1425 	close(local_fd);
1426 	sshbuf_free(msg);
1427 	free(handle);
1428 
1429 	return(status);
1430 }
1431 
1432 static int
1433 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1434     int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1435     int resume_flag, int fsync_flag)
1436 {
1437 	int i, ret = 0;
1438 	SFTP_DIRENT **dir_entries;
1439 	char *filename, *new_src, *new_dst;
1440 	mode_t mode = 0777;
1441 
1442 	if (depth >= MAX_DIR_DEPTH) {
1443 		error("Maximum directory depth exceeded: %d levels", depth);
1444 		return -1;
1445 	}
1446 
1447 	if (dirattrib == NULL &&
1448 	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1449 		error("Unable to stat remote directory \"%s\"", src);
1450 		return -1;
1451 	}
1452 	if (!S_ISDIR(dirattrib->perm)) {
1453 		error("\"%s\" is not a directory", src);
1454 		return -1;
1455 	}
1456 	if (print_flag)
1457 		mprintf("Retrieving %s\n", src);
1458 
1459 	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1460 		mode = dirattrib->perm & 01777;
1461 	else {
1462 		debug("Server did not send permissions for "
1463 		    "directory \"%s\"", dst);
1464 	}
1465 
1466 	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1467 		error("mkdir %s: %s", dst, strerror(errno));
1468 		return -1;
1469 	}
1470 
1471 	if (do_readdir(conn, src, &dir_entries) == -1) {
1472 		error("%s: Failed to get directory contents", src);
1473 		return -1;
1474 	}
1475 
1476 	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1477 		filename = dir_entries[i]->filename;
1478 
1479 		new_dst = path_append(dst, filename);
1480 		new_src = path_append(src, filename);
1481 
1482 		if (S_ISDIR(dir_entries[i]->a.perm)) {
1483 			if (strcmp(filename, ".") == 0 ||
1484 			    strcmp(filename, "..") == 0)
1485 				continue;
1486 			if (download_dir_internal(conn, new_src, new_dst,
1487 			    depth + 1, &(dir_entries[i]->a), preserve_flag,
1488 			    print_flag, resume_flag, fsync_flag) == -1)
1489 				ret = -1;
1490 		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1491 			if (do_download(conn, new_src, new_dst,
1492 			    &(dir_entries[i]->a), preserve_flag,
1493 			    resume_flag, fsync_flag) == -1) {
1494 				error("Download of file %s to %s failed",
1495 				    new_src, new_dst);
1496 				ret = -1;
1497 			}
1498 		} else
1499 			logit("%s: not a regular file\n", new_src);
1500 
1501 		free(new_dst);
1502 		free(new_src);
1503 	}
1504 
1505 	if (preserve_flag) {
1506 		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1507 			struct timeval tv[2];
1508 			tv[0].tv_sec = dirattrib->atime;
1509 			tv[1].tv_sec = dirattrib->mtime;
1510 			tv[0].tv_usec = tv[1].tv_usec = 0;
1511 			if (utimes(dst, tv) == -1)
1512 				error("Can't set times on \"%s\": %s",
1513 				    dst, strerror(errno));
1514 		} else
1515 			debug("Server did not send times for directory "
1516 			    "\"%s\"", dst);
1517 	}
1518 
1519 	free_sftp_dirents(dir_entries);
1520 
1521 	return ret;
1522 }
1523 
1524 int
1525 download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1526     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1527     int fsync_flag)
1528 {
1529 	char *src_canon;
1530 	int ret;
1531 
1532 	if ((src_canon = do_realpath(conn, src)) == NULL) {
1533 		error("Unable to canonicalize path \"%s\"", src);
1534 		return -1;
1535 	}
1536 
1537 	ret = download_dir_internal(conn, src_canon, dst, 0,
1538 	    dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1539 	free(src_canon);
1540 	return ret;
1541 }
1542 
1543 int
1544 do_upload(struct sftp_conn *conn, const char *local_path,
1545     const char *remote_path, int preserve_flag, int resume, int fsync_flag)
1546 {
1547 	int r, local_fd;
1548 	u_int status = SSH2_FX_OK;
1549 	u_int id;
1550 	u_char type;
1551 	off_t offset, progress_counter;
1552 	u_char *handle, *data;
1553 	struct sshbuf *msg;
1554 	struct stat sb;
1555 	Attrib a, *c = NULL;
1556 	u_int32_t startid;
1557 	u_int32_t ackid;
1558 	struct outstanding_ack {
1559 		u_int id;
1560 		u_int len;
1561 		off_t offset;
1562 		TAILQ_ENTRY(outstanding_ack) tq;
1563 	};
1564 	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1565 	struct outstanding_ack *ack = NULL;
1566 	size_t handle_len;
1567 
1568 	TAILQ_INIT(&acks);
1569 
1570 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1571 		error("Couldn't open local file \"%s\" for reading: %s",
1572 		    local_path, strerror(errno));
1573 		return(-1);
1574 	}
1575 	if (fstat(local_fd, &sb) == -1) {
1576 		error("Couldn't fstat local file \"%s\": %s",
1577 		    local_path, strerror(errno));
1578 		close(local_fd);
1579 		return(-1);
1580 	}
1581 	if (!S_ISREG(sb.st_mode)) {
1582 		error("%s is not a regular file", local_path);
1583 		close(local_fd);
1584 		return(-1);
1585 	}
1586 	stat_to_attrib(&sb, &a);
1587 
1588 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1589 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1590 	a.perm &= 0777;
1591 	if (!preserve_flag)
1592 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1593 
1594 	if (resume) {
1595 		/* Get remote file size if it exists */
1596 		if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1597 			close(local_fd);
1598 			return -1;
1599 		}
1600 
1601 		if ((off_t)c->size >= sb.st_size) {
1602 			error("destination file bigger or same size as "
1603 			      "source file");
1604 			close(local_fd);
1605 			return -1;
1606 		}
1607 
1608 		if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1609 			close(local_fd);
1610 			return -1;
1611 		}
1612 	}
1613 
1614 	if ((msg = sshbuf_new()) == NULL)
1615 		fatal("%s: sshbuf_new failed", __func__);
1616 
1617 	/* Send open request */
1618 	id = conn->msg_id++;
1619 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1620 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1621 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1622 	    (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1623 	    (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
1624 	    (r = encode_attrib(msg, &a)) != 0)
1625 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1626 	send_msg(conn, msg);
1627 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1628 
1629 	sshbuf_reset(msg);
1630 
1631 	handle = get_handle(conn, id, &handle_len,
1632 	    "remote open(\"%s\")", remote_path);
1633 	if (handle == NULL) {
1634 		close(local_fd);
1635 		sshbuf_free(msg);
1636 		return -1;
1637 	}
1638 
1639 	startid = ackid = id + 1;
1640 	data = xmalloc(conn->transfer_buflen);
1641 
1642 	/* Read from local and write to remote */
1643 	offset = progress_counter = (resume ? c->size : 0);
1644 	if (showprogress)
1645 		start_progress_meter(local_path, sb.st_size,
1646 		    &progress_counter);
1647 
1648 	for (;;) {
1649 		int len;
1650 
1651 		/*
1652 		 * Can't use atomicio here because it returns 0 on EOF,
1653 		 * thus losing the last block of the file.
1654 		 * Simulate an EOF on interrupt, allowing ACKs from the
1655 		 * server to drain.
1656 		 */
1657 		if (interrupted || status != SSH2_FX_OK)
1658 			len = 0;
1659 		else do
1660 			len = read(local_fd, data, conn->transfer_buflen);
1661 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1662 
1663 		if (len == -1)
1664 			fatal("Couldn't read from \"%s\": %s", local_path,
1665 			    strerror(errno));
1666 
1667 		if (len != 0) {
1668 			ack = xcalloc(1, sizeof(*ack));
1669 			ack->id = ++id;
1670 			ack->offset = offset;
1671 			ack->len = len;
1672 			TAILQ_INSERT_TAIL(&acks, ack, tq);
1673 
1674 			sshbuf_reset(msg);
1675 			if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
1676 			    (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
1677 			    (r = sshbuf_put_string(msg, handle,
1678 			    handle_len)) != 0 ||
1679 			    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1680 			    (r = sshbuf_put_string(msg, data, len)) != 0)
1681 				fatal("%s: buffer error: %s",
1682 				    __func__, ssh_err(r));
1683 			send_msg(conn, msg);
1684 			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1685 			    id, (unsigned long long)offset, len);
1686 		} else if (TAILQ_FIRST(&acks) == NULL)
1687 			break;
1688 
1689 		if (ack == NULL)
1690 			fatal("Unexpected ACK %u", id);
1691 
1692 		if (id == startid || len == 0 ||
1693 		    id - ackid >= conn->num_requests) {
1694 			u_int rid;
1695 
1696 			sshbuf_reset(msg);
1697 			get_msg(conn, msg);
1698 			if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1699 			    (r = sshbuf_get_u32(msg, &rid)) != 0)
1700 				fatal("%s: buffer error: %s",
1701 				    __func__, ssh_err(r));
1702 
1703 			if (type != SSH2_FXP_STATUS)
1704 				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1705 				    "got %d", SSH2_FXP_STATUS, type);
1706 
1707 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1708 				fatal("%s: buffer error: %s",
1709 				    __func__, ssh_err(r));
1710 			debug3("SSH2_FXP_STATUS %u", status);
1711 
1712 			/* Find the request in our queue */
1713 			for (ack = TAILQ_FIRST(&acks);
1714 			    ack != NULL && ack->id != rid;
1715 			    ack = TAILQ_NEXT(ack, tq))
1716 				;
1717 			if (ack == NULL)
1718 				fatal("Can't find request for ID %u", rid);
1719 			TAILQ_REMOVE(&acks, ack, tq);
1720 			debug3("In write loop, ack for %u %u bytes at %lld",
1721 			    ack->id, ack->len, (long long)ack->offset);
1722 			++ackid;
1723 			progress_counter += ack->len;
1724 			free(ack);
1725 		}
1726 		offset += len;
1727 		if (offset < 0)
1728 			fatal("%s: offset < 0", __func__);
1729 	}
1730 	sshbuf_free(msg);
1731 
1732 	if (showprogress)
1733 		stop_progress_meter();
1734 	free(data);
1735 
1736 	if (status != SSH2_FX_OK) {
1737 		error("Couldn't write to remote file \"%s\": %s",
1738 		    remote_path, fx2txt(status));
1739 		status = SSH2_FX_FAILURE;
1740 	}
1741 
1742 	if (close(local_fd) == -1) {
1743 		error("Couldn't close local file \"%s\": %s", local_path,
1744 		    strerror(errno));
1745 		status = SSH2_FX_FAILURE;
1746 	}
1747 
1748 	/* Override umask and utimes if asked */
1749 	if (preserve_flag)
1750 		do_fsetstat(conn, handle, handle_len, &a);
1751 
1752 	if (fsync_flag)
1753 		(void)do_fsync(conn, handle, handle_len);
1754 
1755 	if (do_close(conn, handle, handle_len) != 0)
1756 		status = SSH2_FX_FAILURE;
1757 
1758 	free(handle);
1759 
1760 	return status == SSH2_FX_OK ? 0 : -1;
1761 }
1762 
1763 static int
1764 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1765     int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
1766 {
1767 	int ret = 0;
1768 	DIR *dirp;
1769 	struct dirent *dp;
1770 	char *filename, *new_src, *new_dst;
1771 	struct stat sb;
1772 	Attrib a, *dirattrib;
1773 
1774 	if (depth >= MAX_DIR_DEPTH) {
1775 		error("Maximum directory depth exceeded: %d levels", depth);
1776 		return -1;
1777 	}
1778 
1779 	if (stat(src, &sb) == -1) {
1780 		error("Couldn't stat directory \"%s\": %s",
1781 		    src, strerror(errno));
1782 		return -1;
1783 	}
1784 	if (!S_ISDIR(sb.st_mode)) {
1785 		error("\"%s\" is not a directory", src);
1786 		return -1;
1787 	}
1788 	if (print_flag)
1789 		mprintf("Entering %s\n", src);
1790 
1791 	attrib_clear(&a);
1792 	stat_to_attrib(&sb, &a);
1793 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1794 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1795 	a.perm &= 01777;
1796 	if (!preserve_flag)
1797 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1798 
1799 	/*
1800 	 * sftp lacks a portable status value to match errno EEXIST,
1801 	 * so if we get a failure back then we must check whether
1802 	 * the path already existed and is a directory.
1803 	 */
1804 	if (do_mkdir(conn, dst, &a, 0) != 0) {
1805 		if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
1806 			return -1;
1807 		if (!S_ISDIR(dirattrib->perm)) {
1808 			error("\"%s\" exists but is not a directory", dst);
1809 			return -1;
1810 		}
1811 	}
1812 
1813 	if ((dirp = opendir(src)) == NULL) {
1814 		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1815 		return -1;
1816 	}
1817 
1818 	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1819 		if (dp->d_ino == 0)
1820 			continue;
1821 		filename = dp->d_name;
1822 		new_dst = path_append(dst, filename);
1823 		new_src = path_append(src, filename);
1824 
1825 		if (lstat(new_src, &sb) == -1) {
1826 			logit("%s: lstat failed: %s", filename,
1827 			    strerror(errno));
1828 			ret = -1;
1829 		} else if (S_ISDIR(sb.st_mode)) {
1830 			if (strcmp(filename, ".") == 0 ||
1831 			    strcmp(filename, "..") == 0)
1832 				continue;
1833 
1834 			if (upload_dir_internal(conn, new_src, new_dst,
1835 			    depth + 1, preserve_flag, print_flag, resume,
1836 			    fsync_flag) == -1)
1837 				ret = -1;
1838 		} else if (S_ISREG(sb.st_mode)) {
1839 			if (do_upload(conn, new_src, new_dst,
1840 			    preserve_flag, resume, fsync_flag) == -1) {
1841 				error("Uploading of file %s to %s failed!",
1842 				    new_src, new_dst);
1843 				ret = -1;
1844 			}
1845 		} else
1846 			logit("%s: not a regular file\n", filename);
1847 		free(new_dst);
1848 		free(new_src);
1849 	}
1850 
1851 	do_setstat(conn, dst, &a);
1852 
1853 	(void) closedir(dirp);
1854 	return ret;
1855 }
1856 
1857 int
1858 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
1859     int preserve_flag, int print_flag, int resume, int fsync_flag)
1860 {
1861 	char *dst_canon;
1862 	int ret;
1863 
1864 	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1865 		error("Unable to canonicalize path \"%s\"", dst);
1866 		return -1;
1867 	}
1868 
1869 	ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1870 	    print_flag, resume, fsync_flag);
1871 
1872 	free(dst_canon);
1873 	return ret;
1874 }
1875 
1876 char *
1877 path_append(const char *p1, const char *p2)
1878 {
1879 	char *ret;
1880 	size_t len = strlen(p1) + strlen(p2) + 2;
1881 
1882 	ret = xmalloc(len);
1883 	strlcpy(ret, p1, len);
1884 	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1885 		strlcat(ret, "/", len);
1886 	strlcat(ret, p2, len);
1887 
1888 	return(ret);
1889 }
1890 
1891