quite stable set of patches
authorHeiko Schlittermann (I24) <hs@schlittermann.de>
Sun, 20 Feb 2011 23:59:48 +0100
changeset 6 d2183655483b
parent 5 399967a8bbf1
child 7 3e755b50b6a4
quite stable set of patches
build.Makefile
dbg.maildirsize
series
src.fixed_ensure_maildirsize
src.lock_maildirsize
src.quota-ignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build.Makefile	Sun Feb 20 23:59:48 2011 +0100
@@ -0,0 +1,78 @@
+# HG changeset patch
+# Parent 5c737d4329e1327fbc2aa16a5227d5ae5bc7ee03
+
+diff -r 5c737d4329e1 Makefile
+--- a/Makefile	Fri Feb 18 18:22:42 2011 +0100
++++ b/Makefile	Fri Feb 18 21:40:42 2011 +0100
+@@ -68,7 +68,8 @@
+ # The installation commands are kept in a separate script, which expects
+ # to be run from inside the build directory.
+ 
+-install:;	@cd build-$(buildname); \
++install:	all
++		@cd build-$(buildname); \
+ 		build=$(build) $(SHELL) ../scripts/exim_install $(INSTALL_ARG)
+ 
+ # Tidy-up targets
+diff -r 5c737d4329e1 OS/Makefile-Base
+--- a/OS/Makefile-Base	Fri Feb 18 18:22:42 2011 +0100
++++ b/OS/Makefile-Base	Fri Feb 18 21:40:42 2011 +0100
+@@ -640,43 +640,43 @@
+ # The lookups library.
+ 
+ buildlookups lookups/lookups.a: config.h
+-	 @cd lookups; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
++	 @cd lookups && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ 	   CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \
+ 	   FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
+-	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE) $(LOOKUP_INCLUDE)"; \
+-	 echo " "
++	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE) $(LOOKUP_INCLUDE)"
++	 @echo " "
+ 
+ # The routers library.
+ 
+ buildrouters routers/routers.a: config.h
+-	 @cd routers; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
++	 @cd routers && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ 	   FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
+-	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"; \
+-	 echo " "
++	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
++	 @echo " "
+ 
+ # The transports library.
+ 
+ buildtransports transports/transports.a: config.h
+-	 @cd transports; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
++	 @cd transports && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ 	   FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
+-	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"; \
+-	 echo " "
++	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
++	 @echo " "
+ 
+ # The library of authorization modules
+ 
+ buildauths auths/auths.a: config.h
+-	 @cd auths; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
++	 @cd auths && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ 	   FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
+-	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"; \
+-	 echo " "
++	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
++	 @echo " "
+ 
+ # The PDKIM library
+ 
+ buildpdkim pdkim/pdkim.a: config.h
+-	 @cd pdkim; $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
++	 @cd pdkim && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ 	   FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
+-	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"; \
+-	 echo " "
++	   INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
++	 @echo " "
+ 
+ # The "clean", "install", and "makefile" targets just pass themselves back to
+ # the main Exim makefile. These targets will be obeyed only if "make" is obeyed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbg.maildirsize	Sun Feb 20 23:59:48 2011 +0100
@@ -0,0 +1,264 @@
+# HG changeset patch
+# Parent 74c82038542f0fe3e9d80b15ecffc5e2598ef52a
+
+diff -r 74c82038542f src/exim.c
+--- a/src/exim.c	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/exim.c	Sat Feb 19 13:38:06 2011 +0100
+@@ -2206,7 +2206,9 @@
+     else
+       {
+       unsigned int selector = D_default;
++      unsigned int extra_selector = 0;
+       debug_selector = 0;
++      debug_extra_selector = 0;
+       debug_file = NULL;
+       if (*argrest == 'd')
+         {
+@@ -2214,9 +2216,10 @@
+         argrest++;
+         }
+       if (*argrest != 0)
+-        decode_bits(&selector, NULL, D_memory, 0, argrest, debug_options,
++        decode_bits(&selector, &extra_selector, D_memory, 0, argrest, debug_options,
+           debug_options_count, US"debug", 0);
+       debug_selector = selector;
++      debug_extra_selector = extra_selector;
+       }
+     break;
+ 
+@@ -3184,7 +3187,7 @@
+ child processes. It should, of course, be 2 for stderr. Also, force the daemon
+ to run in the foreground. */
+ 
+-if (debug_selector != 0)
++if (debug_selector|debug_extra_selector != 0)
+   {
+   debug_file = stderr;
+   debug_fd = fileno(debug_file);
+diff -r 74c82038542f src/globals.c
+--- a/src/globals.c	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/globals.c	Sat Feb 19 13:38:06 2011 +0100
+@@ -449,6 +449,7 @@
+   { US"load",           D_load },
+   { US"local_scan",     D_local_scan },
+   { US"lookup",         D_lookup },
++  { US"maildirsize",	DX_maildirsize },
+   { US"memory",         D_memory },
+   { US"pid",            D_pid },
+   { US"process_info",   D_process_info },
+@@ -466,6 +467,7 @@
+ };
+ int     debug_options_count    = sizeof(debug_options)/sizeof(bit_table);
+ unsigned int debug_selector    = 0;
++unsigned int debug_extra_selector = 0;
+ int     delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 };
+ uschar *delay_warning_condition=
+   US"${if or {"
+diff -r 74c82038542f src/local_scan.h
+--- a/src/local_scan.h	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/local_scan.h	Sat Feb 19 13:38:06 2011 +0100
+@@ -139,6 +139,7 @@
+ /* Global variables that are documented as visible in the function. */
+ 
+ extern unsigned int debug_selector;    /* Debugging bits */
++extern unsigned int debug_extra_selector;    /* Debugging bits */
+ 
+ extern int     body_linecount;         /* Line count in body */
+ extern int     body_zerocount;         /* Binary zero count in body */
+diff -r 74c82038542f src/log.c
+--- a/src/log.c	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/log.c	Sat Feb 19 13:38:06 2011 +0100
+@@ -1303,7 +1303,7 @@
+ debug_selector = D_default;
+ if (opts)
+   {
+-  decode_bits(&debug_selector, NULL, D_memory, 0, opts,
++  decode_bits(&debug_selector, &debug_extra_selector, D_memory, 0, opts,
+       debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
+   }
+ 
+diff -r 74c82038542f src/macros.h
+--- a/src/macros.h	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/macros.h	Sat Feb 19 13:38:06 2011 +0100
+@@ -100,7 +100,9 @@
+ 
+ /* Debugging control */
+ 
+-#define DEBUG(x)      if ((debug_selector & (x)) != 0)
++//#define DEBUG(x)      if (((debug_selector & (x)) || (debug_extra_selector & (x))) != 0)
++#define DEBUG(x)      if(x & 0x80000000 ? (debug_extra_selector & ((x) & 0x0fffffff)) : 
++
+ #define HDEBUG(x)     if (host_checking || (debug_selector & (x)) != 0)
+ 
+ /* The default From: text for DSNs */
+@@ -327,6 +329,8 @@
+ #define D_uid                        0x20000000
+ #define D_verify                     0x40000000
+ 
++#define DX_maildirsize               0x80000001
++
+ /* The D_all value must always have all bits set, as it is recognized specially
+ by the function that decodes debug and log selectors. This is to enable it to
+ set all the bits in a multi-word selector. Debug doesn't use this yet, but we
+diff -r 74c82038542f src/transports/tf_maildir.c
+--- a/src/transports/tf_maildir.c	Sat Feb 19 13:30:33 2011 +0100
++++ b/src/transports/tf_maildir.c	Sat Feb 19 13:38:06 2011 +0100
+@@ -215,7 +215,7 @@
+ len = Ustrlen(buffer);
+ (void)lseek(fd, 0, SEEK_END);
+ (void)write(fd, buffer, len);
+-DEBUG(D_transport)
++DEBUG(D_transport|DX_maildirsize)
+   debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer);
+ }
+ 
+@@ -292,7 +292,7 @@
+ 
+   if (Ustat(buffer, &statbuf) < 0)
+     {
+-    DEBUG(D_transport)
++    DEBUG(D_transport|DX_maildirsize)
+       debug_printf("maildir_compute_size: stat error %d for %s: %s\n", errno,
+         buffer, strerror(errno));
+     continue;
+@@ -300,7 +300,7 @@
+ 
+   if ((statbuf.st_mode & S_IFMT) != S_IFDIR)
+     {
+-    DEBUG(D_transport)
++    DEBUG(D_transport|DX_maildirsize)
+       debug_printf("skipping %s/%s: not a directory\n", path, name);
+     continue;
+     }
+@@ -327,7 +327,7 @@
+   }
+ 
+ closedir(dir);
+-DEBUG(D_transport)
++DEBUG(D_transport|DX_maildirsize)
+   {
+   if (timestamp_only)
+     debug_printf("maildir_compute_size (timestamp_only): %ld\n",
+@@ -391,7 +391,7 @@
+ 
+ filename = string_sprintf("%s/maildirsize", path);
+ 
+-DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path);
++DEBUG(D_transport|DX_maildirsize) debug_printf("looking for maildirsize in %s\n", path);
+ fd = Uopen(filename, O_CREAT|O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600);
+ if (fd < 0) return -1;
+ 
+@@ -420,7 +420,7 @@
+ count = read(fd, buffer, sizeof(buffer));
+ if (count >= sizeof(buffer))
+   {
+-  DEBUG(D_transport)
++  DEBUG(D_transport|DX_maildirsize)
+     debug_printf("maildirsize file too big (%d): recalculating\n", count);
+   goto RECALCULATE;
+   }
+@@ -428,7 +428,7 @@
+ 
+ /* Read the quota parameters from the first line of the data. */
+ 
+-DEBUG(D_transport)
++DEBUG(D_transport|DX_maildirsize)
+   debug_printf("reading quota parameters from maildirsize data\n");
+ 
+ for (;;)
+@@ -443,7 +443,7 @@
+     else if (*endptr == 'C') cached_quota_filecount = (int)n;
+   if (!isalpha(*endptr++))
+     {
+-    DEBUG(D_transport)
++    DEBUG(D_transport|DX_maildirsize)
+       debug_printf("quota parameter number not followed by letter in "
+         "\"%.*s\": recalculating maildirsize\n", (int)(endptr - buffer),
+         buffer);
+@@ -452,7 +452,7 @@
+   if (*endptr == '\n' || *endptr == 0) break;
+   if (*endptr++ != ',')
+     {
+-    DEBUG(D_transport)
++    DEBUG(D_transport|DX_maildirsize)
+       debug_printf("quota parameter not followed by comma in "
+         "\"%.*s\": recalculating maildirsize\n", (int)(endptr - buffer),
+         buffer);
+@@ -466,7 +466,7 @@
+ if (cached_quota != ob->quota_value ||
+     cached_quota_filecount != ob->quota_filecount_value)
+   {
+-  DEBUG(D_transport)
++  DEBUG(D_transport|DX_maildirsize)
+     debug_printf("cached quota is out of date: recalculating\n"
+       "  quota=" OFF_T_FMT " cached_quota=" OFF_T_FMT " filecount_quota=%d "
+       "cached_quota_filecount=%d\n", ob->quota_value,
+@@ -477,7 +477,7 @@
+ /* Quota values agree; parse the rest of the data to get the sizes. At this
+ stage, *endptr points either to 0 or to '\n'.  */
+ 
+-DEBUG(D_transport)
++DEBUG(D_transport|DX_maildirsize)
+   debug_printf("computing maildir size from maildirsize data\n");
+ 
+ while (*endptr++ == '\n')
+@@ -502,7 +502,7 @@
+   {
+   if (size < 0 || filecount < 0)
+     {
+-    DEBUG(D_transport) debug_printf("negative value in maildirsize "
++    DEBUG(D_transport|DX_maildirsize) debug_printf("negative value in maildirsize "
+       "(size=" OFF_T_FMT " count=%d): recalculating\n", size, filecount);
+     goto RECALCULATE;
+     }
+@@ -517,7 +517,7 @@
+     struct stat statbuf;
+     if (linecount > 1)
+       {
+-      DEBUG(D_transport) debug_printf("over quota and maildirsize has "
++      DEBUG(D_transport|DX_maildirsize) debug_printf("over quota and maildirsize has "
+         "more than 1 entry: recalculating\n");
+       goto RECALCULATE;
+       }
+@@ -526,7 +526,7 @@
+ 
+     if (time(NULL) - statbuf.st_mtime > 15*60)
+       {
+-      DEBUG(D_transport) debug_printf("over quota and maildirsize is older "
++      DEBUG(D_transport|DX_maildirsize) debug_printf("over quota and maildirsize is older "
+         "than 15 minutes: recalculating\n");
+       goto RECALCULATE;
+       }
+@@ -543,7 +543,7 @@
+   uschar *tempname;
+   struct timeval tv;
+ 
+-  DEBUG(D_transport)
++  DEBUG(D_transport|DX_maildirsize)
+     {
+     uschar *p = endptr;
+     while (p > buffer && p[-1] != '\n') p--;
+@@ -587,12 +587,12 @@
+   /* If any of the directories have been modified since the last timestamp we
+   saw, we have to junk this maildirsize file. */
+ 
+-  DEBUG(D_transport) debug_printf("checking subdirectory timestamps\n");
++  DEBUG(D_transport|DX_maildirsize) debug_printf("checking subdirectory timestamps\n");
+   new_latest = 0;
+   (void)maildir_compute_size(path, NULL, &new_latest , NULL, dir_regex, TRUE);
+   if (new_latest > old_latest)
+     {
+-    DEBUG(D_transport) debug_printf("abandoning maildirsize because of "
++    DEBUG(D_transport|DX_maildirsize) debug_printf("abandoning maildirsize because of "
+       "a later subdirectory modification\n");
+     (void)Uunlink(filename);
+     (void)close(fd);
+@@ -604,7 +604,7 @@
+ lock.l_type = F_UNLCK;
+ if (fd > 0) fcntl(fd, F_SETLKW, &lock);
+ 
+-DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT
++DEBUG(D_transport|DX_maildirsize) debug_printf("returning maildir size=" OFF_T_FMT
+   " filecount=%d\n", size, filecount);
+ *returned_size = size;
+ *returned_filecount = filecount;
--- a/series	Sun Feb 13 23:07:24 2011 +0100
+++ b/series	Sun Feb 20 23:59:48 2011 +0100
@@ -1,3 +1,8 @@
 doc.maildir_tag
+build.Makefile
+src.bail-out-on-BOM
 src.maildir_use_size_file
-src.bail-out-on-BOM
+src.fixed_ensure_maildirsize
+src.lock_maildirsize
+dbg.maildirsize #+wip
+src.quota-ignore #+wip
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src.fixed_ensure_maildirsize	Sun Feb 20 23:59:48 2011 +0100
@@ -0,0 +1,41 @@
+# HG changeset patch
+# Parent bb312f4baa8351ad1e97b991721f71c4c96b13ac
+
+diff -r bb312f4baa83 src/transports/appendfile.c
+--- a/src/transports/appendfile.c	Tue Feb 15 11:23:53 2011 +0100
++++ b/src/transports/appendfile.c	Fri Feb 18 00:02:06 2011 +0100
+@@ -1263,7 +1263,6 @@
+ 
+ #ifdef SUPPORT_MAILDIR
+ int maildirsize_fd = -1;      /* fd for maildirsize file */
+-int maildir_save_errno;
+ #endif
+ 
+ 
+@@ -2911,11 +2910,12 @@
+ #ifdef SUPPORT_MAILDIR
+ if (!disable_quota)
+   {
++  int save_errno;
+   if (yield == OK && maildirsize_fd >= 0)
+     maildir_record_length(maildirsize_fd, message_size);
+-  maildir_save_errno = errno;    /* Preserve errno while closing the file */
++  save_errno = errno;            /* Preserve errno while closing the file */
+   (void)close(maildirsize_fd);
+-  errno = maildir_save_errno;
++  errno = save_errno;
+   }
+ #endif  /* SUPPORT_MAILDIR */
+ 
+diff -r bb312f4baa83 src/transports/tf_maildir.c
+--- a/src/transports/tf_maildir.c	Tue Feb 15 11:23:53 2011 +0100
++++ b/src/transports/tf_maildir.c	Fri Feb 18 00:02:06 2011 +0100
+@@ -584,7 +584,7 @@
+       "a later subdirectory modification\n");
+     (void)Uunlink(filename);
+     (void)close(fd);
+-    fd = -1;
++    fd = -2;
+     }
+   }
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src.lock_maildirsize	Sun Feb 20 23:59:48 2011 +0100
@@ -0,0 +1,260 @@
+# HG changeset patch
+# Parent 5037ac63d7aece4b5e96e26bace1ab4b7e791804
+
+diff -r 5037ac63d7ae Local/Makefile
+--- a/Local/Makefile	Sat Feb 19 13:42:16 2011 +0100
++++ b/Local/Makefile	Sun Feb 20 23:37:25 2011 +0100
+@@ -1,4 +1,5 @@
+ # $Cambridge: exim/src/src/EDITME,v 1.27 2010/06/12 15:21:25 jetmore Exp $
++EXTRALIBS_EXIM=-lrt
+ 
+ ##################################################
+ #          The Exim mail transport agent         #
+diff -r 5037ac63d7ae src/transports/appendfile.c
+--- a/src/transports/appendfile.c	Sat Feb 19 13:42:16 2011 +0100
++++ b/src/transports/appendfile.c	Sun Feb 20 23:37:25 2011 +0100
+@@ -13,6 +13,7 @@
+ 
+ #ifdef SUPPORT_MAILDIR
+ #include "tf_maildir.h"
++extern int lockfd;				/* from tf_maildir */	// hs12
+ #endif
+ 
+ 
+@@ -278,8 +279,8 @@
+ gid = gid;
+ 
+ if (ob->expand_maildir_use_size_file)
+-	ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
+-		US"`maildir_use_size_file` in transport", tblock->name);
++  ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
++    US"`maildir_use_size_file` in transport", tblock->name);
+ 
+ /* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size,
+ mailbox_filecount */
+@@ -841,7 +842,7 @@
+               sigalrm_seen set if there has been a timeout
+ */
+ 
+-static int
++int
+ apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
+     int flocktime)
+ {
+@@ -887,7 +888,6 @@
+ 
+ 
+ 
+-
+ #ifdef SUPPORT_MBX
+ /*************************************************
+ *         Copy message into MBX mailbox          *
+@@ -2416,18 +2416,32 @@
+       {
+       off_t size;
+       int filecount;
++      uschar *excuse;
++
++      struct timespec t0, t1;
++      clock_gettime(CLOCK_REALTIME, &t0);
+ 
+       maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex,
+-        &size, &filecount);
++        &size, &filecount, &excuse);
+ 
+       if (maildirsize_fd == -1)
+         {
+         addr->basic_errno = errno;
+-        addr->message = string_sprintf("while opening or reading "
+-          "%s/maildirsize", check_path);
++        //addr->message = string_sprintf("%s", excuse);
++        addr->message = excuse;
+         return FALSE;
+         }
+ 
++
++      clock_gettime(CLOCK_REALTIME, &t1);
++      t1.tv_sec -= t0.tv_sec;
++      t1.tv_nsec -= t0.tv_nsec;
++      if (t1.tv_nsec < 0) { t1.tv_sec--; t1.tv_nsec *= -1; }
++      DEBUG(D_transport) {
++         if (t1.tv_sec >= 1) debug_printf("%s/maildirsize was locked for %d.09ld seconds\n",
++          check_path, t1.tv_sec, t1.tv_nsec);
++      }
++          
+       if (mailbox_size < 0) mailbox_size = size;
+       if (mailbox_filecount < 0) mailbox_filecount = filecount;
+       }
+@@ -3125,6 +3139,8 @@
+       uschar *renamename = newname;
+       fd = -1;
+ 
++			if (lockfd >= 0) (void)apply_lock(lockfd, F_RDLCK, 1, 120, 0, 0);  // hs12
++
+       DEBUG(D_transport) debug_printf("renaming temporary file\n");
+ 
+       /* If there is no rename name set, we are in a non-maildir, non-mailstore
+@@ -3245,6 +3261,7 @@
+           filename = dataname = NULL;   /* Prevents attempt to unlink at end */
+           }
+         }        /* maildir or mailstore */
++
+       }          /* successful write + close */
+     }            /* isdirectory */
+   }              /* write success */
+@@ -3280,6 +3297,11 @@
+ detected, in order to get the file closed and the lock file tidied away. */
+ 
+ RETURN:
++if (lockfd >= 0) 
++  {
++	(void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0); // hs12
++	(void)close(lockfd);
++	}
+ 
+ #ifdef SUPPORT_MBX
+ if (mbx_lockfd >= 0)
+diff -r 5037ac63d7ae src/transports/appendfile.h
+--- a/src/transports/appendfile.h	Sat Feb 19 13:42:16 2011 +0100
++++ b/src/transports/appendfile.h	Sun Feb 20 23:37:25 2011 +0100
+@@ -95,5 +95,8 @@
+ /* Function that is shared with tf_maildir.c */
+ 
+ extern off_t  check_dir_size(uschar *, int *, const pcre *);
++extern int apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
++    int flocktime);
++
+ 
+ /* End of transports/appendfile.h */
+diff -r 5037ac63d7ae src/transports/tf_maildir.c
+--- a/src/transports/tf_maildir.c	Sat Feb 19 13:42:16 2011 +0100
++++ b/src/transports/tf_maildir.c	Sun Feb 20 23:37:25 2011 +0100
+@@ -367,13 +367,16 @@
+ 
+ Returns:           >=0  a file descriptor for an open maildirsize file
+                    -1   there was an error opening or accessing the file
++				        or locking
+                    -2   the file was removed because of a race
+ */
+ 
++int lockfd = -1;	// hs12
++
+ int
+ maildir_ensure_sizefile(uschar *path, appendfile_transport_options_block *ob,
+   const pcre *regex, const pcre *dir_regex, off_t *returned_size,
+-  int *returned_filecount)
++  int *returned_filecount, uschar **excuse)
+ {
+ int count, fd;
+ off_t cached_quota = 0;
+@@ -381,25 +384,80 @@
+ int filecount = 0;
+ int linecount = 0;
+ off_t size = 0;
+-uschar *filename;
++uschar *filename, *lockname, *hitchname;
+ uschar buffer[MAX_FILE_SIZE];
+ uschar *ptr = buffer;
+ uschar *endptr;
+ 
++filename = string_sprintf("%s/maildirsize", path);
++lockname = string_sprintf("%s.lock", filename);
++hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname,
++      (unsigned int)(time(NULL)), (unsigned int)getpid());
++
++/* Try to create a lock file. Here we should copy the loop from appendfile.c,
++since our approach is quite simplified */
++lockfd = Uopen(lockname, O_CREAT|O_RDWR, ob->mode ? ob->mode : 0600);
++if (lockfd < 0)
++  {
++    if (errno != ENOENT)
++	  {
++	  *excuse = string_sprintf("open %s", lockname);
++	  return -1;
++	  }
++
++	lockfd = Uopen(hitchname, O_WRONLY|O_CREAT|O_EXCL, ob->mode ? ob->mode : 0600);
++	if (lockfd < 0) 
++	  {
++		*excuse = string_sprintf("open %s", hitchname);
++		return -1;
++	  }
++	if (link(hitchname, lockname) < 0)
++	  {
++	  int save_errno = errno;
++	  (void)unlink(hitchname);
++	  errno = save_errno;
++	  if (errno != EEXIST) 
++		{
++		  *excuse = string_sprintf("link %s -> %s", hitchname, lockname);
++		  return -1;
++		}
++	  (void)close(lockfd);
++	  lockfd = Uopen(lockname, O_WRONLY, ob->mode ? ob->mode : 0600);
++	  if (lockfd < 0) 
++		{
++		*excuse = string_sprintf("open %s", lockname);
++		return -1;
++		}
++	  }
++	(void)unlink(hitchname);
++  }
++	
++
++/* Before doing anything here we try to open and lock the maildirsize.lock
++file. This should prevent/avoid races and parallel recalculations. We
++need to do this on an extra lockfile, since the maildirsize file itself
++gets renamed during the recalculation. */
++
++if (lockfd >= 0)
++(void)apply_lock(lockfd, F_WRLCK, 1, 120, 0, 0);	// hs12
++if (sigalrm_seen) 
++  {
++  *excuse = string_sprintf("timeout locking %s", lockname);
++  return -1;
++  }
++DEBUG(D_transport) debug_printf("locked (WR) %s\n", lockname);
++
+ /* Try a few times to open or create the file, in case another process is doing
+ the same thing. */
+ 
+-filename = string_sprintf("%s/maildirsize", path);
+-
+ DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path);
+ fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600);
+-if (fd < 0)
+-  {
++if (fd < 0) {
+   if (errno != ENOENT) return -1;
+   DEBUG(D_transport)
+     debug_printf("%s does not exist: recalculating\n", filename);
+   goto RECALCULATE;
+-  }
++}
+ 
+ /* The file has been successfully opened. Check that the cached quota value is
+ still correct, and that the size of the file is still small enough. If so,
+@@ -588,8 +646,10 @@
+     }
+   }
+ 
++	DEBUG(D_transport) debug_printf("releasing lock\n");
++  (void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0);
++
+ /* Return the sizes and the file descriptor, if any */
+-
+ DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT
+   " filecount=%d\n", size, filecount);
+ *returned_size = size;
+diff -r 5037ac63d7ae src/transports/tf_maildir.h
+--- a/src/transports/tf_maildir.h	Sat Feb 19 13:42:16 2011 +0100
++++ b/src/transports/tf_maildir.h	Sun Feb 20 23:37:25 2011 +0100
+@@ -16,7 +16,7 @@
+                 uschar *);
+ extern int    maildir_ensure_sizefile(uschar *,
+                 appendfile_transport_options_block *, const pcre *,
+-                const pcre *, off_t *, int *);
++                const pcre *, off_t *, int *, uschar **);
+ extern void   maildir_record_length(int, int);
+ 
+ /* End of tf_maildir.h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src.quota-ignore	Sun Feb 20 23:59:48 2011 +0100
@@ -0,0 +1,99 @@
+# HG changeset patch
+# Parent 717fd3d2296015e18687e4b3ecb259f7ded5e15f
+
+diff -r 717fd3d22960 src/transports/appendfile.c
+--- a/src/transports/appendfile.c	Sun Feb 13 14:05:44 2011 +0100
++++ b/src/transports/appendfile.c	Tue Feb 15 11:18:53 2011 +0100
+@@ -31,6 +31,8 @@
+ #define THRESHOLD_CHECK  (ob->quota_warn_threshold_value > 0 && \
+   (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
+ 
++#define QUOTA_CHECK      (ob->quota_value > 0 && !ob->quota_no_check)
++
+ 
+ /* Options specific to the appendfile transport. They must be in alphabetic
+ order (note that "_" comes before the lower case letters). Some of them are
+@@ -236,7 +238,9 @@
+   FALSE,          /* mailstore_format */
+   FALSE,          /* mbx_format */
+   FALSE,          /* quota_warn_threshold_is_percent */
+-  TRUE            /* quota_is_inclusive */
++  TRUE,           /* quota_is_inclusive */
++  FALSE,          /* quota_no_check */
++  FALSE           /* quota_filecount_no_check */
+ };
+ 
+ 
+@@ -270,6 +274,7 @@
+   (appendfile_transport_options_block *)(tblock->options_block);
+ uschar *q = ob->quota;
+ double default_value = 0.0;
++int no_check = 0;
+ int i;
+ 
+ addrlist = addrlist;    /* Keep picky compilers happy */
+@@ -323,6 +328,15 @@
+       rest++;
+       }
+ 
++
++    /* For quota and quota_filecount there may be options
++    appended. Currently only "no_check", so we can be lazy parsing it */
++    if (i < 2 && Ustrstr(rest, "/no_check") == rest)
++      {
++	 no_check = 1;
++	 rest += strlen("/no_check");
++      }
++
+     while (isspace(*rest)) rest++;
+ 
+     if (*rest != 0)
+@@ -340,12 +354,14 @@
+     case 0:
+     if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4) which = US"quota";
+     ob->quota_value = (off_t)d;
++    ob->quota_no_check = no_check;
+     q = ob->quota_filecount;
+     break;
+ 
+     case 1:
+     if (d >= 2.0*1024.0*1024.0*1024.0) which = US"quota_filecount";
+     ob->quota_filecount_value = (int)d;
++    ob->quota_filecount_no_check = no_check;
+     q = ob->quota_warn_threshold;
+     break;
+ 
+@@ -1382,10 +1398,12 @@
+ DEBUG(D_transport)
+   {
+   debug_printf("appendfile: mode=%o notify_comsat=%d quota=" OFF_T_FMT
++    "%s"
+     " warning=" OFF_T_FMT "%s\n"
+     "  %s=%s format=%s\n  message_prefix=%s\n  message_suffix=%s\n  "
+     "maildir_use_size_file=%s\n",
+     mode, ob->notify_comsat, ob->quota_value,
++    ob->quota_no_check? " (no_check)" : ""
+     ob->quota_warn_threshold_value,
+     ob->quota_warn_threshold_is_percent? "%" : "",
+     isdirectory? "directory" : "file",
+@@ -2274,7 +2292,7 @@
+   create the file. When maildir support is not compiled,
+   ob->maildir_use_size_file is always FALSE. */
+ 
+-  if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
++  if (QUOTA_CHECK || THRESHOLD_CHECK || ob->maildir_use_size_file)
+     {
+     const uschar *error;
+     int offset;
+diff -r 717fd3d22960 src/transports/appendfile.h
+--- a/src/transports/appendfile.h	Sun Feb 13 14:05:44 2011 +0100
++++ b/src/transports/appendfile.h	Tue Feb 15 11:18:53 2011 +0100
+@@ -72,6 +72,8 @@
+   BOOL  mbx_format;
+   BOOL  quota_warn_threshold_is_percent;
+   BOOL  quota_is_inclusive;
++  BOOL  quota_no_check;
++  BOOL  quota_filecount_no_check;
+ } appendfile_transport_options_block;
+ 
+ /* Restricted creation options */