# HG changeset patch # User Heiko Schlittermann (I24) # Date 1298242788 -3600 # Node ID d2183655483b08d46fb62dbca3bad1127d530938 # Parent 399967a8bbf16bccd29ce8a65e9eb42ded1c2356 quite stable set of patches diff -r 399967a8bbf1 -r d2183655483b build.Makefile --- /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 diff -r 399967a8bbf1 -r d2183655483b dbg.maildirsize --- /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; diff -r 399967a8bbf1 -r d2183655483b series --- 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 diff -r 399967a8bbf1 -r d2183655483b src.fixed_ensure_maildirsize --- /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; + } + } + diff -r 399967a8bbf1 -r d2183655483b src.lock_maildirsize --- /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 */ diff -r 399967a8bbf1 -r d2183655483b src.quota-ignore --- /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 */