xref: /netbsd-src/crypto/external/bsd/openssh/dist/sftp-client.c (revision 63aea4bd5b445e491ff0389fe27ec78b3099dba3)
1 /*	$NetBSD: sftp-client.c,v 1.14 2015/07/03 01:00:00 christos Exp $	*/
2 /* $OpenBSD: sftp-client.c,v 1.120 2015/05/28 04:50:53 djm 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.14 2015/07/03 01:00:00 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 
53 #include "sftp.h"
54 #include "sftp-common.h"
55 #include "sftp-client.h"
56 
57 extern volatile sig_atomic_t interrupted;
58 extern int showprogress;
59 
60 /* Minimum amount of data to read at a time */
61 #define MIN_READ_SIZE	512
62 
63 /* Maximum depth to descend in directory trees */
64 #define MAX_DIR_DEPTH 64
65 
66 struct sftp_conn {
67 	int fd_in;
68 	int fd_out;
69 	u_int transfer_buflen;
70 	u_int num_requests;
71 	u_int version;
72 	u_int msg_id;
73 #define SFTP_EXT_POSIX_RENAME	0x00000001
74 #define SFTP_EXT_STATVFS	0x00000002
75 #define SFTP_EXT_FSTATVFS	0x00000004
76 #define SFTP_EXT_HARDLINK	0x00000008
77 #define SFTP_EXT_FSYNC		0x00000010
78 	u_int exts;
79 	u_int64_t limit_kbps;
80 	struct bwlimit bwlimit_in, bwlimit_out;
81 };
82 
83 static u_char *
84 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
85     const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
86 
87 /* ARGSUSED */
88 static int
89 sftpio(void *_bwlimit, size_t amount)
90 {
91 	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
92 
93 	bandwidth_limit(bwlimit, amount);
94 	return 0;
95 }
96 
97 static void
98 send_msg(struct sftp_conn *conn, struct sshbuf *m)
99 {
100 	u_char mlen[4];
101 	struct iovec iov[2];
102 
103 	if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
104 		fatal("Outbound message too long %zu", sshbuf_len(m));
105 
106 	/* Send length first */
107 	put_u32(mlen, sshbuf_len(m));
108 	iov[0].iov_base = mlen;
109 	iov[0].iov_len = sizeof(mlen);
110 	iov[1].iov_base = __UNCONST(sshbuf_ptr(m));
111 	iov[1].iov_len = sshbuf_len(m);
112 
113 	if (atomiciov6(writev, conn->fd_out, iov, 2,
114 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
115 	    sshbuf_len(m) + sizeof(mlen))
116 		fatal("Couldn't send packet: %s", strerror(errno));
117 
118 	sshbuf_reset(m);
119 }
120 
121 static void
122 get_msg(struct sftp_conn *conn, struct sshbuf *m)
123 {
124 	u_int msg_len;
125 	u_char *p;
126 	int r;
127 
128 	if ((r = sshbuf_reserve(m, 4, &p)) != 0)
129 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
130 	if (atomicio6(read, conn->fd_in, p, 4,
131 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
132 		if (errno == EPIPE)
133 			fatal("Connection closed");
134 		else
135 			fatal("Couldn't read packet: %s", strerror(errno));
136 	}
137 
138 	if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
139 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
140 	if (msg_len > SFTP_MAX_MSG_LENGTH)
141 		fatal("Received message too long %u", msg_len);
142 
143 	if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
144 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
145 	if (atomicio6(read, conn->fd_in, p, msg_len,
146 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
147 	    != msg_len) {
148 		if (errno == EPIPE)
149 			fatal("Connection closed");
150 		else
151 			fatal("Read packet: %s", strerror(errno));
152 	}
153 }
154 
155 static void
156 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
157     u_int len)
158 {
159 	struct sshbuf *msg;
160 	int r;
161 
162 	if ((msg = sshbuf_new()) == NULL)
163 		fatal("%s: sshbuf_new failed", __func__);
164 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
165 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
166 	    (r = sshbuf_put_string(msg, s, len)) != 0)
167 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
168 	send_msg(conn, msg);
169 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
170 	sshbuf_free(msg);
171 }
172 
173 static void
174 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
175     const void *s, u_int len, Attrib *a)
176 {
177 	struct sshbuf *msg;
178 	int r;
179 
180 	if ((msg = sshbuf_new()) == NULL)
181 		fatal("%s: sshbuf_new failed", __func__);
182 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
183 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
184 	    (r = sshbuf_put_string(msg, s, len)) != 0 ||
185 	    (r = encode_attrib(msg, a)) != 0)
186 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
187 	send_msg(conn, msg);
188 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
189 	sshbuf_free(msg);
190 }
191 
192 static u_int
193 get_status(struct sftp_conn *conn, u_int expected_id)
194 {
195 	struct sshbuf *msg;
196 	u_char type;
197 	u_int id, status;
198 	int r;
199 
200 	if ((msg = sshbuf_new()) == NULL)
201 		fatal("%s: sshbuf_new failed", __func__);
202 	get_msg(conn, msg);
203 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
204 	    (r = sshbuf_get_u32(msg, &id)) != 0)
205 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
206 
207 	if (id != expected_id)
208 		fatal("ID mismatch (%u != %u)", id, expected_id);
209 	if (type != SSH2_FXP_STATUS)
210 		fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
211 		    SSH2_FXP_STATUS, type);
212 
213 	if ((r = sshbuf_get_u32(msg, &status)) != 0)
214 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
215 	sshbuf_free(msg);
216 
217 	debug3("SSH2_FXP_STATUS %u", status);
218 
219 	return status;
220 }
221 
222 static u_char *
223 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
224     const char *errfmt, ...)
225 {
226 	struct sshbuf *msg;
227 	u_int id, status;
228 	u_char type;
229 	u_char *handle;
230 	char errmsg[256];
231 	va_list args;
232 	int r;
233 
234 	va_start(args, errfmt);
235 	if (errfmt != NULL)
236 		vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
237 	va_end(args);
238 
239 	if ((msg = sshbuf_new()) == NULL)
240 		fatal("%s: sshbuf_new failed", __func__);
241 	get_msg(conn, msg);
242 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
243 	    (r = sshbuf_get_u32(msg, &id)) != 0)
244 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
245 
246 	if (id != expected_id)
247 		fatal("%s: ID mismatch (%u != %u)",
248 		    errfmt == NULL ? __func__ : errmsg, id, expected_id);
249 	if (type == SSH2_FXP_STATUS) {
250 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
251 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
252 		if (errfmt != NULL)
253 			error("%s: %s", errmsg, fx2txt(status));
254 		sshbuf_free(msg);
255 		return(NULL);
256 	} else if (type != SSH2_FXP_HANDLE)
257 		fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
258 		    errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
259 
260 	if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
261 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
262 	sshbuf_free(msg);
263 
264 	return handle;
265 }
266 
267 static Attrib *
268 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
269 {
270 	struct sshbuf *msg;
271 	u_int id;
272 	u_char type;
273 	int r;
274 	static Attrib a;
275 
276 	if ((msg = sshbuf_new()) == NULL)
277 		fatal("%s: sshbuf_new failed", __func__);
278 	get_msg(conn, msg);
279 
280 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
281 	    (r = sshbuf_get_u32(msg, &id)) != 0)
282 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
283 
284 	debug3("Received stat reply T:%u I:%u", type, id);
285 	if (id != expected_id)
286 		fatal("ID mismatch (%u != %u)", id, expected_id);
287 	if (type == SSH2_FXP_STATUS) {
288 		u_int status;
289 
290 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
291 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
292 		if (quiet)
293 			debug("Couldn't stat remote file: %s", fx2txt(status));
294 		else
295 			error("Couldn't stat remote file: %s", fx2txt(status));
296 		sshbuf_free(msg);
297 		return(NULL);
298 	} else if (type != SSH2_FXP_ATTRS) {
299 		fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
300 		    SSH2_FXP_ATTRS, type);
301 	}
302 	if ((r = decode_attrib(msg, &a)) != 0) {
303 		error("%s: couldn't decode attrib: %s", __func__, ssh_err(r));
304 		sshbuf_free(msg);
305 		return NULL;
306 	}
307 	sshbuf_free(msg);
308 
309 	return &a;
310 }
311 
312 static int
313 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
314     u_int expected_id, int quiet)
315 {
316 	struct sshbuf *msg;
317 	u_char type;
318 	u_int id;
319 	u_int64_t flag;
320 	int r;
321 
322 	if ((msg = sshbuf_new()) == NULL)
323 		fatal("%s: sshbuf_new failed", __func__);
324 	get_msg(conn, msg);
325 
326 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
327 	    (r = sshbuf_get_u32(msg, &id)) != 0)
328 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
329 
330 	debug3("Received statvfs reply T:%u I:%u", type, id);
331 	if (id != expected_id)
332 		fatal("ID mismatch (%u != %u)", id, expected_id);
333 	if (type == SSH2_FXP_STATUS) {
334 		u_int status;
335 
336 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
337 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
338 		if (quiet)
339 			debug("Couldn't statvfs: %s", fx2txt(status));
340 		else
341 			error("Couldn't statvfs: %s", fx2txt(status));
342 		sshbuf_free(msg);
343 		return -1;
344 	} else if (type != SSH2_FXP_EXTENDED_REPLY) {
345 		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
346 		    SSH2_FXP_EXTENDED_REPLY, type);
347 	}
348 
349 	memset(st, 0, sizeof(*st));
350 	if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
351 	    (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
352 	    (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
353 	    (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
354 	    (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
355 	    (r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
356 	    (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
357 	    (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
358 	    (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
359 	    (r = sshbuf_get_u64(msg, &flag)) != 0 ||
360 	    (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
361 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
362 
363 	st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
364 	st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
365 
366 	sshbuf_free(msg);
367 
368 	return 0;
369 }
370 
371 struct sftp_conn *
372 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
373     u_int64_t limit_kbps)
374 {
375 	u_char type;
376 	struct sshbuf *msg;
377 	struct sftp_conn *ret;
378 	int r;
379 
380 	ret = xcalloc(1, sizeof(*ret));
381 	ret->msg_id = 1;
382 	ret->fd_in = fd_in;
383 	ret->fd_out = fd_out;
384 	ret->transfer_buflen = transfer_buflen;
385 	ret->num_requests = num_requests;
386 	ret->exts = 0;
387 	ret->limit_kbps = 0;
388 
389 	if ((msg = sshbuf_new()) == NULL)
390 		fatal("%s: sshbuf_new failed", __func__);
391 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
392 	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
393 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
394 	send_msg(ret, msg);
395 
396 	sshbuf_reset(msg);
397 
398 	get_msg(ret, msg);
399 
400 	/* Expecting a VERSION reply */
401 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
402 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
403 	if (type != SSH2_FXP_VERSION) {
404 		error("Invalid packet back from SSH2_FXP_INIT (type %u)",
405 		    type);
406 		sshbuf_free(msg);
407 		free(ret);
408 		return(NULL);
409 	}
410 	if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
411 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
412 
413 	debug2("Remote version: %u", ret->version);
414 
415 	/* Check for extensions */
416 	while (sshbuf_len(msg) > 0) {
417 		char *name;
418 		u_char *value;
419 		size_t vlen;
420 		int known = 0;
421 
422 		if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
423 		    (r = sshbuf_get_string(msg, &value, &vlen)) != 0)
424 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
425 		if (strcmp(name, "posix-rename@openssh.com") == 0 &&
426 		    strcmp((char *)value, "1") == 0) {
427 			ret->exts |= SFTP_EXT_POSIX_RENAME;
428 			known = 1;
429 		} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
430 		    strcmp((char *)value, "2") == 0) {
431 			ret->exts |= SFTP_EXT_STATVFS;
432 			known = 1;
433 		} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
434 		    strcmp((char *)value, "2") == 0) {
435 			ret->exts |= SFTP_EXT_FSTATVFS;
436 			known = 1;
437 		} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
438 		    strcmp((char *)value, "1") == 0) {
439 			ret->exts |= SFTP_EXT_HARDLINK;
440 			known = 1;
441 		} else if (strcmp(name, "fsync@openssh.com") == 0 &&
442 		    strcmp((char *)value, "1") == 0) {
443 			ret->exts |= SFTP_EXT_FSYNC;
444 			known = 1;
445 		}
446 		if (known) {
447 			debug2("Server supports extension \"%s\" revision %s",
448 			    name, value);
449 		} else {
450 			debug2("Unrecognised server extension \"%s\"", name);
451 		}
452 		free(name);
453 		free(value);
454 	}
455 
456 	sshbuf_free(msg);
457 
458 	/* Some filexfer v.0 servers don't support large packets */
459 	if (ret->version == 0)
460 		ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
461 
462 	ret->limit_kbps = limit_kbps;
463 	if (ret->limit_kbps > 0) {
464 		bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
465 		    ret->transfer_buflen);
466 		bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
467 		    ret->transfer_buflen);
468 	}
469 
470 	return ret;
471 }
472 
473 u_int
474 sftp_proto_version(struct sftp_conn *conn)
475 {
476 	return conn->version;
477 }
478 
479 int
480 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
481 {
482 	u_int id, status;
483 	struct sshbuf *msg;
484 	int r;
485 
486 	if ((msg = sshbuf_new()) == NULL)
487 		fatal("%s: sshbuf_new failed", __func__);
488 
489 	id = conn->msg_id++;
490 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_CLOSE)) != 0 ||
491 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
492 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
493 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
494 	send_msg(conn, msg);
495 	debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
496 
497 	status = get_status(conn, id);
498 	if (status != SSH2_FX_OK)
499 		error("Couldn't close file: %s", fx2txt(status));
500 
501 	sshbuf_free(msg);
502 
503 	return status == SSH2_FX_OK ? 0 : -1;
504 }
505 
506 
507 static int
508 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
509     SFTP_DIRENT ***dir)
510 {
511 	struct sshbuf *msg;
512 	u_int count, id, i, expected_id, ents = 0;
513 	size_t handle_len;
514 	u_char type;
515 	char *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 				printf("%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 		printf("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) != SSH2_FX_OK)
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 	u_int status;
1769 	DIR *dirp;
1770 	struct dirent *dp;
1771 	char *filename, *new_src, *new_dst;
1772 	struct stat sb;
1773 	Attrib a;
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 	status = do_mkdir(conn, dst, &a, 0);
1801 	/*
1802 	 * we lack a portable status for errno EEXIST,
1803 	 * so if we get a SSH2_FX_FAILURE back we must check
1804 	 * if it was created successfully.
1805 	 */
1806 	if (status != SSH2_FX_OK) {
1807 		if (status != SSH2_FX_FAILURE)
1808 			return -1;
1809 		if (do_stat(conn, dst, 0) == NULL)
1810 			return -1;
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