xref: /netbsd-src/crypto/external/bsd/openssh/dist/sftp-client.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: sftp-client.c,v 1.20 2018/04/06 18:59:00 christos Exp $	*/
2 /* $OpenBSD: sftp-client.c,v 1.128 2017/11/28 21:10:22 dtucker Exp $ */
3 /*
4  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* XXX: memleaks */
20 /* XXX: signed vs unsigned */
21 /* XXX: remove all logging, only return status codes */
22 /* XXX: copy between two remote sites */
23 
24 #include "includes.h"
25 __RCSID("$NetBSD: sftp-client.c,v 1.20 2018/04/06 18:59:00 christos Exp $");
26 
27 #include <sys/param.h>	/* MIN MAX */
28 #include <sys/types.h>
29 #include <sys/poll.h>
30 #include <sys/queue.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/statvfs.h>
34 #include <sys/uio.h>
35 
36 #include <dirent.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "xmalloc.h"
47 #include "ssherr.h"
48 #include "sshbuf.h"
49 #include "log.h"
50 #include "atomicio.h"
51 #include "progressmeter.h"
52 #include "misc.h"
53 #include "utf8.h"
54 
55 #include "sftp.h"
56 #include "sftp-common.h"
57 #include "sftp-client.h"
58 
59 extern volatile sig_atomic_t interrupted;
60 extern int showprogress;
61 
62 /* Minimum amount of data to read at a time */
63 #define MIN_READ_SIZE	512
64 
65 /* Maximum depth to descend in directory trees */
66 #define MAX_DIR_DEPTH 64
67 
68 struct sftp_conn {
69 	int fd_in;
70 	int fd_out;
71 	u_int transfer_buflen;
72 	u_int num_requests;
73 	u_int version;
74 	u_int msg_id;
75 #define SFTP_EXT_POSIX_RENAME	0x00000001
76 #define SFTP_EXT_STATVFS	0x00000002
77 #define SFTP_EXT_FSTATVFS	0x00000004
78 #define SFTP_EXT_HARDLINK	0x00000008
79 #define SFTP_EXT_FSYNC		0x00000010
80 	u_int exts;
81 	u_int64_t limit_kbps;
82 	struct bwlimit bwlimit_in, bwlimit_out;
83 };
84 
85 static u_char *
86 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
87     const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
88 
89 /* ARGSUSED */
90 static int
91 sftpio(void *_bwlimit, size_t amount)
92 {
93 	struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
94 
95 	bandwidth_limit(bwlimit, amount);
96 	return 0;
97 }
98 
99 static void
100 send_msg(struct sftp_conn *conn, struct sshbuf *m)
101 {
102 	u_char mlen[4];
103 	struct iovec iov[2];
104 
105 	if (sshbuf_len(m) > SFTP_MAX_MSG_LENGTH)
106 		fatal("Outbound message too long %zu", sshbuf_len(m));
107 
108 	/* Send length first */
109 	put_u32(mlen, sshbuf_len(m));
110 	iov[0].iov_base = mlen;
111 	iov[0].iov_len = sizeof(mlen);
112 	iov[1].iov_base = __UNCONST(sshbuf_ptr(m));
113 	iov[1].iov_len = sshbuf_len(m);
114 
115 	if (atomiciov6(writev, conn->fd_out, iov, 2,
116 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
117 	    sshbuf_len(m) + sizeof(mlen))
118 		fatal("Couldn't send packet: %s", strerror(errno));
119 
120 	sshbuf_reset(m);
121 }
122 
123 static void
124 get_msg_extended(struct sftp_conn *conn, struct sshbuf *m, int initial)
125 {
126 	u_int msg_len;
127 	u_char *p;
128 	int r;
129 
130 	if ((r = sshbuf_reserve(m, 4, &p)) != 0)
131 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
132 	if (atomicio6(read, conn->fd_in, p, 4,
133 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
134 		if (errno == EPIPE || errno == ECONNRESET)
135 			fatal("Connection closed");
136 		else
137 			fatal("Couldn't read packet: %s", strerror(errno));
138 	}
139 
140 	if ((r = sshbuf_get_u32(m, &msg_len)) != 0)
141 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
142 	if (msg_len > SFTP_MAX_MSG_LENGTH) {
143 		do_log2(initial ? SYSLOG_LEVEL_ERROR : SYSLOG_LEVEL_FATAL,
144 		    "Received message too long %u", msg_len);
145 		fatal("Ensure the remote shell produces no output "
146 		    "for non-interactive sessions.");
147 	}
148 
149 	if ((r = sshbuf_reserve(m, msg_len, &p)) != 0)
150 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
151 	if (atomicio6(read, conn->fd_in, p, msg_len,
152 	    conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
153 	    != msg_len) {
154 		if (errno == EPIPE)
155 			fatal("Connection closed");
156 		else
157 			fatal("Read packet: %s", strerror(errno));
158 	}
159 }
160 
161 static void
162 get_msg(struct sftp_conn *conn, struct sshbuf *m)
163 {
164 	get_msg_extended(conn, m, 0);
165 }
166 
167 static void
168 send_string_request(struct sftp_conn *conn, u_int id, u_int code, const char *s,
169     u_int len)
170 {
171 	struct sshbuf *msg;
172 	int r;
173 
174 	if ((msg = sshbuf_new()) == NULL)
175 		fatal("%s: sshbuf_new failed", __func__);
176 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
177 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
178 	    (r = sshbuf_put_string(msg, s, len)) != 0)
179 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
180 	send_msg(conn, msg);
181 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
182 	sshbuf_free(msg);
183 }
184 
185 static void
186 send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
187     const void *s, u_int len, Attrib *a)
188 {
189 	struct sshbuf *msg;
190 	int r;
191 
192 	if ((msg = sshbuf_new()) == NULL)
193 		fatal("%s: sshbuf_new failed", __func__);
194 	if ((r = sshbuf_put_u8(msg, code)) != 0 ||
195 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
196 	    (r = sshbuf_put_string(msg, s, len)) != 0 ||
197 	    (r = encode_attrib(msg, a)) != 0)
198 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
199 	send_msg(conn, msg);
200 	debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
201 	sshbuf_free(msg);
202 }
203 
204 static u_int
205 get_status(struct sftp_conn *conn, u_int expected_id)
206 {
207 	struct sshbuf *msg;
208 	u_char type;
209 	u_int id, status;
210 	int r;
211 
212 	if ((msg = sshbuf_new()) == NULL)
213 		fatal("%s: sshbuf_new failed", __func__);
214 	get_msg(conn, msg);
215 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
216 	    (r = sshbuf_get_u32(msg, &id)) != 0)
217 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
218 
219 	if (id != expected_id)
220 		fatal("ID mismatch (%u != %u)", id, expected_id);
221 	if (type != SSH2_FXP_STATUS)
222 		fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
223 		    SSH2_FXP_STATUS, type);
224 
225 	if ((r = sshbuf_get_u32(msg, &status)) != 0)
226 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
227 	sshbuf_free(msg);
228 
229 	debug3("SSH2_FXP_STATUS %u", status);
230 
231 	return status;
232 }
233 
234 static u_char *
235 get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
236     const char *errfmt, ...)
237 {
238 	struct sshbuf *msg;
239 	u_int id, status;
240 	u_char type;
241 	u_char *handle;
242 	char errmsg[256];
243 	va_list args;
244 	int r;
245 
246 	va_start(args, errfmt);
247 	if (errfmt != NULL)
248 		vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
249 	va_end(args);
250 
251 	if ((msg = sshbuf_new()) == NULL)
252 		fatal("%s: sshbuf_new failed", __func__);
253 	get_msg(conn, msg);
254 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
255 	    (r = sshbuf_get_u32(msg, &id)) != 0)
256 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
257 
258 	if (id != expected_id)
259 		fatal("%s: ID mismatch (%u != %u)",
260 		    errfmt == NULL ? __func__ : errmsg, id, expected_id);
261 	if (type == SSH2_FXP_STATUS) {
262 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
263 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
264 		if (errfmt != NULL)
265 			error("%s: %s", errmsg, fx2txt(status));
266 		sshbuf_free(msg);
267 		return(NULL);
268 	} else if (type != SSH2_FXP_HANDLE)
269 		fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
270 		    errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
271 
272 	if ((r = sshbuf_get_string(msg, &handle, len)) != 0)
273 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
274 	sshbuf_free(msg);
275 
276 	return handle;
277 }
278 
279 static Attrib *
280 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
281 {
282 	struct sshbuf *msg;
283 	u_int id;
284 	u_char type;
285 	int r;
286 	static Attrib a;
287 
288 	if ((msg = sshbuf_new()) == NULL)
289 		fatal("%s: sshbuf_new failed", __func__);
290 	get_msg(conn, msg);
291 
292 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
293 	    (r = sshbuf_get_u32(msg, &id)) != 0)
294 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
295 
296 	debug3("Received stat reply T:%u I:%u", type, id);
297 	if (id != expected_id)
298 		fatal("ID mismatch (%u != %u)", id, expected_id);
299 	if (type == SSH2_FXP_STATUS) {
300 		u_int status;
301 
302 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
303 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
304 		if (quiet)
305 			debug("Couldn't stat remote file: %s", fx2txt(status));
306 		else
307 			error("Couldn't stat remote file: %s", fx2txt(status));
308 		sshbuf_free(msg);
309 		return(NULL);
310 	} else if (type != SSH2_FXP_ATTRS) {
311 		fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
312 		    SSH2_FXP_ATTRS, type);
313 	}
314 	if ((r = decode_attrib(msg, &a)) != 0) {
315 		error("%s: couldn't decode attrib: %s", __func__, ssh_err(r));
316 		sshbuf_free(msg);
317 		return NULL;
318 	}
319 	sshbuf_free(msg);
320 
321 	return &a;
322 }
323 
324 static int
325 get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
326     u_int expected_id, int quiet)
327 {
328 	struct sshbuf *msg;
329 	u_char type;
330 	u_int id;
331 	u_int64_t flag;
332 	int r;
333 
334 	if ((msg = sshbuf_new()) == NULL)
335 		fatal("%s: sshbuf_new failed", __func__);
336 	get_msg(conn, msg);
337 
338 	if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
339 	    (r = sshbuf_get_u32(msg, &id)) != 0)
340 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
341 
342 	debug3("Received statvfs reply T:%u I:%u", type, id);
343 	if (id != expected_id)
344 		fatal("ID mismatch (%u != %u)", id, expected_id);
345 	if (type == SSH2_FXP_STATUS) {
346 		u_int status;
347 
348 		if ((r = sshbuf_get_u32(msg, &status)) != 0)
349 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
350 		if (quiet)
351 			debug("Couldn't statvfs: %s", fx2txt(status));
352 		else
353 			error("Couldn't statvfs: %s", fx2txt(status));
354 		sshbuf_free(msg);
355 		return -1;
356 	} else if (type != SSH2_FXP_EXTENDED_REPLY) {
357 		fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
358 		    SSH2_FXP_EXTENDED_REPLY, type);
359 	}
360 
361 	memset(st, 0, sizeof(*st));
362 	if ((r = sshbuf_get_u64(msg, &st->f_bsize)) != 0 ||
363 	    (r = sshbuf_get_u64(msg, &st->f_frsize)) != 0 ||
364 	    (r = sshbuf_get_u64(msg, &st->f_blocks)) != 0 ||
365 	    (r = sshbuf_get_u64(msg, &st->f_bfree)) != 0 ||
366 	    (r = sshbuf_get_u64(msg, &st->f_bavail)) != 0 ||
367 	    (r = sshbuf_get_u64(msg, &st->f_files)) != 0 ||
368 	    (r = sshbuf_get_u64(msg, &st->f_ffree)) != 0 ||
369 	    (r = sshbuf_get_u64(msg, &st->f_favail)) != 0 ||
370 	    (r = sshbuf_get_u64(msg, &st->f_fsid)) != 0 ||
371 	    (r = sshbuf_get_u64(msg, &flag)) != 0 ||
372 	    (r = sshbuf_get_u64(msg, &st->f_namemax)) != 0)
373 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
374 
375 	st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
376 	st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
377 
378 	sshbuf_free(msg);
379 
380 	return 0;
381 }
382 
383 struct sftp_conn *
384 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
385     u_int64_t limit_kbps)
386 {
387 	u_char type;
388 	struct sshbuf *msg;
389 	struct sftp_conn *ret;
390 	int r;
391 
392 	ret = xcalloc(1, sizeof(*ret));
393 	ret->msg_id = 1;
394 	ret->fd_in = fd_in;
395 	ret->fd_out = fd_out;
396 	ret->transfer_buflen = transfer_buflen;
397 	ret->num_requests = num_requests;
398 	ret->exts = 0;
399 	ret->limit_kbps = 0;
400 
401 	if ((msg = sshbuf_new()) == NULL)
402 		fatal("%s: sshbuf_new failed", __func__);
403 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_INIT)) != 0 ||
404 	    (r = sshbuf_put_u32(msg, SSH2_FILEXFER_VERSION)) != 0)
405 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
406 	send_msg(ret, msg);
407 
408 	sshbuf_reset(msg);
409 
410 	get_msg_extended(ret, msg, 1);
411 
412 	/* Expecting a VERSION reply */
413 	if ((r = sshbuf_get_u8(msg, &type)) != 0)
414 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
415 	if (type != SSH2_FXP_VERSION) {
416 		error("Invalid packet back from SSH2_FXP_INIT (type %u)",
417 		    type);
418 		sshbuf_free(msg);
419 		free(ret);
420 		return(NULL);
421 	}
422 	if ((r = sshbuf_get_u32(msg, &ret->version)) != 0)
423 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
424 
425 	debug2("Remote version: %u", ret->version);
426 
427 	/* Check for extensions */
428 	while (sshbuf_len(msg) > 0) {
429 		char *name;
430 		u_char *value;
431 		size_t vlen;
432 		int known = 0;
433 
434 		if ((r = sshbuf_get_cstring(msg, &name, NULL)) != 0 ||
435 		    (r = sshbuf_get_string(msg, &value, &vlen)) != 0)
436 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
437 		if (strcmp(name, "posix-rename@openssh.com") == 0 &&
438 		    strcmp((char *)value, "1") == 0) {
439 			ret->exts |= SFTP_EXT_POSIX_RENAME;
440 			known = 1;
441 		} else if (strcmp(name, "statvfs@openssh.com") == 0 &&
442 		    strcmp((char *)value, "2") == 0) {
443 			ret->exts |= SFTP_EXT_STATVFS;
444 			known = 1;
445 		} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
446 		    strcmp((char *)value, "2") == 0) {
447 			ret->exts |= SFTP_EXT_FSTATVFS;
448 			known = 1;
449 		} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
450 		    strcmp((char *)value, "1") == 0) {
451 			ret->exts |= SFTP_EXT_HARDLINK;
452 			known = 1;
453 		} else if (strcmp(name, "fsync@openssh.com") == 0 &&
454 		    strcmp((char *)value, "1") == 0) {
455 			ret->exts |= SFTP_EXT_FSYNC;
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;
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;
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 	sshbuf_reset(msg);
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 	sshbuf_reset(msg);
1120 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1121 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1122 	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1123 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0)
1124 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1125 	send_msg(conn, msg);
1126 	sshbuf_free(msg);
1127 
1128 	return get_decode_statvfs(conn, st, id, quiet);
1129 }
1130 #endif
1131 
1132 static void
1133 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1134     u_int len, const u_char *handle, u_int handle_len)
1135 {
1136 	struct sshbuf *msg;
1137 	int r;
1138 
1139 	if ((msg = sshbuf_new()) == NULL)
1140 		fatal("%s: sshbuf_new failed", __func__);
1141 	sshbuf_reset(msg);
1142 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1143 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1144 	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1145 	    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1146 	    (r = sshbuf_put_u32(msg, len)) != 0)
1147 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1148 	send_msg(conn, msg);
1149 	sshbuf_free(msg);
1150 }
1151 
1152 int
1153 do_download(struct sftp_conn *conn, const char *remote_path,
1154     const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
1155     int fsync_flag)
1156 {
1157 	Attrib junk;
1158 	struct sshbuf *msg;
1159 	u_char *handle;
1160 	int local_fd = -1, write_error;
1161 	int read_error, write_errno, reordered = 0, r;
1162 	u_int64_t offset = 0, size, highwater;
1163 	u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
1164 	off_t progress_counter;
1165 	size_t handle_len;
1166 	struct stat st;
1167 	struct request {
1168 		u_int id;
1169 		size_t len;
1170 		u_int64_t offset;
1171 		TAILQ_ENTRY(request) tq;
1172 	};
1173 	TAILQ_HEAD(reqhead, request) requests;
1174 	struct request *req;
1175 	u_char type;
1176 
1177 	status = -1;
1178 	TAILQ_INIT(&requests);
1179 
1180 	if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
1181 		return -1;
1182 
1183 	/* Do not preserve set[ug]id here, as we do not preserve ownership */
1184 	if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1185 		mode = a->perm & 0777;
1186 	else
1187 		mode = 0666;
1188 
1189 	if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
1190 	    (!S_ISREG(a->perm))) {
1191 		error("Cannot download non-regular file: %s", remote_path);
1192 		return(-1);
1193 	}
1194 
1195 	if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
1196 		size = a->size;
1197 	else
1198 		size = 0;
1199 
1200 	buflen = conn->transfer_buflen;
1201 	if ((msg = sshbuf_new()) == NULL)
1202 		fatal("%s: sshbuf_new failed", __func__);
1203 
1204 	attrib_clear(&junk); /* Send empty attributes */
1205 
1206 	/* Send open request */
1207 	id = conn->msg_id++;
1208 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1209 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1210 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1211 	    (r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 ||
1212 	    (r = encode_attrib(msg, &junk)) != 0)
1213 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1214 	send_msg(conn, msg);
1215 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1216 
1217 	handle = get_handle(conn, id, &handle_len,
1218 	    "remote open(\"%s\")", remote_path);
1219 	if (handle == NULL) {
1220 		sshbuf_free(msg);
1221 		return(-1);
1222 	}
1223 
1224 	local_fd = open(local_path,
1225 	    O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
1226 	if (local_fd == -1) {
1227 		error("Couldn't open local file \"%s\" for writing: %s",
1228 		    local_path, strerror(errno));
1229 		goto fail;
1230 	}
1231 	offset = highwater = 0;
1232 	if (resume_flag) {
1233 		if (fstat(local_fd, &st) == -1) {
1234 			error("Unable to stat local file \"%s\": %s",
1235 			    local_path, strerror(errno));
1236 			goto fail;
1237 		}
1238 		if (st.st_size < 0) {
1239 			error("\"%s\" has negative size", local_path);
1240 			goto fail;
1241 		}
1242 		if ((u_int64_t)st.st_size > size) {
1243 			error("Unable to resume download of \"%s\": "
1244 			    "local file is larger than remote", local_path);
1245  fail:
1246 			do_close(conn, handle, handle_len);
1247 			sshbuf_free(msg);
1248 			free(handle);
1249 			if (local_fd != -1)
1250 				close(local_fd);
1251 			return -1;
1252 		}
1253 		offset = highwater = st.st_size;
1254 	}
1255 
1256 	/* Read from remote and write to local */
1257 	write_error = read_error = write_errno = num_req = 0;
1258 	max_req = 1;
1259 	progress_counter = offset;
1260 
1261 	if (showprogress && size != 0)
1262 		start_progress_meter(remote_path, size, &progress_counter);
1263 
1264 	while (num_req > 0 || max_req > 0) {
1265 		u_char *data;
1266 		size_t len;
1267 
1268 		/*
1269 		 * Simulate EOF on interrupt: stop sending new requests and
1270 		 * allow outstanding requests to drain gracefully
1271 		 */
1272 		if (interrupted) {
1273 			if (num_req == 0) /* If we haven't started yet... */
1274 				break;
1275 			max_req = 0;
1276 		}
1277 
1278 		/* Send some more requests */
1279 		while (num_req < max_req) {
1280 			debug3("Request range %llu -> %llu (%d/%d)",
1281 			    (unsigned long long)offset,
1282 			    (unsigned long long)offset + buflen - 1,
1283 			    num_req, max_req);
1284 			req = xcalloc(1, sizeof(*req));
1285 			req->id = conn->msg_id++;
1286 			req->len = buflen;
1287 			req->offset = offset;
1288 			offset += buflen;
1289 			num_req++;
1290 			TAILQ_INSERT_TAIL(&requests, req, tq);
1291 			send_read_request(conn, req->id, req->offset,
1292 			    req->len, handle, handle_len);
1293 		}
1294 
1295 		sshbuf_reset(msg);
1296 		get_msg(conn, msg);
1297 		if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1298 		    (r = sshbuf_get_u32(msg, &id)) != 0)
1299 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
1300 		debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
1301 
1302 		/* Find the request in our queue */
1303 		for (req = TAILQ_FIRST(&requests);
1304 		    req != NULL && req->id != id;
1305 		    req = TAILQ_NEXT(req, tq))
1306 			;
1307 		if (req == NULL)
1308 			fatal("Unexpected reply %u", id);
1309 
1310 		switch (type) {
1311 		case SSH2_FXP_STATUS:
1312 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1313 				fatal("%s: buffer error: %s",
1314 				    __func__, ssh_err(r));
1315 			if (status != SSH2_FX_EOF)
1316 				read_error = 1;
1317 			max_req = 0;
1318 			TAILQ_REMOVE(&requests, req, tq);
1319 			free(req);
1320 			num_req--;
1321 			break;
1322 		case SSH2_FXP_DATA:
1323 			if ((r = sshbuf_get_string(msg, &data, &len)) != 0)
1324 				fatal("%s: buffer error: %s",
1325 				    __func__, ssh_err(r));
1326 			debug3("Received data %llu -> %llu",
1327 			    (unsigned long long)req->offset,
1328 			    (unsigned long long)req->offset + len - 1);
1329 			if (len > req->len)
1330 				fatal("Received more data than asked for "
1331 				    "%zu > %zu", len, req->len);
1332 			if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
1333 			    atomicio(vwrite, local_fd, data, len) != len) &&
1334 			    !write_error) {
1335 				write_errno = errno;
1336 				write_error = 1;
1337 				max_req = 0;
1338 			}
1339 			else if (!reordered && req->offset <= highwater)
1340 				highwater = req->offset + len;
1341 			else if (!reordered && req->offset > highwater)
1342 				reordered = 1;
1343 			progress_counter += len;
1344 			free(data);
1345 
1346 			if (len == req->len) {
1347 				TAILQ_REMOVE(&requests, req, tq);
1348 				free(req);
1349 				num_req--;
1350 			} else {
1351 				/* Resend the request for the missing data */
1352 				debug3("Short data block, re-requesting "
1353 				    "%llu -> %llu (%2d)",
1354 				    (unsigned long long)req->offset + len,
1355 				    (unsigned long long)req->offset +
1356 				    req->len - 1, num_req);
1357 				req->id = conn->msg_id++;
1358 				req->len -= len;
1359 				req->offset += len;
1360 				send_read_request(conn, req->id,
1361 				    req->offset, req->len, handle, handle_len);
1362 				/* Reduce the request size */
1363 				if (len < buflen)
1364 					buflen = MAXIMUM(MIN_READ_SIZE, len);
1365 			}
1366 			if (max_req > 0) { /* max_req = 0 iff EOF received */
1367 				if (size > 0 && offset > size) {
1368 					/* Only one request at a time
1369 					 * after the expected EOF */
1370 					debug3("Finish at %llu (%2d)",
1371 					    (unsigned long long)offset,
1372 					    num_req);
1373 					max_req = 1;
1374 				} else if (max_req <= conn->num_requests) {
1375 					++max_req;
1376 				}
1377 			}
1378 			break;
1379 		default:
1380 			fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
1381 			    SSH2_FXP_DATA, type);
1382 		}
1383 	}
1384 
1385 	if (showprogress && size)
1386 		stop_progress_meter();
1387 
1388 	/* Sanity check */
1389 	if (TAILQ_FIRST(&requests) != NULL)
1390 		fatal("Transfer complete, but requests still in queue");
1391 	/* Truncate at highest contiguous point to avoid holes on interrupt */
1392 	if (read_error || write_error || interrupted) {
1393 		if (reordered && resume_flag) {
1394 			error("Unable to resume download of \"%s\": "
1395 			    "server reordered requests", local_path);
1396 		}
1397 		debug("truncating at %llu", (unsigned long long)highwater);
1398 		if (ftruncate(local_fd, highwater) == -1)
1399 			error("ftruncate \"%s\": %s", local_path,
1400 			    strerror(errno));
1401 	}
1402 	if (read_error) {
1403 		error("Couldn't read from remote file \"%s\" : %s",
1404 		    remote_path, fx2txt(status));
1405 		status = -1;
1406 		do_close(conn, handle, handle_len);
1407 	} else if (write_error) {
1408 		error("Couldn't write to \"%s\": %s", local_path,
1409 		    strerror(write_errno));
1410 		status = SSH2_FX_FAILURE;
1411 		do_close(conn, handle, handle_len);
1412 	} else {
1413 		if (do_close(conn, handle, handle_len) != 0 || interrupted)
1414 			status = SSH2_FX_FAILURE;
1415 		else
1416 			status = SSH2_FX_OK;
1417 		/* Override umask and utimes if asked */
1418 		if (preserve_flag && fchmod(local_fd, mode) == -1)
1419 			error("Couldn't set mode on \"%s\": %s", local_path,
1420 			    strerror(errno));
1421 		if (preserve_flag &&
1422 		    (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
1423 			struct timeval tv[2];
1424 			tv[0].tv_sec = a->atime;
1425 			tv[1].tv_sec = a->mtime;
1426 			tv[0].tv_usec = tv[1].tv_usec = 0;
1427 			if (utimes(local_path, tv) == -1)
1428 				error("Can't set times on \"%s\": %s",
1429 				    local_path, strerror(errno));
1430 		}
1431 		if (fsync_flag) {
1432 			debug("syncing \"%s\"", local_path);
1433 			if (fsync(local_fd) == -1)
1434 				error("Couldn't sync file \"%s\": %s",
1435 				    local_path, strerror(errno));
1436 		}
1437 	}
1438 	close(local_fd);
1439 	sshbuf_free(msg);
1440 	free(handle);
1441 
1442 	return(status);
1443 }
1444 
1445 static int
1446 download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1447     int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
1448     int resume_flag, int fsync_flag)
1449 {
1450 	int i, ret = 0;
1451 	SFTP_DIRENT **dir_entries;
1452 	char *filename, *new_src, *new_dst;
1453 	mode_t mode = 0777;
1454 
1455 	if (depth >= MAX_DIR_DEPTH) {
1456 		error("Maximum directory depth exceeded: %d levels", depth);
1457 		return -1;
1458 	}
1459 
1460 	if (dirattrib == NULL &&
1461 	    (dirattrib = do_stat(conn, src, 1)) == NULL) {
1462 		error("Unable to stat remote directory \"%s\"", src);
1463 		return -1;
1464 	}
1465 	if (!S_ISDIR(dirattrib->perm)) {
1466 		error("\"%s\" is not a directory", src);
1467 		return -1;
1468 	}
1469 	if (print_flag)
1470 		mprintf("Retrieving %s\n", src);
1471 
1472 	if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
1473 		mode = dirattrib->perm & 01777;
1474 	else {
1475 		debug("Server did not send permissions for "
1476 		    "directory \"%s\"", dst);
1477 	}
1478 
1479 	if (mkdir(dst, mode) == -1 && errno != EEXIST) {
1480 		error("mkdir %s: %s", dst, strerror(errno));
1481 		return -1;
1482 	}
1483 
1484 	if (do_readdir(conn, src, &dir_entries) == -1) {
1485 		error("%s: Failed to get directory contents", src);
1486 		return -1;
1487 	}
1488 
1489 	for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
1490 		filename = dir_entries[i]->filename;
1491 
1492 		new_dst = path_append(dst, filename);
1493 		new_src = path_append(src, filename);
1494 
1495 		if (S_ISDIR(dir_entries[i]->a.perm)) {
1496 			if (strcmp(filename, ".") == 0 ||
1497 			    strcmp(filename, "..") == 0)
1498 				continue;
1499 			if (download_dir_internal(conn, new_src, new_dst,
1500 			    depth + 1, &(dir_entries[i]->a), preserve_flag,
1501 			    print_flag, resume_flag, fsync_flag) == -1)
1502 				ret = -1;
1503 		} else if (S_ISREG(dir_entries[i]->a.perm) ) {
1504 			if (do_download(conn, new_src, new_dst,
1505 			    &(dir_entries[i]->a), preserve_flag,
1506 			    resume_flag, fsync_flag) == -1) {
1507 				error("Download of file %s to %s failed",
1508 				    new_src, new_dst);
1509 				ret = -1;
1510 			}
1511 		} else
1512 			logit("%s: not a regular file\n", new_src);
1513 
1514 		free(new_dst);
1515 		free(new_src);
1516 	}
1517 
1518 	if (preserve_flag) {
1519 		if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1520 			struct timeval tv[2];
1521 			tv[0].tv_sec = dirattrib->atime;
1522 			tv[1].tv_sec = dirattrib->mtime;
1523 			tv[0].tv_usec = tv[1].tv_usec = 0;
1524 			if (utimes(dst, tv) == -1)
1525 				error("Can't set times on \"%s\": %s",
1526 				    dst, strerror(errno));
1527 		} else
1528 			debug("Server did not send times for directory "
1529 			    "\"%s\"", dst);
1530 	}
1531 
1532 	free_sftp_dirents(dir_entries);
1533 
1534 	return ret;
1535 }
1536 
1537 int
1538 download_dir(struct sftp_conn *conn, const char *src, const char *dst,
1539     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1540     int fsync_flag)
1541 {
1542 	char *src_canon;
1543 	int ret;
1544 
1545 	if ((src_canon = do_realpath(conn, src)) == NULL) {
1546 		error("Unable to canonicalize path \"%s\"", src);
1547 		return -1;
1548 	}
1549 
1550 	ret = download_dir_internal(conn, src_canon, dst, 0,
1551 	    dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1552 	free(src_canon);
1553 	return ret;
1554 }
1555 
1556 int
1557 do_upload(struct sftp_conn *conn, const char *local_path,
1558     const char *remote_path, int preserve_flag, int resume, int fsync_flag)
1559 {
1560 	int r, local_fd;
1561 	u_int status = SSH2_FX_OK;
1562 	u_int id;
1563 	u_char type;
1564 	off_t offset, progress_counter;
1565 	u_char *handle, *data;
1566 	struct sshbuf *msg;
1567 	struct stat sb;
1568 	Attrib a, *c = NULL;
1569 	u_int32_t startid;
1570 	u_int32_t ackid;
1571 	struct outstanding_ack {
1572 		u_int id;
1573 		u_int len;
1574 		off_t offset;
1575 		TAILQ_ENTRY(outstanding_ack) tq;
1576 	};
1577 	TAILQ_HEAD(ackhead, outstanding_ack) acks;
1578 	struct outstanding_ack *ack = NULL;
1579 	size_t handle_len;
1580 
1581 	TAILQ_INIT(&acks);
1582 
1583 	if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
1584 		error("Couldn't open local file \"%s\" for reading: %s",
1585 		    local_path, strerror(errno));
1586 		return(-1);
1587 	}
1588 	if (fstat(local_fd, &sb) == -1) {
1589 		error("Couldn't fstat local file \"%s\": %s",
1590 		    local_path, strerror(errno));
1591 		close(local_fd);
1592 		return(-1);
1593 	}
1594 	if (!S_ISREG(sb.st_mode)) {
1595 		error("%s is not a regular file", local_path);
1596 		close(local_fd);
1597 		return(-1);
1598 	}
1599 	stat_to_attrib(&sb, &a);
1600 
1601 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1602 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1603 	a.perm &= 0777;
1604 	if (!preserve_flag)
1605 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1606 
1607 	if (resume) {
1608 		/* Get remote file size if it exists */
1609 		if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1610 			close(local_fd);
1611 			return -1;
1612 		}
1613 
1614 		if ((off_t)c->size >= sb.st_size) {
1615 			error("destination file bigger or same size as "
1616 			      "source file");
1617 			close(local_fd);
1618 			return -1;
1619 		}
1620 
1621 		if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1622 			close(local_fd);
1623 			return -1;
1624 		}
1625 	}
1626 
1627 	if ((msg = sshbuf_new()) == NULL)
1628 		fatal("%s: sshbuf_new failed", __func__);
1629 
1630 	/* Send open request */
1631 	id = conn->msg_id++;
1632 	if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 ||
1633 	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1634 	    (r = sshbuf_put_cstring(msg, remote_path)) != 0 ||
1635 	    (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1636 	    (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 ||
1637 	    (r = encode_attrib(msg, &a)) != 0)
1638 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1639 	send_msg(conn, msg);
1640 	debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1641 
1642 	sshbuf_reset(msg);
1643 
1644 	handle = get_handle(conn, id, &handle_len,
1645 	    "remote open(\"%s\")", remote_path);
1646 	if (handle == NULL) {
1647 		close(local_fd);
1648 		sshbuf_free(msg);
1649 		return -1;
1650 	}
1651 
1652 	startid = ackid = id + 1;
1653 	data = xmalloc(conn->transfer_buflen);
1654 
1655 	/* Read from local and write to remote */
1656 	offset = progress_counter = (resume ? c->size : 0);
1657 	if (showprogress)
1658 		start_progress_meter(local_path, sb.st_size,
1659 		    &progress_counter);
1660 
1661 	for (;;) {
1662 		int len;
1663 
1664 		/*
1665 		 * Can't use atomicio here because it returns 0 on EOF,
1666 		 * thus losing the last block of the file.
1667 		 * Simulate an EOF on interrupt, allowing ACKs from the
1668 		 * server to drain.
1669 		 */
1670 		if (interrupted || status != SSH2_FX_OK)
1671 			len = 0;
1672 		else do
1673 			len = read(local_fd, data, conn->transfer_buflen);
1674 		while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1675 
1676 		if (len == -1)
1677 			fatal("Couldn't read from \"%s\": %s", local_path,
1678 			    strerror(errno));
1679 
1680 		if (len != 0) {
1681 			ack = xcalloc(1, sizeof(*ack));
1682 			ack->id = ++id;
1683 			ack->offset = offset;
1684 			ack->len = len;
1685 			TAILQ_INSERT_TAIL(&acks, ack, tq);
1686 
1687 			sshbuf_reset(msg);
1688 			if ((r = sshbuf_put_u8(msg, SSH2_FXP_WRITE)) != 0 ||
1689 			    (r = sshbuf_put_u32(msg, ack->id)) != 0 ||
1690 			    (r = sshbuf_put_string(msg, handle,
1691 			    handle_len)) != 0 ||
1692 			    (r = sshbuf_put_u64(msg, offset)) != 0 ||
1693 			    (r = sshbuf_put_string(msg, data, len)) != 0)
1694 				fatal("%s: buffer error: %s",
1695 				    __func__, ssh_err(r));
1696 			send_msg(conn, msg);
1697 			debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1698 			    id, (unsigned long long)offset, len);
1699 		} else if (TAILQ_FIRST(&acks) == NULL)
1700 			break;
1701 
1702 		if (ack == NULL)
1703 			fatal("Unexpected ACK %u", id);
1704 
1705 		if (id == startid || len == 0 ||
1706 		    id - ackid >= conn->num_requests) {
1707 			u_int rid;
1708 
1709 			sshbuf_reset(msg);
1710 			get_msg(conn, msg);
1711 			if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
1712 			    (r = sshbuf_get_u32(msg, &rid)) != 0)
1713 				fatal("%s: buffer error: %s",
1714 				    __func__, ssh_err(r));
1715 
1716 			if (type != SSH2_FXP_STATUS)
1717 				fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1718 				    "got %d", SSH2_FXP_STATUS, type);
1719 
1720 			if ((r = sshbuf_get_u32(msg, &status)) != 0)
1721 				fatal("%s: buffer error: %s",
1722 				    __func__, ssh_err(r));
1723 			debug3("SSH2_FXP_STATUS %u", status);
1724 
1725 			/* Find the request in our queue */
1726 			for (ack = TAILQ_FIRST(&acks);
1727 			    ack != NULL && ack->id != rid;
1728 			    ack = TAILQ_NEXT(ack, tq))
1729 				;
1730 			if (ack == NULL)
1731 				fatal("Can't find request for ID %u", rid);
1732 			TAILQ_REMOVE(&acks, ack, tq);
1733 			debug3("In write loop, ack for %u %u bytes at %lld",
1734 			    ack->id, ack->len, (long long)ack->offset);
1735 			++ackid;
1736 			progress_counter += ack->len;
1737 			free(ack);
1738 		}
1739 		offset += len;
1740 		if (offset < 0)
1741 			fatal("%s: offset < 0", __func__);
1742 	}
1743 	sshbuf_free(msg);
1744 
1745 	if (showprogress)
1746 		stop_progress_meter();
1747 	free(data);
1748 
1749 	if (status != SSH2_FX_OK) {
1750 		error("Couldn't write to remote file \"%s\": %s",
1751 		    remote_path, fx2txt(status));
1752 		status = SSH2_FX_FAILURE;
1753 	}
1754 
1755 	if (close(local_fd) == -1) {
1756 		error("Couldn't close local file \"%s\": %s", local_path,
1757 		    strerror(errno));
1758 		status = SSH2_FX_FAILURE;
1759 	}
1760 
1761 	/* Override umask and utimes if asked */
1762 	if (preserve_flag)
1763 		do_fsetstat(conn, handle, handle_len, &a);
1764 
1765 	if (fsync_flag)
1766 		(void)do_fsync(conn, handle, handle_len);
1767 
1768 	if (do_close(conn, handle, handle_len) != 0)
1769 		status = SSH2_FX_FAILURE;
1770 
1771 	free(handle);
1772 
1773 	return status == SSH2_FX_OK ? 0 : -1;
1774 }
1775 
1776 static int
1777 upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
1778     int depth, int preserve_flag, int print_flag, int resume, int fsync_flag)
1779 {
1780 	int ret = 0;
1781 	DIR *dirp;
1782 	struct dirent *dp;
1783 	char *filename, *new_src, *new_dst;
1784 	struct stat sb;
1785 	Attrib a, *dirattrib;
1786 
1787 	if (depth >= MAX_DIR_DEPTH) {
1788 		error("Maximum directory depth exceeded: %d levels", depth);
1789 		return -1;
1790 	}
1791 
1792 	if (stat(src, &sb) == -1) {
1793 		error("Couldn't stat directory \"%s\": %s",
1794 		    src, strerror(errno));
1795 		return -1;
1796 	}
1797 	if (!S_ISDIR(sb.st_mode)) {
1798 		error("\"%s\" is not a directory", src);
1799 		return -1;
1800 	}
1801 	if (print_flag)
1802 		mprintf("Entering %s\n", src);
1803 
1804 	attrib_clear(&a);
1805 	stat_to_attrib(&sb, &a);
1806 	a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1807 	a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1808 	a.perm &= 01777;
1809 	if (!preserve_flag)
1810 		a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1811 
1812 	/*
1813 	 * sftp lacks a portable status value to match errno EEXIST,
1814 	 * so if we get a failure back then we must check whether
1815 	 * the path already existed and is a directory.
1816 	 */
1817 	if (do_mkdir(conn, dst, &a, 0) != 0) {
1818 		if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
1819 			return -1;
1820 		if (!S_ISDIR(dirattrib->perm)) {
1821 			error("\"%s\" exists but is not a directory", dst);
1822 			return -1;
1823 		}
1824 	}
1825 
1826 	if ((dirp = opendir(src)) == NULL) {
1827 		error("Failed to open dir \"%s\": %s", src, strerror(errno));
1828 		return -1;
1829 	}
1830 
1831 	while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1832 		if (dp->d_ino == 0)
1833 			continue;
1834 		filename = dp->d_name;
1835 		new_dst = path_append(dst, filename);
1836 		new_src = path_append(src, filename);
1837 
1838 		if (lstat(new_src, &sb) == -1) {
1839 			logit("%s: lstat failed: %s", filename,
1840 			    strerror(errno));
1841 			ret = -1;
1842 		} else if (S_ISDIR(sb.st_mode)) {
1843 			if (strcmp(filename, ".") == 0 ||
1844 			    strcmp(filename, "..") == 0)
1845 				continue;
1846 
1847 			if (upload_dir_internal(conn, new_src, new_dst,
1848 			    depth + 1, preserve_flag, print_flag, resume,
1849 			    fsync_flag) == -1)
1850 				ret = -1;
1851 		} else if (S_ISREG(sb.st_mode)) {
1852 			if (do_upload(conn, new_src, new_dst,
1853 			    preserve_flag, resume, fsync_flag) == -1) {
1854 				error("Uploading of file %s to %s failed!",
1855 				    new_src, new_dst);
1856 				ret = -1;
1857 			}
1858 		} else
1859 			logit("%s: not a regular file\n", filename);
1860 		free(new_dst);
1861 		free(new_src);
1862 	}
1863 
1864 	do_setstat(conn, dst, &a);
1865 
1866 	(void) closedir(dirp);
1867 	return ret;
1868 }
1869 
1870 int
1871 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
1872     int preserve_flag, int print_flag, int resume, int fsync_flag)
1873 {
1874 	char *dst_canon;
1875 	int ret;
1876 
1877 	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1878 		error("Unable to canonicalize path \"%s\"", dst);
1879 		return -1;
1880 	}
1881 
1882 	ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1883 	    print_flag, resume, fsync_flag);
1884 
1885 	free(dst_canon);
1886 	return ret;
1887 }
1888 
1889 char *
1890 path_append(const char *p1, const char *p2)
1891 {
1892 	char *ret;
1893 	size_t len = strlen(p1) + strlen(p2) + 2;
1894 
1895 	ret = xmalloc(len);
1896 	strlcpy(ret, p1, len);
1897 	if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
1898 		strlcat(ret, "/", len);
1899 	strlcat(ret, p2, len);
1900 
1901 	return(ret);
1902 }
1903 
1904