Index: tftpd.8 =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/tftpd.8,v retrieving revision 1.21 diff -u -r1.21 tftpd.8 --- tftpd.8 3 Jun 2007 15:32:06 -0000 1.21 +++ tftpd.8 13 Nov 2007 06:11:08 -0000 @@ -40,7 +40,7 @@ .Nd Internet Trivial File Transfer Protocol server .Sh SYNOPSIS .Nm tftpd -.Op Fl cClnw +.Op Fl cClnwW .Op Fl s Ar directory .Op Fl u Ar user .Op Fl U Ar umask @@ -184,6 +184,14 @@ 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. .El .Sh SEE ALSO .Xr tftp 1 , @@ -212,10 +220,15 @@ .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 W +option was 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). Index: tftpd.c =================================================================== RCS file: /home/ncvs/src/libexec/tftpd/tftpd.c,v retrieving revision 1.37 diff -u -r1.37 tftpd.c --- tftpd.c 31 May 2005 17:22:53 -0000 1.37 +++ tftpd.c 13 Nov 2007 06:11:09 -0000 @@ -110,6 +110,7 @@ static int logging; static int ipchroot; static int create_new = 0; +static int increase_name = 0; static mode_t mask = S_IWGRP|S_IWOTH; static const char *errtomsg(int); @@ -134,7 +135,7 @@ 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, "cClns:u:U:wW")) != -1) { switch (ch) { case 'c': ipchroot = 1; @@ -160,6 +161,10 @@ 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 +518,54 @@ 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 i; + int fd; + time_t tval; + struct tm lt; + char yyyymmdd[10]; + char newname[MAXPATHLEN]; + struct stat sb; + int ret; + + /* Make sure the new filename is not too long */ + if (strlen(filename) > MAXPATHLEN - 12) { + syslog(LOG_WARNING, + "Filename too long (%d characters, %d maximum)", + strlen(filename), MAXPATHLEN - 12); + return (-EACCESS); + } + + /* If we can't find anything, fail */ + fd = -1; + + /* Append the YYYYMMDD string to the filename */ + time(&tval); + lt = *localtime(&tval); + strftime(yyyymmdd, sizeof(yyyymmdd), "%Y%m%d", <); + + /* 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 fd; + } + + return (-ENOSPC); +} + +/* * Validate file access. Since we * have no uid or gid, for now require * file to exist and be publicly @@ -610,10 +663,18 @@ 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) { + fd = find_next_name(filename); + if (fd < 0) + return (-fd); + } 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);