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