diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-28 22:11:49 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-28 22:11:49 +0000 |
| commit | 6c615a6c0718667d64fa45bb3169ec7d8a1c0ad5 (patch) | |
| tree | d7f3d2ad8722c78c18b012170f1ac35e63c4d368 | |
| parent | b9ad75fa602dd72b042b2ea08ce86da50746ab30 (diff) | |
| download | busybox-w32-6c615a6c0718667d64fa45bb3169ec7d8a1c0ad5.tar.gz busybox-w32-6c615a6c0718667d64fa45bb3169ec7d8a1c0ad5.tar.bz2 busybox-w32-6c615a6c0718667d64fa45bb3169ec7d8a1c0ad5.zip | |
ftpgetput: add comment about EPSV (extended PASV).
Fix bug where we were using lstat instead of stat.
Added many TODOs.
| -rw-r--r-- | networking/ftpgetput.c | 104 |
1 files changed, 65 insertions, 39 deletions
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index a1ee05426..3a9930cd7 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c | |||
| @@ -68,29 +68,6 @@ static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf) | |||
| 68 | return n; | 68 | return n; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) | ||
| 72 | { | ||
| 73 | char *buf_ptr; | ||
| 74 | unsigned port_num; | ||
| 75 | |||
| 76 | /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] | ||
| 77 | * Server's IP is N1.N2.N3.N4 (we ignore it) | ||
| 78 | * Server's port for data connection is P1*256+P2 */ | ||
| 79 | buf_ptr = strrchr(buf, ')'); | ||
| 80 | if (buf_ptr) *buf_ptr = '\0'; | ||
| 81 | |||
| 82 | buf_ptr = strrchr(buf, ','); | ||
| 83 | *buf_ptr = '\0'; | ||
| 84 | port_num = xatoul_range(buf_ptr + 1, 0, 255); | ||
| 85 | |||
| 86 | buf_ptr = strrchr(buf, ','); | ||
| 87 | *buf_ptr = '\0'; | ||
| 88 | port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; | ||
| 89 | |||
| 90 | set_nport(server->lsa, htons(port_num)); | ||
| 91 | return xconnect_stream(server->lsa); | ||
| 92 | } | ||
| 93 | |||
| 94 | static FILE *ftp_login(ftp_host_info_t *server) | 71 | static FILE *ftp_login(ftp_host_info_t *server) |
| 95 | { | 72 | { |
| 96 | FILE *control_stream; | 73 | FILE *control_stream; |
| @@ -125,6 +102,29 @@ static FILE *ftp_login(ftp_host_info_t *server) | |||
| 125 | return control_stream; | 102 | return control_stream; |
| 126 | } | 103 | } |
| 127 | 104 | ||
| 105 | static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) | ||
| 106 | { | ||
| 107 | char *buf_ptr; | ||
| 108 | unsigned port_num; | ||
| 109 | |||
| 110 | /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] | ||
| 111 | * Server's IP is N1.N2.N3.N4 (we ignore it) | ||
| 112 | * Server's port for data connection is P1*256+P2 */ | ||
| 113 | buf_ptr = strrchr(buf, ')'); | ||
| 114 | if (buf_ptr) *buf_ptr = '\0'; | ||
| 115 | |||
| 116 | buf_ptr = strrchr(buf, ','); | ||
| 117 | *buf_ptr = '\0'; | ||
| 118 | port_num = xatoul_range(buf_ptr + 1, 0, 255); | ||
| 119 | |||
| 120 | buf_ptr = strrchr(buf, ','); | ||
| 121 | *buf_ptr = '\0'; | ||
| 122 | port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; | ||
| 123 | |||
| 124 | set_nport(server->lsa, htons(port_num)); | ||
| 125 | return xconnect_stream(server->lsa); | ||
| 126 | } | ||
| 127 | |||
| 128 | #if !ENABLE_FTPGET | 128 | #if !ENABLE_FTPGET |
| 129 | int ftp_receive(ftp_host_info_t *server, FILE *control_stream, | 129 | int ftp_receive(ftp_host_info_t *server, FILE *control_stream, |
| 130 | const char *local_path, char *server_path); | 130 | const char *local_path, char *server_path); |
| @@ -141,7 +141,25 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream, | |||
| 141 | int fd_local = -1; | 141 | int fd_local = -1; |
| 142 | off_t beg_range = 0; | 142 | off_t beg_range = 0; |
| 143 | 143 | ||
| 144 | /* Connect to the data socket */ | 144 | /* |
| 145 | TODO: PASV command will not work for IPv6. RFC2428 describes | ||
| 146 | IPv6-capable "extended PASV" - EPSV. | ||
| 147 | |||
| 148 | "EPSV [protocol]" asks server to bind to and listen on a data port | ||
| 149 | in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. | ||
| 150 | If not specified, defaults to "same as used for control connection". | ||
| 151 | If server understood you, it should answer "229 <some text>(|||port|)" | ||
| 152 | where "|" are literal pipe chars and "port" is ASCII decimal port#. | ||
| 153 | |||
| 154 | There is also an IPv6-capable replacement for PORT (EPRT), | ||
| 155 | but we don't need that. | ||
| 156 | |||
| 157 | TODO: fold in sending of PASV/EPSV and parsing of response into | ||
| 158 | xconnect_ftpdata(). (Also, need to stop ignoring IP address in PASV | ||
| 159 | response). | ||
| 160 | */ | ||
| 161 | |||
| 162 | /* connect to the data socket */ | ||
| 145 | if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { | 163 | if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { |
| 146 | ftp_die("PASV", buf); | 164 | ftp_die("PASV", buf); |
| 147 | } | 165 | } |
| @@ -162,8 +180,9 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream, | |||
| 162 | 180 | ||
| 163 | if (do_continue) { | 181 | if (do_continue) { |
| 164 | struct stat sbuf; | 182 | struct stat sbuf; |
| 165 | if (lstat(local_path, &sbuf) < 0) { | 183 | /* lstat would be wrong here! */ |
| 166 | bb_perror_msg_and_die("lstat"); | 184 | if (stat(local_path, &sbuf) < 0) { |
| 185 | bb_perror_msg_and_die("stat"); | ||
| 167 | } | 186 | } |
| 168 | if (sbuf.st_size > 0) { | 187 | if (sbuf.st_size > 0) { |
| 169 | beg_range = sbuf.st_size; | 188 | beg_range = sbuf.st_size; |
| @@ -186,22 +205,25 @@ int ftp_receive(ftp_host_info_t *server, FILE *control_stream, | |||
| 186 | ftp_die("RETR", buf); | 205 | ftp_die("RETR", buf); |
| 187 | } | 206 | } |
| 188 | 207 | ||
| 189 | /* only make a local file if we know that one exists on the remote server */ | 208 | /* make local _after_ we know that remote file exists */ |
| 190 | if (fd_local == -1) { | 209 | if (fd_local == -1) { |
| 191 | if (do_continue) { | 210 | fd_local = xopen(local_path, |
| 192 | fd_local = xopen(local_path, O_APPEND | O_WRONLY); | 211 | do_continue ? (O_APPEND | O_WRONLY) |
| 193 | } else { | 212 | : (O_CREAT | O_TRUNC | O_WRONLY) |
| 194 | fd_local = xopen(local_path, O_CREAT | O_TRUNC | O_WRONLY); | 213 | ); |
| 195 | } | ||
| 196 | } | 214 | } |
| 197 | 215 | ||
| 198 | /* Copy the file */ | 216 | // TODO: merge tail of ftp_receive and ftp_send starting from here |
| 199 | if (filesize != -1) { | 217 | |
| 218 | /* copy the file */ | ||
| 219 | if (filesize != -1) { // NEVER HAPPENS, filesize is always -1 | ||
| 200 | if (bb_copyfd_size(fd_data, fd_local, filesize) == -1) | 220 | if (bb_copyfd_size(fd_data, fd_local, filesize) == -1) |
| 201 | return EXIT_FAILURE; | 221 | return EXIT_FAILURE; |
| 202 | } else { | 222 | } else { |
| 203 | if (bb_copyfd_eof(fd_data, fd_local) == -1) | 223 | if (bb_copyfd_eof(fd_data, fd_local) == -1) { |
| 224 | /* error msg is already printed by bb_copyfd_eof */ | ||
| 204 | return EXIT_FAILURE; | 225 | return EXIT_FAILURE; |
| 226 | } | ||
| 205 | } | 227 | } |
| 206 | 228 | ||
| 207 | /* close it all down */ | 229 | /* close it all down */ |
| @@ -229,7 +251,7 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream, | |||
| 229 | int fd_local; | 251 | int fd_local; |
| 230 | int response; | 252 | int response; |
| 231 | 253 | ||
| 232 | /* Connect to the data socket */ | 254 | /* connect to the data socket */ |
| 233 | if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { | 255 | if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { |
| 234 | ftp_die("PASV", buf); | 256 | ftp_die("PASV", buf); |
| 235 | } | 257 | } |
| @@ -241,6 +263,9 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream, | |||
| 241 | fd_local = xopen(local_path, O_RDONLY); | 263 | fd_local = xopen(local_path, O_RDONLY); |
| 242 | fstat(fd_local, &sbuf); | 264 | fstat(fd_local, &sbuf); |
| 243 | 265 | ||
| 266 | // TODO: do we really need to send ALLO? It's ancient... | ||
| 267 | // Doesn't it break "ftpput .. .. fifo" too? | ||
| 268 | |||
| 244 | sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size); | 269 | sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size); |
| 245 | response = ftpcmd(buf, NULL, control_stream, buf); | 270 | response = ftpcmd(buf, NULL, control_stream, buf); |
| 246 | switch (response) { | 271 | switch (response) { |
| @@ -248,7 +273,7 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream, | |||
| 248 | case 202: | 273 | case 202: |
| 249 | break; | 274 | break; |
| 250 | default: | 275 | default: |
| 251 | close(fd_local); | 276 | close(fd_local); // TODO: why bother? |
| 252 | ftp_die("ALLO", buf); | 277 | ftp_die("ALLO", buf); |
| 253 | break; | 278 | break; |
| 254 | } | 279 | } |
| @@ -259,13 +284,14 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream, | |||
| 259 | case 150: | 284 | case 150: |
| 260 | break; | 285 | break; |
| 261 | default: | 286 | default: |
| 262 | close(fd_local); | 287 | close(fd_local); // TODO: why bother? |
| 263 | ftp_die("STOR", buf); | 288 | ftp_die("STOR", buf); |
| 264 | } | 289 | } |
| 265 | 290 | ||
| 266 | /* transfer the file */ | 291 | /* transfer the file */ |
| 267 | if (bb_copyfd_eof(fd_local, fd_data) == -1) { | 292 | if (bb_copyfd_eof(fd_local, fd_data) == -1) { |
| 268 | exit(EXIT_FAILURE); | 293 | /* error msg is already printed by bb_copyfd_eof */ |
| 294 | return EXIT_FAILURE; | ||
| 269 | } | 295 | } |
| 270 | 296 | ||
| 271 | /* close it all down */ | 297 | /* close it all down */ |
