<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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 &lt;tmb2@po.cwru.edu&gt;


--- ./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 &lt;sys/types.h&gt;
+#include &lt;sys/time.h&gt;
 #include &lt;sys/stat.h&gt;
 #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 &gt; 15) { ++len; q /= 16; }
+ if (s)
+  {
+   s += len;
+   do { c = u &amp; 15; *--s = (c &gt; 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 &lt; str_len(host); ++loop)
+  {
+   if (host[loop] == '/')
+    {
+     if (!stralloc_cats(&amp;hostname,"057")) temp_nomem();
+     continue;
+    }
+   if (host[loop] == ':')
+    {
+     if (!stralloc_cats(&amp;hostname,"072")) temp_nomem();
+     continue;
+    }
+   if (!stralloc_append(&amp;hostname,s+loop)) temp_nomem();
+  }
+
  for (loop = 0;;++loop)
   {
-   time = now();
+   gettimeofday(&amp;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,&amp;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(&amp;ssout) == -1) goto fail;
+ if (fstat(fd, &amp;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 */
</pre></body></html>