summaryrefslogtreecommitdiff
path: root/sftp-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-client.c')
-rw-r--r--sftp-client.c110
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"
31RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $"); 31RCSID("$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
47extern 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
49struct sftp_conn { 55struct 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 {
58static void 64static void
59send_msg(int fd, Buffer *m) 65send_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
77static void 83static void
78get_msg(int fd, Buffer *m) 84get_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
105static void 108static 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) {