Author: marius
Date: Wed Sep 22 20:27:59 2010
New Revision: 213027
URL: http://svn.freebsd.org/changeset/base/213027

Log:
  MFC: r173852
  
  Add the -W options, which acts the same as -w but will generate
  unique names based on the submitted filename, a strftime(3) format
  string and a two digit sequence number.
  
  By default the strftime(3) format string is %Y%m%d (YYYYMMDD), but
  this can be changed by the -F option.
  
  PR:           bin/106049 (based on patch in that PR)
  Approved by:  grog@ (mentor)

Modified:
  stable/7/libexec/tftpd/Makefile
  stable/7/libexec/tftpd/tftpd.8
  stable/7/libexec/tftpd/tftpd.c
Directory Properties:
  stable/7/libexec/tftpd/   (props changed)

Modified: stable/7/libexec/tftpd/Makefile
==============================================================================
--- stable/7/libexec/tftpd/Makefile     Wed Sep 22 20:17:34 2010        
(r213026)
+++ stable/7/libexec/tftpd/Makefile     Wed Sep 22 20:27:59 2010        
(r213027)
@@ -5,6 +5,7 @@ PROG=   tftpd
 SRCS=  tftpd.c tftpsubs.c
 DPADD= ${LIBUTIL}
 LDADD= -lutil
+WFORMAT=0
 MAN=   tftpd.8
 CFLAGS+=-I${.CURDIR}/../../usr.bin/tftp
 .PATH: ${.CURDIR}/../../usr.bin/tftp

Modified: stable/7/libexec/tftpd/tftpd.8
==============================================================================
--- stable/7/libexec/tftpd/tftpd.8      Wed Sep 22 20:17:34 2010        
(r213026)
+++ stable/7/libexec/tftpd/tftpd.8      Wed Sep 22 20:27:59 2010        
(r213027)
@@ -40,7 +40,8 @@
 .Nd Internet Trivial File Transfer Protocol server
 .Sh SYNOPSIS
 .Nm tftpd
-.Op Fl cClnw
+.Op Fl cClnwW
+.Op Fl F Ar strftime-format
 .Op Fl s Ar directory
 .Op Fl u Ar user
 .Op Fl U Ar umask
@@ -142,6 +143,13 @@ except it falls back to
 specified via
 .Fl s
 if a directory does not exist for the client's IP.
+.It Fl F
+Use this
+.Xr strftime 3
+compatible format string for the creation of the suffix if
+.Fl W
+is specified.
+By default the string "%Y%m%d" is used.
 .It Fl l
 Log all requests using
 .Xr syslog 3
@@ -184,6 +192,17 @@ Allow write requests to create new files
 By default
 .Nm
 requires that the file specified in a write request exist.
+Note that this only works in directories writable by the user
+specified with
+.Fl u
+option
+.It Fl W
+As
+.Fl w
+but append a YYYYMMDD.nn sequence number to the end of the filename.
+Note that the string YYYYMMDD can be changed the
+.Fl F
+option.
 .El
 .Sh SEE ALSO
 .Xr tftp 1 ,
@@ -212,10 +231,17 @@ the
 .Fl u
 option was introduced in
 .Fx 4.2 ,
-and the
+the
 .Fl c
 option was introduced in
-.Fx 4.3 .
+.Fx 4.3 ,
+and the
+.Fl F
+and
+.Fl W
+options were introduced in
+.Fx 7 .
+.Pp
 .Sh BUGS
 Files larger than 33488896 octets (65535 blocks) cannot be transferred
 without client and server supporting blocksize negotiation (RFC1783).

Modified: stable/7/libexec/tftpd/tftpd.c
==============================================================================
--- stable/7/libexec/tftpd/tftpd.c      Wed Sep 22 20:17:34 2010        
(r213026)
+++ stable/7/libexec/tftpd/tftpd.c      Wed Sep 22 20:27:59 2010        
(r213027)
@@ -110,6 +110,8 @@ static int  suppress_naks;
 static int     logging;
 static int     ipchroot;
 static int     create_new = 0;
+static char    *newfile_format = "%Y%m%d";
+static int     increase_name = 0;
 static mode_t  mask = S_IWGRP|S_IWOTH;
 
 static const char *errtomsg(int);
@@ -134,7 +136,7 @@ main(int argc, char *argv[])
        tzset();                        /* syslog in localtime */
 
        openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_FTP);
-       while ((ch = getopt(argc, argv, "cClns:u:U:w")) != -1) {
+       while ((ch = getopt(argc, argv, "cCF:lns:u:U:wW")) != -1) {
                switch (ch) {
                case 'c':
                        ipchroot = 1;
@@ -142,6 +144,9 @@ main(int argc, char *argv[])
                case 'C':
                        ipchroot = 2;
                        break;
+               case 'F':
+                       newfile_format = optarg;
+                       break;
                case 'l':
                        logging = 1;
                        break;
@@ -160,6 +165,10 @@ main(int argc, char *argv[])
                case 'w':
                        create_new = 1;
                        break;
+               case 'W':
+                       create_new = 1;
+                       increase_name = 1;
+                       break;
                default:
                        syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
                }
@@ -513,6 +522,57 @@ option_fail:
 FILE *file;
 
 /*
+ * Find the next value for YYYYMMDD.nn when the file to be written should
+ * be unique. Due to the limitations of nn, we will fail if nn reaches 100.
+ * Besides, that is four updates per hour on a file, which is kind of
+ * execessive anyway.
+ */
+static int
+find_next_name(char *filename, int *fd)
+{
+       int i;
+       time_t tval;
+       size_t len;
+       struct tm lt;
+       char yyyymmdd[MAXPATHLEN];
+       char newname[MAXPATHLEN];
+       struct stat sb;
+       int ret;
+
+       /* Create the YYYYMMDD part of the filename */
+       time(&tval);
+       lt = *localtime(&tval);
+       len = strftime(yyyymmdd, sizeof(yyyymmdd), newfile_format, &lt);
+       if (len == 0) {
+               syslog(LOG_WARNING,
+                       "Filename suffix too long (%d characters maximum)",
+                       MAXPATHLEN);
+               return (EACCESS);
+       }
+
+       /* Make sure the new filename is not too long */
+       if (strlen(filename) > MAXPATHLEN - len - 5) {
+               syslog(LOG_WARNING,
+                       "Filename too long (%d characters, %d maximum)",
+                       strlen(filename), MAXPATHLEN - len - 5);
+               return (EACCESS);
+       }
+
+       /* Find the first file which doesn't exist */
+       for (i = 0; i < 100; i++) {
+               sprintf(newname, "%s.%s.%02d", filename, yyyymmdd, i);
+               *fd = open(newname,
+                   O_WRONLY | O_CREAT | O_EXCL, 
+                   S_IRUSR | S_IWUSR | S_IRGRP |
+                   S_IWGRP | S_IROTH | S_IWOTH);
+               if (*fd > 0)
+                       return 0;
+       }
+
+       return (EEXIST);
+}
+
+/*
  * Validate file access.  Since we
  * have no uid or gid, for now require
  * file to exist and be publicly
@@ -528,6 +588,7 @@ validate_access(char **filep, int mode)
 {
        struct stat stbuf;
        int     fd;
+       int     error;
        struct dirlist *dirp;
        static char pathname[MAXPATHLEN];
        char *filename = *filep;
@@ -610,10 +671,18 @@ validate_access(char **filep, int mode)
        if (mode == RRQ)
                fd = open(filename, O_RDONLY);
        else {
-               if (create_new)
-                       fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0666);
-               else
-                       fd = open(filename, O_WRONLY|O_TRUNC);
+               if (create_new) {
+                       if (increase_name) {
+                               error = find_next_name(filename, &fd);
+                               if (error > 0)
+                                       return (error + 100);
+                       } else
+                               fd = open(filename,
+                                   O_WRONLY | O_TRUNC | O_CREAT, 
+                                   S_IRUSR | S_IWUSR | S_IRGRP | 
+                                   S_IWGRP | S_IROTH | S_IWOTH );
+               } else
+                       fd = open(filename, O_WRONLY | O_TRUNC);
        }
        if (fd < 0)
                return (errno + 100);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to