fs-posix.c revision 02c335c23bf5fa225a467c19f2c063fb0dc7b8c3
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2010-2016 Dovecot authors, see the included COPYING file */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen#define FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS (60*10)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen char *temp_file_prefix, *root_path, *path_prefix;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenfs_posix_init(struct fs *_fs, const char *args, const struct fs_settings *set)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *const *tmp;
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen fs->temp_file_prefix = set->temp_file_prefix != NULL ?
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen i_strdup(set->temp_file_prefix) : i_strdup("temp.dovecot.");
1b75b342eca820e52ca27e6bc33e0062d63eece3Timo Sirainen fs->temp_file_prefix_len = strlen(fs->temp_file_prefix);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fs->fs.set.temp_file_prefix = fs->temp_file_prefix;
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen fs->lock_method = FS_POSIX_LOCK_METHOD_DOTLOCK;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fs->path_prefix = i_strconcat(arg + 7, "/", NULL);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int mode;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fs_set_error(_fs, "Invalid mode value: %s", arg+5);
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic enum fs_properties fs_posix_get_properties(struct fs *fs ATTR_UNUSED)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen /* FS_PROPERTY_DIRECTORIES not returned because fs_delete()
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen automatically rmdir()s parents. This could be changed later though,
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen but SIS code at least would need to be changed to support it. */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen return FS_PROPERTY_LOCKS | FS_PROPERTY_FASTCOPY | FS_PROPERTY_RENAME |
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen FS_PROPERTY_STAT | FS_PROPERTY_ITER | FS_PROPERTY_RELIABLEITER;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenfs_posix_get_mode(struct posix_fs *fs, const char *path, mode_t *mode_r)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen const char *p;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fs_set_error(&fs->fs, "stat(%s) failed: %m", path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen /* setgid set - copy mode from parent */
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainenstatic int fs_posix_mkdir_parents(struct posix_fs *fs, const char *path)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fs_set_error(&fs->fs, "mkdir_parents(%s) failed: %m", dir);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic int fs_posix_rmdir_parents(struct posix_fs *fs, const char *path)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen const char *p;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen /* success, continue to parent */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen } else if (errno == ENOTEMPTY || errno == EEXIST) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen /* there are other entries in this directory */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen } else if (errno == EBUSY || errno == ENOENT) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen /* some other not-unexpected error */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen fs_set_error(&fs->fs, "rmdir(%s) failed: %m", path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic int fs_posix_create(struct posix_fs_file *file)
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen unsigned int try_count = 0;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if ((slash = strrchr(file->full_path, '/')) != NULL) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen str_append_n(str, file->full_path, slash - file->full_path);
d29c3ac4da9857ffcce57eec726d042c292e2becTimo Sirainen if (fs_posix_get_mode(fs, str_c(str), &mode) < 0)
17fc2a887a5683b2e1bbd6bd9fdf0cdb97b509fbTimo Sirainen fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen if (fs_posix_mkdir_parents(fs, str_c(str)) < 0)
7d102c66eb1755e1894cf56e3594cd744e855238Timo Sirainen fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
96e3a90451b495d8bedbe5dd731539269cb8c08dStephan Bosch fs_set_error(&fs->fs, "safe_mkstemp(%s) failed: %m", str_c(str));
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic int fs_posix_open(struct posix_fs_file *file)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic struct fs_file *
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenfs_posix_file_init(struct fs *_fs, const char *path,
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen file->file.path = i_strdup_printf("%s/%s", path,
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen file->full_path = fs->path_prefix == NULL ? i_strdup(file->file.path) :
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen i_strconcat(fs->path_prefix, file->file.path, NULL);
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainenstatic void fs_posix_file_close(struct fs_file *_file)
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainen if (file->fd != -1 && file->file.output == NULL) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen fs_set_critical(file->file.fs, "close(%s) failed: %m",
30f128cc663b8aeb68bb3bfb9ed49ab2e48029e1Timo Sirainenstatic void fs_posix_file_deinit(struct fs_file *_file)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen /* failed to create/replace this. delete the temp file */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen fs_set_critical(_file->fs, "unlink(%s) failed: %m",
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic int fs_posix_open_for_read(struct posix_fs_file *file)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainenstatic bool fs_posix_prefetch(struct fs_file *_file, uoff_t length ATTR_UNUSED)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen/* HAVE_POSIX_FADVISE alone isn't enough for CentOS 4.9 */
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen if (posix_fadvise(file->fd, 0, length, POSIX_FADV_WILLNEED) < 0) {
ba54c712141b9764a2e06ed8dfb35bc3154b53c7Timo Sirainen i_error("posix_fadvise(%s) failed: %m", file->full_path);
return FALSE;
if (ret < 0)
return ret;
static struct istream *
return input;
int ret;
case FS_OPEN_MODE_CREATE:
if (ret < 0) {
case FS_OPEN_MODE_REPLACE:
i_unreached();
if (ret < 0) {
case FS_OPEN_MODE_APPEND:
if (ret == 0) {
case FS_OPEN_MODE_CREATE:
case FS_OPEN_MODE_REPLACE:
if (ret == 0)
case FS_OPEN_MODE_READONLY:
i_unreached();
#ifndef HAVE_FLOCK
if (secs == 0) {
if (ret < 0) {
secs == 0 ? 0 :
if (ret < 0) {
if (ret <= 0)
return ret;
unsigned int try_count = 0;
int ret;
try_count++;
if (ret < 0) {
unsigned int try_count = 0;
int ret;
try_count++;
if (ret < 0) {
static struct fs_iter *
bool ret;
T_BEGIN {
} T_END;
return ret;
struct dirent *d;
return NULL;
errno = 0;
#ifdef HAVE_DIRENT_D_TYPE
switch (d->d_type) {
case DT_UNKNOWN:
case DT_REG:
case DT_LNK:
return d->d_name;
case DT_DIR:
return d->d_name;
return d->d_name;
if (errno != 0) {
return NULL;
int ret = 0;
return ret;
NULL,