diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-09 02:23:45 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-09 02:23:45 +0000 |
commit | ffb4bb3034b44bb61d8916f3e197e80c76062f1d (patch) | |
tree | d2f5a6a60e4f6c825dc8400f060c7015ee880d68 /networking/ftpd.c | |
parent | 73c571a5fff95d0f50f4fc509c35fedca73122bc (diff) | |
download | busybox-w32-ffb4bb3034b44bb61d8916f3e197e80c76062f1d.tar.gz busybox-w32-ffb4bb3034b44bb61d8916f3e197e80c76062f1d.tar.bz2 busybox-w32-ffb4bb3034b44bb61d8916f3e197e80c76062f1d.zip |
ftpd: further code shrink
function old new delta
port_pasv_cleanup - 50 +50
replace_char - 30 +30
ftp_write_str_common 102 104 +2
handle_dir_common 209 204 -5
ftpd_main 1990 1970 -20
port_cleanup 23 - -23
pasv_cleanup 28 - -28
handle_upload_common 320 273 -47
------------------------------------------------------------------------------
(add/remove: 2/2 grow/shrink: 1/3 up/down: 82/-123) Total: -41 bytes
Diffstat (limited to 'networking/ftpd.c')
-rw-r--r-- | networking/ftpd.c | 377 |
1 files changed, 185 insertions, 192 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c index 6289edf0c..404bc98c3 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -9,6 +9,8 @@ | |||
9 | * | 9 | * |
10 | * Options: | 10 | * Options: |
11 | * -w - enable FTP write commands | 11 | * -w - enable FTP write commands |
12 | * | ||
13 | * TODO: implement "421 Timeout" thingy (alarm(60) while waiting for a cmd). | ||
12 | */ | 14 | */ |
13 | 15 | ||
14 | #include "libbb.h" | 16 | #include "libbb.h" |
@@ -98,7 +100,7 @@ struct globals { | |||
98 | int data_fd; | 100 | int data_fd; |
99 | off_t restart_pos; | 101 | off_t restart_pos; |
100 | char *ftp_cmp; | 102 | char *ftp_cmp; |
101 | const char *ftp_arg; | 103 | char *ftp_arg; |
102 | #if ENABLE_FEATURE_FTP_WRITE | 104 | #if ENABLE_FEATURE_FTP_WRITE |
103 | char *rnfr_filename; | 105 | char *rnfr_filename; |
104 | #endif | 106 | #endif |
@@ -156,22 +158,25 @@ replace_char(char *str, char from, char to) | |||
156 | } | 158 | } |
157 | 159 | ||
158 | static void | 160 | static void |
159 | ftp_write_str_common(unsigned int status, const char *str, char sep) | 161 | ftp_write_str_common(unsigned status, const char *str, char sep) |
160 | { | 162 | { |
161 | char *escaped_str, *response; | 163 | char *escaped_str, *response; |
162 | size_t len; | 164 | int len; |
163 | 165 | ||
164 | escaped_str = replace_text(str, '\377', "\377\377"); | 166 | /* FTP allegedly uses telnet protocol for command link. |
167 | * In telnet, 0xff is an escape char, and needs to be escaped: */ | ||
168 | escaped_str = replace_text(str, '\xff', "\xff\xff"); | ||
165 | 169 | ||
166 | response = xasprintf("%u%c%s\r\n", status, sep, escaped_str); | 170 | response = xasprintf("%u%c%s\r", status, sep, escaped_str); |
167 | free(escaped_str); | 171 | free(escaped_str); |
168 | 172 | ||
173 | /* ?! does FTP send embedded LFs as NULs? wow */ | ||
169 | len = strlen(response); | 174 | len = strlen(response); |
170 | replace_char(response, '\n', '\0'); | 175 | replace_char(response, '\n', '\0'); |
171 | 176 | ||
172 | /* Change trailing '\0' back to '\n' */ | 177 | response[len++] = '\n'; /* tack on trailing '\n' */ |
173 | response[len - 1] = '\n'; | ||
174 | xwrite(STDIN_FILENO, response, len); | 178 | xwrite(STDIN_FILENO, response, len); |
179 | free(response); | ||
175 | } | 180 | } |
176 | 181 | ||
177 | static void | 182 | static void |
@@ -198,35 +203,68 @@ cmdio_write_raw(const char *p_text) | |||
198 | xwrite_str(STDIN_FILENO, p_text); | 203 | xwrite_str(STDIN_FILENO, p_text); |
199 | } | 204 | } |
200 | 205 | ||
201 | static uint32_t | 206 | static void |
202 | cmdio_get_cmd_and_arg(void) | 207 | handle_pwd(void) |
203 | { | 208 | { |
204 | size_t len; | 209 | char *cwd, *promoted_cwd, *response; |
205 | uint32_t cmdval; | ||
206 | char *cmd; | ||
207 | 210 | ||
208 | free(G.ftp_cmp); | 211 | cwd = xrealloc_getcwd_or_warn(NULL); |
209 | len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */ | 212 | if (cwd == NULL) |
210 | G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len); | 213 | cwd = xstrdup(""); |
211 | if (!cmd) | ||
212 | exit(0); | ||
213 | 214 | ||
214 | len = strlen(cmd) - 1; | 215 | /* We have to promote each " to "" */ |
215 | while (len >= 0 && cmd[len] == '\r') { | 216 | promoted_cwd = replace_text(cwd, '\"', "\"\""); |
216 | cmd[len] = '\0'; | 217 | free(cwd); |
217 | len--; | 218 | response = xasprintf("\"%s\"", promoted_cwd); |
219 | free(promoted_cwd); | ||
220 | cmdio_write(FTP_PWDOK, response); | ||
221 | free(response); | ||
222 | } | ||
223 | |||
224 | static void | ||
225 | handle_cwd(void) | ||
226 | { | ||
227 | if (!G.ftp_arg || chdir(G.ftp_arg) != 0) { | ||
228 | cmdio_write(FTP_FILEFAIL, "Can't change directory"); | ||
229 | return; | ||
218 | } | 230 | } |
231 | cmdio_write_ok(FTP_CWDOK); | ||
232 | } | ||
219 | 233 | ||
220 | G.ftp_arg = strchr(cmd, ' '); | 234 | static void |
221 | if (G.ftp_arg != NULL) { | 235 | handle_cdup(void) |
222 | *(char *)G.ftp_arg = '\0'; | 236 | { |
223 | G.ftp_arg++; | 237 | G.ftp_arg = (char*)".."; |
238 | handle_cwd(); | ||
239 | } | ||
240 | |||
241 | static void | ||
242 | handle_type(void) | ||
243 | { | ||
244 | if (G.ftp_arg | ||
245 | && ( ((G.ftp_arg[0] | 0x20) == 'i' && G.ftp_arg[1] == '\0') | ||
246 | || !strcasecmp(G.ftp_arg, "L8") | ||
247 | || !strcasecmp(G.ftp_arg, "L 8") | ||
248 | ) | ||
249 | ) { | ||
250 | cmdio_write_ok(FTP_TYPEOK); | ||
251 | } else { | ||
252 | cmdio_write(FTP_BADCMD, "Unrecognised TYPE command"); | ||
224 | } | 253 | } |
225 | cmdval = 0; | 254 | } |
226 | while (*cmd) | ||
227 | cmdval = (cmdval << 8) + ((unsigned char)*cmd++ & (unsigned char)~0x20); | ||
228 | 255 | ||
229 | return cmdval; | 256 | static void |
257 | handle_help(void) | ||
258 | { | ||
259 | cmdio_write_hyphen(FTP_HELP, "Recognized commands:"); | ||
260 | cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n" | ||
261 | " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n" | ||
262 | " REST RETR STAT STRU SYST TYPE USER\r\n" | ||
263 | #if ENABLE_FEATURE_FTP_WRITE | ||
264 | " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n" | ||
265 | #endif | ||
266 | ); | ||
267 | cmdio_write(FTP_HELP, "Help OK"); | ||
230 | } | 268 | } |
231 | 269 | ||
232 | static void | 270 | static void |
@@ -265,7 +303,7 @@ ftpdataio_get_port_fd(void) | |||
265 | { | 303 | { |
266 | int remote_fd; | 304 | int remote_fd; |
267 | 305 | ||
268 | /* Do we want die or print error to client? */ | 306 | /* Do we want to die or print error to client? */ |
269 | remote_fd = xconnect_stream(G.port_addr); | 307 | remote_fd = xconnect_stream(G.port_addr); |
270 | 308 | ||
271 | init_data_sock_params(remote_fd); | 309 | init_data_sock_params(remote_fd); |
@@ -289,16 +327,16 @@ ftpdataio_dispose_transfer_fd(void) | |||
289 | G.data_fd = -1; | 327 | G.data_fd = -1; |
290 | } | 328 | } |
291 | 329 | ||
292 | static int | 330 | static inline int |
293 | port_active(void) | 331 | port_active(void) |
294 | { | 332 | { |
295 | return (G.port_addr != NULL) ? 1: 0; | 333 | return (G.port_addr != NULL); |
296 | } | 334 | } |
297 | 335 | ||
298 | static int | 336 | static inline int |
299 | pasv_active(void) | 337 | pasv_active(void) |
300 | { | 338 | { |
301 | return (G.pasv_listen_fd != -1) ? 1 : 0; | 339 | return (G.pasv_listen_fd > STDOUT_FILENO); |
302 | } | 340 | } |
303 | 341 | ||
304 | static int | 342 | static int |
@@ -318,41 +356,6 @@ get_remote_transfer_fd(const char *p_status_msg) | |||
318 | return remote_fd; | 356 | return remote_fd; |
319 | } | 357 | } |
320 | 358 | ||
321 | static void | ||
322 | handle_pwd(void) | ||
323 | { | ||
324 | char *cwd, *promoted_cwd, *response; | ||
325 | |||
326 | cwd = xrealloc_getcwd_or_warn(NULL); | ||
327 | if (cwd == NULL) | ||
328 | cwd = xstrdup(""); | ||
329 | |||
330 | /* We have to promote each " to "" */ | ||
331 | promoted_cwd = replace_text(cwd, '\"', "\"\""); | ||
332 | free(cwd); | ||
333 | response = xasprintf("\"%s\"", promoted_cwd); | ||
334 | free(promoted_cwd); | ||
335 | cmdio_write(FTP_PWDOK, response); | ||
336 | free(response); | ||
337 | } | ||
338 | |||
339 | static void | ||
340 | handle_cwd(void) | ||
341 | { | ||
342 | if (!G.ftp_arg || chdir(G.ftp_arg) != 0) { | ||
343 | cmdio_write(FTP_FILEFAIL, "Can't change directory"); | ||
344 | return; | ||
345 | } | ||
346 | cmdio_write_ok(FTP_CWDOK); | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | handle_cdup(void) | ||
351 | { | ||
352 | G.ftp_arg = ".."; | ||
353 | handle_cwd(); | ||
354 | } | ||
355 | |||
356 | static int | 359 | static int |
357 | data_transfer_checks_ok(void) | 360 | data_transfer_checks_ok(void) |
358 | { | 361 | { |
@@ -365,15 +368,10 @@ data_transfer_checks_ok(void) | |||
365 | } | 368 | } |
366 | 369 | ||
367 | static void | 370 | static void |
368 | port_cleanup(void) | 371 | port_pasv_cleanup(void) |
369 | { | 372 | { |
370 | free(G.port_addr); | 373 | free(G.port_addr); |
371 | G.port_addr = NULL; | 374 | G.port_addr = NULL; |
372 | } | ||
373 | |||
374 | static void | ||
375 | pasv_cleanup(void) | ||
376 | { | ||
377 | if (G.pasv_listen_fd > STDOUT_FILENO) | 375 | if (G.pasv_listen_fd > STDOUT_FILENO) |
378 | close(G.pasv_listen_fd); | 376 | close(G.pasv_listen_fd); |
379 | G.pasv_listen_fd = -1; | 377 | G.pasv_listen_fd = -1; |
@@ -385,10 +383,10 @@ handle_pasv(void) | |||
385 | int bind_retries = 10; | 383 | int bind_retries = 10; |
386 | unsigned short port; | 384 | unsigned short port; |
387 | enum { min_port = 1024, max_port = 65535 }; | 385 | enum { min_port = 1024, max_port = 65535 }; |
388 | char *addr, *wire_addr, *response; | 386 | char *addr, *response; |
387 | |||
388 | port_pasv_cleanup(); | ||
389 | 389 | ||
390 | pasv_cleanup(); | ||
391 | port_cleanup(); | ||
392 | G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); | 390 | G.pasv_listen_fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); |
393 | setsockopt_reuseaddr(G.pasv_listen_fd); | 391 | setsockopt_reuseaddr(G.pasv_listen_fd); |
394 | 392 | ||
@@ -413,14 +411,13 @@ handle_pasv(void) | |||
413 | bb_error_msg_and_die("can't create pasv socket"); | 411 | bb_error_msg_and_die("can't create pasv socket"); |
414 | 412 | ||
415 | addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa); | 413 | addr = xmalloc_sockaddr2dotted_noport(&G.local_addr->u.sa); |
416 | wire_addr = replace_text(addr, '.', ","); | 414 | replace_char(addr, '.', ','); |
417 | free(addr); | ||
418 | 415 | ||
419 | response = xasprintf("Entering Passive Mode (%s,%u,%u)", | 416 | response = xasprintf("Entering Passive Mode (%s,%u,%u)", |
420 | wire_addr, (int)(port >> 8), (int)(port & 255)); | 417 | addr, (int)(port >> 8), (int)(port & 255)); |
418 | free(addr); | ||
421 | 419 | ||
422 | cmdio_write(FTP_PASVOK, response); | 420 | cmdio_write(FTP_PASVOK, response); |
423 | free(wire_addr); | ||
424 | free(response); | 421 | free(response); |
425 | } | 422 | } |
426 | 423 | ||
@@ -428,37 +425,35 @@ static void | |||
428 | handle_port(void) | 425 | handle_port(void) |
429 | { | 426 | { |
430 | unsigned short port; | 427 | unsigned short port; |
431 | char *raw = NULL, *port_part; | 428 | char *raw, *port_part; |
432 | len_and_sockaddr *lsa = NULL; | 429 | len_and_sockaddr *lsa = NULL; |
433 | 430 | ||
434 | pasv_cleanup(); | 431 | port_pasv_cleanup(); |
435 | port_cleanup(); | ||
436 | 432 | ||
437 | if (G.ftp_arg == NULL) | 433 | raw = G.ftp_arg; |
438 | goto bail; | ||
439 | 434 | ||
440 | raw = replace_text(G.ftp_arg, ',', "."); | 435 | /* buglets: |
436 | * xatou16 will accept wrong input, | ||
437 | * xatou16 will exit instead of generating error to peer | ||
438 | */ | ||
441 | 439 | ||
442 | port_part = strrchr(raw, '.'); | 440 | port_part = strrchr(raw, ','); |
443 | if (port_part == NULL) | 441 | if (port_part == NULL) |
444 | goto bail; | 442 | goto bail; |
445 | |||
446 | port = xatou16(&port_part[1]); | 443 | port = xatou16(&port_part[1]); |
447 | *port_part = '\0'; | 444 | *port_part = '\0'; |
448 | 445 | ||
449 | port_part = strrchr(raw, '.'); | 446 | port_part = strrchr(raw, ','); |
450 | if (port_part == NULL) | 447 | if (port_part == NULL) |
451 | goto bail; | 448 | goto bail; |
452 | |||
453 | port |= xatou16(&port_part[1]) << 8; | 449 | port |= xatou16(&port_part[1]) << 8; |
454 | *port_part = '\0'; | 450 | *port_part = '\0'; |
455 | 451 | ||
452 | replace_char(raw, ',', '.'); | ||
456 | lsa = xdotted2sockaddr(raw, port); | 453 | lsa = xdotted2sockaddr(raw, port); |
457 | 454 | ||
458 | bail: | ||
459 | free(raw); | ||
460 | |||
461 | if (lsa == NULL) { | 455 | if (lsa == NULL) { |
456 | bail: | ||
462 | cmdio_write(FTP_BADCMD, "Illegal PORT command"); | 457 | cmdio_write(FTP_BADCMD, "Illegal PORT command"); |
463 | return; | 458 | return; |
464 | } | 459 | } |
@@ -528,10 +523,10 @@ handle_retr(void) | |||
528 | else | 523 | else |
529 | cmdio_write_ok(FTP_TRANSFEROK); | 524 | cmdio_write_ok(FTP_TRANSFEROK); |
530 | 525 | ||
531 | port_pasv_cleanup_out: | 526 | port_pasv_cleanup_out: |
532 | port_cleanup(); | 527 | port_pasv_cleanup(); |
533 | pasv_cleanup(); | 528 | |
534 | file_close_out: | 529 | file_close_out: |
535 | close(opened_file); | 530 | close(opened_file); |
536 | } | 531 | } |
537 | 532 | ||
@@ -691,12 +686,11 @@ handle_dir_common(int full_details, int stat_cmd) | |||
691 | } else | 686 | } else |
692 | write_dirstats(fd, ".", full_details); | 687 | write_dirstats(fd, ".", full_details); |
693 | 688 | ||
694 | bail: | 689 | bail: |
695 | /* Well, if we can't open directory/file it doesn't matter */ | 690 | /* Well, if we can't open directory/file it doesn't matter */ |
696 | if (!stat_cmd) { | 691 | if (!stat_cmd) { |
697 | ftpdataio_dispose_transfer_fd(); | 692 | ftpdataio_dispose_transfer_fd(); |
698 | pasv_cleanup(); | 693 | port_pasv_cleanup(); |
699 | port_cleanup(); | ||
700 | cmdio_write_ok(FTP_TRANSFEROK); | 694 | cmdio_write_ok(FTP_TRANSFEROK); |
701 | } else | 695 | } else |
702 | cmdio_write_ok(FTP_STATFILE_OK); | 696 | cmdio_write_ok(FTP_STATFILE_OK); |
@@ -728,98 +722,8 @@ handle_stat(void) | |||
728 | cmdio_write_ok(FTP_STATOK); | 722 | cmdio_write_ok(FTP_STATOK); |
729 | } | 723 | } |
730 | 724 | ||
731 | static void | ||
732 | handle_type(void) | ||
733 | { | ||
734 | if (G.ftp_arg | ||
735 | && ( ((G.ftp_arg[0] | 0x20) == 'i' && G.ftp_arg[1] == '\0') | ||
736 | || !strcasecmp(G.ftp_arg, "L8") | ||
737 | || !strcasecmp(G.ftp_arg, "L 8") | ||
738 | ) | ||
739 | ) { | ||
740 | cmdio_write_ok(FTP_TYPEOK); | ||
741 | } else { | ||
742 | cmdio_write(FTP_BADCMD, "Unrecognised TYPE command"); | ||
743 | } | ||
744 | } | ||
745 | |||
746 | static void | ||
747 | handle_help(void) | ||
748 | { | ||
749 | cmdio_write_hyphen(FTP_HELP, "Recognized commands:"); | ||
750 | cmdio_write_raw(" ALLO CDUP CWD HELP LIST\r\n" | ||
751 | " MODE NLST NOOP PASS PASV PORT PWD QUIT\r\n" | ||
752 | " REST RETR STAT STRU SYST TYPE USER\r\n" | ||
753 | #if ENABLE_FEATURE_FTP_WRITE | ||
754 | " APPE DELE MKD RMD RNFR RNTO STOR STOU\r\n" | ||
755 | #endif | ||
756 | ); | ||
757 | cmdio_write(FTP_HELP, "Help OK"); | ||
758 | } | ||
759 | |||
760 | #if ENABLE_FEATURE_FTP_WRITE | 725 | #if ENABLE_FEATURE_FTP_WRITE |
761 | static void | 726 | static void |
762 | handle_upload_common(int is_append, int is_unique) | ||
763 | { | ||
764 | char *tempname = NULL; | ||
765 | int trans_ret; | ||
766 | int new_file_fd; | ||
767 | int remote_fd; | ||
768 | off_t offset = G.restart_pos; | ||
769 | |||
770 | G.restart_pos = 0; | ||
771 | if (!G.ftp_arg || !data_transfer_checks_ok()) | ||
772 | return; | ||
773 | |||
774 | if (is_unique) { | ||
775 | tempname = xstrdup("FILE: uniq.XXXXXX"); | ||
776 | /* | ||
777 | * XXX Use mkostemp here? vsftpd opens file with O_CREAT, O_WRONLY, | ||
778 | * O_APPEND and O_EXCL flags... | ||
779 | */ | ||
780 | new_file_fd = mkstemp(tempname + 6); | ||
781 | } else { | ||
782 | /* XXX Do we need check if ftp_arg != NULL? */ | ||
783 | if (!is_append && offset == 0) | ||
784 | new_file_fd = open(G.ftp_arg, O_CREAT | O_WRONLY | O_APPEND | O_NONBLOCK | O_TRUNC, 0666); | ||
785 | else | ||
786 | new_file_fd = open(G.ftp_arg, O_CREAT | O_WRONLY | O_APPEND | O_NONBLOCK, 0666); | ||
787 | } | ||
788 | |||
789 | if (new_file_fd < 0) { | ||
790 | cmdio_write(FTP_UPLOADFAIL, "Can't create file"); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | if (!is_append && offset != 0) { | ||
795 | /* warning, allows seek past end of file! Check for seek > size? */ | ||
796 | xlseek(new_file_fd, offset, SEEK_SET); | ||
797 | } | ||
798 | |||
799 | if (tempname) { | ||
800 | remote_fd = get_remote_transfer_fd(tempname); | ||
801 | free(tempname); | ||
802 | } else | ||
803 | remote_fd = get_remote_transfer_fd("Ok to send data"); | ||
804 | |||
805 | if (remote_fd < 0) | ||
806 | goto bail; | ||
807 | |||
808 | trans_ret = bb_copyfd_eof(remote_fd, new_file_fd); | ||
809 | ftpdataio_dispose_transfer_fd(); | ||
810 | |||
811 | if (trans_ret < 0) | ||
812 | cmdio_write(FTP_BADSENDFILE, "Failure writing to local file"); | ||
813 | else | ||
814 | cmdio_write_ok(FTP_TRANSFEROK); | ||
815 | |||
816 | bail: | ||
817 | port_cleanup(); | ||
818 | pasv_cleanup(); | ||
819 | close(new_file_fd); | ||
820 | } | ||
821 | |||
822 | static void | ||
823 | handle_mkd(void) | 727 | handle_mkd(void) |
824 | { | 728 | { |
825 | if (!G.ftp_arg || mkdir(G.ftp_arg, 0777) != 0) { | 729 | if (!G.ftp_arg || mkdir(G.ftp_arg, 0777) != 0) { |
@@ -892,6 +796,62 @@ handle_rnto(void) | |||
892 | } | 796 | } |
893 | 797 | ||
894 | static void | 798 | static void |
799 | handle_upload_common(int is_append, int is_unique) | ||
800 | { | ||
801 | char *tempname = NULL; | ||
802 | int trans_ret; | ||
803 | int local_file_fd; | ||
804 | int remote_fd; | ||
805 | off_t offset; | ||
806 | |||
807 | offset = G.restart_pos; | ||
808 | G.restart_pos = 0; | ||
809 | |||
810 | if (!data_transfer_checks_ok()) | ||
811 | return; | ||
812 | |||
813 | local_file_fd = -1; | ||
814 | if (is_unique) { | ||
815 | tempname = xstrdup("FILE: uniq.XXXXXX"); | ||
816 | local_file_fd = mkstemp(tempname + 6); | ||
817 | } else if (G.ftp_arg) { | ||
818 | int flags = O_WRONLY | O_CREAT | O_TRUNC; | ||
819 | if (is_append) | ||
820 | flags = O_WRONLY | O_CREAT | O_APPEND; | ||
821 | if (offset) | ||
822 | flags = O_WRONLY | O_CREAT; | ||
823 | local_file_fd = open(G.ftp_arg, flags, 0666); | ||
824 | } | ||
825 | if (local_file_fd < 0) { | ||
826 | cmdio_write(FTP_UPLOADFAIL, "Can't create file"); | ||
827 | return; | ||
828 | } | ||
829 | |||
830 | /* TODO: paranoia: fstat it, refuse to do anything if it's not a regular file */ | ||
831 | |||
832 | if (offset) | ||
833 | xlseek(local_file_fd, offset, SEEK_SET); | ||
834 | |||
835 | remote_fd = get_remote_transfer_fd(tempname ? tempname : "Ok to send data"); | ||
836 | free(tempname); | ||
837 | |||
838 | if (remote_fd < 0) | ||
839 | goto bail; | ||
840 | |||
841 | trans_ret = bb_copyfd_eof(remote_fd, local_file_fd); | ||
842 | ftpdataio_dispose_transfer_fd(); | ||
843 | |||
844 | if (trans_ret < 0) | ||
845 | cmdio_write(FTP_BADSENDFILE, "Failure writing to local file"); | ||
846 | else | ||
847 | cmdio_write_ok(FTP_TRANSFEROK); | ||
848 | |||
849 | bail: | ||
850 | port_pasv_cleanup(); | ||
851 | close(local_file_fd); | ||
852 | } | ||
853 | |||
854 | static void | ||
895 | handle_stor(void) | 855 | handle_stor(void) |
896 | { | 856 | { |
897 | handle_upload_common(0, 0); | 857 | handle_upload_common(0, 0); |
@@ -900,16 +860,49 @@ handle_stor(void) | |||
900 | static void | 860 | static void |
901 | handle_appe(void) | 861 | handle_appe(void) |
902 | { | 862 | { |
863 | G.restart_pos = 0; | ||
903 | handle_upload_common(1, 0); | 864 | handle_upload_common(1, 0); |
904 | } | 865 | } |
905 | 866 | ||
906 | static void | 867 | static void |
907 | handle_stou(void) | 868 | handle_stou(void) |
908 | { | 869 | { |
870 | G.restart_pos = 0; | ||
909 | handle_upload_common(0, 1); | 871 | handle_upload_common(0, 1); |
910 | } | 872 | } |
911 | #endif /* ENABLE_FEATURE_FTP_WRITE */ | 873 | #endif /* ENABLE_FEATURE_FTP_WRITE */ |
912 | 874 | ||
875 | static uint32_t | ||
876 | cmdio_get_cmd_and_arg(void) | ||
877 | { | ||
878 | size_t len; | ||
879 | uint32_t cmdval; | ||
880 | char *cmd; | ||
881 | |||
882 | free(G.ftp_cmp); | ||
883 | len = 8 * 1024; /* Paranoia. Peer may send 1 gigabyte long cmd... */ | ||
884 | G.ftp_cmp = cmd = xmalloc_reads(STDIN_FILENO, NULL, &len); | ||
885 | if (!cmd) | ||
886 | exit(0); | ||
887 | |||
888 | len = strlen(cmd) - 1; | ||
889 | while (len >= 0 && cmd[len] == '\r') { | ||
890 | cmd[len] = '\0'; | ||
891 | len--; | ||
892 | } | ||
893 | |||
894 | G.ftp_arg = strchr(cmd, ' '); | ||
895 | if (G.ftp_arg != NULL) { | ||
896 | *G.ftp_arg = '\0'; | ||
897 | G.ftp_arg++; | ||
898 | } | ||
899 | cmdval = 0; | ||
900 | while (*cmd) | ||
901 | cmdval = (cmdval << 8) + ((unsigned char)*cmd++ & (unsigned char)~0x20); | ||
902 | |||
903 | return cmdval; | ||
904 | } | ||
905 | |||
913 | int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 906 | int ftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
914 | int ftpd_main(int argc UNUSED_PARAM, char **argv) | 907 | int ftpd_main(int argc UNUSED_PARAM, char **argv) |
915 | { | 908 | { |