Skip to content

Commit 07dbecb

Browse files
committed
email: Fix bugs with maildir creation and maildir temp files.
Fix a few issues with maildirs revealed by some high-throughput testing. * utils.c: If a directory is created between checking and creating it, return success, not failure. * mod_smtp_delivery_local: Include specific error message to handle duplicate maildir temp files. * mod_mail: Add a unique ID for maildir temp filenames to ensure uniqueness.
1 parent a0b0828 commit 07dbecb

3 files changed

Lines changed: 14 additions & 3 deletions

File tree

bbs/utils.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,10 @@ int bbs_ensure_directory_exists(const char *path)
802802
if (eaccess(path, R_OK | X_OK)) {
803803
int derr = errno;
804804
if (mkdir(path, 0700)) {
805+
if (errno == EEXIST) {
806+
/* Encountered a race condition in creating the directory, that's fine */
807+
return 0;
808+
}
805809
/* The directory probably already exists, but we can't access it for some reason. */
806810
bbs_warning("mkdir(%s) failed: %s\n", path, strerror(errno));
807811
bbs_error("Can't access directory %s: %s\n", path, strerror(derr));

modules/mod_mail.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -991,13 +991,16 @@ int maildir_mktemp(const char *path, char *buf, size_t len, char *newbuf)
991991
struct timeval tvnow;
992992
struct stat st;
993993
int fd;
994+
static int maildir_tmp_uniqueid_suffix = 0;
994995

995996
for (;;) {
997+
int suffix;
996998
#pragma GCC diagnostic ignored "-Waggregate-return"
997999
tvnow = bbs_tvnow();
9981000
#pragma GCC diagnostic pop
999-
snprintf(buf, len, "%s/tmp/%lu%06lu", path, tvnow.tv_sec, tvnow.tv_usec);
1000-
snprintf(newbuf, len, "%s/new/%lu%06lu", path, tvnow.tv_sec, tvnow.tv_usec);
1001+
suffix = bbs_atomic_fetchadd_int(&maildir_tmp_uniqueid_suffix, +1); /* Use a monotonically increasing unique ID to absolutely guarantee uniqueness */
1002+
snprintf(buf, len, "%s/tmp/%lu%06lu_%d", path, tvnow.tv_sec, tvnow.tv_usec, suffix);
1003+
snprintf(newbuf, len, "%s/new/%lu%06lu_%d", path, tvnow.tv_sec, tvnow.tv_usec, suffix);
10011004
if (stat(buf, &st) == -1 && errno == ENOENT) {
10021005
/* Error means it doesn't exist. */
10031006
if (stat(newbuf, &st) == -1 && errno == ENOENT) {

modules/mod_smtp_delivery_local.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ static int appendmsg(struct smtp_session *smtp, struct smtp_response *resp, stru
190190
}
191191

192192
if (rename(tmpfile, newfile)) {
193-
bbs_error("rename %s -> %s failed: %s\n", tmpfile, newfile, strerror(errno));
193+
if (errno == ENOENT && !bbs_file_exists(tmpfile) && bbs_file_exists(newfile)) {
194+
bbs_error("%s already renamed to %s?\n", tmpfile, newfile);
195+
} else {
196+
bbs_error("rename %s -> %s failed: %s\n", tmpfile, newfile, strerror(errno));
197+
}
194198
return -1;
195199
} else {
196200
char maildir[256];

0 commit comments

Comments
 (0)