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