file-create-locked.c (dovecot-2.3.16) | : | file-create-locked.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 25 | skipping to change at line 25 | |||
creation to work even while the directory is simultaneously being | creation to work even while the directory is simultaneously being | |||
rmdir()ed. */ | rmdir()ed. */ | |||
#define MAX_MKDIR_COUNT 10 | #define MAX_MKDIR_COUNT 10 | |||
#define MAX_RETRY_COUNT 1000 | #define MAX_RETRY_COUNT 1000 | |||
static int | static int | |||
try_lock_existing(int fd, const char *path, | try_lock_existing(int fd, const char *path, | |||
const struct file_create_settings *set, | const struct file_create_settings *set, | |||
struct file_lock **lock_r, const char **error_r) | struct file_lock **lock_r, const char **error_r) | |||
{ | { | |||
struct file_lock_settings lock_set = set->lock_settings; | ||||
struct stat st1, st2; | struct stat st1, st2; | |||
int ret; | int ret; | |||
lock_set.unlink_on_free = FALSE; | ||||
lock_set.close_on_free = FALSE; | ||||
if (fstat(fd, &st1) < 0) { | if (fstat(fd, &st1) < 0) { | |||
*error_r = t_strdup_printf("fstat(%s) failed: %m", path); | *error_r = t_strdup_printf("fstat(%s) failed: %m", path); | |||
return -1; | return -1; | |||
} | } | |||
if (file_wait_lock_error(fd, path, F_WRLCK, set->lock_method, | if (file_wait_lock(fd, path, F_WRLCK, &lock_set, set->lock_timeout_secs, | |||
set->lock_timeout_secs, lock_r, error_r) <= 0) | lock_r, error_r) <= 0) | |||
return -1; | return -1; | |||
if (stat(path, &st2) == 0) { | if (stat(path, &st2) == 0) { | |||
ret = st1.st_ino == st2.st_ino && | ret = st1.st_ino == st2.st_ino && | |||
CMP_DEV_T(st1.st_dev, st2.st_dev) ? 1 : 0; | CMP_DEV_T(st1.st_dev, st2.st_dev) ? 1 : 0; | |||
} else if (errno == ENOENT) { | } else if (errno == ENOENT) { | |||
ret = 0; | ret = 0; | |||
} else { | } else { | |||
*error_r = t_strdup_printf("stat(%s) failed: %m", path); | *error_r = t_strdup_printf("stat(%s) failed: %m", path); | |||
ret = -1; | ret = -1; | |||
} | } | |||
if (ret <= 0) { | if (ret <= 0) { | |||
/* the fd is closed next - no need to unlock */ | /* the fd is closed next - no need to unlock */ | |||
file_lock_free(lock_r); | file_lock_free(lock_r); | |||
} else { | ||||
file_lock_set_unlink_on_free( | ||||
*lock_r, set->lock_settings.unlink_on_free); | ||||
file_lock_set_close_on_free( | ||||
*lock_r, set->lock_settings.close_on_free); | ||||
} | } | |||
return ret; | return ret; | |||
} | } | |||
static int | static int | |||
try_mkdir(const char *path, const struct file_create_settings *set, | try_mkdir(const char *path, const struct file_create_settings *set, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
uid_t uid = set->mkdir_uid != 0 ? set->mkdir_uid : (uid_t)-1; | uid_t uid = set->mkdir_uid != 0 ? set->mkdir_uid : (uid_t)-1; | |||
gid_t gid = set->mkdir_gid != 0 ? set->mkdir_gid : (gid_t)-1; | gid_t gid = set->mkdir_gid != 0 ? set->mkdir_gid : (gid_t)-1; | |||
skipping to change at line 106 | skipping to change at line 115 | |||
int orig_errno = errno; | int orig_errno = errno; | |||
if ((ret = try_mkdir(path, set, error_r)) < 0) | if ((ret = try_mkdir(path, set, error_r)) < 0) | |||
return -1; | return -1; | |||
errno = orig_errno; | errno = orig_errno; | |||
} | } | |||
if (fd == -1) { | if (fd == -1) { | |||
*error_r = t_strdup_printf("safe_mkstemp(%s) failed: %m", path); | *error_r = t_strdup_printf("safe_mkstemp(%s) failed: %m", path); | |||
return -1; | return -1; | |||
} | } | |||
struct file_lock_settings lock_set = set->lock_settings; | ||||
lock_set.unlink_on_free = FALSE; | ||||
lock_set.close_on_free = FALSE; | ||||
ret = -1; | ret = -1; | |||
if (file_try_lock_error(fd, str_c(temp_path), F_WRLCK, | if (file_try_lock(fd, str_c(temp_path), F_WRLCK, &lock_set, | |||
set->lock_method, lock_r, error_r) <= 0) { | lock_r, error_r) <= 0) { | |||
} else if (link(str_c(temp_path), path) < 0) { | } else if (link(str_c(temp_path), path) < 0) { | |||
if (errno == EEXIST) { | if (errno == EEXIST) { | |||
/* just created by somebody else */ | /* just created by somebody else */ | |||
ret = 0; | ret = 0; | |||
} else if (errno == ENOENT) { | } else if (errno == ENOENT) { | |||
/* nobody should be deleting the temp file unless the | /* nobody should be deleting the temp file unless the | |||
entire directory is deleted. */ | entire directory is deleted. */ | |||
*error_r = t_strdup_printf( | *error_r = t_strdup_printf( | |||
"Temporary file %s was unexpectedly deleted", | "Temporary file %s was unexpectedly deleted", | |||
str_c(temp_path)); | str_c(temp_path)); | |||
} else { | } else { | |||
*error_r = t_strdup_printf("link(%s, %s) failed: %m", | *error_r = t_strdup_printf("link(%s, %s) failed: %m", | |||
str_c(temp_path), path); | str_c(temp_path), path); | |||
} | } | |||
file_lock_free(lock_r); | file_lock_free(lock_r); | |||
} else { | } else { | |||
file_lock_set_path(*lock_r, path); | file_lock_set_path(*lock_r, path); | |||
file_lock_set_unlink_on_free( | ||||
*lock_r, set->lock_settings.unlink_on_free); | ||||
file_lock_set_close_on_free( | ||||
*lock_r, set->lock_settings.close_on_free); | ||||
i_unlink_if_exists(str_c(temp_path)); | i_unlink_if_exists(str_c(temp_path)); | |||
*fd_r = fd; | *fd_r = fd; | |||
return 1; | return 1; | |||
} | } | |||
orig_errno = errno; | orig_errno = errno; | |||
i_close_fd(&fd); | i_close_fd(&fd); | |||
i_unlink_if_exists(str_c(temp_path)); | i_unlink_if_exists(str_c(temp_path)); | |||
errno = orig_errno; | errno = orig_errno; | |||
return ret; | return ret; | |||
} | } | |||
End of changes. 7 change blocks. | ||||
4 lines changed or deleted | 21 lines changed or added |