diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-18 00:45:00 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-03-18 00:45:00 +0000 |
commit | 1432cb4bd9daf304111dd19e0011f8756c32e327 (patch) | |
tree | 89accfc8fd6cef0d885cbb890e5b484a29fcfaf0 | |
parent | 3a7a1eba2e2b3cc05f000fc739d3548dd0a0872d (diff) | |
download | busybox-w32-1432cb4bd9daf304111dd19e0011f8756c32e327.tar.gz busybox-w32-1432cb4bd9daf304111dd19e0011f8756c32e327.tar.bz2 busybox-w32-1432cb4bd9daf304111dd19e0011f8756c32e327.zip |
ftpd: add support for MDTM, I see clients often use it,
it may allow client-side caching.
function old new delta
ftpd_main 2232 2306 +74
gmtime_r - 19 +19
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 93/0) Total: 93 bytes
-rw-r--r-- | networking/ftpd.c | 80 |
1 files changed, 69 insertions, 11 deletions
diff --git a/networking/ftpd.c b/networking/ftpd.c index f005d129c..b295ddf4f 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c | |||
@@ -7,7 +7,9 @@ | |||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | 7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
8 | * | 8 | * |
9 | * Only subset of FTP protocol is implemented but vast majority of clients | 9 | * Only subset of FTP protocol is implemented but vast majority of clients |
10 | * should not have any problem. You have to run this daemon via inetd. | 10 | * should not have any problem. |
11 | * | ||
12 | * You have to run this daemon via inetd. | ||
11 | */ | 13 | */ |
12 | 14 | ||
13 | #include "libbb.h" | 15 | #include "libbb.h" |
@@ -172,11 +174,11 @@ cmdio_write(uint32_t status_str, const char *str) | |||
172 | char *response; | 174 | char *response; |
173 | int len; | 175 | int len; |
174 | 176 | ||
175 | /* FTP allegedly uses telnet protocol for command link. | 177 | /* FTP uses telnet protocol for command link. |
176 | * In telnet, 0xff is an escape char, and needs to be escaped: */ | 178 | * In telnet, 0xff is an escape char, and needs to be escaped: */ |
177 | response = escape_text((char *) &status_str, str, (0xff << 8) + '\r'); | 179 | response = escape_text((char *) &status_str, str, (0xff << 8) + '\r'); |
178 | 180 | ||
179 | /* ?! does FTP send embedded LFs as NULs? wow */ | 181 | /* FTP sends embedded LFs as NULs */ |
180 | len = replace_char(response, '\n', '\0'); | 182 | len = replace_char(response, '\n', '\0'); |
181 | 183 | ||
182 | response[len++] = '\n'; /* tack on trailing '\n' */ | 184 | response[len++] = '\n'; /* tack on trailing '\n' */ |
@@ -315,6 +317,7 @@ handle_feat(unsigned status) | |||
315 | cmdio_write_raw(" EPSV\r\n" | 317 | cmdio_write_raw(" EPSV\r\n" |
316 | " PASV\r\n" | 318 | " PASV\r\n" |
317 | " REST STREAM\r\n" | 319 | " REST STREAM\r\n" |
320 | " MDTM\r\n" | ||
318 | " SIZE\r\n"); | 321 | " SIZE\r\n"); |
319 | cmdio_write(status, " Ok"); | 322 | cmdio_write(status, " Ok"); |
320 | } | 323 | } |
@@ -726,11 +729,43 @@ handle_stat_file(void) | |||
726 | handle_dir_common(LONG_LISTING + USE_CTRL_CONN); | 729 | handle_dir_common(LONG_LISTING + USE_CTRL_CONN); |
727 | } | 730 | } |
728 | 731 | ||
732 | /* This can be extended to handle MLST, as all info is available | ||
733 | * in struct stat for that: | ||
734 | * MLST file_name | ||
735 | * 250-Listing file_name | ||
736 | * type=file;size=4161;modify=19970214165800; /dir/dir/file_name | ||
737 | * 250 End | ||
738 | * Nano-doc: | ||
739 | * MLST [<file or dir name, "." assumed if not given>] | ||
740 | * Returned name should be either the same as requested, or fully qualified. | ||
741 | * If there was no parameter, return "" or (preferred) fully-qualified name. | ||
742 | * Returned "facts" (case is not important): | ||
743 | * size - size in octets | ||
744 | * modify - last modification time | ||
745 | * type - entry type (file,dir,OS.unix=block) | ||
746 | * (+ cdir and pdir types for MLSD) | ||
747 | * unique - unique id of file/directory (inode#) | ||
748 | * perm - | ||
749 | * a: can be appended to (APPE) | ||
750 | * d: can be deleted (RMD/DELE) | ||
751 | * f: can be renamed (RNFR) | ||
752 | * r: can be read (RETR) | ||
753 | * w: can be written (STOR) | ||
754 | * e: can CWD into this dir | ||
755 | * l: this dir can be listed (dir only!) | ||
756 | * c: can create files in this dir | ||
757 | * m: can create dirs in this dir (MKD) | ||
758 | * p: can delete files in this dir | ||
759 | * UNIX.mode - unix file mode | ||
760 | */ | ||
729 | static void | 761 | static void |
730 | handle_size(void) | 762 | handle_size_or_mdtm(int need_size) |
731 | { | 763 | { |
732 | struct stat statbuf; | 764 | struct stat statbuf; |
733 | char buf[sizeof(STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n") + sizeof(off_t)*3]; | 765 | struct tm broken_out; |
766 | char buf[(sizeof("NNN %"OFF_FMT"u\r\n") + sizeof(off_t) * 3) | ||
767 | | sizeof("NNN YYYYMMDDhhmmss\r\n") | ||
768 | ]; | ||
734 | 769 | ||
735 | if (!G.ftp_arg | 770 | if (!G.ftp_arg |
736 | || stat(G.ftp_arg, &statbuf) != 0 | 771 | || stat(G.ftp_arg, &statbuf) != 0 |
@@ -739,7 +774,18 @@ handle_size(void) | |||
739 | WRITE_ERR(FTP_FILEFAIL); | 774 | WRITE_ERR(FTP_FILEFAIL); |
740 | return; | 775 | return; |
741 | } | 776 | } |
742 | sprintf(buf, STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n", statbuf.st_size); | 777 | if (need_size) { |
778 | sprintf(buf, STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n", statbuf.st_size); | ||
779 | } else { | ||
780 | gmtime_r(&statbuf.st_mtime, &broken_out); | ||
781 | sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n", | ||
782 | broken_out.tm_year + 1900, | ||
783 | broken_out.tm_mon, | ||
784 | broken_out.tm_mday, | ||
785 | broken_out.tm_hour, | ||
786 | broken_out.tm_min, | ||
787 | broken_out.tm_sec); | ||
788 | } | ||
743 | cmdio_write_raw(buf); | 789 | cmdio_write_raw(buf); |
744 | } | 790 | } |
745 | 791 | ||
@@ -936,6 +982,7 @@ enum { | |||
936 | const_FEAT = mk_const4('F', 'E', 'A', 'T'), | 982 | const_FEAT = mk_const4('F', 'E', 'A', 'T'), |
937 | const_HELP = mk_const4('H', 'E', 'L', 'P'), | 983 | const_HELP = mk_const4('H', 'E', 'L', 'P'), |
938 | const_LIST = mk_const4('L', 'I', 'S', 'T'), | 984 | const_LIST = mk_const4('L', 'I', 'S', 'T'), |
985 | const_MDTM = mk_const4('M', 'D', 'T', 'M'), | ||
939 | const_MKD = mk_const3('M', 'K', 'D'), | 986 | const_MKD = mk_const3('M', 'K', 'D'), |
940 | const_MODE = mk_const4('M', 'O', 'D', 'E'), | 987 | const_MODE = mk_const4('M', 'O', 'D', 'E'), |
941 | const_NLST = mk_const4('N', 'L', 'S', 'T'), | 988 | const_NLST = mk_const4('N', 'L', 'S', 'T'), |
@@ -1112,7 +1159,12 @@ int ftpd_main(int argc, char **argv) | |||
1112 | return 0; | 1159 | return 0; |
1113 | } | 1160 | } |
1114 | else if (cmdval == const_USER) | 1161 | else if (cmdval == const_USER) |
1115 | WRITE_OK(FTP_GIVEPWORD); | 1162 | /* This would mean "ok, now give me PASS". */ |
1163 | /*WRITE_OK(FTP_GIVEPWORD);*/ | ||
1164 | /* vsftpd can be configured to not require that, | ||
1165 | * and this also saves one roundtrip: | ||
1166 | */ | ||
1167 | WRITE_OK(FTP_LOGINOK); | ||
1116 | else if (cmdval == const_PASS) | 1168 | else if (cmdval == const_PASS) |
1117 | WRITE_OK(FTP_LOGINOK); | 1169 | WRITE_OK(FTP_LOGINOK); |
1118 | else if (cmdval == const_NOOP) | 1170 | else if (cmdval == const_NOOP) |
@@ -1134,14 +1186,20 @@ int ftpd_main(int argc, char **argv) | |||
1134 | else if (cmdval == const_CDUP) /* cd .. */ | 1186 | else if (cmdval == const_CDUP) /* cd .. */ |
1135 | handle_cdup(); | 1187 | handle_cdup(); |
1136 | /* HELP is nearly useless, but we can reuse FEAT for it */ | 1188 | /* HELP is nearly useless, but we can reuse FEAT for it */ |
1189 | /* lftp uses FEAT */ | ||
1137 | else if (cmdval == const_HELP || cmdval == const_FEAT) | 1190 | else if (cmdval == const_HELP || cmdval == const_FEAT) |
1138 | handle_feat(cmdval == const_HELP ? STRNUM32(FTP_HELP) : STRNUM32(FTP_STATOK)); | 1191 | handle_feat(cmdval == const_HELP |
1192 | ? STRNUM32(FTP_HELP) | ||
1193 | : STRNUM32(FTP_STATOK) | ||
1194 | ); | ||
1139 | else if (cmdval == const_LIST) /* ls -l */ | 1195 | else if (cmdval == const_LIST) /* ls -l */ |
1140 | handle_list(); | 1196 | handle_list(); |
1141 | else if (cmdval == const_NLST) /* "name list", bare ls */ | 1197 | else if (cmdval == const_NLST) /* "name list", bare ls */ |
1142 | handle_nlst(); | 1198 | handle_nlst(); |
1143 | else if (cmdval == const_SIZE) | 1199 | /* SIZE is crucial for wget's download indicator etc */ |
1144 | handle_size(); | 1200 | /* Mozilla, lftp use MDTM (presumably for caching) */ |
1201 | else if (cmdval == const_SIZE || cmdval == const_MDTM) | ||
1202 | handle_size_or_mdtm(cmdval == const_SIZE); | ||
1145 | else if (cmdval == const_STAT) { | 1203 | else if (cmdval == const_STAT) { |
1146 | if (G.ftp_arg == NULL) | 1204 | if (G.ftp_arg == NULL) |
1147 | handle_stat(); | 1205 | handle_stat(); |
@@ -1194,7 +1252,7 @@ int ftpd_main(int argc, char **argv) | |||
1194 | else { | 1252 | else { |
1195 | /* Which unsupported commands were seen in the wild? | 1253 | /* Which unsupported commands were seen in the wild? |
1196 | * (doesn't necessarily mean "we must support them") | 1254 | * (doesn't necessarily mean "we must support them") |
1197 | * lftp 3.6.3: MDTM - works fine without it anyway | 1255 | * foo 1.2.3: XXXX - comment |
1198 | */ | 1256 | */ |
1199 | cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n"); | 1257 | cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n"); |
1200 | } | 1258 | } |