2 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 /* XXX: signed vs unsigned */
19 /* XXX: remove all logging, only return status codes */
20 /* XXX: copy between two remote sites */
23 RCSID("$OpenBSD: sftp-client.c,v 1.53 2005/03/10 22:01:05 deraadt Exp $");
25 #include "openbsd-compat/sys-queue.h"
33 #include "progressmeter.h"
36 #include "sftp-common.h"
37 #include "sftp-client.h"
39 extern volatile sig_atomic_t interrupted
;
40 extern int showprogress
;
42 /* Minimum amount of data to read at at time */
43 #define MIN_READ_SIZE 512
45 /* Maximum packet size */
46 #define MAX_MSG_LENGTH (256 * 1024)
51 u_int transfer_buflen
;
58 send_msg(int fd
, Buffer
*m
)
62 if (buffer_len(m
) > MAX_MSG_LENGTH
)
63 fatal("Outbound message too long %u", buffer_len(m
));
65 /* Send length first */
66 PUT_32BIT(mlen
, buffer_len(m
));
67 if (atomicio(vwrite
, fd
, mlen
, sizeof(mlen
)) <= 0)
68 fatal("Couldn't send packet: %s", strerror(errno
));
70 if (atomicio(vwrite
, fd
, buffer_ptr(m
), buffer_len(m
)) <= 0)
71 fatal("Couldn't send packet: %s", strerror(errno
));
77 get_msg(int fd
, Buffer
*m
)
82 buffer_append_space(m
, 4);
83 len
= atomicio(read
, fd
, buffer_ptr(m
), 4);
85 fatal("Connection closed");
87 fatal("Couldn't read packet: %s", strerror(errno
));
89 msg_len
= buffer_get_int(m
);
90 if (msg_len
> MAX_MSG_LENGTH
)
91 fatal("Received message too long %u", msg_len
);
93 buffer_append_space(m
, msg_len
);
94 len
= atomicio(read
, fd
, buffer_ptr(m
), msg_len
);
96 fatal("Connection closed");
98 fatal("Read packet: %s", strerror(errno
));
102 send_string_request(int fd
, u_int id
, u_int code
, char *s
,
108 buffer_put_char(&msg
, code
);
109 buffer_put_int(&msg
, id
);
110 buffer_put_string(&msg
, s
, len
);
112 debug3("Sent message fd %d T:%u I:%u", fd
, code
, id
);
117 send_string_attrs_request(int fd
, u_int id
, u_int code
, char *s
,
118 u_int len
, Attrib
*a
)
123 buffer_put_char(&msg
, code
);
124 buffer_put_int(&msg
, id
);
125 buffer_put_string(&msg
, s
, len
);
126 encode_attrib(&msg
, a
);
128 debug3("Sent message fd %d T:%u I:%u", fd
, code
, id
);
133 get_status(int fd
, u_int expected_id
)
136 u_int type
, id
, status
;
140 type
= buffer_get_char(&msg
);
141 id
= buffer_get_int(&msg
);
143 if (id
!= expected_id
)
144 fatal("ID mismatch (%u != %u)", id
, expected_id
);
145 if (type
!= SSH2_FXP_STATUS
)
146 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
147 SSH2_FXP_STATUS
, type
);
149 status
= buffer_get_int(&msg
);
152 debug3("SSH2_FXP_STATUS %u", status
);
158 get_handle(int fd
, u_int expected_id
, u_int
*len
)
166 type
= buffer_get_char(&msg
);
167 id
= buffer_get_int(&msg
);
169 if (id
!= expected_id
)
170 fatal("ID mismatch (%u != %u)", id
, expected_id
);
171 if (type
== SSH2_FXP_STATUS
) {
172 int status
= buffer_get_int(&msg
);
174 error("Couldn't get handle: %s", fx2txt(status
));
177 } else if (type
!= SSH2_FXP_HANDLE
)
178 fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
179 SSH2_FXP_HANDLE
, type
);
181 handle
= buffer_get_string(&msg
, len
);
188 get_decode_stat(int fd
, u_int expected_id
, int quiet
)
197 type
= buffer_get_char(&msg
);
198 id
= buffer_get_int(&msg
);
200 debug3("Received stat reply T:%u I:%u", type
, id
);
201 if (id
!= expected_id
)
202 fatal("ID mismatch (%u != %u)", id
, expected_id
);
203 if (type
== SSH2_FXP_STATUS
) {
204 int status
= buffer_get_int(&msg
);
207 debug("Couldn't stat remote file: %s", fx2txt(status
));
209 error("Couldn't stat remote file: %s", fx2txt(status
));
212 } else if (type
!= SSH2_FXP_ATTRS
) {
213 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
214 SSH2_FXP_ATTRS
, type
);
216 a
= decode_attrib(&msg
);
223 do_init(int fd_in
, int fd_out
, u_int transfer_buflen
, u_int num_requests
)
228 struct sftp_conn
*ret
;
231 buffer_put_char(&msg
, SSH2_FXP_INIT
);
232 buffer_put_int(&msg
, SSH2_FILEXFER_VERSION
);
233 send_msg(fd_out
, &msg
);
237 get_msg(fd_in
, &msg
);
239 /* Expecting a VERSION reply */
240 if ((type
= buffer_get_char(&msg
)) != SSH2_FXP_VERSION
) {
241 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
246 version
= buffer_get_int(&msg
);
248 debug2("Remote version: %d", version
);
250 /* Check for extensions */
251 while (buffer_len(&msg
) > 0) {
252 char *name
= buffer_get_string(&msg
, NULL
);
253 char *value
= buffer_get_string(&msg
, NULL
);
255 debug2("Init extension: \"%s\"", name
);
262 ret
= xmalloc(sizeof(*ret
));
264 ret
->fd_out
= fd_out
;
265 ret
->transfer_buflen
= transfer_buflen
;
266 ret
->num_requests
= num_requests
;
267 ret
->version
= version
;
270 /* Some filexfer v.0 servers don't support large packets */
272 ret
->transfer_buflen
= MIN(ret
->transfer_buflen
, 20480);
278 sftp_proto_version(struct sftp_conn
*conn
)
280 return(conn
->version
);
284 do_close(struct sftp_conn
*conn
, char *handle
, u_int handle_len
)
292 buffer_put_char(&msg
, SSH2_FXP_CLOSE
);
293 buffer_put_int(&msg
, id
);
294 buffer_put_string(&msg
, handle
, handle_len
);
295 send_msg(conn
->fd_out
, &msg
);
296 debug3("Sent message SSH2_FXP_CLOSE I:%u", id
);
298 status
= get_status(conn
->fd_in
, id
);
299 if (status
!= SSH2_FX_OK
)
300 error("Couldn't close file: %s", fx2txt(status
));
309 do_lsreaddir(struct sftp_conn
*conn
, char *path
, int printflag
,
313 u_int type
, id
, handle_len
, i
, expected_id
, ents
= 0;
319 buffer_put_char(&msg
, SSH2_FXP_OPENDIR
);
320 buffer_put_int(&msg
, id
);
321 buffer_put_cstring(&msg
, path
);
322 send_msg(conn
->fd_out
, &msg
);
326 handle
= get_handle(conn
->fd_in
, id
, &handle_len
);
332 *dir
= xmalloc(sizeof(**dir
));
336 for (; !interrupted
;) {
339 id
= expected_id
= conn
->msg_id
++;
341 debug3("Sending SSH2_FXP_READDIR I:%u", id
);
344 buffer_put_char(&msg
, SSH2_FXP_READDIR
);
345 buffer_put_int(&msg
, id
);
346 buffer_put_string(&msg
, handle
, handle_len
);
347 send_msg(conn
->fd_out
, &msg
);
351 get_msg(conn
->fd_in
, &msg
);
353 type
= buffer_get_char(&msg
);
354 id
= buffer_get_int(&msg
);
356 debug3("Received reply T:%u I:%u", type
, id
);
358 if (id
!= expected_id
)
359 fatal("ID mismatch (%u != %u)", id
, expected_id
);
361 if (type
== SSH2_FXP_STATUS
) {
362 int status
= buffer_get_int(&msg
);
364 debug3("Received SSH2_FXP_STATUS %d", status
);
366 if (status
== SSH2_FX_EOF
) {
369 error("Couldn't read directory: %s",
371 do_close(conn
, handle
, handle_len
);
375 } else if (type
!= SSH2_FXP_NAME
)
376 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
377 SSH2_FXP_NAME
, type
);
379 count
= buffer_get_int(&msg
);
382 debug3("Received %d SSH2_FXP_NAME responses", count
);
383 for (i
= 0; i
< count
; i
++) {
384 char *filename
, *longname
;
387 filename
= buffer_get_string(&msg
, NULL
);
388 longname
= buffer_get_string(&msg
, NULL
);
389 a
= decode_attrib(&msg
);
392 printf("%s\n", longname
);
395 *dir
= xrealloc(*dir
, sizeof(**dir
) *
397 (*dir
)[ents
] = xmalloc(sizeof(***dir
));
398 (*dir
)[ents
]->filename
= xstrdup(filename
);
399 (*dir
)[ents
]->longname
= xstrdup(longname
);
400 memcpy(&(*dir
)[ents
]->a
, a
, sizeof(*a
));
401 (*dir
)[++ents
] = NULL
;
410 do_close(conn
, handle
, handle_len
);
413 /* Don't return partial matches on interrupt */
414 if (interrupted
&& dir
!= NULL
&& *dir
!= NULL
) {
415 free_sftp_dirents(*dir
);
416 *dir
= xmalloc(sizeof(**dir
));
424 do_readdir(struct sftp_conn
*conn
, char *path
, SFTP_DIRENT
***dir
)
426 return(do_lsreaddir(conn
, path
, 0, dir
));
429 void free_sftp_dirents(SFTP_DIRENT
**s
)
433 for (i
= 0; s
[i
]; i
++) {
434 xfree(s
[i
]->filename
);
435 xfree(s
[i
]->longname
);
442 do_rm(struct sftp_conn
*conn
, char *path
)
446 debug2("Sending SSH2_FXP_REMOVE \"%s\"", path
);
449 send_string_request(conn
->fd_out
, id
, SSH2_FXP_REMOVE
, path
,
451 status
= get_status(conn
->fd_in
, id
);
452 if (status
!= SSH2_FX_OK
)
453 error("Couldn't delete file: %s", fx2txt(status
));
458 do_mkdir(struct sftp_conn
*conn
, char *path
, Attrib
*a
)
463 send_string_attrs_request(conn
->fd_out
, id
, SSH2_FXP_MKDIR
, path
,
466 status
= get_status(conn
->fd_in
, id
);
467 if (status
!= SSH2_FX_OK
)
468 error("Couldn't create directory: %s", fx2txt(status
));
474 do_rmdir(struct sftp_conn
*conn
, char *path
)
479 send_string_request(conn
->fd_out
, id
, SSH2_FXP_RMDIR
, path
,
482 status
= get_status(conn
->fd_in
, id
);
483 if (status
!= SSH2_FX_OK
)
484 error("Couldn't remove directory: %s", fx2txt(status
));
490 do_stat(struct sftp_conn
*conn
, char *path
, int quiet
)
496 send_string_request(conn
->fd_out
, id
,
497 conn
->version
== 0 ? SSH2_FXP_STAT_VERSION_0
: SSH2_FXP_STAT
,
500 return(get_decode_stat(conn
->fd_in
, id
, quiet
));
504 do_lstat(struct sftp_conn
*conn
, char *path
, int quiet
)
508 if (conn
->version
== 0) {
510 debug("Server version does not support lstat operation");
512 logit("Server version does not support lstat operation");
513 return(do_stat(conn
, path
, quiet
));
517 send_string_request(conn
->fd_out
, id
, SSH2_FXP_LSTAT
, path
,
520 return(get_decode_stat(conn
->fd_in
, id
, quiet
));
524 do_fstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
, int quiet
)
529 send_string_request(conn
->fd_out
, id
, SSH2_FXP_FSTAT
, handle
,
532 return(get_decode_stat(conn
->fd_in
, id
, quiet
));
536 do_setstat(struct sftp_conn
*conn
, char *path
, Attrib
*a
)
541 send_string_attrs_request(conn
->fd_out
, id
, SSH2_FXP_SETSTAT
, path
,
544 status
= get_status(conn
->fd_in
, id
);
545 if (status
!= SSH2_FX_OK
)
546 error("Couldn't setstat on \"%s\": %s", path
,
553 do_fsetstat(struct sftp_conn
*conn
, char *handle
, u_int handle_len
,
559 send_string_attrs_request(conn
->fd_out
, id
, SSH2_FXP_FSETSTAT
, handle
,
562 status
= get_status(conn
->fd_in
, id
);
563 if (status
!= SSH2_FX_OK
)
564 error("Couldn't fsetstat: %s", fx2txt(status
));
570 do_realpath(struct sftp_conn
*conn
, char *path
)
573 u_int type
, expected_id
, count
, id
;
574 char *filename
, *longname
;
577 expected_id
= id
= conn
->msg_id
++;
578 send_string_request(conn
->fd_out
, id
, SSH2_FXP_REALPATH
, path
,
583 get_msg(conn
->fd_in
, &msg
);
584 type
= buffer_get_char(&msg
);
585 id
= buffer_get_int(&msg
);
587 if (id
!= expected_id
)
588 fatal("ID mismatch (%u != %u)", id
, expected_id
);
590 if (type
== SSH2_FXP_STATUS
) {
591 u_int status
= buffer_get_int(&msg
);
593 error("Couldn't canonicalise: %s", fx2txt(status
));
595 } else if (type
!= SSH2_FXP_NAME
)
596 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
597 SSH2_FXP_NAME
, type
);
599 count
= buffer_get_int(&msg
);
601 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count
);
603 filename
= buffer_get_string(&msg
, NULL
);
604 longname
= buffer_get_string(&msg
, NULL
);
605 a
= decode_attrib(&msg
);
607 debug3("SSH_FXP_REALPATH %s -> %s", path
, filename
);
617 do_rename(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
624 /* Send rename request */
626 buffer_put_char(&msg
, SSH2_FXP_RENAME
);
627 buffer_put_int(&msg
, id
);
628 buffer_put_cstring(&msg
, oldpath
);
629 buffer_put_cstring(&msg
, newpath
);
630 send_msg(conn
->fd_out
, &msg
);
631 debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath
,
635 status
= get_status(conn
->fd_in
, id
);
636 if (status
!= SSH2_FX_OK
)
637 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath
,
638 newpath
, fx2txt(status
));
644 do_symlink(struct sftp_conn
*conn
, char *oldpath
, char *newpath
)
649 if (conn
->version
< 3) {
650 error("This server does not support the symlink operation");
651 return(SSH2_FX_OP_UNSUPPORTED
);
656 /* Send symlink request */
658 buffer_put_char(&msg
, SSH2_FXP_SYMLINK
);
659 buffer_put_int(&msg
, id
);
660 buffer_put_cstring(&msg
, oldpath
);
661 buffer_put_cstring(&msg
, newpath
);
662 send_msg(conn
->fd_out
, &msg
);
663 debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath
,
667 status
= get_status(conn
->fd_in
, id
);
668 if (status
!= SSH2_FX_OK
)
669 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath
,
670 newpath
, fx2txt(status
));
676 do_readlink(struct sftp_conn
*conn
, char *path
)
679 u_int type
, expected_id
, count
, id
;
680 char *filename
, *longname
;
683 expected_id
= id
= conn
->msg_id
++;
684 send_string_request(conn
->fd_out
, id
, SSH2_FXP_READLINK
, path
,
689 get_msg(conn
->fd_in
, &msg
);
690 type
= buffer_get_char(&msg
);
691 id
= buffer_get_int(&msg
);
693 if (id
!= expected_id
)
694 fatal("ID mismatch (%u != %u)", id
, expected_id
);
696 if (type
== SSH2_FXP_STATUS
) {
697 u_int status
= buffer_get_int(&msg
);
699 error("Couldn't readlink: %s", fx2txt(status
));
701 } else if (type
!= SSH2_FXP_NAME
)
702 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
703 SSH2_FXP_NAME
, type
);
705 count
= buffer_get_int(&msg
);
707 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count
);
709 filename
= buffer_get_string(&msg
, NULL
);
710 longname
= buffer_get_string(&msg
, NULL
);
711 a
= decode_attrib(&msg
);
713 debug3("SSH_FXP_READLINK %s -> %s", path
, filename
);
723 send_read_request(int fd_out
, u_int id
, u_int64_t offset
, u_int len
,
724 char *handle
, u_int handle_len
)
730 buffer_put_char(&msg
, SSH2_FXP_READ
);
731 buffer_put_int(&msg
, id
);
732 buffer_put_string(&msg
, handle
, handle_len
);
733 buffer_put_int64(&msg
, offset
);
734 buffer_put_int(&msg
, len
);
735 send_msg(fd_out
, &msg
);
740 do_download(struct sftp_conn
*conn
, char *remote_path
, char *local_path
,
746 int local_fd
, status
, num_req
, max_req
, write_error
;
747 int read_error
, write_errno
;
748 u_int64_t offset
, size
;
749 u_int handle_len
, mode
, type
, id
, buflen
;
750 off_t progress_counter
;
755 TAILQ_ENTRY(request
) tq
;
757 TAILQ_HEAD(reqhead
, request
) requests
;
760 TAILQ_INIT(&requests
);
762 a
= do_stat(conn
, remote_path
, 0);
766 /* XXX: should we preserve set[ug]id? */
767 if (a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
)
768 mode
= a
->perm
& 0777;
772 if ((a
->flags
& SSH2_FILEXFER_ATTR_PERMISSIONS
) &&
773 (!S_ISREG(a
->perm
))) {
774 error("Cannot download non-regular file: %s", remote_path
);
778 if (a
->flags
& SSH2_FILEXFER_ATTR_SIZE
)
783 buflen
= conn
->transfer_buflen
;
786 /* Send open request */
788 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
789 buffer_put_int(&msg
, id
);
790 buffer_put_cstring(&msg
, remote_path
);
791 buffer_put_int(&msg
, SSH2_FXF_READ
);
792 attrib_clear(&junk
); /* Send empty attributes */
793 encode_attrib(&msg
, &junk
);
794 send_msg(conn
->fd_out
, &msg
);
795 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
797 handle
= get_handle(conn
->fd_in
, id
, &handle_len
);
798 if (handle
== NULL
) {
803 local_fd
= open(local_path
, O_WRONLY
| O_CREAT
| O_TRUNC
,
805 if (local_fd
== -1) {
806 error("Couldn't open local file \"%s\" for writing: %s",
807 local_path
, strerror(errno
));
813 /* Read from remote and write to local */
814 write_error
= read_error
= write_errno
= num_req
= offset
= 0;
816 progress_counter
= 0;
818 if (showprogress
&& size
!= 0)
819 start_progress_meter(remote_path
, size
, &progress_counter
);
821 while (num_req
> 0 || max_req
> 0) {
826 * Simulate EOF on interrupt: stop sending new requests and
827 * allow outstanding requests to drain gracefully
830 if (num_req
== 0) /* If we haven't started yet... */
835 /* Send some more requests */
836 while (num_req
< max_req
) {
837 debug3("Request range %llu -> %llu (%d/%d)",
838 (unsigned long long)offset
,
839 (unsigned long long)offset
+ buflen
- 1,
841 req
= xmalloc(sizeof(*req
));
842 req
->id
= conn
->msg_id
++;
844 req
->offset
= offset
;
847 TAILQ_INSERT_TAIL(&requests
, req
, tq
);
848 send_read_request(conn
->fd_out
, req
->id
, req
->offset
,
849 req
->len
, handle
, handle_len
);
853 get_msg(conn
->fd_in
, &msg
);
854 type
= buffer_get_char(&msg
);
855 id
= buffer_get_int(&msg
);
856 debug3("Received reply T:%u I:%u R:%d", type
, id
, max_req
);
858 /* Find the request in our queue */
859 for (req
= TAILQ_FIRST(&requests
);
860 req
!= NULL
&& req
->id
!= id
;
861 req
= TAILQ_NEXT(req
, tq
))
864 fatal("Unexpected reply %u", id
);
867 case SSH2_FXP_STATUS
:
868 status
= buffer_get_int(&msg
);
869 if (status
!= SSH2_FX_EOF
)
872 TAILQ_REMOVE(&requests
, req
, tq
);
877 data
= buffer_get_string(&msg
, &len
);
878 debug3("Received data %llu -> %llu",
879 (unsigned long long)req
->offset
,
880 (unsigned long long)req
->offset
+ len
- 1);
882 fatal("Received more data than asked for "
883 "%u > %u", len
, req
->len
);
884 if ((lseek(local_fd
, req
->offset
, SEEK_SET
) == -1 ||
885 atomicio(vwrite
, local_fd
, data
, len
) != len
) &&
891 progress_counter
+= len
;
894 if (len
== req
->len
) {
895 TAILQ_REMOVE(&requests
, req
, tq
);
899 /* Resend the request for the missing data */
900 debug3("Short data block, re-requesting "
901 "%llu -> %llu (%2d)",
902 (unsigned long long)req
->offset
+ len
,
903 (unsigned long long)req
->offset
+
904 req
->len
- 1, num_req
);
905 req
->id
= conn
->msg_id
++;
908 send_read_request(conn
->fd_out
, req
->id
,
909 req
->offset
, req
->len
, handle
, handle_len
);
910 /* Reduce the request size */
912 buflen
= MAX(MIN_READ_SIZE
, len
);
914 if (max_req
> 0) { /* max_req = 0 iff EOF received */
915 if (size
> 0 && offset
> size
) {
916 /* Only one request at a time
917 * after the expected EOF */
918 debug3("Finish at %llu (%2d)",
919 (unsigned long long)offset
,
922 } else if (max_req
<= conn
->num_requests
) {
928 fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
929 SSH2_FXP_DATA
, type
);
933 if (showprogress
&& size
)
934 stop_progress_meter();
937 if (TAILQ_FIRST(&requests
) != NULL
)
938 fatal("Transfer complete, but requests still in queue");
941 error("Couldn't read from remote file \"%s\" : %s",
942 remote_path
, fx2txt(status
));
943 do_close(conn
, handle
, handle_len
);
944 } else if (write_error
) {
945 error("Couldn't write to \"%s\": %s", local_path
,
946 strerror(write_errno
));
948 do_close(conn
, handle
, handle_len
);
950 status
= do_close(conn
, handle
, handle_len
);
952 /* Override umask and utimes if asked */
954 if (pflag
&& fchmod(local_fd
, mode
) == -1)
956 if (pflag
&& chmod(local_path
, mode
) == -1)
957 #endif /* HAVE_FCHMOD */
958 error("Couldn't set mode on \"%s\": %s", local_path
,
960 if (pflag
&& (a
->flags
& SSH2_FILEXFER_ATTR_ACMODTIME
)) {
961 struct timeval tv
[2];
962 tv
[0].tv_sec
= a
->atime
;
963 tv
[1].tv_sec
= a
->mtime
;
964 tv
[0].tv_usec
= tv
[1].tv_usec
= 0;
965 if (utimes(local_path
, tv
) == -1)
966 error("Can't set times on \"%s\": %s",
967 local_path
, strerror(errno
));
978 do_upload(struct sftp_conn
*conn
, char *local_path
, char *remote_path
,
981 int local_fd
, status
;
982 u_int handle_len
, id
, type
;
990 struct outstanding_ack
{
994 TAILQ_ENTRY(outstanding_ack
) tq
;
996 TAILQ_HEAD(ackhead
, outstanding_ack
) acks
;
997 struct outstanding_ack
*ack
= NULL
;
1001 if ((local_fd
= open(local_path
, O_RDONLY
, 0)) == -1) {
1002 error("Couldn't open local file \"%s\" for reading: %s",
1003 local_path
, strerror(errno
));
1006 if (fstat(local_fd
, &sb
) == -1) {
1007 error("Couldn't fstat local file \"%s\": %s",
1008 local_path
, strerror(errno
));
1012 if (!S_ISREG(sb
.st_mode
)) {
1013 error("%s is not a regular file", local_path
);
1017 stat_to_attrib(&sb
, &a
);
1019 a
.flags
&= ~SSH2_FILEXFER_ATTR_SIZE
;
1020 a
.flags
&= ~SSH2_FILEXFER_ATTR_UIDGID
;
1023 a
.flags
&= ~SSH2_FILEXFER_ATTR_ACMODTIME
;
1027 /* Send open request */
1028 id
= conn
->msg_id
++;
1029 buffer_put_char(&msg
, SSH2_FXP_OPEN
);
1030 buffer_put_int(&msg
, id
);
1031 buffer_put_cstring(&msg
, remote_path
);
1032 buffer_put_int(&msg
, SSH2_FXF_WRITE
|SSH2_FXF_CREAT
|SSH2_FXF_TRUNC
);
1033 encode_attrib(&msg
, &a
);
1034 send_msg(conn
->fd_out
, &msg
);
1035 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id
, remote_path
);
1039 handle
= get_handle(conn
->fd_in
, id
, &handle_len
);
1040 if (handle
== NULL
) {
1046 startid
= ackid
= id
+ 1;
1047 data
= xmalloc(conn
->transfer_buflen
);
1049 /* Read from local and write to remote */
1052 start_progress_meter(local_path
, sb
.st_size
, &offset
);
1058 * Can't use atomicio here because it returns 0 on EOF,
1059 * thus losing the last block of the file.
1060 * Simulate an EOF on interrupt, allowing ACKs from the
1066 len
= read(local_fd
, data
, conn
->transfer_buflen
);
1067 while ((len
== -1) && (errno
== EINTR
|| errno
== EAGAIN
));
1070 fatal("Couldn't read from \"%s\": %s", local_path
,
1074 ack
= xmalloc(sizeof(*ack
));
1076 ack
->offset
= offset
;
1078 TAILQ_INSERT_TAIL(&acks
, ack
, tq
);
1081 buffer_put_char(&msg
, SSH2_FXP_WRITE
);
1082 buffer_put_int(&msg
, ack
->id
);
1083 buffer_put_string(&msg
, handle
, handle_len
);
1084 buffer_put_int64(&msg
, offset
);
1085 buffer_put_string(&msg
, data
, len
);
1086 send_msg(conn
->fd_out
, &msg
);
1087 debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
1088 id
, (unsigned long long)offset
, len
);
1089 } else if (TAILQ_FIRST(&acks
) == NULL
)
1093 fatal("Unexpected ACK %u", id
);
1095 if (id
== startid
|| len
== 0 ||
1096 id
- ackid
>= conn
->num_requests
) {
1100 get_msg(conn
->fd_in
, &msg
);
1101 type
= buffer_get_char(&msg
);
1102 r_id
= buffer_get_int(&msg
);
1104 if (type
!= SSH2_FXP_STATUS
)
1105 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
1106 "got %d", SSH2_FXP_STATUS
, type
);
1108 status
= buffer_get_int(&msg
);
1109 debug3("SSH2_FXP_STATUS %d", status
);
1111 /* Find the request in our queue */
1112 for (ack
= TAILQ_FIRST(&acks
);
1113 ack
!= NULL
&& ack
->id
!= r_id
;
1114 ack
= TAILQ_NEXT(ack
, tq
))
1117 fatal("Can't find request for ID %u", r_id
);
1118 TAILQ_REMOVE(&acks
, ack
, tq
);
1120 if (status
!= SSH2_FX_OK
) {
1121 error("Couldn't write to remote file \"%s\": %s",
1122 remote_path
, fx2txt(status
));
1123 do_close(conn
, handle
, handle_len
);
1129 debug3("In write loop, ack for %u %u bytes at %llu",
1130 ack
->id
, ack
->len
, (unsigned long long)ack
->offset
);
1137 stop_progress_meter();
1140 if (close(local_fd
) == -1) {
1141 error("Couldn't close local file \"%s\": %s", local_path
,
1143 do_close(conn
, handle
, handle_len
);
1148 /* Override umask and utimes if asked */
1150 do_fsetstat(conn
, handle
, handle_len
, &a
);
1152 status
= do_close(conn
, handle
, handle_len
);