bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen/* Try mkdir() + lock creation multiple times. This allows the lock file
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen creation to work even while the directory is simultaneously being
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen rmdir()ed. */
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen struct file_lock **lock_r, const char **error_r)
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("fstat(%s) failed: %m", path);
715fa0c143cf457c94bbac7554767c28413cf680Timo Sirainen if (file_wait_lock_error(fd, path, F_WRLCK, set->lock_method,
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen set->lock_timeout_secs, lock_r, error_r) <= 0)
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("stat(%s) failed: %m", path);
799b19bb4f69f7a5491b4c4c3fcfc7b346297762Timo Sirainen /* the fd is closed next - no need to unlock */
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainentry_mkdir(const char *path, const struct file_create_settings *set,
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen const char **error_r)
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen uid_t uid = set->mkdir_uid != 0 ? set->mkdir_uid : (uid_t)-1;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen gid_t gid = set->mkdir_gid != 0 ? set->mkdir_gid : (gid_t)-1;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen ret = mkdir_parents_chown(dir, set->mkdir_mode, uid, gid);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen ret = mkdir_parents_chgrp(dir, set->mkdir_mode,
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen *error_r = t_strdup_printf("mkdir_parents(%s) failed: %m", dir);
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainentry_create_new(const char *path, const struct file_create_settings *set,
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen int *fd_r, struct file_lock **lock_r, const char **error_r)
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen uid_t uid = set->uid != 0 ? set->uid : (uid_t)-1;
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen uid_t gid = set->gid != 0 ? set->gid : (gid_t)-1;
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen for (unsigned int i = 0; ret > 0; i++) {
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen fd = safe_mkstemp_group(temp_path, mode, gid, set->gid_origin);
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen if (fd != -1 || errno != ENOENT || set->mkdir_mode == 0 ||
d6e3deea85740b3af60e9f5bab32e98beba12d93Timo Sirainen if ((ret = try_mkdir(path, set, error_r)) < 0)
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("safe_mkstemp(%s) failed: %m", path);
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen if (file_try_lock_error(fd, str_c(temp_path), F_WRLCK,
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen } else if (link(str_c(temp_path), path) < 0) {
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen /* just created by somebody else */
ee0a6db8fe59b301c58b99e073687ae049d29a53Timo Sirainen /* nobody should be deleting the temp file unless the
ee0a6db8fe59b301c58b99e073687ae049d29a53Timo Sirainen entire directory is deleted. */
ee0a6db8fe59b301c58b99e073687ae049d29a53Timo Sirainen "Temporary file %s was unexpectedly deleted",
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("link(%s, %s) failed: %m",
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainenint file_create_locked(const char *path, const struct file_create_settings *set,
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen const char **error_r)
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen unsigned int i;
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen for (i = 0; i < MAX_RETRY_COUNT; i++) {
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen ret = try_lock_existing(fd, path, set, lock_r, error_r);
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen /* successfully locked an existing file */
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("open(%s) failed: %m", path);
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen /* try to create the file */
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen ret = try_create_new(path, set, &fd, lock_r, error_r);
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen /* successfully created a new locked file */
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen /* the file was just created - try again opening and
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen locking it */
a63907c14bd96eec1493eb893a043137c1799485Timo Sirainen *error_r = t_strdup_printf("Creating a locked file %s keeps failing", path);