# HG changeset patch # User Timo Sirainen # Date 1288893042 0 # Node ID 952dc335eb75861a0bb2d0cea1e9354346cabcd8 # Parent ed94f6d615ef2fbf8794eadbeada5877d0c74841 lib-fs / posix: If create/link/rename fails with ENOENT, try creating parent dir multiple times. This avoids random failures when the parent dir happens to be removed at just the right time. diff -r ed94f6d615ef -r 952dc335eb75 src/lib-fs/fs-posix.c --- a/src/lib-fs/fs-posix.c Thu Nov 04 17:00:42 2010 +0000 +++ b/src/lib-fs/fs-posix.c Thu Nov 04 17:50:42 2010 +0000 @@ -18,6 +18,7 @@ #include #define FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS (60*10) +#define MAX_MKDIR_RETRY_COUNT 5 enum fs_posix_lock_method { FS_POSIX_LOCK_METHOD_FLOCK, @@ -85,13 +86,16 @@ fname = strrchr(path, '/'); if (fname == NULL) - return 0; + return 1; dir = t_strdup_until(path, fname); - if (mkdir_parents(dir, 0700) < 0 && errno != EEXIST) { + if (mkdir_parents(dir, 0700) == 0) + return 0; + else if (errno == EEXIST) + return 1; + else { fs_set_error(fs, "mkdir_parents(%s) failed: %m", dir); return -1; } - return 0; } static int @@ -101,6 +105,7 @@ struct fs *_fs = &fs->fs; string_t *str = t_str_new(256); const char *slash = strrchr(path, '/'); + unsigned int try_count = 0; int fd; if (slash != NULL) @@ -108,10 +113,13 @@ str_append(str, fs->temp_file_prefix); fd = safe_mkstemp_hostpid(str, 0600, (uid_t)-1, (gid_t)-1); - if (fd == -1 && errno == ENOENT && (flags & FS_OPEN_FLAG_MKDIR) != 0) { + while (fd == -1 && errno == ENOENT && + try_count <= MAX_MKDIR_RETRY_COUNT && + (flags & FS_OPEN_FLAG_MKDIR) != 0) { if (fs_posix_create_parent_dir(_fs, path) < 0) return -1; fd = safe_mkstemp_hostpid(str, 0600, (uid_t)-1, (gid_t)-1); + try_count++; } if (fd == -1) { fs_set_error(_fs, "safe_mkstemp(%s) failed: %m", str_c(str)); @@ -454,13 +462,16 @@ static int fs_posix_link(struct fs *fs, const char *src, const char *dest) { + unsigned int try_count = 0; int ret; ret = link(src, dest); - if (ret < 0 && errno == ENOENT) { + while (ret < 0 && errno == ENOENT && + try_count <= MAX_MKDIR_RETRY_COUNT) { if (fs_posix_create_parent_dir(fs, dest) < 0) return -1; ret = link(src, dest); + try_count++; } if (ret < 0) { fs_set_error(fs, "link(%s, %s) failed: %m", src, dest); @@ -471,13 +482,16 @@ static int fs_posix_rename(struct fs *fs, const char *src, const char *dest) { + unsigned int try_count = 0; int ret; ret = rename(src, dest); - if (ret < 0 && errno == ENOENT) { + while (ret < 0 && errno == ENOENT && + try_count <= MAX_MKDIR_RETRY_COUNT) { if (fs_posix_create_parent_dir(fs, dest) < 0) return -1; ret = rename(src, dest); + try_count++; } if (ret < 0) { fs_set_error(fs, "link(%s, %s) failed: %m", src, dest);