xref: /openbsd/usr.bin/ssh/sftp-client.c (revision e5dd7070)
1 /* $OpenBSD: sftp-client.c,v 1.136 2020/05/15 03:57:33 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 	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 				goto out;
621 			}
622 
623 			if (print_flag)
624 				mprintf("%s\n", longname);
625 
626 			/*
627 			 * Directory entries should never contain '/'
628 			 * These can be used to attack recursive ops
629 			 * (e.g. send '../../../../etc/passwd')
630 			 */
631 			if (strchr(filename, '/') != NULL) {
632 				error("Server sent suspect path \"%s\" "
633 				    "during readdir of \"%s\"", filename, path);
634 			} else if (dir) {
635 				*dir = xreallocarray(*dir, ents + 2, sizeof(**dir));
636 				(*dir)[ents] = xcalloc(1, sizeof(***dir));
637 				(*dir)[ents]->filename = xstrdup(filename);
638 				(*dir)[ents]->longname = xstrdup(longname);
639 				memcpy(&(*dir)[ents]->a, &a, sizeof(a));
640 				(*dir)[++ents] = NULL;
641 			}
642 			free(filename);
643 			free(longname);
644 		}
645 	}
646 	status = 0;
647 
648  out:
649 	sshbuf_free(msg);
650 	do_close(conn, handle, handle_len);
651 	free(handle);
652 
653 	if (status != 0 && dir != NULL) {
654 		/* Don't return results on error */
655 		free_sftp_dirents(*dir);
656 		*dir = NULL;
657 	} else if (interrupted && dir != NULL && *dir != NULL) {
658 		/* Don't return partial matches on interrupt */
659 		free_sftp_dirents(*dir);
660 		*dir = xcalloc(1, sizeof(**dir));
661 		**dir = NULL;
662 	}
663 
664 	return status == SSH2_FX_OK ? 0 : -1;
665 }
666 
667 int
668 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
669 {
670 	return(do_lsreaddir(conn, path, 0, dir));
671 }
672 
673 void free_sftp_dirents(SFTP_DIRENT **s)
674 {
675 	int i;
676 
677 	if (s == NULL)
678 		return;
679 	for (i = 0; s[i]; i++) {
680 		free(s[i]->filename);
681 		free(s[i]->longname);
682 		free(s[i]);
683 	}
684 	free(s);
685 }
686 
687 int
688 do_rm(struct sftp_conn *conn, const char *path)
689 {
690 	u_int status, id;
691 
692 	debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
693 
694 	id = conn->msg_id++;
695 	send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
696 	status = get_status(conn, id);
697 	if (status != SSH2_FX_OK)
698 		error("Couldn't delete file: %s", fx2txt(status));
699 	return status == SSH2_FX_OK ? 0 : -1;
700 }
701 
702 int
703 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
704 {
705 	u_int status, id;
706 
707 	id = conn->msg_id++;
708 	send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
709 	    strlen(path), a);
710 
711 	status = get_status(conn, id);
712 	if (status != SSH2_FX_OK && print_flag)
713 		error("Couldn't create directory: %s", fx2txt(status));
714 
715 	return status == SSH2_FX_OK ? 0 : -1;
716 }
717 
718 int
719 do_rmdir(struct sftp_conn *conn, const char *path)
720 {
721 	u_int status, id;
722 
723 	id = conn->msg_id++;
724 	send_string_request(conn, id, SSH2_FXP_RMDIR, path,
725 	    strlen(path));
726 
727 	status = get_status(conn, id);
728 	if (status != SSH2_FX_OK)
729 		error("Couldn't remove directory: %s", fx2txt(status));
730 
731 	return status == SSH2_FX_OK ? 0 : -1;
732 }
733 
734 Attrib *
735 do_stat(struct sftp_conn *conn, const char *path, int quiet)
736 {
737 	u_int id;
738 
739 	id = conn->msg_id++;
740 
741 	send_string_request(conn, id,
742 	    conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
743 	    path, strlen(path));
744 
745 	return(get_decode_stat(conn, id, quiet));
746 }
747 
748 Attrib *
749 do_lstat(struct sftp_conn *conn, const char *path, int quiet)
750 {
751 	u_int id;
752 
753 	if (conn->version == 0) {
754 		if (quiet)
755 			debug("Server version does not support lstat operation");
756 		else
757 			logit("Server version does not support lstat operation");
758 		return(do_stat(conn, path, quiet));
759 	}
760 
761 	id = conn->msg_id++;
762 	send_string_request(conn, id, SSH2_FXP_LSTAT, path,
763 	    strlen(path));
764 
765 	return(get_decode_stat(conn, id, quiet));
766 }
767 
768 #ifdef notyet
769 Attrib *
770 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
771     int quiet)
772 {
773 	u_int id;
774 
775 	id = conn->msg_id++;
776 	send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
777 	    handle_len);
778 
779 	return(get_decode_stat(conn, id, quiet));
780 }
781 #endif
782 
783 int
784 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
785 {
786 	u_int status, id;
787 
788 	id = conn->msg_id++;
789 	send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
790 	    strlen(path), a);
791 
792 	status = get_status(conn, id);
793 	if (status != SSH2_FX_OK)
794 		error("Couldn't setstat on \"%s\": %s", path,
795 		    fx2txt(status));
796 
797 	return status == SSH2_FX_OK ? 0 : -1;
798 }
799 
800 int
801 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
802     Attrib *a)
803 {
804 	u_int status, id;
805 
806 	id = conn->msg_id++;
807 	send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
808 	    handle_len, a);
809 
810 	status = get_status(conn, id);
811 	if (status != SSH2_FX_OK)
812 		error("Couldn't fsetstat: %s", fx2txt(status));
813 
814 	return status == SSH2_FX_OK ? 0 : -1;
815 }
816 
817 char *
818 do_realpath(struct sftp_conn *conn, const char *path)
819 {
820 	struct sshbuf *msg;
821 	u_int expected_id, count, id;
822 	char *filename, *longname;
823 	Attrib a;
824 	u_char type;
825 	int r;
826 
827 	expected_id = id = conn->msg_id++;
828 	send_string_request(conn, id, SSH2_FXP_REALPATH, path,
829 	    strlen(path));
830 
831 	if ((msg = sshbuf_new()) == NULL)
832 		fatal("%s: sshbuf_new failed", __func__);
833 
834 	get_msg(conn, msg);
835 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
836 	    (r = sshbuf_get_u32(msg, &id)) != 0)
837 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
838 
839 	if (id != expected_id)
840 		fatal("ID mismatch (%u != %u)", id, expected_id);
841 
842 	if (type == SSH2_FXP_STATUS) {
843 		u_int status;
844 
845 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
846 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
847 		error("Couldn't canonicalize: %s", fx2txt(status));
848 		sshbuf_free(msg);
849 		return NULL;
850 	} else if (type != SSH2_FXP_NAME)
851 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
852 		    SSH2_FXP_NAME, type);
853 
854 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
855 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
856 	if (count != 1)
857 		fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
858 
859 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
860 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
861 	    (r = decode_attrib(msg, &a)) != 0)
862 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
863 
864 	debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
865 	    (unsigned long)a.size);
866 
867 	free(longname);
868 
869 	sshbuf_free(msg);
870 
871 	return(filename);
872 }
873 
874 int
875 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
876     int force_legacy)
877 {
878 	struct sshbuf *msg;
879 	u_int status, id;
880 	int r, use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
881 
882 	if ((msg = sshbuf_new()) == NULL)
883 		fatal("%s: sshbuf_new failed", __func__);
884 
885 	/* Send rename request */
886 	id = conn->msg_id++;
887 	if (use_ext) {
888 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
889 		    (r = sshbuf_put_u32(msg, id)) != 0 ||
890 		    (r = sshbuf_put_cstring(msg,
891 		    "posix-rename@openssh.com")) != 0)
892 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
893 	} else {
894 		if ((r = sshbuf_put_u8(msg, SSH2_FXP_RENAME)) != 0 ||
895 		    (r = sshbuf_put_u32(msg, id)) != 0)
896 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
897 	}
898 	if ((r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
899 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
900 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
901 	send_msg(conn, msg);
902 	debug3("Sent message %s \"%s\" -> \"%s\"",
903 	    use_ext ? "posix-rename@openssh.com" :
904 	    "SSH2_FXP_RENAME", oldpath, newpath);
905 	sshbuf_free(msg);
906 
907 	status = get_status(conn, id);
908 	if (status != SSH2_FX_OK)
909 		error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
910 		    newpath, fx2txt(status));
911 
912 	return status == SSH2_FX_OK ? 0 : -1;
913 }
914 
915 int
916 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
917 {
918 	struct sshbuf *msg;
919 	u_int status, id;
920 	int r;
921 
922 	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
923 		error("Server does not support hardlink@openssh.com extension");
924 		return -1;
925 	}
926 
927 	if ((msg = sshbuf_new()) == NULL)
928 		fatal("%s: sshbuf_new failed", __func__);
929 
930 	/* Send link request */
931 	id = conn->msg_id++;
932 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
933 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
934 	    (r = sshbuf_put_cstring(msg, "hardlink@openssh.com")) != 0 ||
935 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
936 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
937 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
938 	send_msg(conn, msg);
939 	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
940 	       oldpath, newpath);
941 	sshbuf_free(msg);
942 
943 	status = get_status(conn, id);
944 	if (status != SSH2_FX_OK)
945 		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
946 		    newpath, fx2txt(status));
947 
948 	return status == SSH2_FX_OK ? 0 : -1;
949 }
950 
951 int
952 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
953 {
954 	struct sshbuf *msg;
955 	u_int status, id;
956 	int r;
957 
958 	if (conn->version < 3) {
959 		error("This server does not support the symlink operation");
960 		return(SSH2_FX_OP_UNSUPPORTED);
961 	}
962 
963 	if ((msg = sshbuf_new()) == NULL)
964 		fatal("%s: sshbuf_new failed", __func__);
965 
966 	/* Send symlink request */
967 	id = conn->msg_id++;
968 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_SYMLINK)) != 0 ||
969 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
970 	    (r = sshbuf_put_cstring(msg, oldpath)) != 0 ||
971 	    (r = sshbuf_put_cstring(msg, newpath)) != 0)
972 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
973 	send_msg(conn, msg);
974 	debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
975 	    newpath);
976 	sshbuf_free(msg);
977 
978 	status = get_status(conn, id);
979 	if (status != SSH2_FX_OK)
980 		error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
981 		    newpath, fx2txt(status));
982 
983 	return status == SSH2_FX_OK ? 0 : -1;
984 }
985 
986 int
987 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
988 {
989 	struct sshbuf *msg;
990 	u_int status, id;
991 	int r;
992 
993 	/* Silently return if the extension is not supported */
994 	if ((conn->exts & SFTP_EXT_FSYNC) == 0)
995 		return -1;
996 
997 	/* Send fsync request */
998 	if ((msg = sshbuf_new()) == NULL)
999 		fatal("%s: sshbuf_new failed", __func__);
1000 	id = conn->msg_id++;
1001 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1002 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1003 	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
1004 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1005 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1006 	send_msg(conn, msg);
1007 	debug3("Sent message fsync@openssh.com I:%u", id);
1008 	sshbuf_free(msg);
1009 
1010 	status = get_status(conn, id);
1011 	if (status != SSH2_FX_OK)
1012 		error("Couldn't sync file: %s", fx2txt(status));
1013 
1014 	return status == SSH2_FX_OK ? 0 : -1;
1015 }
1016 
1017 #ifdef notyet
1018 char *
1019 do_readlink(struct sftp_conn *conn, const char *path)
1020 {
1021 	struct sshbuf *msg;
1022 	u_int expected_id, count, id;
1023 	char *filename, *longname;
1024 	Attrib a;
1025 	u_char type;
1026 	int r;
1027 
1028 	expected_id = id = conn->msg_id++;
1029 	send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
1030 
1031 	if ((msg = sshbuf_new()) == NULL)
1032 		fatal("%s: sshbuf_new failed", __func__);
1033 
1034 	get_msg(conn, msg);
1035 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1036 	    (r = sshbuf_get_u32(msg, &id)) != 0)
1037 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1038 
1039 	if (id != expected_id)
1040 		fatal("ID mismatch (%u != %u)", id, expected_id);
1041 
1042 	if (type == SSH2_FXP_STATUS) {
1043 		u_int status;
1044 
1045 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
1046 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1047 		error("Couldn't readlink: %s", fx2txt(status));
1048 		sshbuf_free(msg);
1049 		return(NULL);
1050 	} else if (type != SSH2_FXP_NAME)
1051 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
1052 		    SSH2_FXP_NAME, type);
1053 
1054 	if ((r = sshbuf_get_u32(msg, &count)) != 0)
1055 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1056 	if (count != 1)
1057 		fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
1058 
1059 	if ((r = sshbuf_get_cstring(msg, &filename, NULL)) != 0 ||
1060 	    (r = sshbuf_get_cstring(msg, &longname, NULL)) != 0 ||
1061 	    (r = decode_attrib(msg, &a)) != 0)
1062 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1063 
1064 	debug3("SSH_FXP_READLINK %s -> %s", path, filename);
1065 
1066 	free(longname);
1067 
1068 	sshbuf_free(msg);
1069 
1070 	return filename;
1071 }
1072 #endif
1073 
1074 int
1075 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
1076     int quiet)
1077 {
1078 	struct sshbuf *msg;
1079 	u_int id;
1080 	int r;
1081 
1082 	if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
1083 		error("Server does not support statvfs@openssh.com extension");
1084 		return -1;
1085 	}
1086 
1087 	id = conn->msg_id++;
1088 
1089 	if ((msg = sshbuf_new()) == NULL)
1090 		fatal("%s: sshbuf_new failed", __func__);
1091 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1092 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1093 	    (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1094 	    (r = sshbuf_put_cstring(msg, path)) != 0)
1095 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1096 	send_msg(conn, msg);
1097 	sshbuf_free(msg);
1098 
1099 	return get_decode_statvfs(conn, st, id, quiet);
1100 }
1101 
1102 #ifdef notyet
1103 int
1104 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
1105     struct sftp_statvfs *st, int quiet)
1106 {
1107 	struct sshbuf *msg;
1108 	u_int id;
1109 
1110 	if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
1111 		error("Server does not support fstatvfs@openssh.com extension");
1112 		return -1;
1113 	}
1114 
1115 	id = conn->msg_id++;
1116 
1117 	if ((msg = sshbuf_new()) == NULL)
1118 		fatal("%s: sshbuf_new failed", __func__);
1119 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1120 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1121 	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1122 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1123 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1124 	send_msg(conn, msg);
1125 	sshbuf_free(msg);
1126 
1127 	return get_decode_statvfs(conn, st, id, quiet);
1128 }
1129 #endif
1130 
1131 int
1132 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
1133 {
1134 	struct sshbuf *msg;
1135 	u_int status, id;
1136 	int r;
1137 
1138 	if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
1139 		error("Server does not support lsetstat@openssh.com extension");
1140 		return -1;
1141 	}
1142 
1143 	id = conn->msg_id++;
1144 	if ((msg = sshbuf_new()) == NULL)
1145 		fatal("%s: sshbuf_new failed", __func__);
1146 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1147 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1148 	    (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
1149 	    (r = sshbuf_put_cstring(msg, path)) != 0 ||
1150 	    (r = encode_attrib(msg, a)) != 0)
1151 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1152 	send_msg(conn, msg);
1153 	sshbuf_free(msg);
1154 
1155 	status = get_status(conn, id);
1156 	if (status != SSH2_FX_OK)
1157 		error("Couldn't setstat on \"%s\": %s", path,
1158 		    fx2txt(status));
1159 
1160 	return status == SSH2_FX_OK ? 0 : -1;
1161 }
1162 
1163 static void
1164 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1165     u_int len, const u_char *handle, u_int handle_len)
1166 {
1167 	struct sshbuf *msg;
1168 	int r;
1169 
1170 	if ((msg = sshbuf_new()) == NULL)
1171 		fatal("%s: sshbuf_new failed", __func__);
1172 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1173 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1174 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1175 	    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1176 	    (r = sshbuf_put_u32(msg, len)) != 0)
1177 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1178 	send_msg(conn, msg);
1179 	sshbuf_free(msg);
1180 }
1181 
1182 int
1183 do_download(struct sftp_conn *conn, const char *remote_path,
1184     const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1185     int fsync_flag)
1186 {
1187 	Attrib junk;
1188 	struct sshbuf *msg;
1189 	u_char *handle;
1190 	int local_fd = -1, write_error;
1191 	int read_error, write_errno, lmodified = 0, reordered = 0, r;
1192 	u_int64_t offset = 0, size, highwater;
1193 	u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1194 	off_t progress_counter;
1195 	size_t handle_len;
1196 	struct stat st;
1197 	struct request {
1198 		u_int id;
1199 		size_t len;
1200 		u_int64_t offset;
1201 		TAILQ_ENTRY(request) tq;
1202 	};
1203 	TAILQ_HEAD(reqhead, request) requests;
1204 	struct request *req;
1205 	u_char type;
1206 
1207 	TAILQ_INIT(&requests);
1208 
1209 	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1210 		return -1;
1211 
1212 	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1213 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1214 		mode = a->perm & 0777;
1215 	else
1216 		mode = 0666;
1217 
1218 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1219 	    (!S_ISREG(a->perm))) {
1220 		error("Cannot download non-regular file: %s", remote_path);
1221 		return(-1);
1222 	}
1223 
1224 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1225 		size = a->size;
1226 	else
1227 		size = 0;
1228 
1229 	buflen = conn->transfer_buflen;
1230 	if ((msg = sshbuf_new()) == NULL)
1231 		fatal("%s: sshbuf_new failed", __func__);
1232 
1233 	attrib_clear(&junk); /* Send empty attributes */
1234 
1235 	/* Send open request */
1236 	id = conn->msg_id++;
1237 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1238 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1239 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1240 	    (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1241 	    (r = encode_attrib(msg, &junk)) != 0)
1242 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1243 	send_msg(conn, msg);
1244 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1245 
1246 	handle = get_handle(conn, id, &handle_len,
1247 	    "remote open(\"%s\")", remote_path);
1248 	if (handle == NULL) {
1249 		sshbuf_free(msg);
1250 		return(-1);
1251 	}
1252 
1253 	local_fd = open(local_path,
1254 	    O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
1255 	if (local_fd == -1) {
1256 		error("Couldn't open local file \"%s\" for writing: %s",
1257 		    local_path, strerror(errno));
1258 		goto fail;
1259 	}
1260 	offset = highwater = 0;
1261 	if (resume_flag) {
1262 		if (fstat(local_fd, &st) == -1) {
1263 			error("Unable to stat local file \"%s\": %s",
1264 			    local_path, strerror(errno));
1265 			goto fail;
1266 		}
1267 		if (st.st_size < 0) {
1268 			error("\"%s\" has negative size", local_path);
1269 			goto fail;
1270 		}
1271 		if ((u_int64_t)st.st_size > size) {
1272 			error("Unable to resume download of \"%s\": "
1273 			    "local file is larger than remote", local_path);
1274  fail:
1275 			do_close(conn, handle, handle_len);
1276 			sshbuf_free(msg);
1277 			free(handle);
1278 			if (local_fd != -1)
1279 				close(local_fd);
1280 			return -1;
1281 		}
1282 		offset = highwater = st.st_size;
1283 	}
1284 
1285 	/* Read from remote and write to local */
1286 	write_error = read_error = write_errno = num_req = 0;
1287 	max_req = 1;
1288 	progress_counter = offset;
1289 
1290 	if (showprogress && size != 0)
1291 		start_progress_meter(remote_path, size, &progress_counter);
1292 
1293 	while (num_req > 0 || max_req > 0) {
1294 		u_char *data;
1295 		size_t len;
1296 
1297 		/*
1298 		 * Simulate EOF on interrupt: stop sending new requests and
1299 		 * allow outstanding requests to drain gracefully
1300 		 */
1301 		if (interrupted) {
1302 			if (num_req == 0) /* If we haven't started yet... */
1303 				break;
1304 			max_req = 0;
1305 		}
1306 
1307 		/* Send some more requests */
1308 		while (num_req < max_req) {
1309 			debug3("Request range %llu -> %llu (%d/%d)",
1310 			    (unsigned long long)offset,
1311 			    (unsigned long long)offset + buflen - 1,
1312 			    num_req, max_req);
1313 			req = xcalloc(1, sizeof(*req));
1314 			req->id = conn->msg_id++;
1315 			req->len = buflen;
1316 			req->offset = offset;
1317 			offset += buflen;
1318 			num_req++;
1319 			TAILQ_INSERT_TAIL(&requests, req, tq);
1320 			send_read_request(conn, req->id, req->offset,
1321 			    req->len, handle, handle_len);
1322 		}
1323 
1324 		sshbuf_reset(msg);
1325 		get_msg(conn, msg);
1326 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1327 		    (r = sshbuf_get_u32(msg, &id)) != 0)
1328 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1329 		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1330 
1331 		/* Find the request in our queue */
1332 		for (req = TAILQ_FIRST(&requests);
1333 		    req != NULL && req->id != id;
1334 		    req = TAILQ_NEXT(req, tq))
1335 			;
1336 		if (req == NULL)
1337 			fatal("Unexpected reply %u", id);
1338 
1339 		switch (type) {
1340 		case SSH2_FXP_STATUS:
1341 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1342 				fatal("%s: buffer error: %s",
1343 				    __func__, ssh_err(r));
1344 			if (status != SSH2_FX_EOF)
1345 				read_error = 1;
1346 			max_req = 0;
1347 			TAILQ_REMOVE(&requests, req, tq);
1348 			free(req);
1349 			num_req--;
1350 			break;
1351 		case SSH2_FXP_DATA:
1352 			if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1353 				fatal("%s: buffer error: %s",
1354 				    __func__, ssh_err(r));
1355 			debug3("Received data %llu -> %llu",
1356 			    (unsigned long long)req->offset,
1357 			    (unsigned long long)req->offset + len - 1);
1358 			if (len > req->len)
1359 				fatal("Received more data than asked for "
1360 				    "%zu > %zu", len, req->len);
1361 			lmodified = 1;
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 (resume_flag && !lmodified)
1462 			logit("File \"%s\" was not modified", local_path);
1463 		else if (fsync_flag) {
1464 			debug("syncing \"%s\"", local_path);
1465 			if (fsync(local_fd) == -1)
1466 				error("Couldn't sync file \"%s\": %s",
1467 				    local_path, strerror(errno));
1468 		}
1469 	}
1470 	close(local_fd);
1471 	sshbuf_free(msg);
1472 	free(handle);
1473 
1474 	return status == SSH2_FX_OK ? 0 : -1;
1475 }
1476 
1477 static int
1478 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1479     int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1480     int resume_flag, int fsync_flag)
1481 {
1482 	int i, ret = 0;
1483 	SFTP_DIRENT **dir_entries;
1484 	char *filename, *new_src = NULL, *new_dst = NULL;
1485 	mode_t mode = 0777;
1486 
1487 	if (depth >= MAX_DIR_DEPTH) {
1488 		error("Maximum directory depth exceeded: %d levels", depth);
1489 		return -1;
1490 	}
1491 
1492 	if (dirattrib == NULL &&
1493 	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1494 		error("Unable to stat remote directory \"%s\"", src);
1495 		return -1;
1496 	}
1497 	if (!S_ISDIR(dirattrib->perm)) {
1498 		error("\"%s\" is not a directory", src);
1499 		return -1;
1500 	}
1501 	if (print_flag)
1502 		mprintf("Retrieving %s\n", src);
1503 
1504 	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1505 		mode = dirattrib->perm & 01777;
1506 	else {
1507 		debug("Server did not send permissions for "
1508 		    "directory \"%s\"", dst);
1509 	}
1510 
1511 	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1512 		error("mkdir %s: %s", dst, strerror(errno));
1513 		return -1;
1514 	}
1515 
1516 	if (do_readdir(conn, src, &dir_entries) == -1) {
1517 		error("%s: Failed to get directory contents", src);
1518 		return -1;
1519 	}
1520 
1521 	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1522 		free(new_dst);
1523 		free(new_src);
1524 
1525 		filename = dir_entries[i]->filename;
1526 		new_dst = path_append(dst, filename);
1527 		new_src = path_append(src, filename);
1528 
1529 		if (S_ISDIR(dir_entries[i]->a.perm)) {
1530 			if (strcmp(filename, ".") == 0 ||
1531 			    strcmp(filename, "..") == 0)
1532 				continue;
1533 			if (download_dir_internal(conn, new_src, new_dst,
1534 			    depth + 1, &(dir_entries[i]->a), preserve_flag,
1535 			    print_flag, resume_flag, fsync_flag) == -1)
1536 				ret = -1;
1537 		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1538 			if (do_download(conn, new_src, new_dst,
1539 			    &(dir_entries[i]->a), preserve_flag,
1540 			    resume_flag, fsync_flag) == -1) {
1541 				error("Download of file %s to %s failed",
1542 				    new_src, new_dst);
1543 				ret = -1;
1544 			}
1545 		} else
1546 			logit("%s: not a regular file\n", new_src);
1547 
1548 	}
1549 	free(new_dst);
1550 	free(new_src);
1551 
1552 	if (preserve_flag) {
1553 		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1554 			struct timeval tv[2];
1555 			tv[0].tv_sec = dirattrib->atime;
1556 			tv[1].tv_sec = dirattrib->mtime;
1557 			tv[0].tv_usec = tv[1].tv_usec = 0;
1558 			if (utimes(dst, tv) == -1)
1559 				error("Can't set times on \"%s\": %s",
1560 				    dst, strerror(errno));
1561 		} else
1562 			debug("Server did not send times for directory "
1563 			    "\"%s\"", dst);
1564 	}
1565 
1566 	free_sftp_dirents(dir_entries);
1567 
1568 	return ret;
1569 }
1570 
1571 int
1572 download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1573     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1574     int fsync_flag)
1575 {
1576 	char *src_canon;
1577 	int ret;
1578 
1579 	if ((src_canon = do_realpath(conn, src)) == NULL) {
1580 		error("Unable to canonicalize path \"%s\"", src);
1581 		return -1;
1582 	}
1583 
1584 	ret = download_dir_internal(conn, src_canon, dst, 0,
1585 	    dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1586 	free(src_canon);
1587 	return ret;
1588 }
1589 
1590 int
1591 do_upload(struct sftp_conn *conn, const char *local_path,
1592     const char *remote_path, int preserve_flag, int resume, int fsync_flag)
1593 {
1594 	int r, local_fd;
1595 	u_int status = SSH2_FX_OK;
1596 	u_int id;
1597 	u_char type;
1598 	off_t offset, progress_counter;
1599 	u_char *handle, *data;
1600 	struct sshbuf *msg;
1601 	struct stat sb;
1602 	Attrib a, *c = NULL;
1603 	u_int32_t startid;
1604 	u_int32_t ackid;
1605 	struct outstanding_ack {
1606 		u_int id;
1607 		u_int len;
1608 		off_t offset;
1609 		TAILQ_ENTRY(outstanding_ack) tq;
1610 	};
1611 	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1612 	struct outstanding_ack *ack = NULL;
1613 	size_t handle_len;
1614 
1615 	TAILQ_INIT(&acks);
1616 
1617 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1618 		error("Couldn't open local file \"%s\" for reading: %s",
1619 		    local_path, strerror(errno));
1620 		return(-1);
1621 	}
1622 	if (fstat(local_fd, &sb) == -1) {
1623 		error("Couldn't fstat local file \"%s\": %s",
1624 		    local_path, strerror(errno));
1625 		close(local_fd);
1626 		return(-1);
1627 	}
1628 	if (!S_ISREG(sb.st_mode)) {
1629 		error("%s is not a regular file", local_path);
1630 		close(local_fd);
1631 		return(-1);
1632 	}
1633 	stat_to_attrib(&sb, &a);
1634 
1635 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1636 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1637 	a.perm &= 0777;
1638 	if (!preserve_flag)
1639 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1640 
1641 	if (resume) {
1642 		/* Get remote file size if it exists */
1643 		if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1644 			close(local_fd);
1645 			return -1;
1646 		}
1647 
1648 		if ((off_t)c->size >= sb.st_size) {
1649 			error("destination file bigger or same size as "
1650 			      "source file");
1651 			close(local_fd);
1652 			return -1;
1653 		}
1654 
1655 		if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1656 			close(local_fd);
1657 			return -1;
1658 		}
1659 	}
1660 
1661 	if ((msg = sshbuf_new()) == NULL)
1662 		fatal("%s: sshbuf_new failed", __func__);
1663 
1664 	/* Send open request */
1665 	id = conn->msg_id++;
1666 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1667 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1668 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1669 	    (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1670 	    (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
1671 	    (r = encode_attrib(msg, &a)) != 0)
1672 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1673 	send_msg(conn, msg);
1674 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1675 
1676 	sshbuf_reset(msg);
1677 
1678 	handle = get_handle(conn, id, &handle_len,
1679 	    "remote open(\"%s\")", remote_path);
1680 	if (handle == NULL) {
1681 		close(local_fd);
1682 		sshbuf_free(msg);
1683 		return -1;
1684 	}
1685 
1686 	startid = ackid = id + 1;
1687 	data = xmalloc(conn->transfer_buflen);
1688 
1689 	/* Read from local and write to remote */
1690 	offset = progress_counter = (resume ? c->size : 0);
1691 	if (showprogress)
1692 		start_progress_meter(local_path, sb.st_size,
1693 		    &progress_counter);
1694 
1695 	for (;;) {
1696 		int len;
1697 
1698 		/*
1699 		 * Can't use atomicio here because it returns 0 on EOF,
1700 		 * thus losing the last block of the file.
1701 		 * Simulate an EOF on interrupt, allowing ACKs from the
1702 		 * server to drain.
1703 		 */
1704 		if (interrupted || status != SSH2_FX_OK)
1705 			len = 0;
1706 		else do
1707 			len = read(local_fd, data, conn->transfer_buflen);
1708 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1709 
1710 		if (len == -1)
1711 			fatal("Couldn't read from \"%s\": %s", local_path,
1712 			    strerror(errno));
1713 
1714 		if (len != 0) {
1715 			ack = xcalloc(1, sizeof(*ack));
1716 			ack->id = ++id;
1717 			ack->offset = offset;
1718 			ack->len = len;
1719 			TAILQ_INSERT_TAIL(&acks, ack, tq);
1720 
1721 			sshbuf_reset(msg);
1722 			if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
1723 			    (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
1724 			    (r = sshbuf_put_string(msg, handle,
1725 			    handle_len)) != 0 ||
1726 			    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1727 			    (r = sshbuf_put_string(msg, data, len)) != 0)
1728 				fatal("%s: buffer error: %s",
1729 				    __func__, ssh_err(r));
1730 			send_msg(conn, msg);
1731 			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1732 			    id, (unsigned long long)offset, len);
1733 		} else if (TAILQ_FIRST(&acks) == NULL)
1734 			break;
1735 
1736 		if (ack == NULL)
1737 			fatal("Unexpected ACK %u", id);
1738 
1739 		if (id == startid || len == 0 ||
1740 		    id - ackid >= conn->num_requests) {
1741 			u_int rid;
1742 
1743 			sshbuf_reset(msg);
1744 			get_msg(conn, msg);
1745 			if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1746 			    (r = sshbuf_get_u32(msg, &rid)) != 0)
1747 				fatal("%s: buffer error: %s",
1748 				    __func__, ssh_err(r));
1749 
1750 			if (type != SSH2_FXP_STATUS)
1751 				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1752 				    "got %d", SSH2_FXP_STATUS, type);
1753 
1754 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1755 				fatal("%s: buffer error: %s",
1756 				    __func__, ssh_err(r));
1757 			debug3("SSH2_FXP_STATUS %u", status);
1758 
1759 			/* Find the request in our queue */
1760 			for (ack = TAILQ_FIRST(&acks);
1761 			    ack != NULL && ack->id != rid;
1762 			    ack = TAILQ_NEXT(ack, tq))
1763 				;
1764 			if (ack == NULL)
1765 				fatal("Can't find request for ID %u", rid);
1766 			TAILQ_REMOVE(&acks, ack, tq);
1767 			debug3("In write loop, ack for %u %u bytes at %lld",
1768 			    ack->id, ack->len, (long long)ack->offset);
1769 			++ackid;
1770 			progress_counter += ack->len;
1771 			free(ack);
1772 		}
1773 		offset += len;
1774 		if (offset < 0)
1775 			fatal("%s: offset < 0", __func__);
1776 	}
1777 	sshbuf_free(msg);
1778 
1779 	if (showprogress)
1780 		stop_progress_meter();
1781 	free(data);
1782 
1783 	if (status != SSH2_FX_OK) {
1784 		error("Couldn't write to remote file \"%s\": %s",
1785 		    remote_path, fx2txt(status));
1786 		status = SSH2_FX_FAILURE;
1787 	}
1788 
1789 	if (close(local_fd) == -1) {
1790 		error("Couldn't close local file \"%s\": %s", local_path,
1791 		    strerror(errno));
1792 		status = SSH2_FX_FAILURE;
1793 	}
1794 
1795 	/* Override umask and utimes if asked */
1796 	if (preserve_flag)
1797 		do_fsetstat(conn, handle, handle_len, &a);
1798 
1799 	if (fsync_flag)
1800 		(void)do_fsync(conn, handle, handle_len);
1801 
1802 	if (do_close(conn, handle, handle_len) != 0)
1803 		status = SSH2_FX_FAILURE;
1804 
1805 	free(handle);
1806 
1807 	return status == SSH2_FX_OK ? 0 : -1;
1808 }
1809 
1810 static int
1811 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1812     int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
1813 {
1814 	int ret = 0;
1815 	DIR *dirp;
1816 	struct dirent *dp;
1817 	char *filename, *new_src = NULL, *new_dst = NULL;
1818 	struct stat sb;
1819 	Attrib a, *dirattrib;
1820 
1821 	if (depth >= MAX_DIR_DEPTH) {
1822 		error("Maximum directory depth exceeded: %d levels", depth);
1823 		return -1;
1824 	}
1825 
1826 	if (stat(src, &sb) == -1) {
1827 		error("Couldn't stat directory \"%s\": %s",
1828 		    src, strerror(errno));
1829 		return -1;
1830 	}
1831 	if (!S_ISDIR(sb.st_mode)) {
1832 		error("\"%s\" is not a directory", src);
1833 		return -1;
1834 	}
1835 	if (print_flag)
1836 		mprintf("Entering %s\n", src);
1837 
1838 	attrib_clear(&a);
1839 	stat_to_attrib(&sb, &a);
1840 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1841 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1842 	a.perm &= 01777;
1843 	if (!preserve_flag)
1844 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1845 
1846 	/*
1847 	 * sftp lacks a portable status value to match errno EEXIST,
1848 	 * so if we get a failure back then we must check whether
1849 	 * the path already existed and is a directory.
1850 	 */
1851 	if (do_mkdir(conn, dst, &a, 0) != 0) {
1852 		if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
1853 			return -1;
1854 		if (!S_ISDIR(dirattrib->perm)) {
1855 			error("\"%s\" exists but is not a directory", dst);
1856 			return -1;
1857 		}
1858 	}
1859 
1860 	if ((dirp = opendir(src)) == NULL) {
1861 		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1862 		return -1;
1863 	}
1864 
1865 	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1866 		if (dp->d_ino == 0)
1867 			continue;
1868 		free(new_dst);
1869 		free(new_src);
1870 		filename = dp->d_name;
1871 		new_dst = path_append(dst, filename);
1872 		new_src = path_append(src, filename);
1873 
1874 		if (lstat(new_src, &sb) == -1) {
1875 			logit("%s: lstat failed: %s", filename,
1876 			    strerror(errno));
1877 			ret = -1;
1878 		} else if (S_ISDIR(sb.st_mode)) {
1879 			if (strcmp(filename, ".") == 0 ||
1880 			    strcmp(filename, "..") == 0)
1881 				continue;
1882 
1883 			if (upload_dir_internal(conn, new_src, new_dst,
1884 			    depth + 1, preserve_flag, print_flag, resume,
1885 			    fsync_flag) == -1)
1886 				ret = -1;
1887 		} else if (S_ISREG(sb.st_mode)) {
1888 			if (do_upload(conn, new_src, new_dst,
1889 			    preserve_flag, resume, fsync_flag) == -1) {
1890 				error("Uploading of file %s to %s failed!",
1891 				    new_src, new_dst);
1892 				ret = -1;
1893 			}
1894 		} else
1895 			logit("%s: not a regular file\n", filename);
1896 	}
1897 	free(new_dst);
1898 	free(new_src);
1899 
1900 	do_setstat(conn, dst, &a);
1901 
1902 	(void) closedir(dirp);
1903 	return ret;
1904 }
1905 
1906 int
1907 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
1908     int preserve_flag, int print_flag, int resume, int fsync_flag)
1909 {
1910 	char *dst_canon;
1911 	int ret;
1912 
1913 	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1914 		error("Unable to canonicalize path \"%s\"", dst);
1915 		return -1;
1916 	}
1917 
1918 	ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1919 	    print_flag, resume, fsync_flag);
1920 
1921 	free(dst_canon);
1922 	return ret;
1923 }
1924 
1925 char *
1926 path_append(const char *p1, const char *p2)
1927 {
1928 	char *ret;
1929 	size_t len = strlen(p1) + strlen(p2) + 2;
1930 
1931 	ret = xmalloc(len);
1932 	strlcpy(ret, p1, len);
1933 	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1934 		strlcat(ret, "/", len);
1935 	strlcat(ret, p2, len);
1936 
1937 	return(ret);
1938 }
1939 
1940