bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "lib.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "buffer.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "str.h"
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include "guid.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "istream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "ostream.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "safe-mkstemp.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "mkdir-parents.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "write-full.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "file-lock.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "file-dotlock.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include "fs-api-private.h"
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <stdio.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <unistd.h>
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#include <dirent.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <fcntl.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#include <sys/stat.h>
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS (60*10)
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen#define MAX_MKDIR_RETRY_COUNT 5
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen#define FS_DEFAULT_MODE 0600
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenenum fs_posix_lock_method {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen FS_POSIX_LOCK_METHOD_FLOCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen FS_POSIX_LOCK_METHOD_DOTLOCK
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct posix_fs {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs fs;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen char *temp_file_prefix, *root_path, *path_prefix;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t temp_file_prefix_len;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen enum fs_posix_lock_method lock_method;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen mode_t mode;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen bool mode_auto;
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen bool have_dirs;
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen bool disable_fsync;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct posix_fs_file {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_file file;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen char *temp_path, *full_path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen enum fs_open_mode open_mode;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen enum fs_open_flags open_flags;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen buffer_t *write_buf;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen bool seek_to_beginning;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstruct posix_fs_lock {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct fs_lock lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct file_lock *file_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dotlock *dotlock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstruct posix_fs_iter {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct fs_iter iter;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen char *path;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen DIR *dir;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen int err;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen};
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic struct fs *fs_posix_alloc(void)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs *fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs = i_new(struct posix_fs, 1);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->fs = fs_class_posix;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return &fs->fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenfs_posix_init(struct fs *_fs, const char *args, const struct fs_settings *set)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *const *tmp;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->temp_file_prefix = set->temp_file_prefix != NULL ?
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_strdup(set->temp_file_prefix) : i_strdup("temp.dovecot.");
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen fs->temp_file_prefix_len = strlen(fs->temp_file_prefix);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->root_path = i_strdup(set->root_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->fs.set.temp_file_prefix = fs->temp_file_prefix;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs->fs.set.root_path = fs->root_path;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen fs->lock_method = FS_POSIX_LOCK_METHOD_FLOCK;
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen fs->mode = FS_DEFAULT_MODE;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
06c1f686fd7cb73b34b5e61370846a692e7d3e37Timo Sirainen tmp = t_strsplit_spaces(args, ":");
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen for (; *tmp != NULL; tmp++) {
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen const char *arg = *tmp;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (strcmp(arg, "lock=flock") == 0)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen fs->lock_method = FS_POSIX_LOCK_METHOD_FLOCK;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen else if (strcmp(arg, "lock=dotlock") == 0)
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen fs->lock_method = FS_POSIX_LOCK_METHOD_DOTLOCK;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen else if (strncmp(arg, "prefix=", 7) == 0) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_free(fs->path_prefix);
e08a3c92eb9470296ea2d6b1834179c8564f3d1fMartti Rannanjärvi fs->path_prefix = i_strdup(arg + 7);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen } else if (strcmp(arg, "mode=auto") == 0) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fs->mode_auto = TRUE;
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen } else if (strcmp(arg, "dirs") == 0) {
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen fs->have_dirs = TRUE;
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen } else if (strcmp(arg, "no-fsync") == 0) {
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen fs->disable_fsync = TRUE;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen } else if (strncmp(arg, "mode=", 5) == 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch unsigned int mode;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_uint_oct(arg+5, &mode) < 0) {
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch fs_set_error(_fs, "Invalid mode value: %s", arg+5);
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch return -1;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch }
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch fs->mode = mode & 0666;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen if (fs->mode == 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_fs, "Invalid mode: %s", arg+5);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen } else {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_fs, "Unknown arg '%s'", arg);
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return -1;
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen }
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_posix_deinit(struct fs *_fs)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs *fs = (struct posix_fs *)_fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(fs->temp_file_prefix);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_free(fs->root_path);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_free(fs->path_prefix);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(fs);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainenstatic enum fs_properties fs_posix_get_properties(struct fs *_fs)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen struct posix_fs *fs = (struct posix_fs *)_fs;
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen enum fs_properties props =
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen FS_PROPERTY_LOCKS | FS_PROPERTY_FASTCOPY | FS_PROPERTY_RENAME |
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen FS_PROPERTY_STAT | FS_PROPERTY_ITER | FS_PROPERTY_RELIABLEITER;
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen /* FS_PROPERTY_DIRECTORIES is not returned normally because fs_delete()
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen automatically rmdir()s parents. For backwards compatibility
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen (especially with SIS code) we'll do it that way, but optionally with
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen "dirs" parameter enable them. This is especially important to be
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen able to use doveadm fs commands to delete empty directories. */
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen if (fs->have_dirs)
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen props |= FS_PROPERTY_DIRECTORIES;
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen return props;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainenstatic int
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainenfs_posix_get_mode(struct posix_fs *fs, const char *path, mode_t *mode_r)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen{
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen struct stat st;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen const char *p;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen *mode_r = fs->mode;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen while (stat(path, &st) < 0) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (errno != ENOENT) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fs_set_error(&fs->fs, "stat(%s) failed: %m", path);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen p = strrchr(path, '/');
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (p != NULL)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen path = t_strdup_until(path, p);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen else if (strcmp(path, ".") != 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen path = ".";
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen else
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return 0;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if ((st.st_mode & S_ISGID) != 0) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen /* setgid set - copy mode from parent */
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen *mode_r = st.st_mode & 0666;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return 0;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen}
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_mkdir_parents(struct posix_fs *fs, const char *path)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen const char *dir, *fname;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen mode_t mode, dir_mode;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fname = strrchr(path, '/');
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fname == NULL)
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen return 1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dir = t_strdup_until(path, fname);
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (fs_posix_get_mode(fs, dir, &mode) < 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen dir_mode = mode;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen if ((dir_mode & 0600) != 0) dir_mode |= 0100;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen if ((dir_mode & 0060) != 0) dir_mode |= 0010;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen if ((dir_mode & 0006) != 0) dir_mode |= 0001;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen if (mkdir_parents(dir, dir_mode) == 0)
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen return 0;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen else if (errno == EEXIST)
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen return 1;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen else {
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen fs_set_error(&fs->fs, "mkdir_parents(%s) failed: %m", dir);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_rmdir_parents(struct posix_fs *fs, const char *path)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *p;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen if (fs->have_dirs)
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen return 0;
aed5d5c058fef5d9aea9005ae3a1d2501b8dcb94Timo Sirainen if (fs->root_path == NULL && fs->path_prefix == NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen while ((p = strrchr(path, '/')) != NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen path = t_strdup_until(path, p);
aed5d5c058fef5d9aea9005ae3a1d2501b8dcb94Timo Sirainen if ((fs->root_path != NULL && strcmp(path, fs->root_path) == 0) ||
aed5d5c058fef5d9aea9005ae3a1d2501b8dcb94Timo Sirainen (fs->path_prefix != NULL && strncmp(path, fs->path_prefix, strlen(path)) == 0))
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (rmdir(path) == 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* success, continue to parent */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else if (errno == ENOTEMPTY || errno == EEXIST) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* there are other entries in this directory */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else if (errno == EBUSY || errno == ENOENT) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* some other not-unexpected error */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "rmdir(%s) failed: %m", path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_create(struct posix_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen string_t *str = t_str_new(256);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *slash;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen unsigned int try_count = 0;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen mode_t mode;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(file->temp_path == NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if ((slash = strrchr(file->full_path, '/')) != NULL) {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen str_append_n(str, file->full_path, slash - file->full_path);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (fs_posix_get_mode(fs, str_c(str), &mode) < 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen str_append_c(str, '/');
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen } else {
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen if (fs_posix_get_mode(fs, ".", &mode) < 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen str_append(str, fs->temp_file_prefix);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen while (fd == -1 && errno == ENOENT &&
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen try_count <= MAX_MKDIR_RETRY_COUNT) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs_posix_mkdir_parents(fs, str_c(str)) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen try_count++;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (fd == -1) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "safe_mkstemp(%s) failed: %m", str_c(str));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->temp_path = i_strdup(str_c(str));
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fd;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_open(struct posix_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen const char *path = file->full_path;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_assert(file->fd == -1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen switch (file->open_mode) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_READONLY:
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fd = open(path, O_RDONLY);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fd == -1)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_APPEND:
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fd = open(path, O_RDWR | O_APPEND);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fd == -1)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_CREATE_UNIQUE_128:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_CREATE:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_REPLACE:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen T_BEGIN {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fd = fs_posix_create(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } T_END;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fd == -1)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic struct fs_file *fs_posix_file_alloc(void)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct posix_fs_file *file = i_new(struct posix_fs_file, 1);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen return &file->file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen}
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic void
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenfs_posix_file_init(struct fs_file *_file, const char *path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_file->fs;
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen guid_128_t guid;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen if (mode != FS_OPEN_MODE_CREATE_UNIQUE_128)
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen file->file.path = i_strdup(path);
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen else {
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen guid_128_generate(guid);
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen file->file.path = i_strdup_printf("%s/%s", path,
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen guid_128_to_string(guid));
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path = fs->path_prefix == NULL ? i_strdup(file->file.path) :
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_strconcat(fs->path_prefix, file->file.path, NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->open_mode = mode;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->open_flags = flags;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen file->fd = -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainenstatic void fs_posix_file_close(struct fs_file *_file)
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen{
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen if (file->fd != -1 && file->file.output == NULL) {
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen if (close(file->fd) < 0) {
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen fs_set_critical(file->file.fs, "close(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen }
9ec1ecbc19af5a312877c0f19d6adf5bc38a7111Timo Sirainen file->fd = -1;
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen }
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen}
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void fs_posix_file_deinit(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(_file->output == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen switch (file->open_mode) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_READONLY:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_APPEND:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_CREATE_UNIQUE_128:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_CREATE:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_REPLACE:
23e079a8583bfa157861991330f27dd1d6c7ae6dTimo Sirainen if (file->temp_path == NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* failed to create/replace this. delete the temp file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (unlink(file->temp_path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_critical(_file->fs, "unlink(%s) failed: %m",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->temp_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(file->temp_path);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_free(file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(file->file.path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenstatic int fs_posix_open_for_read(struct posix_fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen i_assert(file->file.output == NULL);
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen i_assert(file->temp_path == NULL);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fd == -1) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs_posix_open(file) < 0)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen return 0;
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen}
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenstatic bool fs_posix_prefetch(struct fs_file *_file, uoff_t length ATTR_UNUSED)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen{
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen if (fs_posix_open_for_read(file) < 0)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen return TRUE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
2a45e925383d56510d318ea47334e939f7d58130Timo Sirainen/* HAVE_POSIX_FADVISE alone isn't enough for CentOS 4.9 */
2a45e925383d56510d318ea47334e939f7d58130Timo Sirainen#if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (posix_fadvise(file->fd, 0, length, POSIX_FADV_WILLNEED) < 0) {
b254b8ec1ea03f400f1390ec24afd826a8c335d9Timo Sirainen e_error(_file->event, "posix_fadvise(%s) failed: %m", file->full_path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return TRUE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
2a45e925383d56510d318ea47334e939f7d58130Timo Sirainen#endif
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return FALSE;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic ssize_t fs_posix_read(struct fs_file *_file, void *buf, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ssize_t ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen if (fs_posix_open_for_read(file) < 0)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (file->seek_to_beginning) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->seek_to_beginning = FALSE;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (lseek(file->fd, 0, SEEK_SET) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_critical(_file->fs, "lseek(%s, 0) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = read(file->fd, buf, size);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "read(%s) failed: %m", file->full_path);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen fs_posix_file_close(_file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic struct istream *
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_posix_read_stream(struct fs_file *_file, size_t max_buffer_size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct istream *input;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen if (fs_posix_open_for_read(file) < 0)
b3f4c31f1533e25380f49f77d5bb1251bf43db2aTimo Sirainen input = i_stream_create_error_str(errno, "%s", fs_last_error(_file->fs));
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen else {
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen /* the stream could live even after the fs_file */
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen input = i_stream_create_fd_autoclose(&file->fd, max_buffer_size);
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_stream_set_name(input, file->full_path);
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen return input;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ece461287e52e22104e881313cea34bc77616a61Timo Sirainenstatic void fs_posix_write_rename_if_needed(struct posix_fs_file *file)
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen{
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen const char *new_fname, *new_prefix, *p;
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen new_fname = fs_metadata_find(&file->file.metadata, FS_METADATA_WRITE_FNAME);
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen if (new_fname == NULL)
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen return;
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen p = strrchr(file->file.path, '/');
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen if (p == NULL)
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen new_prefix = "";
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen else
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen new_prefix = t_strdup_until(file->file.path, p+1);
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen i_free(file->file.path);
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen file->file.path = i_strconcat(new_prefix, new_fname, NULL);
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen i_free(file->full_path);
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen file->full_path = fs->path_prefix == NULL ? i_strdup(file->file.path) :
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen i_strconcat(fs->path_prefix, file->file.path, NULL);
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen}
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write_finish(struct posix_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
3d798ec32957fea788cdefbc002f2e0fbb6f0556Timo Sirainen int ret, old_errno;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen if ((file->open_flags & FS_OPEN_FLAG_FSYNC) != 0 &&
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen !fs->disable_fsync) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fdatasync(file->fd) < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->file.fs, "fdatasync(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen fs_posix_write_rename_if_needed(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen switch (file->open_mode) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_CREATE_UNIQUE_128:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_CREATE:
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if ((ret = link(file->temp_path, file->full_path)) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(file->file.fs, "link(%s, %s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->temp_path, file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
3d798ec32957fea788cdefbc002f2e0fbb6f0556Timo Sirainen old_errno = errno;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (unlink(file->temp_path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(file->file.fs, "unlink(%s) failed: %m",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->temp_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
3d798ec32957fea788cdefbc002f2e0fbb6f0556Timo Sirainen errno = old_errno;
876cc43339ec681ff4857cd31a7e65a9c47e5730Timo Sirainen if (ret < 0) {
876cc43339ec681ff4857cd31a7e65a9c47e5730Timo Sirainen fs_posix_file_close(&file->file);
876cc43339ec681ff4857cd31a7e65a9c47e5730Timo Sirainen i_free_and_null(file->temp_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
876cc43339ec681ff4857cd31a7e65a9c47e5730Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_REPLACE:
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (rename(file->temp_path, file->full_path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(file->file.fs, "rename(%s, %s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->temp_path, file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen default:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_unreached();
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_free_and_null(file->temp_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->seek_to_beginning = TRUE;
1c9cfe77c67389fbb43cfc386e3c32a13aea63e8Timo Sirainen /* allow opening the file after writing to it */
1c9cfe77c67389fbb43cfc386e3c32a13aea63e8Timo Sirainen file->open_mode = FS_OPEN_MODE_READONLY;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write(struct fs_file *_file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ssize_t ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (file->fd == -1) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs_posix_open(file) < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return -1;
abb404575a238f27ea03b6049880f30f1656ddc4Timo Sirainen i_assert(file->fd != -1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (file->open_mode != FS_OPEN_MODE_APPEND) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (write_full(file->fd, data, size) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs, "write(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return fs_posix_write_finish(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* atomic append - it should either succeed or fail */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = write(file->fd, data, size);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "write(%s) failed: %m", file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if ((size_t)ret != size) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen "write(%s) returned %"PRIuSIZE_T"/%"PRIuSIZE_T,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path, (size_t)ret, size);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen errno = ENOSPC;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_posix_write_stream(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_assert(_file->output == NULL);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (file->open_mode == FS_OPEN_MODE_APPEND) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->write_buf = buffer_create_dynamic(default_pool, 1024*32);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen _file->output = o_stream_create_buffer(file->write_buf);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else if (file->fd == -1 && fs_posix_open(file) < 0) {
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen _file->output = o_stream_create_error_str(errno, "%s",
6516e7c2cfb84bbdaff7d748df0a0f1f6f39f75dTimo Sirainen fs_file_last_error(_file));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else {
adea69875046ece77dc36abd3f88a241a3f17ad9Timo Sirainen i_assert(file->fd != -1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen _file->output = o_stream_create_fd_file(file->fd,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen (uoff_t)-1, FALSE);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen o_stream_set_name(_file->output, file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write_stream_finish(struct fs_file *_file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret = success ? 0 : -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen o_stream_destroy(&_file->output);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen switch (file->open_mode) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_APPEND:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret == 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = fs_posix_write(_file, file->write_buf->data,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->write_buf->used);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen buffer_free(&file->write_buf);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_CREATE:
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_CREATE_UNIQUE_128:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_OPEN_MODE_REPLACE:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret == 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = fs_posix_write_finish(file);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen case FS_OPEN_MODE_READONLY:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_unreached();
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return ret < 0 ? -1 : 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_posix_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs *fs = (struct posix_fs *)_file->fs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct dotlock_settings dotlock_set;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_lock fs_lock, *ret_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret = -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&fs_lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_lock.lock.file = _file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen switch (fs->lock_method) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_POSIX_LOCK_METHOD_FLOCK:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#ifndef HAVE_FLOCK
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs, "flock() not supported by OS "
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen "(for file %s)", file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#else
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (secs == 0) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_try_lock(file->fd, file->full_path, F_WRLCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen FILE_LOCK_METHOD_FLOCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen &fs_lock.file_lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen } else {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_wait_lock(file->fd, file->full_path, F_WRLCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen FILE_LOCK_METHOD_FLOCK, secs,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen &fs_lock.file_lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs, "flock(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#endif
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen case FS_POSIX_LOCK_METHOD_DOTLOCK:
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&dotlock_set);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dotlock_set.stale_timeout = FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dotlock_set.use_excl_lock = TRUE;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dotlock_set.timeout = secs;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_dotlock_create(&dotlock_set, file->full_path,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen secs == 0 ? 0 :
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen DOTLOCK_CREATE_FLAG_NONBLOCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen &fs_lock.dotlock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen "file_dotlock_create(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen break;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret <= 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret_lock = i_new(struct posix_fs_lock, 1);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *ret_lock = fs_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen *lock_r = &ret_lock->lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_posix_unlock(struct fs_lock *_lock)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_lock *lock = (struct posix_fs_lock *)_lock;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (lock->file_lock != NULL)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file_unlock(&lock->file_lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (lock->dotlock != NULL)
6cb2c6ecddcdbeac9e6c73a292244747e12a793eTimo Sirainen file_dotlock_delete(&lock->dotlock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen i_free(lock);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_exists(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct stat st;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (stat(file->full_path, &st) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (errno != ENOENT) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_file->fs, "stat(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_stat(struct fs_file *_file, struct stat *st_r)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen
3b39022ea0513363241cf852b7d454c841584ea1Timo Sirainen /* in case output != NULL it means that we're still writing to the file
3b39022ea0513363241cf852b7d454c841584ea1Timo Sirainen and fs_stat() shouldn't stat the unfinished file. this is done by
3b39022ea0513363241cf852b7d454c841584ea1Timo Sirainen fs-sis after fs_copy(). */
3b39022ea0513363241cf852b7d454c841584ea1Timo Sirainen if (file->fd != -1 && _file->output == NULL) {
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen if (fstat(file->fd, st_r) < 0) {
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen fs_set_error(_file->fs, "fstat(%s) failed: %m", file->full_path);
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen return -1;
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen }
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen } else {
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen if (stat(file->full_path, st_r) < 0) {
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen fs_set_error(_file->fs, "stat(%s) failed: %m", file->full_path);
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen return -1;
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_copy(struct fs_file *_src, struct fs_file *_dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen struct posix_fs_file *src = (struct posix_fs_file *)_src;
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen struct posix_fs_file *dest = (struct posix_fs_file *)_dest;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_src->fs;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen unsigned int try_count = 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen ret = link(src->full_path, dest->full_path);
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen if (errno == EEXIST && dest->open_mode == FS_OPEN_MODE_REPLACE) {
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen /* destination file already exists - replace it */
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink_if_exists(dest->full_path);
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen ret = link(src->full_path, dest->full_path);
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen }
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen while (ret < 0 && errno == ENOENT &&
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen try_count <= MAX_MKDIR_RETRY_COUNT) {
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen if (fs_posix_mkdir_parents(fs, dest->full_path) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen ret = link(src->full_path, dest->full_path);
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen try_count++;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_src->fs, "link(%s, %s) failed: %m",
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen src->full_path, dest->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_rename(struct fs_file *_src, struct fs_file *_dest)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_src->fs;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *src = (struct posix_fs_file *)_src;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *dest = (struct posix_fs_file *)_dest;
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen unsigned int try_count = 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen int ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = rename(src->full_path, dest->full_path);
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen while (ret < 0 && errno == ENOENT &&
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen try_count <= MAX_MKDIR_RETRY_COUNT) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (fs_posix_mkdir_parents(fs, dest->full_path) < 0)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = rename(src->full_path, dest->full_path);
46b0fad7bc31f63f6f969b487bef2178beb125faTimo Sirainen try_count++;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen if (ret < 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_src->fs, "rename(%s, %s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen src->full_path, dest->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return -1;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_delete(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_file->fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (unlink(file->full_path) < 0) {
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen if (!UNLINK_EISDIR(errno)) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "unlink(%s) failed: %m", file->full_path);
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen return -1;
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen }
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen /* attempting to delete a directory. convert it to rmdir()
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen automatically. */
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (rmdir(file->full_path) < 0) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "rmdir(%s) failed: %m", file->full_path);
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen return -1;
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen (void)fs_posix_rmdir_parents(fs, file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen return 0;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenstatic struct fs_iter *fs_posix_iter_alloc(void)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs_iter *iter = i_new(struct posix_fs_iter, 1);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen return &iter->iter;
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen}
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenstatic void
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenfs_posix_iter_init(struct fs_iter *_iter, const char *path,
4110f968c96680d61ca47bd7a903a254b911addaTimo Sirainen enum fs_iter_flags flags ATTR_UNUSED)
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen{
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_iter->fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen iter->path = fs->path_prefix == NULL ? i_strdup(path) :
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_strconcat(fs->path_prefix, path, NULL);
0c509a394d47dc49e2792b3ab0a26817b9d8b2a5Timo Sirainen if (iter->path[0] == '\0') {
0c509a394d47dc49e2792b3ab0a26817b9d8b2a5Timo Sirainen i_free(iter->path);
0c509a394d47dc49e2792b3ab0a26817b9d8b2a5Timo Sirainen iter->path = i_strdup(".");
0c509a394d47dc49e2792b3ab0a26817b9d8b2a5Timo Sirainen }
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen iter->dir = opendir(iter->path);
a58b73c69e2d608843406b5809063d038ae67699Timo Sirainen if (iter->dir == NULL && errno != ENOENT) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen iter->err = errno;
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs_set_error(_iter->fs, "opendir(%s) failed: %m", iter->path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstatic bool fs_posix_iter_want(struct posix_fs_iter *iter, const char *fname)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen bool ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen T_BEGIN {
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen const char *path = t_strdup_printf("%s/%s", iter->path, fname);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct stat st;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (stat(path, &st) < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen ret = FALSE;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen else if (!S_ISDIR(st.st_mode))
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen ret = (iter->iter.flags & FS_ITER_FLAG_DIRS) == 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen else
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen ret = (iter->iter.flags & FS_ITER_FLAG_DIRS) != 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } T_END;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return ret;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic const char *fs_posix_iter_next(struct fs_iter *_iter)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_iter->fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct dirent *d;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (iter->dir == NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen errno = 0;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen for (; (d = readdir(iter->dir)) != NULL; errno = 0) {
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if (strcmp(d->d_name, ".") == 0 ||
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen strcmp(d->d_name, "..") == 0)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen continue;
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen if (strncmp(d->d_name, fs->temp_file_prefix,
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen fs->temp_file_prefix_len) == 0)
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen continue;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#ifdef HAVE_DIRENT_D_TYPE
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen switch (d->d_type) {
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen case DT_UNKNOWN:
b757d62e117269b28a8db7848003076f3dd4cc1aTimo Sirainen if (fs_posix_iter_want(iter, d->d_name))
b757d62e117269b28a8db7848003076f3dd4cc1aTimo Sirainen return d->d_name;
b757d62e117269b28a8db7848003076f3dd4cc1aTimo Sirainen break;
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen case DT_REG:
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen case DT_LNK:
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if ((iter->iter.flags & FS_ITER_FLAG_DIRS) == 0)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen return d->d_name;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen break;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen case DT_DIR:
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if ((iter->iter.flags & FS_ITER_FLAG_DIRS) != 0)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen return d->d_name;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen break;
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen default:
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen break;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#else
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if (fs_posix_iter_want(iter, d->d_name))
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return d->d_name;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen#endif
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (errno != 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen iter->err = errno;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_iter->fs, "readdir(%s) failed: %m", iter->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen}
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_iter_deinit(struct fs_iter *_iter)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen int ret = 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
e84429cf1f7eee3e9e0445723cc92c0dcd20b43dTimo Sirainen if (iter->dir != NULL && closedir(iter->dir) < 0 && iter->err == 0) {
bda58aef5d3c4448cc80a955d4c185a920c12ddaTimo Sirainen iter->err = errno;
bda58aef5d3c4448cc80a955d4c185a920c12ddaTimo Sirainen fs_set_error(_iter->fs, "closedir(%s) failed: %m", iter->path);
bda58aef5d3c4448cc80a955d4c185a920c12ddaTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (iter->err != 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen errno = iter->err;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen ret = -1;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_free(iter->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen i_free(iter);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return ret;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen}
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
6e8fce0589289d10e6dcd9b71fde763492bb29b8Timo Sirainenconst struct fs fs_class_posix = {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .name = "posix",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen .v = {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_alloc,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_init,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_deinit,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_get_properties,
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen fs_posix_file_alloc,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_file_init,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_file_deinit,
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen fs_posix_file_close,
3dcb9fd82c1edd40bea1ad572ed39f024686e463Timo Sirainen NULL,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen NULL, NULL,
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen fs_default_set_metadata,
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen NULL,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_prefetch,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_read,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_read_stream,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_write,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_write_stream,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_write_stream_finish,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_lock,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_unlock,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_exists,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_stat,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_copy,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_posix_rename,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_delete,
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs_posix_iter_alloc,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_iter_init,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_iter_next,
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen fs_posix_iter_deinit,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen NULL,
a63cd84128875485e40ed804dbf0b0945526989cTimo Sirainen NULL,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};