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