fs-posix.c revision 8296531314913c7f9d4ab1857c6f79ff1308a12f
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2010-2016 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;
976459a13f69fab7eabf6dbf0442a5fb697a61b3Timo Sirainen unsigned int temp_file_prefix_len;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen enum fs_posix_lock_method lock_method;
3718da94157b9fa8d98c9f62f50133df504c7486Timo Sirainen mode_t mode;
0b0285689239ac08a324aff4b160ff2e920af4beTimo Sirainen bool mode_auto;
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
d4c3d55021bcbf2b062f4782b1cde9115d35aefcTimo 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;
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
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic enum fs_properties fs_posix_get_properties(struct fs *fs ATTR_UNUSED)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen /* FS_PROPERTY_DIRECTORIES not returned because fs_delete()
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen automatically rmdir()s parents. This could be changed later though,
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen but SIS code at least would need to be changed to support it. */
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return FS_PROPERTY_LOCKS | FS_PROPERTY_FASTCOPY | FS_PROPERTY_RENAME |
1183340bf4fda4040268aa4ba7a816b567659c08Timo Sirainen FS_PROPERTY_STAT | FS_PROPERTY_ITER | FS_PROPERTY_RELIABLEITER;
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
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (fs->root_path == NULL)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return 0;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen while ((p = strrchr(path, '/')) != NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen path = t_strdup_until(path, p);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (strcmp(path, fs->root_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
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenstatic struct fs_file *
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainenfs_posix_file_init(struct fs *_fs, const char *path,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen enum fs_open_mode mode, enum fs_open_flags flags)
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen{
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_file *file;
d0f9c91ed9ccffa384ef2eebb1083b372591f02aTimo Sirainen guid_128_t guid;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file = i_new(struct posix_fs_file, 1);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen file->file.fs = _fs;
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;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return &file->file;
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) {
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen i_error("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
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainenstatic int fs_posix_write_finish(struct posix_fs_file *file)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
3d798ec32957fea788cdefbc002f2e0fbb6f0556Timo Sirainen int ret, old_errno;
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen
d11111fc5356108b6408a58b4ff1811d5b5678edTimo Sirainen if ((file->open_flags & FS_OPEN_FLAG_FSYNC) != 0) {
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
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;
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 {
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
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen memset(&fs_lock, 0, sizeof(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:
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen memset(&dotlock_set, 0, sizeof(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
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainenstatic struct fs_iter *
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainenfs_posix_iter_init(struct fs *_fs, const char *path, enum fs_iter_flags flags)
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen{
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen struct posix_fs *fs = (struct posix_fs *)_fs;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen struct posix_fs_iter *iter;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen iter = i_new(struct posix_fs_iter, 1);
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen iter->iter.fs = _fs;
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen iter->iter.flags = flags;
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;
b6c48e71a9413ac90a0414dfeb7d1248c144eeb2Timo Sirainen fs_set_error(_fs, "opendir(%s) failed: %m", iter->path);
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return &iter->iter;
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:
63e94e8f57920b510fcdc479c5482ba9f4337a5cTimo Sirainen if (!fs_posix_iter_want(iter, d->d_name))
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen break;
6937ddd8bda6a452164090b4b7cf9a07836866ceTimo Sirainen /* fall through */
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,
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,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen NULL, 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,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_iter_init,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_posix_iter_next,
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen fs_posix_iter_deinit,
8296531314913c7f9d4ab1857c6f79ff1308a12fTimo Sirainen NULL
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen }
c33d3f93abf8392fdc60e12bea41ffd12cc85a8dTimo Sirainen};