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