diff options
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 110 |
1 files changed, 72 insertions, 38 deletions
diff --git a/sftp-client.c b/sftp-client.c index f6a73f379..3b3279e65 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2001,2002 Damien Miller. All rights reserved. | 2 | * Copyright (c) 2001-2003 Damien Miller. All rights reserved. |
3 | * | 3 | * |
4 | * Redistribution and use in source and binary forms, with or without | 4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions | 5 | * modification, are permitted provided that the following conditions |
@@ -28,7 +28,7 @@ | |||
28 | /* XXX: copy between two remote sites */ | 28 | /* XXX: copy between two remote sites */ |
29 | 29 | ||
30 | #include "includes.h" | 30 | #include "includes.h" |
31 | RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $"); | 31 | RCSID("$OpenBSD: sftp-client.c,v 1.42 2003/03/05 22:33:43 markus Exp $"); |
32 | 32 | ||
33 | #include "openbsd-compat/sys-queue.h" | 33 | #include "openbsd-compat/sys-queue.h" |
34 | 34 | ||
@@ -38,14 +38,20 @@ RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $"); | |||
38 | #include "xmalloc.h" | 38 | #include "xmalloc.h" |
39 | #include "log.h" | 39 | #include "log.h" |
40 | #include "atomicio.h" | 40 | #include "atomicio.h" |
41 | #include "progressmeter.h" | ||
41 | 42 | ||
42 | #include "sftp.h" | 43 | #include "sftp.h" |
43 | #include "sftp-common.h" | 44 | #include "sftp-common.h" |
44 | #include "sftp-client.h" | 45 | #include "sftp-client.h" |
45 | 46 | ||
47 | extern int showprogress; | ||
48 | |||
46 | /* Minimum amount of data to read at at time */ | 49 | /* Minimum amount of data to read at at time */ |
47 | #define MIN_READ_SIZE 512 | 50 | #define MIN_READ_SIZE 512 |
48 | 51 | ||
52 | /* Maximum packet size */ | ||
53 | #define MAX_MSG_LENGTH (256 * 1024) | ||
54 | |||
49 | struct sftp_conn { | 55 | struct sftp_conn { |
50 | int fd_in; | 56 | int fd_in; |
51 | int fd_out; | 57 | int fd_out; |
@@ -58,48 +64,45 @@ struct sftp_conn { | |||
58 | static void | 64 | static void |
59 | send_msg(int fd, Buffer *m) | 65 | send_msg(int fd, Buffer *m) |
60 | { | 66 | { |
61 | int mlen = buffer_len(m); | 67 | u_char mlen[4]; |
62 | int len; | 68 | |
63 | Buffer oqueue; | 69 | if (buffer_len(m) > MAX_MSG_LENGTH) |
70 | fatal("Outbound message too long %u", buffer_len(m)); | ||
64 | 71 | ||
65 | buffer_init(&oqueue); | 72 | /* Send length first */ |
66 | buffer_put_int(&oqueue, mlen); | 73 | PUT_32BIT(mlen, buffer_len(m)); |
67 | buffer_append(&oqueue, buffer_ptr(m), mlen); | 74 | if (atomicio(write, fd, mlen, sizeof(mlen)) <= 0) |
68 | buffer_consume(m, mlen); | 75 | fatal("Couldn't send packet: %s", strerror(errno)); |
69 | 76 | ||
70 | len = atomicio(write, fd, buffer_ptr(&oqueue), buffer_len(&oqueue)); | 77 | if (atomicio(write, fd, buffer_ptr(m), buffer_len(m)) <= 0) |
71 | if (len <= 0) | ||
72 | fatal("Couldn't send packet: %s", strerror(errno)); | 78 | fatal("Couldn't send packet: %s", strerror(errno)); |
73 | 79 | ||
74 | buffer_free(&oqueue); | 80 | buffer_clear(m); |
75 | } | 81 | } |
76 | 82 | ||
77 | static void | 83 | static void |
78 | get_msg(int fd, Buffer *m) | 84 | get_msg(int fd, Buffer *m) |
79 | { | 85 | { |
80 | u_int len, msg_len; | 86 | ssize_t len; |
81 | unsigned char buf[4096]; | 87 | u_int msg_len; |
82 | 88 | ||
83 | len = atomicio(read, fd, buf, 4); | 89 | buffer_append_space(m, 4); |
90 | len = atomicio(read, fd, buffer_ptr(m), 4); | ||
84 | if (len == 0) | 91 | if (len == 0) |
85 | fatal("Connection closed"); | 92 | fatal("Connection closed"); |
86 | else if (len == -1) | 93 | else if (len == -1) |
87 | fatal("Couldn't read packet: %s", strerror(errno)); | 94 | fatal("Couldn't read packet: %s", strerror(errno)); |
88 | 95 | ||
89 | msg_len = GET_32BIT(buf); | 96 | msg_len = buffer_get_int(m); |
90 | if (msg_len > 256 * 1024) | 97 | if (msg_len > MAX_MSG_LENGTH) |
91 | fatal("Received message too long %u", msg_len); | 98 | fatal("Received message too long %u", msg_len); |
92 | 99 | ||
93 | while (msg_len) { | 100 | buffer_append_space(m, msg_len); |
94 | len = atomicio(read, fd, buf, MIN(msg_len, sizeof(buf))); | 101 | len = atomicio(read, fd, buffer_ptr(m), msg_len); |
95 | if (len == 0) | 102 | if (len == 0) |
96 | fatal("Connection closed"); | 103 | fatal("Connection closed"); |
97 | else if (len == -1) | 104 | else if (len == -1) |
98 | fatal("Couldn't read packet: %s", strerror(errno)); | 105 | fatal("Read packet: %s", strerror(errno)); |
99 | |||
100 | msg_len -= len; | ||
101 | buffer_append(m, buf, len); | ||
102 | } | ||
103 | } | 106 | } |
104 | 107 | ||
105 | static void | 108 | static void |
@@ -371,6 +374,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
371 | error("Couldn't read directory: %s", | 374 | error("Couldn't read directory: %s", |
372 | fx2txt(status)); | 375 | fx2txt(status)); |
373 | do_close(conn, handle, handle_len); | 376 | do_close(conn, handle, handle_len); |
377 | xfree(handle); | ||
374 | return(status); | 378 | return(status); |
375 | } | 379 | } |
376 | } else if (type != SSH2_FXP_NAME) | 380 | } else if (type != SSH2_FXP_NAME) |
@@ -660,7 +664,7 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
660 | 664 | ||
661 | status = get_status(conn->fd_in, id); | 665 | status = get_status(conn->fd_in, id); |
662 | if (status != SSH2_FX_OK) | 666 | if (status != SSH2_FX_OK) |
663 | error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, | 667 | error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, |
664 | newpath, fx2txt(status)); | 668 | newpath, fx2txt(status)); |
665 | 669 | ||
666 | return(status); | 670 | return(status); |
@@ -741,6 +745,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
741 | int read_error, write_errno; | 745 | int read_error, write_errno; |
742 | u_int64_t offset, size; | 746 | u_int64_t offset, size; |
743 | u_int handle_len, mode, type, id, buflen; | 747 | u_int handle_len, mode, type, id, buflen; |
748 | off_t progress_counter; | ||
744 | struct request { | 749 | struct request { |
745 | u_int id; | 750 | u_int id; |
746 | u_int len; | 751 | u_int len; |
@@ -758,13 +763,13 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
758 | 763 | ||
759 | /* XXX: should we preserve set[ug]id? */ | 764 | /* XXX: should we preserve set[ug]id? */ |
760 | if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) | 765 | if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
761 | mode = S_IWRITE | (a->perm & 0777); | 766 | mode = a->perm & 0777; |
762 | else | 767 | else |
763 | mode = 0666; | 768 | mode = 0666; |
764 | 769 | ||
765 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && | 770 | if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
766 | (a->perm & S_IFDIR)) { | 771 | (!S_ISREG(a->perm))) { |
767 | error("Cannot download a directory: %s", remote_path); | 772 | error("Cannot download non-regular file: %s", remote_path); |
768 | return(-1); | 773 | return(-1); |
769 | } | 774 | } |
770 | 775 | ||
@@ -793,7 +798,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
793 | return(-1); | 798 | return(-1); |
794 | } | 799 | } |
795 | 800 | ||
796 | local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode); | 801 | local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, |
802 | mode | S_IWRITE); | ||
797 | if (local_fd == -1) { | 803 | if (local_fd == -1) { |
798 | error("Couldn't open local file \"%s\" for writing: %s", | 804 | error("Couldn't open local file \"%s\" for writing: %s", |
799 | local_path, strerror(errno)); | 805 | local_path, strerror(errno)); |
@@ -805,6 +811,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
805 | /* Read from remote and write to local */ | 811 | /* Read from remote and write to local */ |
806 | write_error = read_error = write_errno = num_req = offset = 0; | 812 | write_error = read_error = write_errno = num_req = offset = 0; |
807 | max_req = 1; | 813 | max_req = 1; |
814 | progress_counter = 0; | ||
815 | |||
816 | if (showprogress) { | ||
817 | if (size) | ||
818 | start_progress_meter(remote_path, size, | ||
819 | &progress_counter); | ||
820 | else | ||
821 | printf("Fetching %s to %s\n", remote_path, local_path); | ||
822 | } | ||
823 | |||
808 | while (num_req > 0 || max_req > 0) { | 824 | while (num_req > 0 || max_req > 0) { |
809 | char *data; | 825 | char *data; |
810 | u_int len; | 826 | u_int len; |
@@ -857,14 +873,15 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
857 | (unsigned long long)req->offset + len - 1); | 873 | (unsigned long long)req->offset + len - 1); |
858 | if (len > req->len) | 874 | if (len > req->len) |
859 | fatal("Received more data than asked for " | 875 | fatal("Received more data than asked for " |
860 | "%u > %u", len, req->len); | 876 | "%u > %u", len, req->len); |
861 | if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || | 877 | if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || |
862 | atomicio(write, local_fd, data, len) != len) && | 878 | atomicio(write, local_fd, data, len) != len) && |
863 | !write_error) { | 879 | !write_error) { |
864 | write_errno = errno; | 880 | write_errno = errno; |
865 | write_error = 1; | 881 | write_error = 1; |
866 | max_req = 0; | 882 | max_req = 0; |
867 | } | 883 | } |
884 | progress_counter += len; | ||
868 | xfree(data); | 885 | xfree(data); |
869 | 886 | ||
870 | if (len == req->len) { | 887 | if (len == req->len) { |
@@ -907,6 +924,9 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
907 | } | 924 | } |
908 | } | 925 | } |
909 | 926 | ||
927 | if (showprogress && size) | ||
928 | stop_progress_meter(); | ||
929 | |||
910 | /* Sanity check */ | 930 | /* Sanity check */ |
911 | if (TAILQ_FIRST(&requests) != NULL) | 931 | if (TAILQ_FIRST(&requests) != NULL) |
912 | fatal("Transfer complete, but requests still in queue"); | 932 | fatal("Transfer complete, but requests still in queue"); |
@@ -930,7 +950,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
930 | if (pflag && chmod(local_path, mode) == -1) | 950 | if (pflag && chmod(local_path, mode) == -1) |
931 | #endif /* HAVE_FCHMOD */ | 951 | #endif /* HAVE_FCHMOD */ |
932 | error("Couldn't set mode on \"%s\": %s", local_path, | 952 | error("Couldn't set mode on \"%s\": %s", local_path, |
933 | strerror(errno)); | 953 | strerror(errno)); |
934 | if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { | 954 | if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { |
935 | struct timeval tv[2]; | 955 | struct timeval tv[2]; |
936 | tv[0].tv_sec = a->atime; | 956 | tv[0].tv_sec = a->atime; |
@@ -938,7 +958,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
938 | tv[0].tv_usec = tv[1].tv_usec = 0; | 958 | tv[0].tv_usec = tv[1].tv_usec = 0; |
939 | if (utimes(local_path, tv) == -1) | 959 | if (utimes(local_path, tv) == -1) |
940 | error("Can't set times on \"%s\": %s", | 960 | error("Can't set times on \"%s\": %s", |
941 | local_path, strerror(errno)); | 961 | local_path, strerror(errno)); |
942 | } | 962 | } |
943 | } | 963 | } |
944 | close(local_fd); | 964 | close(local_fd); |
@@ -983,6 +1003,11 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
983 | close(local_fd); | 1003 | close(local_fd); |
984 | return(-1); | 1004 | return(-1); |
985 | } | 1005 | } |
1006 | if (!S_ISREG(sb.st_mode)) { | ||
1007 | error("%s is not a regular file", local_path); | ||
1008 | close(local_fd); | ||
1009 | return(-1); | ||
1010 | } | ||
986 | stat_to_attrib(&sb, &a); | 1011 | stat_to_attrib(&sb, &a); |
987 | 1012 | ||
988 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; | 1013 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; |
@@ -1017,6 +1042,11 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1017 | 1042 | ||
1018 | /* Read from local and write to remote */ | 1043 | /* Read from local and write to remote */ |
1019 | offset = 0; | 1044 | offset = 0; |
1045 | if (showprogress) | ||
1046 | start_progress_meter(local_path, sb.st_size, &offset); | ||
1047 | else | ||
1048 | printf("Uploading %s to %s\n", local_path, remote_path); | ||
1049 | |||
1020 | for (;;) { | 1050 | for (;;) { |
1021 | int len; | 1051 | int len; |
1022 | 1052 | ||
@@ -1047,7 +1077,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1047 | buffer_put_string(&msg, data, len); | 1077 | buffer_put_string(&msg, data, len); |
1048 | send_msg(conn->fd_out, &msg); | 1078 | send_msg(conn->fd_out, &msg); |
1049 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", | 1079 | debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", |
1050 | id, (unsigned long long)offset, len); | 1080 | id, (unsigned long long)offset, len); |
1051 | } else if (TAILQ_FIRST(&acks) == NULL) | 1081 | } else if (TAILQ_FIRST(&acks) == NULL) |
1052 | break; | 1082 | break; |
1053 | 1083 | ||
@@ -1081,9 +1111,11 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1081 | 1111 | ||
1082 | if (status != SSH2_FX_OK) { | 1112 | if (status != SSH2_FX_OK) { |
1083 | error("Couldn't write to remote file \"%s\": %s", | 1113 | error("Couldn't write to remote file \"%s\": %s", |
1084 | remote_path, fx2txt(status)); | 1114 | remote_path, fx2txt(status)); |
1085 | do_close(conn, handle, handle_len); | 1115 | do_close(conn, handle, handle_len); |
1086 | close(local_fd); | 1116 | close(local_fd); |
1117 | xfree(data); | ||
1118 | xfree(ack); | ||
1087 | goto done; | 1119 | goto done; |
1088 | } | 1120 | } |
1089 | debug3("In write loop, ack for %u %u bytes at %llu", | 1121 | debug3("In write loop, ack for %u %u bytes at %llu", |
@@ -1093,6 +1125,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1093 | } | 1125 | } |
1094 | offset += len; | 1126 | offset += len; |
1095 | } | 1127 | } |
1128 | if (showprogress) | ||
1129 | stop_progress_meter(); | ||
1096 | xfree(data); | 1130 | xfree(data); |
1097 | 1131 | ||
1098 | if (close(local_fd) == -1) { | 1132 | if (close(local_fd) == -1) { |