aboutsummaryrefslogtreecommitdiff
path: root/networking/ftpgetput.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-29 07:37:42 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-29 07:37:42 +0000
commit0e7940ae906ea9f29050323fced2bc48f70008af (patch)
treeb94d4438e18c2ff139371c7eaa1d1c8fc7134150 /networking/ftpgetput.c
parent6c615a6c0718667d64fa45bb3169ec7d8a1c0ad5 (diff)
downloadbusybox-w32-0e7940ae906ea9f29050323fced2bc48f70008af.tar.gz
busybox-w32-0e7940ae906ea9f29050323fced2bc48f70008af.tar.bz2
busybox-w32-0e7940ae906ea9f29050323fced2bc48f70008af.zip
ftpgetput: deal with long-standing TODOs:
- do not use ALLO on upload - move globals to "struct globals" - move buf[] there too - remove commented out "filesize" code - other shrinkage function old new delta xconnect_ftpdata 117 127 +10 ftp_die 49 59 +10 ftpcmd 292 301 +9 verbose_flag 1 - -1 do_continue 1 - -1 ftpgetput_main 405 352 -53 ftp_receive 451 394 -57 ftp_send 325 185 -140 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 3/3 up/down: 29/-252) Total: -223 bytes
Diffstat (limited to 'networking/ftpgetput.c')
-rw-r--r--networking/ftpgetput.c196
1 files changed, 82 insertions, 114 deletions
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c
index 3a9930cd7..57adb52c1 100644
--- a/networking/ftpgetput.c
+++ b/networking/ftpgetput.c
@@ -15,28 +15,43 @@
15 15
16#include "libbb.h" 16#include "libbb.h"
17 17
18typedef struct ftp_host_info_s { 18struct globals {
19 const char *user; 19 const char *user;
20 const char *password; 20 const char *password;
21 struct len_and_sockaddr *lsa; 21 struct len_and_sockaddr *lsa;
22} ftp_host_info_t; 22 int verbose_flag;
23 23 int do_continue;
24static smallint verbose_flag; 24 char buf[1]; /* actually [BUF_SIZE] */
25static smallint do_continue; 25};
26 26#define G (*(struct globals*)&bb_common_bufsiz1)
27static void ftp_die(const char *msg, const char *remote) ATTRIBUTE_NORETURN; 27enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) };
28static void ftp_die(const char *msg, const char *remote) 28struct BUG_G_too_big {
29 char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
30};
31#define user (G.user )
32#define password (G.password )
33#define lsa (G.lsa )
34#define verbose_flag (G.verbose_flag)
35#define do_continue (G.do_continue )
36#define buf (G.buf )
37#define INIT_G() do { \
38} while (0)
39
40
41static void ftp_die(const char *msg) ATTRIBUTE_NORETURN;
42static void ftp_die(const char *msg)
29{ 43{
44 const char *cp = buf; /* buf holds peer's response */
45
30 /* Guard against garbage from remote server */ 46 /* Guard against garbage from remote server */
31 const char *cp = remote; 47 while (*cp >= ' ' && *cp < '\x7f')
32 while (*cp >= ' ' && *cp < '\x7f') cp++; 48 cp++;
33 bb_error_msg_and_die("unexpected server response%s%s: %.*s", 49 bb_error_msg_and_die("unexpected server response%s%s: %.*s",
34 msg ? " to " : "", msg ? msg : "", 50 msg ? " to " : "", msg ? msg : "",
35 (int)(cp - remote), remote); 51 (int)(cp - buf), buf);
36} 52}
37 53
38 54static int ftpcmd(const char *s1, const char *s2, FILE *stream)
39static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
40{ 55{
41 unsigned n; 56 unsigned n;
42 if (verbose_flag) { 57 if (verbose_flag) {
@@ -44,16 +59,13 @@ static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
44 } 59 }
45 60
46 if (s1) { 61 if (s1) {
47 if (s2) { 62 fprintf(stream, (s2 ? "%s %s\r\n" : "%s %s\r\n"+3), s1, s2);
48 fprintf(stream, "%s %s\r\n", s1, s2);
49 } else {
50 fprintf(stream, "%s\r\n", s1);
51 }
52 } 63 }
64
53 do { 65 do {
54 char *buf_ptr; 66 char *buf_ptr;
55 67
56 if (fgets(buf, 510, stream) == NULL) { 68 if (fgets(buf, BUFSZ - 2, stream) == NULL) {
57 bb_perror_msg_and_die("fgets"); 69 bb_perror_msg_and_die("fgets");
58 } 70 }
59 buf_ptr = strstr(buf, "\r\n"); 71 buf_ptr = strstr(buf, "\r\n");
@@ -68,41 +80,40 @@ static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf)
68 return n; 80 return n;
69} 81}
70 82
71static FILE *ftp_login(ftp_host_info_t *server) 83static FILE *ftp_login(void)
72{ 84{
73 FILE *control_stream; 85 FILE *control_stream;
74 char buf[512];
75 86
76 /* Connect to the command socket */ 87 /* Connect to the command socket */
77 control_stream = fdopen(xconnect_stream(server->lsa), "r+"); 88 control_stream = fdopen(xconnect_stream(lsa), "r+");
78 if (control_stream == NULL) { 89 if (control_stream == NULL) {
79 /* fdopen failed - extremely unlikely */ 90 /* fdopen failed - extremely unlikely */
80 bb_perror_nomsg_and_die(); 91 bb_perror_nomsg_and_die();
81 } 92 }
82 93
83 if (ftpcmd(NULL, NULL, control_stream, buf) != 220) { 94 if (ftpcmd(NULL, NULL, control_stream) != 220) {
84 ftp_die(NULL, buf); 95 ftp_die(NULL);
85 } 96 }
86 97
87 /* Login to the server */ 98 /* Login to the server */
88 switch (ftpcmd("USER", server->user, control_stream, buf)) { 99 switch (ftpcmd("USER", user, control_stream)) {
89 case 230: 100 case 230:
90 break; 101 break;
91 case 331: 102 case 331:
92 if (ftpcmd("PASS", server->password, control_stream, buf) != 230) { 103 if (ftpcmd("PASS", password, control_stream) != 230) {
93 ftp_die("PASS", buf); 104 ftp_die("PASS");
94 } 105 }
95 break; 106 break;
96 default: 107 default:
97 ftp_die("USER", buf); 108 ftp_die("USER");
98 } 109 }
99 110
100 ftpcmd("TYPE I", NULL, control_stream, buf); 111 ftpcmd("TYPE I", NULL, control_stream);
101 112
102 return control_stream; 113 return control_stream;
103} 114}
104 115
105static int xconnect_ftpdata(ftp_host_info_t *server, char *buf) 116static int xconnect_ftpdata(void)
106{ 117{
107 char *buf_ptr; 118 char *buf_ptr;
108 unsigned port_num; 119 unsigned port_num;
@@ -121,21 +132,18 @@ static int xconnect_ftpdata(ftp_host_info_t *server, char *buf)
121 *buf_ptr = '\0'; 132 *buf_ptr = '\0';
122 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; 133 port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
123 134
124 set_nport(server->lsa, htons(port_num)); 135 set_nport(lsa, htons(port_num));
125 return xconnect_stream(server->lsa); 136 return xconnect_stream(lsa);
126} 137}
127 138
128#if !ENABLE_FTPGET 139#if !ENABLE_FTPGET
129int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 140int ftp_receive(FILE *control_stream,
130 const char *local_path, char *server_path); 141 const char *local_path, char *server_path);
131#else 142#else
132static 143static
133int ftp_receive(ftp_host_info_t *server, FILE *control_stream, 144int ftp_receive(FILE *control_stream,
134 const char *local_path, char *server_path) 145 const char *local_path, char *server_path)
135{ 146{
136 char buf[512];
137/* I think 'filesize' usage here is bogus. Let's see... */
138 //off_t filesize = -1;
139#define filesize ((off_t)-1) 147#define filesize ((off_t)-1)
140 int fd_data; 148 int fd_data;
141 int fd_local = -1; 149 int fd_local = -1;
@@ -160,16 +168,12 @@ response).
160*/ 168*/
161 169
162 /* connect to the data socket */ 170 /* connect to the data socket */
163 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 171 if (ftpcmd("PASV", NULL, control_stream) != 227) {
164 ftp_die("PASV", buf); 172 ftp_die("PASV");
165 } 173 }
166 fd_data = xconnect_ftpdata(server, buf); 174 fd_data = xconnect_ftpdata();
167 175
168 if (ftpcmd("SIZE", server_path, control_stream, buf) == 213) { 176 if (ftpcmd("SIZE", server_path, control_stream) != 213) {
169 //filesize = BB_STRTOOFF(buf + 4, NULL, 10);
170 //if (errno || filesize < 0)
171 // ftp_die("SIZE", buf);
172 } else {
173 do_continue = 0; 177 do_continue = 0;
174 } 178 }
175 179
@@ -193,16 +197,13 @@ response).
193 197
194 if (do_continue) { 198 if (do_continue) {
195 sprintf(buf, "REST %"OFF_FMT"d", beg_range); 199 sprintf(buf, "REST %"OFF_FMT"d", beg_range);
196 if (ftpcmd(buf, NULL, control_stream, buf) != 350) { 200 if (ftpcmd(buf, NULL, control_stream) != 350) {
197 do_continue = 0; 201 do_continue = 0;
198 } else {
199 //if (filesize != -1)
200 // filesize -= beg_range;
201 } 202 }
202 } 203 }
203 204
204 if (ftpcmd("RETR", server_path, control_stream, buf) > 150) { 205 if (ftpcmd("RETR", server_path, control_stream) > 150) {
205 ftp_die("RETR", buf); 206 ftp_die("RETR");
206 } 207 }
207 208
208 /* make local _after_ we know that remote file exists */ 209 /* make local _after_ we know that remote file exists */
@@ -216,76 +217,52 @@ response).
216// TODO: merge tail of ftp_receive and ftp_send starting from here 217// TODO: merge tail of ftp_receive and ftp_send starting from here
217 218
218 /* copy the file */ 219 /* copy the file */
219 if (filesize != -1) { // NEVER HAPPENS, filesize is always -1 220 if (bb_copyfd_eof(fd_data, fd_local) == -1) {
220 if (bb_copyfd_size(fd_data, fd_local, filesize) == -1) 221 /* error msg is already printed by bb_copyfd_eof */
221 return EXIT_FAILURE; 222 return EXIT_FAILURE;
222 } else {
223 if (bb_copyfd_eof(fd_data, fd_local) == -1) {
224 /* error msg is already printed by bb_copyfd_eof */
225 return EXIT_FAILURE;
226 }
227 } 223 }
228 224
229 /* close it all down */ 225 /* close it all down */
230 close(fd_data); 226 close(fd_data);
231 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 227 if (ftpcmd(NULL, NULL, control_stream) != 226) {
232 ftp_die(NULL, buf); 228 ftp_die(NULL);
233 } 229 }
234 ftpcmd("QUIT", NULL, control_stream, buf); 230 ftpcmd("QUIT", NULL, control_stream);
235 231
236 return EXIT_SUCCESS; 232 return EXIT_SUCCESS;
237} 233}
238#endif 234#endif
239 235
240#if !ENABLE_FTPPUT 236#if !ENABLE_FTPPUT
241int ftp_send(ftp_host_info_t *server, FILE *control_stream, 237int ftp_send(FILE *control_stream,
242 const char *server_path, char *local_path); 238 const char *server_path, char *local_path);
243#else 239#else
244static 240static
245int ftp_send(ftp_host_info_t *server, FILE *control_stream, 241int ftp_send(FILE *control_stream,
246 const char *server_path, char *local_path) 242 const char *server_path, char *local_path)
247{ 243{
248 struct stat sbuf;
249 char buf[512];
250 int fd_data; 244 int fd_data;
251 int fd_local; 245 int fd_local;
252 int response; 246 int response;
253 247
254 /* connect to the data socket */ 248 /* connect to the data socket */
255 if (ftpcmd("PASV", NULL, control_stream, buf) != 227) { 249 if (ftpcmd("PASV", NULL, control_stream) != 227) {
256 ftp_die("PASV", buf); 250 ftp_die("PASV");
257 } 251 }
258 fd_data = xconnect_ftpdata(server, buf); 252 fd_data = xconnect_ftpdata();
259 253
260 /* get the local file */ 254 /* get the local file */
261 fd_local = STDIN_FILENO; 255 fd_local = STDIN_FILENO;
262 if (NOT_LONE_DASH(local_path)) { 256 if (NOT_LONE_DASH(local_path))
263 fd_local = xopen(local_path, O_RDONLY); 257 fd_local = xopen(local_path, O_RDONLY);
264 fstat(fd_local, &sbuf); 258
265 259 response = ftpcmd("STOR", server_path, control_stream);
266// TODO: do we really need to send ALLO? It's ancient...
267// Doesn't it break "ftpput .. .. fifo" too?
268
269 sprintf(buf, "ALLO %"OFF_FMT"u", sbuf.st_size);
270 response = ftpcmd(buf, NULL, control_stream, buf);
271 switch (response) {
272 case 200:
273 case 202:
274 break;
275 default:
276 close(fd_local); // TODO: why bother?
277 ftp_die("ALLO", buf);
278 break;
279 }
280 }
281 response = ftpcmd("STOR", server_path, control_stream, buf);
282 switch (response) { 260 switch (response) {
283 case 125: 261 case 125:
284 case 150: 262 case 150:
285 break; 263 break;
286 default: 264 default:
287 close(fd_local); // TODO: why bother? 265 ftp_die("STOR");
288 ftp_die("STOR", buf);
289 } 266 }
290 267
291 /* transfer the file */ 268 /* transfer the file */
@@ -296,10 +273,10 @@ int ftp_send(ftp_host_info_t *server, FILE *control_stream,
296 273
297 /* close it all down */ 274 /* close it all down */
298 close(fd_data); 275 close(fd_data);
299 if (ftpcmd(NULL, NULL, control_stream, buf) != 226) { 276 if (ftpcmd(NULL, NULL, control_stream) != 226) {
300 ftp_die("close", buf); 277 ftp_die("close");
301 } 278 }
302 ftpcmd("QUIT", NULL, control_stream, buf); 279 ftpcmd("QUIT", NULL, control_stream);
303 280
304 return EXIT_SUCCESS; 281 return EXIT_SUCCESS;
305} 282}
@@ -324,30 +301,28 @@ static const char ftpgetput_longopts[] ALIGN1 =
324int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 301int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
325int ftpgetput_main(int argc ATTRIBUTE_UNUSED, char **argv) 302int ftpgetput_main(int argc ATTRIBUTE_UNUSED, char **argv)
326{ 303{
327 /* content-length of the file */
328 unsigned opt; 304 unsigned opt;
329 const char *port = "ftp"; 305 const char *port = "ftp";
330 /* socket to ftp server */ 306 /* socket to ftp server */
331 FILE *control_stream; 307 FILE *control_stream;
332 /* continue previous transfer (-c) */
333 ftp_host_info_t *server;
334 308
335#if ENABLE_FTPPUT && !ENABLE_FTPGET 309#if ENABLE_FTPPUT && !ENABLE_FTPGET
336# define ftp_action ftp_send 310# define ftp_action ftp_send
337#elif ENABLE_FTPGET && !ENABLE_FTPPUT 311#elif ENABLE_FTPGET && !ENABLE_FTPPUT
338# define ftp_action ftp_receive 312# define ftp_action ftp_receive
339#else 313#else
340 int (*ftp_action)(ftp_host_info_t *, FILE *, const char *, char *) = ftp_send; 314 int (*ftp_action)(FILE *, const char *, char *) = ftp_send;
315
341 /* Check to see if the command is ftpget or ftput */ 316 /* Check to see if the command is ftpget or ftput */
342 if (applet_name[3] == 'g') { 317 if (applet_name[3] == 'g') {
343 ftp_action = ftp_receive; 318 ftp_action = ftp_receive;
344 } 319 }
345#endif 320#endif
346 321
322 INIT_G();
347 /* Set default values */ 323 /* Set default values */
348 server = xmalloc(sizeof(*server)); 324 user = "anonymous";
349 server->user = "anonymous"; 325 password = "busybox@";
350 server->password = "busybox@";
351 326
352 /* 327 /*
353 * Decipher the command line 328 * Decipher the command line
@@ -355,29 +330,22 @@ int ftpgetput_main(int argc ATTRIBUTE_UNUSED, char **argv)
355#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS 330#if ENABLE_FEATURE_FTPGETPUT_LONG_OPTIONS
356 applet_long_options = ftpgetput_longopts; 331 applet_long_options = ftpgetput_longopts;
357#endif 332#endif
358 opt_complementary = "=3"; /* must have 3 params */ 333 opt_complementary = "=3:vv:cc"; /* must have 3 params; -v and -c count */
359 opt = getopt32(argv, "cvu:p:P:", &server->user, &server->password, &port); 334 opt = getopt32(argv, "cvu:p:P:", &user, &password, &port,
335 &verbose_flag, &do_continue);
360 argv += optind; 336 argv += optind;
361 337
362 /* Process the non-option command line arguments */
363 if (opt & FTPGETPUT_OPT_CONTINUE) {
364 do_continue = 1;
365 }
366 if (opt & FTPGETPUT_OPT_VERBOSE) {
367 verbose_flag = 1;
368 }
369
370 /* We want to do exactly _one_ DNS lookup, since some 338 /* We want to do exactly _one_ DNS lookup, since some
371 * sites (i.e. ftp.us.debian.org) use round-robin DNS 339 * sites (i.e. ftp.us.debian.org) use round-robin DNS
372 * and we want to connect to only one IP... */ 340 * and we want to connect to only one IP... */
373 server->lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21)); 341 lsa = xhost2sockaddr(argv[0], bb_lookup_port(port, "tcp", 21));
374 if (verbose_flag) { 342 if (verbose_flag) {
375 printf("Connecting to %s (%s)\n", argv[0], 343 printf("Connecting to %s (%s)\n", argv[0],
376 xmalloc_sockaddr2dotted(&server->lsa->u.sa)); 344 xmalloc_sockaddr2dotted(&lsa->u.sa));
377 } 345 }
378 346
379 /* Connect/Setup/Configure the FTP session */ 347 /* Connect/Setup/Configure the FTP session */
380 control_stream = ftp_login(server); 348 control_stream = ftp_login();
381 349
382 return ftp_action(server, control_stream, argv[1], argv[2]); 350 return ftp_action(control_stream, argv[1], argv[2]);
383} 351}