X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Ftransports%2Ftf_maildir.c;h=93bbba455c1a91675ecf46e171783e65153a66f6;hb=2ad7897851d62bc690844f416d4ca2fabedf9459;hp=9a2685ac0067a8821d7708ab04e753da9790638e;hpb=c988f1f4faa9f679f79beddf3c14676c5dcb8e28;p=exim.git diff --git a/src/src/transports/tf_maildir.c b/src/src/transports/tf_maildir.c index 9a2685ac0..93bbba455 100644 --- a/src/src/transports/tf_maildir.c +++ b/src/src/transports/tf_maildir.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/transports/tf_maildir.c,v 1.3 2005/01/04 10:00:45 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions in support of the use of maildirsize files for handling quotas in @@ -29,46 +27,49 @@ calculations are not hard wired in, but are supplied as a regex. */ *************************************************/ /* This function is called at the start of a maildir delivery, to ensure that -all the relevant directories exist. +all the relevant directories exist. It also creates a maildirfolder file if the +base directory matches a given pattern. Argument: path the base directory name addr the address item (for setting an error message) create_directory true if we are allowed to create missing directories dirmode the mode for created directories + maildirfolder_create_regex + the pattern to match for maildirfolder creation Returns: TRUE on success; FALSE on failure */ BOOL maildir_ensure_directories(uschar *path, address_item *addr, - BOOL create_directory, int dirmode) + BOOL create_directory, int dirmode, uschar *maildirfolder_create_regex) { int i; struct stat statbuf; -char *subdirs[] = { "/tmp", "/new", "/cur" }; +const char *subdirs[] = { "/tmp", "/new", "/cur" }; DEBUG(D_transport) debug_printf("ensuring maildir directories exist in %s\n", path); /* First ensure that the path we have is a directory; if it does not exist, create it. Then make sure the tmp, new & cur subdirs of the maildir are -there. If not, fail which aborts the delivery (even though the cur subdir is +there. If not, fail. This aborts the delivery (even though the cur subdir is not actually needed for delivery). Handle all 4 directory tests/creates in a loop so that code can be shared. */ for (i = 0; i < 4; i++) { int j; - uschar *dir, *mdir; + const uschar *dir, *mdir; if (i == 0) { - mdir = US""; + mdir = CUS""; dir = path; } else { - mdir = US subdirs[i-1]; + mdir = CUS subdirs[i-1]; dir = mdir + 1; } @@ -135,7 +136,55 @@ for (i = 0; i < 4; i++) } } -return TRUE; /* All directories exist */ +/* If the basic path matches maildirfolder_create_regex, we are dealing with +a subfolder, and should ensure that a maildirfolder file exists. */ + +if (maildirfolder_create_regex != NULL) + { + const uschar *error; + int offset; + const pcre *regex; + + DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n"); + + regex = pcre_compile(CS maildirfolder_create_regex, PCRE_COPT, + (const char **)&error, &offset, NULL); + + if (regex == NULL) + { + addr->message = string_sprintf("appendfile: regular expression " + "error: %s at offset %d while compiling %s", error, offset, + maildirfolder_create_regex); + return FALSE; + } + + if (pcre_exec(regex, NULL, CS path, Ustrlen(path), 0, 0, NULL, 0) >= 0) + { + uschar *fname = string_sprintf("%s/maildirfolder", path); + if (Ustat(fname, &statbuf) == 0) + { + DEBUG(D_transport) debug_printf("maildirfolder already exists\n"); + } + else + { + int fd = Uopen(fname, O_WRONLY|O_APPEND|O_CREAT, 0600); + if (fd < 0) + { + addr->message = string_sprintf("appendfile: failed to create " + "maildirfolder file in %s directory: %s", path, strerror(errno)); + return FALSE; + } + (void)close(fd); + DEBUG(D_transport) debug_printf("created maildirfolder file\n"); + } + } + else + { + DEBUG(D_transport) debug_printf("maildirfolder file not required\n"); + } + } + +return TRUE; /* Everything exists that should exist */ } @@ -163,7 +212,7 @@ uschar buffer[256]; sprintf(CS buffer, "%d 1\n", size); len = Ustrlen(buffer); (void)lseek(fd, 0, SEEK_END); -(void)write(fd, buffer, len); +len = write(fd, buffer, len); DEBUG(D_transport) debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer); } @@ -198,12 +247,12 @@ Arguments: Returns: the sum of the sizes of the messages */ -int +off_t maildir_compute_size(uschar *path, int *filecount, time_t *latest, const pcre *regex, const pcre *dir_regex, BOOL timestamp_only) { DIR *dir; -int sum = 0; +off_t sum = 0; struct dirent *ent; struct stat statbuf; @@ -282,8 +331,9 @@ DEBUG(D_transport) debug_printf("maildir_compute_size (timestamp_only): %ld\n", (long int) *latest); else - debug_printf("maildir_compute_size: path=%s\n sum=%d filecount=%d " - "timestamp=%ld\n", path, sum, *filecount, (long int) *latest); + debug_printf("maildir_compute_size: path=%s\n sum=" OFF_T_FMT + " filecount=%d timestamp=%ld\n", + path, sum, *filecount, (long int) *latest); } return sum; } @@ -320,15 +370,15 @@ Returns: >=0 a file descriptor for an open maildirsize file int maildir_ensure_sizefile(uschar *path, appendfile_transport_options_block *ob, - const pcre *regex, const pcre *dir_regex, int *returned_size, + const pcre *regex, const pcre *dir_regex, off_t *returned_size, int *returned_filecount) { int count, fd; -int cached_quota = 0; +off_t cached_quota = 0; int cached_quota_filecount = 0; -int size = 0; int filecount = 0; int linecount = 0; +off_t size = 0; uschar *filename; uschar buffer[MAX_FILE_SIZE]; uschar *ptr = buffer; @@ -340,7 +390,7 @@ 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, 0); +fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600); if (fd < 0) { if (errno != ENOENT) return -1; @@ -369,14 +419,14 @@ DEBUG(D_transport) for (;;) { - long int n = Ustrtol(ptr, &endptr, 10); + off_t n = (off_t)Ustrtod(ptr, &endptr); /* Only two data items are currently defined; ignore any others that may be present. The spec is for a number followed by a letter. Anything else we reject and recalculate. */ if (*endptr == 'S') cached_quota = n; - else if (*endptr == 'C') cached_quota_filecount = n; + else if (*endptr == 'C') cached_quota_filecount = (int)n; if (!isalpha(*endptr++)) { DEBUG(D_transport) @@ -404,9 +454,9 @@ if (cached_quota != ob->quota_value || { DEBUG(D_transport) debug_printf("cached quota is out of date: recalculating\n" - " quota=%d cached_quota=%d filecount_quota=%d " - "cached_quota_filecount=%d\n", ob->quota_value, cached_quota, - ob->quota_filecount_value, cached_quota_filecount); + " quota=" OFF_T_FMT " cached_quota=" OFF_T_FMT " filecount_quota=%d " + "cached_quota_filecount=%d\n", ob->quota_value, + cached_quota, ob->quota_filecount_value, cached_quota_filecount); goto RECALCULATE; } @@ -421,7 +471,7 @@ while (*endptr++ == '\n') if (*endptr == 0) break; linecount++; ptr = endptr; - size += Ustrtol(ptr, &endptr, 10); + size += (off_t)Ustrtod(ptr, &endptr); if (*endptr != ' ') break; ptr = endptr + 1; filecount += Ustrtol(ptr, &endptr, 10); @@ -436,13 +486,13 @@ values is negative. */ if (*endptr == 0) { - if (size < 0 || filecount < 0) + if (size < 0 || filecount < 0) { DEBUG(D_transport) debug_printf("negative value in maildirsize " - "(size=%d count=%d): recalculating\n", size, filecount); - goto RECALCULATE; - } - + "(size=" OFF_T_FMT " count=%d): recalculating\n", size, filecount); + goto RECALCULATE; + } + if (ob->quota_value > 0 && (size + (ob->quota_is_inclusive? message_size : 0) > ob->quota_value || (ob->quota_filecount_value > 0 && @@ -497,25 +547,25 @@ else RECALCULATE: - if (fd >= 0) close(fd); + if (fd >= 0) (void)close(fd); old_latest = 0; filecount = 0; size = maildir_compute_size(path, &filecount, &old_latest, regex, dir_regex, FALSE); (void)gettimeofday(&tv, NULL); - tempname = string_sprintf("%s/tmp/%lu.H%luP%lu.%s", path, tv.tv_sec, - tv.tv_usec, getpid(), primary_hostname); + tempname = string_sprintf("%s/tmp/" TIME_T_FMT ".H%luP%lu.%s", + path, tv.tv_sec, tv.tv_usec, (long unsigned) getpid(), primary_hostname); - fd = Uopen(tempname, O_RDWR|O_CREAT|O_EXCL, 0600); + fd = Uopen(tempname, O_RDWR|O_CREAT|O_EXCL, ob->mode ? ob->mode : 0600); if (fd >= 0) { - (void)sprintf(CS buffer, "%dS,%dC\n%d %d\n", ob->quota_value, - ob->quota_filecount_value, size, filecount); + (void)sprintf(CS buffer, OFF_T_FMT "S,%dC\n" OFF_T_FMT " %d\n", + ob->quota_value, ob->quota_filecount_value, size, filecount); len = Ustrlen(buffer); if (write(fd, buffer, len) != len || Urename(tempname, filename) < 0) { - close(fd); + (void)close(fd); fd = -1; } } @@ -531,15 +581,15 @@ else DEBUG(D_transport) debug_printf("abandoning maildirsize because of " "a later subdirectory modification\n"); (void)Uunlink(filename); - close(fd); - fd = -1; + (void)close(fd); + fd = -2; } } /* Return the sizes and the file descriptor, if any */ -DEBUG(D_transport) debug_printf("returning maildir size=%d filecount=%d\n", - size, filecount); +DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT + " filecount=%d\n", size, filecount); *returned_size = size; *returned_filecount = filecount; return fd;