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