dict-fs.c (dovecot-2.3.16) | : | dict-fs.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 14 | skipping to change at line 14 | |||
#include "array.h" | #include "array.h" | |||
#include "fs-api.h" | #include "fs-api.h" | |||
#include "istream.h" | #include "istream.h" | |||
#include "str.h" | #include "str.h" | |||
#include "dict-transaction-memory.h" | #include "dict-transaction-memory.h" | |||
#include "dict-private.h" | #include "dict-private.h" | |||
struct fs_dict { | struct fs_dict { | |||
struct dict dict; | struct dict dict; | |||
struct fs *fs; | struct fs *fs; | |||
char *username; | ||||
}; | }; | |||
struct fs_dict_iterate_context { | struct fs_dict_iterate_context { | |||
struct dict_iterate_context ctx; | struct dict_iterate_context ctx; | |||
const char **paths; | char *path; | |||
unsigned int path_idx; | ||||
enum dict_iterate_flags flags; | enum dict_iterate_flags flags; | |||
pool_t value_pool; | pool_t value_pool; | |||
struct fs_iter *fs_iter; | struct fs_iter *fs_iter; | |||
const char *values[2]; | const char *values[2]; | |||
char *error; | char *error; | |||
}; | }; | |||
static int | static int | |||
fs_dict_init(struct dict *driver, const char *uri, | fs_dict_init(struct dict *driver, const char *uri, | |||
const struct dict_settings *set, | const struct dict_settings *set, | |||
skipping to change at line 48 | skipping to change at line 46 | |||
p = strchr(uri, ':'); | p = strchr(uri, ':'); | |||
if (p == NULL) { | if (p == NULL) { | |||
fs_driver = uri; | fs_driver = uri; | |||
fs_args = ""; | fs_args = ""; | |||
} else { | } else { | |||
fs_driver = t_strdup_until(uri, p); | fs_driver = t_strdup_until(uri, p); | |||
fs_args = p+1; | fs_args = p+1; | |||
} | } | |||
i_zero(&fs_set); | i_zero(&fs_set); | |||
fs_set.username = set->username; | ||||
fs_set.base_dir = set->base_dir; | fs_set.base_dir = set->base_dir; | |||
if (fs_init(fs_driver, fs_args, &fs_set, &fs, error_r) < 0) | if (fs_init(fs_driver, fs_args, &fs_set, &fs, error_r) < 0) | |||
return -1; | return -1; | |||
dict = i_new(struct fs_dict, 1); | dict = i_new(struct fs_dict, 1); | |||
dict->dict = *driver; | dict->dict = *driver; | |||
dict->fs = fs; | dict->fs = fs; | |||
dict->username = i_strdup(set->username); | ||||
*dict_r = &dict->dict; | *dict_r = &dict->dict; | |||
return 0; | return 0; | |||
} | } | |||
static void fs_dict_deinit(struct dict *_dict) | static void fs_dict_deinit(struct dict *_dict) | |||
{ | { | |||
struct fs_dict *dict = (struct fs_dict *)_dict; | struct fs_dict *dict = (struct fs_dict *)_dict; | |||
fs_deinit(&dict->fs); | fs_deinit(&dict->fs); | |||
i_free(dict->username); | ||||
i_free(dict); | i_free(dict); | |||
} | } | |||
/* Remove unsafe paths */ | /* Remove unsafe paths */ | |||
static const char *fs_dict_escape_key(const char *key) | static const char *fs_dict_escape_key(const char *key) | |||
{ | { | |||
const char *ptr; | const char *ptr; | |||
string_t *new_key = NULL; | string_t *new_key = NULL; | |||
/* we take the slow path always if we see potential | /* we take the slow path always if we see potential | |||
need for escaping */ | need for escaping */ | |||
skipping to change at line 99 | skipping to change at line 94 | |||
else | else | |||
str_append(new_key, "/."); | str_append(new_key, "/."); | |||
key = ptr + 2; | key = ptr + 2; | |||
} | } | |||
if (new_key == NULL) | if (new_key == NULL) | |||
return key; | return key; | |||
str_append(new_key, key); | str_append(new_key, key); | |||
return str_c(new_key); | return str_c(new_key); | |||
} | } | |||
static const char *fs_dict_get_full_key(struct fs_dict *dict, const char *key) | static const char *fs_dict_get_full_key(const char *username, const char *key) | |||
{ | { | |||
key = fs_dict_escape_key(key); | key = fs_dict_escape_key(key); | |||
if (str_begins(key, DICT_PATH_SHARED)) | if (str_begins(key, DICT_PATH_SHARED)) | |||
return key + strlen(DICT_PATH_SHARED); | return key + strlen(DICT_PATH_SHARED); | |||
else if (str_begins(key, DICT_PATH_PRIVATE)) { | else if (str_begins(key, DICT_PATH_PRIVATE)) { | |||
return t_strdup_printf("%s/%s", dict->username, | return t_strdup_printf("%s/%s", username, | |||
key + strlen(DICT_PATH_PRIVATE)); | key + strlen(DICT_PATH_PRIVATE)); | |||
} else { | } else { | |||
i_unreached(); | i_unreached(); | |||
} | } | |||
} | } | |||
static int fs_dict_lookup(struct dict *_dict, pool_t pool, const char *key, | static int fs_dict_lookup(struct dict *_dict, const struct dict_op_settings *set | |||
, | ||||
pool_t pool, const char *key, | ||||
const char **value_r, const char **error_r) | const char **value_r, const char **error_r) | |||
{ | { | |||
struct fs_dict *dict = (struct fs_dict *)_dict; | struct fs_dict *dict = (struct fs_dict *)_dict; | |||
struct fs_file *file; | struct fs_file *file; | |||
struct istream *input; | struct istream *input; | |||
const unsigned char *data; | const unsigned char *data; | |||
size_t size; | size_t size; | |||
const char *path; | const char *path; | |||
string_t *str; | string_t *str; | |||
int ret; | int ret; | |||
path = fs_dict_get_full_key(dict, key); | path = fs_dict_get_full_key(set->username, key); | |||
file = fs_file_init(dict->fs, path, FS_OPEN_MODE_READONLY); | file = fs_file_init(dict->fs, path, FS_OPEN_MODE_READONLY); | |||
input = fs_read_stream(file, IO_BLOCK_SIZE); | input = fs_read_stream(file, IO_BLOCK_SIZE); | |||
(void)i_stream_read(input); | (void)i_stream_read(input); | |||
str = str_new(pool, i_stream_get_data_size(input)+1); | str = str_new(pool, i_stream_get_data_size(input)+1); | |||
while ((ret = i_stream_read_more(input, &data, &size)) > 0) { | while ((ret = i_stream_read_more(input, &data, &size)) > 0) { | |||
str_append_data(str, data, size); | str_append_data(str, data, size); | |||
i_stream_skip(input, size); | i_stream_skip(input, size); | |||
} | } | |||
i_assert(ret == -1); | i_assert(ret == -1); | |||
skipping to change at line 155 | skipping to change at line 151 | |||
path, i_stream_get_error(input)); | path, i_stream_get_error(input)); | |||
} | } | |||
} | } | |||
i_stream_unref(&input); | i_stream_unref(&input); | |||
fs_file_deinit(&file); | fs_file_deinit(&file); | |||
return ret; | return ret; | |||
} | } | |||
static struct dict_iterate_context * | static struct dict_iterate_context * | |||
fs_dict_iterate_init(struct dict *_dict, const char *const *paths, | fs_dict_iterate_init(struct dict *_dict, const struct dict_op_settings *set, | |||
enum dict_iterate_flags flags) | const char *path, enum dict_iterate_flags flags) | |||
{ | { | |||
struct fs_dict *dict = (struct fs_dict *)_dict; | struct fs_dict *dict = (struct fs_dict *)_dict; | |||
struct fs_dict_iterate_context *iter; | struct fs_dict_iterate_context *iter; | |||
/* these flags are not supported for now */ | /* these flags are not supported for now */ | |||
i_assert((flags & DICT_ITERATE_FLAG_RECURSE) == 0); | i_assert((flags & DICT_ITERATE_FLAG_RECURSE) == 0); | |||
i_assert((flags & DICT_ITERATE_FLAG_EXACT_KEY) == 0); | i_assert((flags & DICT_ITERATE_FLAG_EXACT_KEY) == 0); | |||
i_assert((flags & (DICT_ITERATE_FLAG_SORT_BY_KEY | | i_assert((flags & (DICT_ITERATE_FLAG_SORT_BY_KEY | | |||
DICT_ITERATE_FLAG_SORT_BY_VALUE)) == 0); | DICT_ITERATE_FLAG_SORT_BY_VALUE)) == 0); | |||
iter = i_new(struct fs_dict_iterate_context, 1); | iter = i_new(struct fs_dict_iterate_context, 1); | |||
iter->ctx.dict = _dict; | iter->ctx.dict = _dict; | |||
iter->paths = p_strarray_dup(default_pool, paths); | iter->path = i_strdup(path); | |||
iter->flags = flags; | iter->flags = flags; | |||
iter->value_pool = pool_alloconly_create("iterate value pool", 128); | iter->value_pool = pool_alloconly_create("iterate value pool", 128); | |||
iter->fs_iter = fs_iter_init(dict->fs, | iter->fs_iter = fs_iter_init(dict->fs, | |||
fs_dict_get_full_key(dict, paths[0]), 0); | fs_dict_get_full_key(set->username, path), 0 ); | |||
return &iter->ctx; | return &iter->ctx; | |||
} | } | |||
static bool fs_dict_iterate(struct dict_iterate_context *ctx, | static bool fs_dict_iterate(struct dict_iterate_context *ctx, | |||
const char **key_r, const char *const **values_r) | const char **key_r, const char *const **values_r) | |||
{ | { | |||
struct fs_dict_iterate_context *iter = | struct fs_dict_iterate_context *iter = | |||
(struct fs_dict_iterate_context *)ctx; | (struct fs_dict_iterate_context *)ctx; | |||
struct fs_dict *dict = (struct fs_dict *)ctx->dict; | struct fs_dict *dict = (struct fs_dict *)ctx->dict; | |||
const char *path, *error; | const char *path, *error; | |||
skipping to change at line 195 | skipping to change at line 191 | |||
if (iter->error != NULL) | if (iter->error != NULL) | |||
return FALSE; | return FALSE; | |||
*key_r = fs_iter_next(iter->fs_iter); | *key_r = fs_iter_next(iter->fs_iter); | |||
if (*key_r == NULL) { | if (*key_r == NULL) { | |||
if (fs_iter_deinit(&iter->fs_iter, &error) < 0) { | if (fs_iter_deinit(&iter->fs_iter, &error) < 0) { | |||
iter->error = i_strdup(error); | iter->error = i_strdup(error); | |||
return FALSE; | return FALSE; | |||
} | } | |||
if (iter->paths[++iter->path_idx] == NULL) | if (iter->path == NULL) | |||
return FALSE; | return FALSE; | |||
path = fs_dict_get_full_key(dict, iter->paths[iter->path_idx]); | path = fs_dict_get_full_key(ctx->set.username, iter->path); | |||
iter->fs_iter = fs_iter_init(dict->fs, path, 0); | iter->fs_iter = fs_iter_init(dict->fs, path, 0); | |||
return fs_dict_iterate(ctx, key_r, values_r); | return fs_dict_iterate(ctx, key_r, values_r); | |||
} | } | |||
path = t_strconcat(iter->paths[iter->path_idx], *key_r, NULL); | path = t_strconcat(iter->path, *key_r, NULL); | |||
if ((iter->flags & DICT_ITERATE_FLAG_NO_VALUE) != 0) { | if ((iter->flags & DICT_ITERATE_FLAG_NO_VALUE) != 0) { | |||
iter->values[0] = NULL; | iter->values[0] = NULL; | |||
*key_r = path; | *key_r = path; | |||
return TRUE; | return TRUE; | |||
} | } | |||
p_clear(iter->value_pool); | p_clear(iter->value_pool); | |||
ret = fs_dict_lookup(ctx->dict, iter->value_pool, path, | struct dict_op_settings set = { | |||
.username = ctx->set.username, | ||||
}; | ||||
ret = fs_dict_lookup(ctx->dict, &set, iter->value_pool, path, | ||||
&iter->values[0], &error); | &iter->values[0], &error); | |||
if (ret < 0) { | if (ret < 0) { | |||
/* I/O error */ | /* I/O error */ | |||
iter->error = i_strdup(error); | iter->error = i_strdup(error); | |||
return FALSE; | return FALSE; | |||
} else if (ret == 0) { | } else if (ret == 0) { | |||
/* file was just deleted, just skip to next one */ | /* file was just deleted, just skip to next one */ | |||
return fs_dict_iterate(ctx, key_r, values_r); | return fs_dict_iterate(ctx, key_r, values_r); | |||
} | } | |||
*key_r = path; | *key_r = path; | |||
skipping to change at line 238 | skipping to change at line 237 | |||
const char *error; | const char *error; | |||
int ret; | int ret; | |||
if (fs_iter_deinit(&iter->fs_iter, &error) < 0 && iter->error == NULL) | if (fs_iter_deinit(&iter->fs_iter, &error) < 0 && iter->error == NULL) | |||
iter->error = i_strdup(error); | iter->error = i_strdup(error); | |||
ret = iter->error != NULL ? -1 : 0; | ret = iter->error != NULL ? -1 : 0; | |||
*error_r = t_strdup(iter->error); | *error_r = t_strdup(iter->error); | |||
pool_unref(&iter->value_pool); | pool_unref(&iter->value_pool); | |||
i_free(iter->paths); | i_free(iter->path); | |||
i_free(iter->error); | i_free(iter->error); | |||
i_free(iter); | i_free(iter); | |||
return ret; | return ret; | |||
} | } | |||
static struct dict_transaction_context * | static struct dict_transaction_context * | |||
fs_dict_transaction_init(struct dict *_dict) | fs_dict_transaction_init(struct dict *_dict) | |||
{ | { | |||
struct dict_transaction_memory_context *ctx; | struct dict_transaction_memory_context *ctx; | |||
pool_t pool; | pool_t pool; | |||
skipping to change at line 266 | skipping to change at line 265 | |||
static int fs_dict_write_changes(struct dict_transaction_memory_context *ctx, | static int fs_dict_write_changes(struct dict_transaction_memory_context *ctx, | |||
const char **error_r) | const char **error_r) | |||
{ | { | |||
struct fs_dict *dict = (struct fs_dict *)ctx->ctx.dict; | struct fs_dict *dict = (struct fs_dict *)ctx->ctx.dict; | |||
struct fs_file *file; | struct fs_file *file; | |||
const struct dict_transaction_memory_change *change; | const struct dict_transaction_memory_change *change; | |||
const char *key; | const char *key; | |||
int ret = 0; | int ret = 0; | |||
array_foreach(&ctx->changes, change) { | array_foreach(&ctx->changes, change) { | |||
key = fs_dict_get_full_key(dict, change->key); | key = fs_dict_get_full_key(ctx->ctx.set.username, change->key); | |||
switch (change->type) { | switch (change->type) { | |||
case DICT_CHANGE_TYPE_SET: | case DICT_CHANGE_TYPE_SET: | |||
file = fs_file_init(dict->fs, key, | file = fs_file_init(dict->fs, key, | |||
FS_OPEN_MODE_REPLACE); | FS_OPEN_MODE_REPLACE); | |||
if (fs_write(file, change->value.str, strlen(change->valu e.str)) < 0) { | if (fs_write(file, change->value.str, strlen(change->valu e.str)) < 0) { | |||
*error_r = t_strdup_printf( | *error_r = t_strdup_printf( | |||
"fs_write(%s) failed: %s", key, | "fs_write(%s) failed: %s", key, | |||
fs_file_last_error(file)); | fs_file_last_error(file)); | |||
ret = -1; | ret = -1; | |||
} | } | |||
End of changes. 18 change blocks. | ||||
20 lines changed or deleted | 20 lines changed or added |