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