bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen#define FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS (60*10)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen char *temp_file_prefix, *root_path, *path_prefix;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenfs_posix_init(struct fs *_fs, const char *args, const struct fs_settings *set)
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);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs->fs.set.temp_file_prefix = fs->temp_file_prefix;
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo Sirainen fs->lock_method = FS_POSIX_LOCK_METHOD_DOTLOCK;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch fs_set_error(_fs, "Invalid mode value: %s", arg+5);
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainenstatic enum fs_properties fs_posix_get_properties(struct fs *_fs)
9826e14054e128a0af3f347761f53f1426d1fc9fTimo Sirainen FS_PROPERTY_LOCKS | FS_PROPERTY_FASTCOPY | FS_PROPERTY_RENAME |
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen FS_PROPERTY_STAT | FS_PROPERTY_ITER | FS_PROPERTY_RELIABLEITER;
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. */
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainenfs_posix_get_mode(struct posix_fs *fs, const char *path, mode_t *mode_r)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen const char *p;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fs_set_error(&fs->fs, "stat(%s) failed: %m", path);
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen /* setgid set - copy mode from parent */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_mkdir_parents(struct posix_fs *fs, const char *path)
8a2401de6de54250ba271bfc53524a847805e8f4Timo Sirainen fs_set_error(&fs->fs, "mkdir_parents(%s) failed: %m", dir);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_rmdir_parents(struct posix_fs *fs, const char *path)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen const char *p;
aed5d5c058fef5d9aea9005ae3a1d2501b8dcb94Timo Sirainen if (fs->root_path == NULL && fs->path_prefix == NULL)
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 /* success, continue to parent */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else if (errno == ENOTEMPTY || errno == EEXIST) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* there are other entries in this directory */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen } else if (errno == EBUSY || errno == ENOENT) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen /* some other not-unexpected error */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "rmdir(%s) failed: %m", path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_create(struct posix_fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
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 fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs_posix_mkdir_parents(fs, str_c(str)) < 0)
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen fd = safe_mkstemp_hostpid(str, mode, (uid_t)-1, (gid_t)-1);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "safe_mkstemp(%s) failed: %m", str_c(str));
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_open(struct posix_fs_file *file)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(&fs->fs, "open(%s) failed: %m", path);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenstatic struct fs_file *fs_posix_file_alloc(void)
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainen struct posix_fs_file *file = i_new(struct posix_fs_file, 1);
86ad48a2e740bd63a9b7299d7f3e229831d9b303Timo Sirainenfs_posix_file_init(struct fs_file *_file, const char *path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
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 file->file.path = i_strdup_printf("%s/%s", path,
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);
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainenstatic void fs_posix_file_close(struct fs_file *_file)
0b32a8d139f6a4f2b18a6444fc66d31b4a1b0da6Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen if (file->fd != -1 && file->file.output == NULL) {
a78468f42df768399d6e3890381a936b439297b0Timo Sirainen fs_set_critical(file->file.fs, "close(%s) failed: %m",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic void fs_posix_file_deinit(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* failed to create/replace this. delete the temp file */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_critical(_file->fs, "unlink(%s) failed: %m",
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenstatic int fs_posix_open_for_read(struct posix_fs_file *file)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainenstatic bool fs_posix_prefetch(struct fs_file *_file, uoff_t length ATTR_UNUSED)
6ff4d08b3313454f181bc8c43fa2ac28bcece0e0Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
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);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic ssize_t fs_posix_read(struct fs_file *_file, void *buf, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_critical(_file->fs, "lseek(%s, 0) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "read(%s) failed: %m", file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic struct istream *
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_posix_read_stream(struct fs_file *_file, size_t max_buffer_size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
b3f4c31f1533e25380f49f77d5bb1251bf43db2aTimo Sirainen input = i_stream_create_error_str(errno, "%s", fs_last_error(_file->fs));
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen /* the stream could live even after the fs_file */
96c5e558bbbcd09eb7cb160077fa1f00ae4e5131Timo Sirainen input = i_stream_create_fd_autoclose(&file->fd, max_buffer_size);
ece461287e52e22104e881313cea34bc77616a61Timo Sirainenstatic void fs_posix_write_rename_if_needed(struct posix_fs_file *file)
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
ece461287e52e22104e881313cea34bc77616a61Timo Sirainen new_fname = fs_metadata_find(&file->file.metadata, FS_METADATA_WRITE_FNAME);
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen new_prefix = t_strdup_until(file->file.path, p+1);
34354d4b9a417b21b9f9b3d286998234c5da02bcTimo Sirainen file->file.path = i_strconcat(new_prefix, new_fname, NULL);
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);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write_finish(struct posix_fs_file *file)
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen struct posix_fs *fs = (struct posix_fs *)file->file.fs;
43b95471c46f3d30b4c7e544acb5f0f2030ca2e0Timo Sirainen if ((file->open_flags & FS_OPEN_FLAG_FSYNC) != 0 &&
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(file->file.fs, "fdatasync(%s) failed: %m",
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",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(file->file.fs, "unlink(%s) failed: %m",
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (rename(file->temp_path, file->full_path) < 0) {
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(file->file.fs, "rename(%s, %s) failed: %m",
1c9cfe77c67389fbb43cfc386e3c32a13aea63e8Timo Sirainen /* allow opening the file after writing to it */
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write(struct fs_file *_file, const void *data, size_t size)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs, "write(%s) failed: %m",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen /* atomic append - it should either succeed or fail */
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "write(%s) failed: %m", file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen "write(%s) returned %"PRIuSIZE_T"/%"PRIuSIZE_T,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_posix_write_stream(struct fs_file *_file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
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",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen _file->output = o_stream_create_fd_file(file->fd,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen o_stream_set_name(_file->output, file->full_path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write_stream_finish(struct fs_file *_file, bool success)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen ret = fs_posix_write(_file, file->write_buf->data,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenfs_posix_lock(struct fs_file *_file, unsigned int secs, struct fs_lock **lock_r)
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 fs_set_error(_file->fs, "flock() not supported by OS "
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_try_lock(file->fd, file->full_path, F_WRLCK,
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_wait_lock(file->fd, file->full_path, F_WRLCK,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen fs_set_error(_file->fs, "flock(%s) failed: %m",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen dotlock_set.stale_timeout = FS_POSIX_DOTLOCK_STALE_TIMEOUT_SECS;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = file_dotlock_create(&dotlock_set, file->full_path,
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen "file_dotlock_create(%s) failed: %m",
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic void fs_posix_unlock(struct fs_lock *_lock)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen struct posix_fs_lock *lock = (struct posix_fs_lock *)_lock;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_exists(struct fs_file *_file)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_file->fs, "stat(%s) failed: %m",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_stat(struct fs_file *_file, struct stat *st_r)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
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 fs_set_error(_file->fs, "fstat(%s) failed: %m", file->full_path);
664bf3e236c214aee86294483c379e4fa66c2e63Timo Sirainen fs_set_error(_file->fs, "stat(%s) failed: %m", file->full_path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_copy(struct fs_file *_src, struct fs_file *_dest)
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;
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen if (errno == EEXIST && dest->open_mode == FS_OPEN_MODE_REPLACE) {
fc525738d566a2b45270d68f2781021cb3755ab1Timo Sirainen /* destination file already exists - replace it */
0084f25dd9c184f68e7a06dd2e01d4a0d31a7a93Timo Sirainen if (fs_posix_mkdir_parents(fs, dest->full_path) < 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_src->fs, "link(%s, %s) failed: %m",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_rename(struct fs_file *_src, struct fs_file *_dest)
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;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = rename(src->full_path, dest->full_path);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen if (fs_posix_mkdir_parents(fs, dest->full_path) < 0)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen ret = rename(src->full_path, dest->full_path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_src->fs, "rename(%s, %s) failed: %m",
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_delete(struct fs_file *_file)
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs_file *file = (struct posix_fs_file *)_file;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_file->fs;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "unlink(%s) failed: %m", file->full_path);
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen /* attempting to delete a directory. convert it to rmdir()
29449424bec807cdd2c694745a47f965aef44dd0Timo Sirainen automatically. */
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_file->fs, "rmdir(%s) failed: %m", file->full_path);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen (void)fs_posix_rmdir_parents(fs, file->full_path);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenstatic struct fs_iter *fs_posix_iter_alloc(void)
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs_iter *iter = i_new(struct posix_fs_iter, 1);
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainenfs_posix_iter_init(struct fs_iter *_iter, const char *path,
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_iter->fs;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen iter->path = fs->path_prefix == NULL ? i_strdup(path) :
4d71d712b42285afbd2a997f3408142ef0d5f899Timo Sirainen fs_set_error(_iter->fs, "opendir(%s) failed: %m", iter->path);
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstatic bool fs_posix_iter_want(struct posix_fs_iter *iter, const char *fname)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen const char *path = t_strdup_printf("%s/%s", iter->path, fname);
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen ret = (iter->iter.flags & FS_ITER_FLAG_DIRS) == 0;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen ret = (iter->iter.flags & FS_ITER_FLAG_DIRS) != 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic const char *fs_posix_iter_next(struct fs_iter *_iter)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_iter->fs;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen for (; (d = readdir(iter->dir)) != NULL; errno = 0) {
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen switch (d->d_type) {
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if ((iter->iter.flags & FS_ITER_FLAG_DIRS) == 0)
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if ((iter->iter.flags & FS_ITER_FLAG_DIRS) != 0)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_set_error(_iter->fs, "readdir(%s) failed: %m", iter->path);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic int fs_posix_iter_deinit(struct fs_iter *_iter)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_iter *iter = (struct posix_fs_iter *)_iter;
e84429cf1f7eee3e9e0445723cc92c0dcd20b43dTimo Sirainen if (iter->dir != NULL && closedir(iter->dir) < 0 && iter->err == 0) {
bda58aef5d3c4448cc80a955d4c185a920c12ddaTimo Sirainen fs_set_error(_iter->fs, "closedir(%s) failed: %m", iter->path);