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);