Some operating systems quickly recycle PIDs, which can lead to collisions between Maildir-style filenames, which must be unique and non-repeatable within one second. This patch is just a means of updating qmail-local to use the format of the revised Maildir protocol, available at: http://cr.yp.to/proto/maildir.html It uses four unique identifiers: * inode number of the file written to Maildir/tmp * device number of the file written to Maildir/tmp * time in microseconds * the PID of the writing process A Maildir-style filename would look like the following: In Maildir/tmp: time.MmicrosecondsPpid.host In Maildir/new: time.IinodeVdeviceMmicrosecondsPpid.host Additionally, this patch further comforms to the revised Maildir protocol by looking through the hostname for instances of '/' and ':', replacing them with "\057" and "\072", respectively, when writing it to disk. Special thanks go to Matthias Andree for design and sanity-checking. --Toby Betts --- ./qmail-local.c.orig Mon Jun 15 06:52:55 1998 +++ ./qmail-local.c Mon Jun 16 16:09:05 2003 @@ -1,4 +1,5 @@ #include +#include #include #include "readwrite.h" #include "sig.h" @@ -41,6 +42,20 @@ void temp_qmail(fn) char *fn; { strerr_die5x(111,"Unable to open ",fn,": ",error_str(errno),". (#4.3.0)"); } +/* writes ulong u in hex to char *s, does not NULL-terminate */ +unsigned int fmt_xlong(s,u) char *s; unsigned long u; +{ + unsigned int len; unsigned long q; unsigned long c; + len = 1; q = u; + while (q > 15) { ++len; q /= 16; } + if (s) + { + s += len; + do { c = u & 15; *--s = (c > 9 ? 'a' - 10 : '0') + c; u /= 16; } while(u); + } + return len; +} + int flagdoit; int flag99; @@ -63,6 +78,7 @@ stralloc cmds = {0}; stralloc messline = {0}; stralloc foo = {0}; +stralloc hostname = {0}; char buf[1024]; char outbuf[1024]; @@ -78,7 +94,7 @@ char *dir; { unsigned long pid; - unsigned long time; + struct timeval time; char host[64]; char *s; int loop; @@ -92,21 +108,37 @@ pid = getpid(); host[0] = 0; gethostname(host,sizeof(host)); + + s = host; + for (loop = 0; loop < str_len(host); ++loop) + { + if (host[loop] == '/') + { + if (!stralloc_cats(&hostname,"\\057")) temp_nomem(); + continue; + } + if (host[loop] == ':') + { + if (!stralloc_cats(&hostname,"\\072")) temp_nomem(); + continue; + } + if (!stralloc_append(&hostname,s+loop)) temp_nomem(); + } + for (loop = 0;;++loop) { - time = now(); + gettimeofday(&time, 0); s = fntmptph; s += fmt_str(s,"tmp/"); - s += fmt_ulong(s,time); *s++ = '.'; - s += fmt_ulong(s,pid); *s++ = '.'; - s += fmt_strn(s,host,sizeof(host)); *s++ = 0; + s += fmt_ulong(s,time.tv_sec); *s++ = '.'; + *s++ = 'M'; s += fmt_ulong(s,time.tv_usec); + *s++ = 'P'; s += fmt_ulong(s,pid); *s++ = '.'; + s += fmt_strn(s,hostname.s,hostname.len); *s++ = 0; if (stat(fntmptph,&st) == -1) if (errno == error_noent) break; /* really should never get to this point */ if (loop == 2) _exit(1); sleep(2); } - str_copy(fnnewtph,fntmptph); - byte_copy(fnnewtph,3,"new"); alarm(86400); fd = open_excl(fntmptph); @@ -124,8 +156,23 @@ } if (substdio_flush(&ssout) == -1) goto fail; + if (fstat(fd, &st) == -1) goto fail; if (fsync(fd) == -1) goto fail; if (close(fd) == -1) goto fail; /* NFS dorks */ + + s = fnnewtph; + s += fmt_str(s,"new/"); + s += fmt_ulong(s,time.tv_sec); *s++ = '.'; + + /* in hexadecimal */ + *s++ = 'I'; s += fmt_xlong(s,st.st_ino); + *s++ = 'V'; s += fmt_xlong(s,st.st_dev); + + /* in decimal */ + *s++ = 'M'; s += fmt_ulong(s,time.tv_usec); + *s++ = 'P'; s += fmt_ulong(s,pid); *s++ = '.'; + + s += fmt_strn(s,hostname.s,hostname.len); *s++ = 0; if (link(fntmptph,fnnewtph) == -1) goto fail; /* if it was error_exist, almost certainly successful; i hate NFS */