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