dovecot-2.2: lib: Avoid race conditions in mkdir*() if directory...
dovecot at dovecot.org
dovecot at dovecot.org
Mon May 25 15:53:09 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/dd2015e1362f
changeset: 18753:dd2015e1362f
user: Timo Sirainen <tss at iki.fi>
date: Mon May 25 11:50:48 2015 -0400
description:
lib: Avoid race conditions in mkdir*() if directory is being deleted at the same time.
Mainly this allows the call to return failure silently without logging
unnecessary errors.
diffstat:
src/lib/mkdir-parents.c | 40 +++++++++++++++++++++++++++++-----------
1 files changed, 29 insertions(+), 11 deletions(-)
diffs (90 lines):
diff -r fdc03f6cc45d -r dd2015e1362f src/lib/mkdir-parents.c
--- a/src/lib/mkdir-parents.c Mon May 25 11:35:53 2015 -0400
+++ b/src/lib/mkdir-parents.c Mon May 25 11:50:48 2015 -0400
@@ -7,6 +7,7 @@
#include "ipwd.h"
#include <sys/stat.h>
+#include <fcntl.h>
#include <unistd.h>
static int ATTR_NULL(5)
@@ -15,11 +16,24 @@
{
string_t *str;
mode_t old_mask;
- int ret, orig_errno;
+ unsigned int i;
+ int ret, fd = -1, orig_errno;
- old_mask = umask(0);
- ret = mkdir(path, mode);
- umask(old_mask);
+ for (i = 0;; i++) {
+ old_mask = umask(0);
+ ret = mkdir(path, mode);
+ umask(old_mask);
+ if (ret < 0)
+ break;
+ fd = open(path, O_RDONLY);
+ if (fd != -1)
+ break;
+ if (errno != ENOENT || i == 3) {
+ i_error("open(%s) failed: %m", path);
+ return -1;
+ }
+ /* it was just rmdir()ed by someone else? retry */
+ }
if (ret < 0) {
if (errno == EISDIR || errno == ENOSYS) {
@@ -29,22 +43,24 @@
ENOSYS check is for NFS mount points. */
errno = EEXIST;
}
+ i_assert(fd == -1);
return -1;
}
- if (chown(path, uid, gid) < 0) {
+ if (fchown(fd, uid, gid) < 0) {
+ i_close_fd(&fd);
orig_errno = errno;
- if (rmdir(path) < 0)
+ if (rmdir(path) < 0 && errno != ENOENT)
i_error("rmdir(%s) failed: %m", path);
errno = orig_errno;
if (errno == EPERM && uid == (uid_t)-1) {
- i_error("%s", eperm_error_get_chgrp("chown", path, gid,
+ i_error("%s", eperm_error_get_chgrp("fchown", path, gid,
gid_origin));
return -1;
}
str = t_str_new(256);
- str_printfa(str, "chown(%s, %ld", path,
+ str_printfa(str, "fchown(%s, %ld", path,
uid == (uid_t)-1 ? -1L : (long)uid);
if (uid != (uid_t)-1) {
struct passwd pw;
@@ -68,15 +84,17 @@
if (gid != (gid_t)-1 && (mode & S_ISGID) == 0) {
/* make sure the directory doesn't have setgid bit enabled
(in case its parent had) */
- if (chmod(path, mode) < 0) {
+ if (fchmod(fd, mode) < 0) {
orig_errno = errno;
- if (rmdir(path) < 0)
+ if (rmdir(path) < 0 && errno != ENOENT)
i_error("rmdir(%s) failed: %m", path);
errno = orig_errno;
- i_error("chmod(%s) failed: %m", path);
+ i_error("fchmod(%s) failed: %m", path);
+ i_close_fd(&fd);
return -1;
}
}
+ i_close_fd(&fd);
return 0;
}
More information about the dovecot-cvs
mailing list