svn commit: [25710] trunk/busybox/networking

vda at busybox.net vda at busybox.net
Wed Mar 18 00:45:01 UTC 2009


Author: vda
Date: 2009-03-18 00:45:00 +0000 (Wed, 18 Mar 2009)
New Revision: 25710

Log:
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



Modified:
   trunk/busybox/networking/ftpd.c


Changeset:
Modified: trunk/busybox/networking/ftpd.c
===================================================================
--- trunk/busybox/networking/ftpd.c	2009-03-17 14:44:20 UTC (rev 25709)
+++ trunk/busybox/networking/ftpd.c	2009-03-18 00:45:00 UTC (rev 25710)
@@ -7,7 +7,9 @@
  * Licensed under GPLv2, see file LICENSE in this tarball for details.
  *
  * Only subset of FTP protocol is implemented but vast majority of clients
- * should not have any problem. You have to run this daemon via inetd.
+ * should not have any problem.
+ *
+ * You have to run this daemon via inetd.
  */
 
 #include "libbb.h"
@@ -172,11 +174,11 @@
 	char *response;
 	int len;
 
-	/* FTP allegedly uses telnet protocol for command link.
+	/* FTP uses telnet protocol for command link.
 	 * In telnet, 0xff is an escape char, and needs to be escaped: */
 	response = escape_text((char *) &status_str, str, (0xff << 8) + '\r');
 
-	/* ?! does FTP send embedded LFs as NULs? wow */
+	/* FTP sends embedded LFs as NULs */
 	len = replace_char(response, '\n', '\0');
 
 	response[len++] = '\n'; /* tack on trailing '\n' */
@@ -315,6 +317,7 @@
 	cmdio_write_raw(" EPSV\r\n"
 			" PASV\r\n"
 			" REST STREAM\r\n"
+			" MDTM\r\n"
 			" SIZE\r\n");
 	cmdio_write(status, " Ok");
 }
@@ -726,11 +729,43 @@
 	handle_dir_common(LONG_LISTING + USE_CTRL_CONN);
 }
 
+/* This can be extended to handle MLST, as all info is available
+ * in struct stat for that:
+ * MLST file_name
+ * 250-Listing file_name
+ *  type=file;size=4161;modify=19970214165800; /dir/dir/file_name
+ * 250 End
+ * Nano-doc:
+ * MLST [<file or dir name, "." assumed if not given>]
+ * Returned name should be either the same as requested, or fully qualified.
+ * If there was no parameter, return "" or (preferred) fully-qualified name.
+ * Returned "facts" (case is not important):
+ *  size    - size in octets
+ *  modify  - last modification time
+ *  type    - entry type (file,dir,OS.unix=block)
+ *            (+ cdir and pdir types for MLSD)
+ *  unique  - unique id of file/directory (inode#)
+ *  perm    -
+ *      a: can be appended to (APPE)
+ *      d: can be deleted (RMD/DELE)
+ *      f: can be renamed (RNFR)
+ *      r: can be read (RETR)
+ *      w: can be written (STOR)
+ *      e: can CWD into this dir
+ *      l: this dir can be listed (dir only!)
+ *      c: can create files in this dir
+ *      m: can create dirs in this dir (MKD)
+ *      p: can delete files in this dir
+ *  UNIX.mode - unix file mode
+ */
 static void
-handle_size(void)
+handle_size_or_mdtm(int need_size)
 {
 	struct stat statbuf;
-	char buf[sizeof(STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n") + sizeof(off_t)*3];
+	struct tm broken_out;
+	char buf[(sizeof("NNN %"OFF_FMT"u\r\n") + sizeof(off_t) * 3)
+		| sizeof("NNN YYYYMMDDhhmmss\r\n")
+	];
 
 	if (!G.ftp_arg
 	 || stat(G.ftp_arg, &statbuf) != 0
@@ -739,7 +774,18 @@
 		WRITE_ERR(FTP_FILEFAIL);
 		return;
 	}
-	sprintf(buf, STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n", statbuf.st_size);
+	if (need_size) {
+		sprintf(buf, STR(FTP_STATFILE_OK)" %"OFF_FMT"u\r\n", statbuf.st_size);
+	} else {
+		gmtime_r(&statbuf.st_mtime, &broken_out);
+		sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n",
+			broken_out.tm_year + 1900,
+			broken_out.tm_mon,
+			broken_out.tm_mday,
+			broken_out.tm_hour,
+			broken_out.tm_min,
+			broken_out.tm_sec);
+	}
 	cmdio_write_raw(buf);
 }
 
@@ -936,6 +982,7 @@
 	const_FEAT = mk_const4('F', 'E', 'A', 'T'),
 	const_HELP = mk_const4('H', 'E', 'L', 'P'),
 	const_LIST = mk_const4('L', 'I', 'S', 'T'),
+	const_MDTM = mk_const4('M', 'D', 'T', 'M'),
 	const_MKD  = mk_const3('M', 'K', 'D'),
 	const_MODE = mk_const4('M', 'O', 'D', 'E'),
 	const_NLST = mk_const4('N', 'L', 'S', 'T'),
@@ -1112,7 +1159,12 @@
 			return 0;
 		}
 		else if (cmdval == const_USER)
-			WRITE_OK(FTP_GIVEPWORD);
+			/* This would mean "ok, now give me PASS". */
+			/*WRITE_OK(FTP_GIVEPWORD);*/
+			/* vsftpd can be configured to not require that,
+			 * and this also saves one roundtrip:
+			 */
+			WRITE_OK(FTP_LOGINOK);
 		else if (cmdval == const_PASS)
 			WRITE_OK(FTP_LOGINOK);
 		else if (cmdval == const_NOOP)
@@ -1134,14 +1186,20 @@
 		else if (cmdval == const_CDUP) /* cd .. */
 			handle_cdup();
 		/* HELP is nearly useless, but we can reuse FEAT for it */
+		/* lftp uses FEAT */
 		else if (cmdval == const_HELP || cmdval == const_FEAT)
-			handle_feat(cmdval == const_HELP ? STRNUM32(FTP_HELP) : STRNUM32(FTP_STATOK));
+			handle_feat(cmdval == const_HELP
+					? STRNUM32(FTP_HELP)
+					: STRNUM32(FTP_STATOK)
+			);
 		else if (cmdval == const_LIST) /* ls -l */
 			handle_list();
 		else if (cmdval == const_NLST) /* "name list", bare ls */
 			handle_nlst();
-		else if (cmdval == const_SIZE)
-			handle_size();
+		/* SIZE is crucial for wget's download indicator etc */
+		/* Mozilla, lftp use MDTM (presumably for caching) */
+		else if (cmdval == const_SIZE || cmdval == const_MDTM)
+			handle_size_or_mdtm(cmdval == const_SIZE);
 		else if (cmdval == const_STAT) {
 			if (G.ftp_arg == NULL)
 				handle_stat();
@@ -1194,7 +1252,7 @@
 		else {
 			/* Which unsupported commands were seen in the wild?
 			 * (doesn't necessarily mean "we must support them")
-			 * lftp 3.6.3: MDTM - works fine without it anyway
+			 * foo 1.2.3: XXXX - comment
 			 */
 			cmdio_write_raw(STR(FTP_BADCMD)" Unknown command\r\n");
 		}



More information about the busybox-cvs mailing list