2 * Copyright (c) 2001-2003 Damien Miller. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 /* XXX: signed vs unsigned */
27 /* XXX: remove all logging, only return status codes */
28 /* XXX: copy between two remote sites */
31 RCSID("$OpenBSD: sftp-client.c,v 1.40 2003/01/10 08:48:15 djm Exp $");
33 #include "openbsd-compat/sys-queue.h"
41 #include "progressmeter.h"
44 #include "sftp-common.h"
45 #include "sftp-client.h"
47 extern int showprogress;
49 /* Minimum amount of data to read at at time */
50 #define MIN_READ_SIZE 512
52 /* Maximum packet size */
53 #define MAX_MSG_LENGTH (256 * 1024)
58 u_int transfer_buflen;
65 send_msg(int fd, Buffer *m)
69 if (buffer_len(m) > MAX_MSG_LENGTH)
70 fatal("Outbound message too long %u", buffer_len(m));
72 /* Send length first */
73 PUT_32BIT(mlen, buffer_len(m));
74 if (atomicio(write, fd, mlen, sizeof(mlen)) <= 0)
75 fatal("Couldn't send packet: %s", strerror(errno));
77 if (atomicio(write, fd, buffer_ptr(m), buffer_len(m)) <= 0)
78 fatal("Couldn't send packet: %s", strerror(errno));
84 get_msg(int fd, Buffer *m)
89 buffer_append_space(m, 4);
90 len = atomicio(read, fd, buffer_ptr(m), 4);
92 fatal("Connection closed");
94 fatal("Couldn't read packet: %s", strerror(errno));
96 msg_len = buffer_get_int(m);
97 if (msg_len > MAX_MSG_LENGTH)
98 fatal("Received message too long %u", msg_len);
100 buffer_append_space(m, msg_len);
101 len = atomicio(read, fd, buffer_ptr(m), msg_len);
103 fatal("Connection closed");
105 fatal("Read packet: %s", strerror(errno));
109 send_string_request(int fd, u_int id, u_int code, char *s,
115 buffer_put_char(&msg, code);
116 buffer_put_int(&msg, id);
117 buffer_put_string(&msg, s, len);
119 debug3("Sent message fd %d T:%u I:%u", fd, code, id);
124 send_string_attrs_request(int fd, u_int id, u_int code, char *s,
125 u_int len, Attrib *a)
130 buffer_put_char(&msg, code);
131 buffer_put_int(&msg, id);
132 buffer_put_string(&msg, s, len);
133 encode_attrib(&msg, a);
135 debug3("Sent message fd %d T:%u I:%u", fd, code, id);
140 get_status(int fd, u_int expected_id)
143 u_int type, id, status;
147 type = buffer_get_char(&msg);
148 id = buffer_get_int(&msg);
150 if (id != expected_id)
151 fatal("ID mismatch (%u != %u)", id, expected_id);
152 if (type != SSH2_FXP_STATUS)
153 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
154 SSH2_FXP_STATUS, type);
156 status = buffer_get_int(&msg);
159 debug3("SSH2_FXP_STATUS %u", status);
165 get_handle(int fd, u_int expected_id, u_int *len)
173 type = buffer_get_char(&msg);
174 id = buffer_get_int(&msg);
176 if (id != expected_id)
177 fatal("ID mismatch (%u != %u)", id, expected_id);
178 if (type == SSH2_FXP_STATUS) {
179 int status = buffer_get_int(&msg);
181 error("Couldn't get handle: %s", fx2txt(status));
183 } else if (type != SSH2_FXP_HANDLE)
184 fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
185 SSH2_FXP_HANDLE, type);
187 handle = buffer_get_string(&msg, len);
194 get_decode_stat(int fd, u_int expected_id, int quiet)
203 type = buffer_get_char(&msg);
204 id = buffer_get_int(&msg);
206 debug3("Received stat reply T:%u I:%u", type, id);
207 if (id != expected_id)
208 fatal("ID mismatch (%u != %u)", id, expected_id);
209 if (type == SSH2_FXP_STATUS) {
210 int status = buffer_get_int(&msg);
213 debug("Couldn't stat remote file: %s", fx2txt(status));
215 error("Couldn't stat remote file: %s", fx2txt(status));
217 } else if (type != SSH2_FXP_ATTRS) {
218 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
219 SSH2_FXP_ATTRS, type);
221 a = decode_attrib(&msg);
228 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
233 struct sftp_conn *ret;
236 buffer_put_char(&msg, SSH2_FXP_INIT);
237 buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
238 send_msg(fd_out, &msg);
242 get_msg(fd_in, &msg);
244 /* Expecting a VERSION reply */
245 if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
246 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
251 version = buffer_get_int(&msg);
253 debug2("Remote version: %d", version);
255 /* Check for extensions */
256 while (buffer_len(&msg) > 0) {
257 char *name = buffer_get_string(&msg, NULL);
258 char *value = buffer_get_string(&msg, NULL);
260 debug2("Init extension: \"%s\"", name);
267 ret = xmalloc(sizeof(*ret));
269 ret->fd_out = fd_out;
270 ret->transfer_buflen = transfer_buflen;
271 ret->num_requests = num_requests;
272 ret->version = version;
275 /* Some filexfer v.0 servers don't support large packets */
277 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
283 sftp_proto_version(struct sftp_conn *conn)
285 return(conn->version);
289 do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
297 buffer_put_char(&msg, SSH2_FXP_CLOSE);
298 buffer_put_int(&msg, id);
299 buffer_put_string(&msg, handle, handle_len);
300 send_msg(conn->fd_out, &msg);
301 debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
303 status = get_status(conn->fd_in, id);
304 if (status != SSH2_FX_OK)
305 error("Couldn't close file: %s", fx2txt(status));
314 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
318 u_int type, id, handle_len, i, expected_id, ents = 0;
324 buffer_put_char(&msg, SSH2_FXP_OPENDIR);
325 buffer_put_int(&msg, id);
326 buffer_put_cstring(&msg, path);
327 send_msg(conn->fd_out, &msg);
331 handle = get_handle(conn->fd_in, id, &handle_len);
337 *dir = xmalloc(sizeof(**dir));
344 id = expected_id = conn->msg_id++;
346 debug3("Sending SSH2_FXP_READDIR I:%u", id);
349 buffer_put_char(&msg, SSH2_FXP_READDIR);
350 buffer_put_int(&msg, id);
351 buffer_put_string(&msg, handle, handle_len);
352 send_msg(conn->fd_out, &msg);
356 get_msg(conn->fd_in, &msg);
358 type = buffer_get_char(&msg);
359 id = buffer_get_int(&msg);
361 debug3("Received reply T:%u I:%u", type, id);
363 if (id != expected_id)
364 fatal("ID mismatch (%u != %u)", id, expected_id);
366 if (type == SSH2_FXP_STATUS) {
367 int status = buffer_get_int(&msg);
369 debug3("Received SSH2_FXP_STATUS %d", status);
371 if (status == SSH2_FX_EOF) {
374 error("Couldn't read directory: %s",
376 do_close(conn, handle, handle_len);
379 } else if (type != SSH2_FXP_NAME)
380 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
381 SSH2_FXP_NAME, type);
383 count = buffer_get_int(&msg);
386 debug3("Received %d SSH2_FXP_NAME responses", count);
387 for (i = 0; i < count; i++) {
388 char *filename, *longname;
391 filename = buffer_get_string(&msg, NULL);
392 longname = buffer_get_string(&msg, NULL);
393 a = decode_attrib(&msg);
396 printf("%s\n", longname);
399 *dir = xrealloc(*dir, sizeof(**dir) *
401 (*dir)[ents] = xmalloc(sizeof(***dir));
402 (*dir)[ents]->filename = xstrdup(filename);
403 (*dir)[ents]->longname = xstrdup(longname);
404 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
405 (*dir)[++ents] = NULL;
414 do_close(conn, handle, handle_len);
421 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
423 return(do_lsreaddir(conn, path, 0, dir));
426 void free_sftp_dirents(SFTP_DIRENT **s)
430 for (i = 0; s[i]; i++) {
431 xfree(s[i]->filename);
432 xfree(s[i]->longname);
439 do_rm(struct sftp_conn *conn, char *path)
443 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
446 send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,
448 status = get_status(conn->fd_in, id);
449 if (status != SSH2_FX_OK)
450 error("Couldn't delete file: %s", fx2txt(status));
455 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)
460 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
463 status = get_status(conn->fd_in, id);
464 if (status != SSH2_FX_OK)
465 error("Couldn't create directory: %s", fx2txt(status));
471 do_rmdir(struct sftp_conn *conn, char *path)
476 send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,
479 status = get_status(conn->fd_in, id);
480 if (status != SSH2_FX_OK)
481 error("Couldn't remove directory: %s", fx2txt(status));
487 do_stat(struct sftp_conn *conn, char *path, int quiet)
493 send_string_request(conn->fd_out, id,
494 conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
497 return(get_decode_stat(conn->fd_in, id, quiet));
501 do_lstat(struct sftp_conn *conn, char *path, int quiet)
505 if (conn->version == 0) {
507 debug("Server version does not support lstat operation");
509 log("Server version does not support lstat operation");
510 return(do_stat(conn, path, quiet));
514 send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,
517 return(get_decode_stat(conn->fd_in, id, quiet));
521 do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
526 send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,
529 return(get_decode_stat(conn->fd_in, id, quiet));
533 do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
538 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,
541 status = get_status(conn->fd_in, id);
542 if (status != SSH2_FX_OK)
543 error("Couldn't setstat on \"%s\": %s", path,
550 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
556 send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,
559 status = get_status(conn->fd_in, id);
560 if (status != SSH2_FX_OK)
561 error("Couldn't fsetstat: %s", fx2txt(status));
567 do_realpath(struct sftp_conn *conn, char *path)
570 u_int type, expected_id, count, id;
571 char *filename, *longname;
574 expected_id = id = conn->msg_id++;
575 send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,
580 get_msg(conn->fd_in, &msg);
581 type = buffer_get_char(&msg);
582 id = buffer_get_int(&msg);
584 if (id != expected_id)
585 fatal("ID mismatch (%u != %u)", id, expected_id);
587 if (type == SSH2_FXP_STATUS) {
588 u_int status = buffer_get_int(&msg);
590 error("Couldn't canonicalise: %s", fx2txt(status));
592 } else if (type != SSH2_FXP_NAME)
593 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
594 SSH2_FXP_NAME, type);
596 count = buffer_get_int(&msg);
598 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
600 filename = buffer_get_string(&msg, NULL);
601 longname = buffer_get_string(&msg, NULL);
602 a = decode_attrib(&msg);
604 debug3("SSH_FXP_REALPATH %s -> %s", path, filename);
614 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
621 /* Send rename request */
623 buffer_put_char(&msg, SSH2_FXP_RENAME);
624 buffer_put_int(&msg, id);
625 buffer_put_cstring(&msg, oldpath);
626 buffer_put_cstring(&msg, newpath);
627 send_msg(conn->fd_out, &msg);
628 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
632 status = get_status(conn->fd_in, id);
633 if (status != SSH2_FX_OK)
634 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
635 newpath, fx2txt(status));
641 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
646 if (conn->version < 3) {
647 error("This server does not support the symlink operation");
648 return(SSH2_FX_OP_UNSUPPORTED);
653 /* Send rename request */
655 buffer_put_char(&msg, SSH2_FXP_SYMLINK);
656 buffer_put_int(&msg, id);
657 buffer_put_cstring(&msg, oldpath);
658 buffer_put_cstring(&msg, newpath);
659 send_msg(conn->fd_out, &msg);
660 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
664 status = get_status(conn->fd_in, id);
665 if (status != SSH2_FX_OK)
666 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
667 newpath, fx2txt(status));
673 do_readlink(struct sftp_conn *conn, char *path)
676 u_int type, expected_id, count, id;
677 char *filename, *longname;
680 expected_id = id = conn->msg_id++;
681 send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,
686 get_msg(conn->fd_in, &msg);
687 type = buffer_get_char(&msg);
688 id = buffer_get_int(&msg);
690 if (id != expected_id)
691 fatal("ID mismatch (%u != %u)", id, expected_id);
693 if (type == SSH2_FXP_STATUS) {
694 u_int status = buffer_get_int(&msg);
696 error("Couldn't readlink: %s", fx2txt(status));
698 } else if (type != SSH2_FXP_NAME)
699 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
700 SSH2_FXP_NAME, type);
702 count = buffer_get_int(&msg);
704 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
706 filename = buffer_get_string(&msg, NULL);
707 longname = buffer_get_string(&msg, NULL);
708 a = decode_attrib(&msg);
710 debug3("SSH_FXP_READLINK %s -> %s", path, filename);
720 send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
721 char *handle, u_int handle_len)
727 buffer_put_char(&msg, SSH2_FXP_READ);
728 buffer_put_int(&msg, id);
729 buffer_put_string(&msg, handle, handle_len);
730 buffer_put_int64(&msg, offset);
731 buffer_put_int(&msg, len);
732 send_msg(fd_out, &msg);
737 do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
743 int local_fd, status, num_req, max_req, write_error;
744 int read_error, write_errno;
745 u_int64_t offset, size;
746 u_int handle_len, mode, type, id, buflen;
747 off_t progress_counter;
752 TAILQ_ENTRY(request) tq;
754 TAILQ_HEAD(reqhead, request) requests;
757 TAILQ_INIT(&requests);
759 a = do_stat(conn, remote_path, 0);
763 /* XXX: should we preserve set[ug]id? */
764 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
765 mode = a->perm & 0777;
769 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
770 (a->perm & S_IFDIR)) {
771 error("Cannot download a directory: %s", remote_path);
775 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
780 buflen = conn->transfer_buflen;
783 /* Send open request */
785 buffer_put_char(&msg, SSH2_FXP_OPEN);
786 buffer_put_int(&msg, id);
787 buffer_put_cstring(&msg, remote_path);
788 buffer_put_int(&msg, SSH2_FXF_READ);
789 attrib_clear(&junk); /* Send empty attributes */
790 encode_attrib(&msg, &junk);
791 send_msg(conn->fd_out, &msg);
792 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
794 handle = get_handle(conn->fd_in, id, &handle_len);
795 if (handle == NULL) {
800 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC,
802 if (local_fd == -1) {
803 error("Couldn't open local file \"%s\" for writing: %s",
804 local_path, strerror(errno));
810 /* Read from remote and write to local */
811 write_error = read_error = write_errno = num_req = offset = 0;
813 progress_counter = 0;
817 start_progress_meter(remote_path, size,
820 printf("Fetching %s to %s\n", remote_path, local_path);
823 while (num_req > 0 || max_req > 0) {
827 /* Send some more requests */
828 while (num_req < max_req) {
829 debug3("Request range %llu -> %llu (%d/%d)",
830 (unsigned long long)offset,
831 (unsigned long long)offset + buflen - 1,
833 req = xmalloc(sizeof(*req));
834 req->id = conn->msg_id++;
836 req->offset = offset;
839 TAILQ_INSERT_TAIL(&requests, req, tq);
840 send_read_request(conn->fd_out, req->id, req->offset,
841 req->len, handle, handle_len);
845 get_msg(conn->fd_in, &msg);
846 type = buffer_get_char(&msg);
847 id = buffer_get_int(&msg);
848 debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
850 /* Find the request in our queue */
851 for(req = TAILQ_FIRST(&requests);
852 req != NULL && req->id != id;
853 req = TAILQ_NEXT(req, tq))
856 fatal("Unexpected reply %u", id);
859 case SSH2_FXP_STATUS:
860 status = buffer_get_int(&msg);
861 if (status != SSH2_FX_EOF)
864 TAILQ_REMOVE(&requests, req, tq);
869 data = buffer_get_string(&msg, &len);
870 debug3("Received data %llu -> %llu",
871 (unsigned long long)req->offset,
872 (unsigned long long)req->offset + len - 1);
874 fatal("Received more data than asked for "
875 "%u > %u", len, req->len);
876 if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
877 atomicio(write, local_fd, data, len) != len) &&
883 progress_counter += len;
886 if (len == req->len) {
887 TAILQ_REMOVE(&requests, req, tq);
891 /* Resend the request for the missing data */
892 debug3("Short data block, re-requesting "
893 "%llu -> %llu (%2d)",
894 (unsigned long long)req->offset + len,
895 (unsigned long long)req->offset +
896 req->len - 1, num_req);
897 req->id = conn->msg_id++;
900 send_read_request(conn->fd_out, req->id,
901 req->offset, req->len, handle, handle_len);
902 /* Reduce the request size */
904 buflen = MAX(MIN_READ_SIZE, len);
906 if (max_req > 0) { /* max_req = 0 iff EOF received */
907 if (size > 0 && offset > size) {
908 /* Only one request at a time
909 * after the expected EOF */
910 debug3("Finish at %llu (%2d)",
911 (unsigned long long)offset,
915 else if (max_req < conn->num_requests + 1) {
921 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
922 SSH2_FXP_DATA, type);
926 if (showprogress && size)
927 stop_progress_meter();
930 if (TAILQ_FIRST(&requests) != NULL)
931 fatal("Transfer complete, but requests still in queue");
934 error("Couldn't read from remote file \"%s\" : %s",
935 remote_path, fx2txt(status));
936 do_close(conn, handle, handle_len);
937 } else if (write_error) {
938 error("Couldn't write to \"%s\": %s", local_path,
939 strerror(write_errno));
941 do_close(conn, handle, handle_len);
943 status = do_close(conn, handle, handle_len);
945 /* Override umask and utimes if asked */
947 if (pflag && fchmod(local_fd, mode) == -1)
949 if (pflag && chmod(local_path, mode) == -1)
950 #endif /* HAVE_FCHMOD */
951 error("Couldn't set mode on \"%s\": %s", local_path,
953 if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
954 struct timeval tv[2];
955 tv[0].tv_sec = a->atime;
956 tv[1].tv_sec = a->mtime;
957 tv[0].tv_usec = tv[1].tv_usec = 0;
958 if (utimes(local_path, tv) == -1)
959 error("Can't set times on \"%s\": %s",
960 local_path, strerror(errno));
971 do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
974 int local_fd, status;
975 u_int handle_len, id, type;
983 struct outstanding_ack {
987 TAILQ_ENTRY(outstanding_ack) tq;
989 TAILQ_HEAD(ackhead, outstanding_ack) acks;
990 struct outstanding_ack *ack;
994 if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
995 error("Couldn't open local file \"%s\" for reading: %s",
996 local_path, strerror(errno));
999 if (fstat(local_fd, &sb) == -1) {
1000 error("Couldn't fstat local file \"%s\": %s",
1001 local_path, strerror(errno));
1005 stat_to_attrib(&sb, &a);
1007 a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
1008 a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
1011 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1015 /* Send open request */
1016 id = conn->msg_id++;
1017 buffer_put_char(&msg, SSH2_FXP_OPEN);
1018 buffer_put_int(&msg, id);
1019 buffer_put_cstring(&msg, remote_path);
1020 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
1021 encode_attrib(&msg, &a);
1022 send_msg(conn->fd_out, &msg);
1023 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
1027 handle = get_handle(conn->fd_in, id, &handle_len);
1028 if (handle == NULL) {
1034 startid = ackid = id + 1;
1035 data = xmalloc(conn->transfer_buflen);
1037 /* Read from local and write to remote */
1040 start_progress_meter(local_path, sb.st_size, &offset);
1042 printf("Uploading %s to %s\n", local_path, remote_path);
1048 * Can't use atomicio here because it returns 0 on EOF, thus losing
1049 * the last block of the file
1052 len = read(local_fd, data, conn->transfer_buflen);
1053 while ((len == -1) && (errno == EINTR || errno == EAGAIN));
1056 fatal("Couldn't read from \"%s\": %s", local_path,
1060 ack = xmalloc(sizeof(*ack));
1062 ack->offset = offset;
1064 TAILQ_INSERT_TAIL(&acks, ack, tq);
1067 buffer_put_char(&msg, SSH2_FXP_WRITE);
1068 buffer_put_int(&msg, ack->id);
1069 buffer_put_string(&msg, handle, handle_len);
1070 buffer_put_int64(&msg, offset);
1071 buffer_put_string(&msg, data, len);
1072 send_msg(conn->fd_out, &msg);
1073 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1074 id, (unsigned long long)offset, len);
1075 } else if (TAILQ_FIRST(&acks) == NULL)
1079 fatal("Unexpected ACK %u", id);
1081 if (id == startid || len == 0 ||
1082 id - ackid >= conn->num_requests) {
1086 get_msg(conn->fd_in, &msg);
1087 type = buffer_get_char(&msg);
1088 r_id = buffer_get_int(&msg);
1090 if (type != SSH2_FXP_STATUS)
1091 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1092 "got %d", SSH2_FXP_STATUS, type);
1094 status = buffer_get_int(&msg);
1095 debug3("SSH2_FXP_STATUS %d", status);
1097 /* Find the request in our queue */
1098 for(ack = TAILQ_FIRST(&acks);
1099 ack != NULL && ack->id != r_id;
1100 ack = TAILQ_NEXT(ack, tq))
1103 fatal("Can't find request for ID %u", r_id);
1104 TAILQ_REMOVE(&acks, ack, tq);
1106 if (status != SSH2_FX_OK) {
1107 error("Couldn't write to remote file \"%s\": %s",
1108 remote_path, fx2txt(status));
1109 do_close(conn, handle, handle_len);
1113 debug3("In write loop, ack for %u %u bytes at %llu",
1114 ack->id, ack->len, (unsigned long long)ack->offset);
1121 stop_progress_meter();
1124 if (close(local_fd) == -1) {
1125 error("Couldn't close local file \"%s\": %s", local_path,
1127 do_close(conn, handle, handle_len);
1132 /* Override umask and utimes if asked */
1134 do_fsetstat(conn, handle, handle_len, &a);
1136 status = do_close(conn, handle, handle_len);