"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/lib-dict/dict-file.c" between
dovecot-2.3.16.tar.gz and dovecot-2.3.17.tar.gz

About: Dovecot is an IMAP and POP3 server, written with security primarily in mind.

dict-file.c  (dovecot-2.3.16):dict-file.c  (dovecot-2.3.17)
skipping to change at line 30 skipping to change at line 30
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
struct file_dict { struct file_dict {
struct dict dict; struct dict dict;
pool_t hash_pool; pool_t hash_pool;
enum file_lock_method lock_method; enum file_lock_method lock_method;
char *path; char *path;
char *home_dir;
bool dict_path_checked;
HASH_TABLE(char *, char *) hash; HASH_TABLE(char *, char *) hash;
int fd; int fd;
bool refreshed; bool refreshed;
}; };
struct file_dict_iterate_path {
const char *path;
size_t len;
};
struct file_dict_iterate_context { struct file_dict_iterate_context {
struct dict_iterate_context ctx; struct dict_iterate_context ctx;
pool_t pool; pool_t pool;
struct hash_iterate_context *iter; struct hash_iterate_context *iter;
struct file_dict_iterate_path *paths; const char *path;
size_t path_len;
enum dict_iterate_flags flags; enum dict_iterate_flags flags;
const char *values[2]; const char *values[2];
const char *error; const char *error;
}; };
static struct dotlock_settings file_dict_dotlock_settings = { static struct dotlock_settings file_dict_dotlock_settings = {
.timeout = 60*2, .timeout = 60*2,
.stale_timeout = 60, .stale_timeout = 60,
.use_io_notify = TRUE .use_io_notify = TRUE
}; };
static int static int
file_dict_ensure_path_home_dir(struct file_dict *dict, const char *home_dir,
const char **error_r)
{
if (null_strcmp(dict->home_dir, home_dir) == 0)
return 0;
if (dict->dict_path_checked) {
*error_r = t_strdup_printf("home_dir changed from %s to %s "
"(requested dict was: %s)", dict->home_dir,
home_dir, dict->path);
return -1;
}
char *_p = dict->path;
dict->path = i_strdup(home_expand_tilde(dict->path, home_dir));
dict->home_dir = i_strdup(home_dir);
i_free(_p);
dict->dict_path_checked = TRUE;
return 0;
}
static int
file_dict_init(struct dict *driver, const char *uri, file_dict_init(struct dict *driver, const char *uri,
const struct dict_settings *set, const struct dict_settings *set ATTR_UNUSED,
struct dict **dict_r, const char **error_r) struct dict **dict_r, const char **error_r)
{ {
struct file_dict *dict; struct file_dict *dict;
const char *p, *path; const char *p, *path;
dict = i_new(struct file_dict, 1); dict = i_new(struct file_dict, 1);
dict->lock_method = FILE_LOCK_METHOD_DOTLOCK; dict->lock_method = FILE_LOCK_METHOD_DOTLOCK;
p = strchr(uri, ':'); p = strchr(uri, ':');
if (p == NULL) { if (p == NULL) {
skipping to change at line 86 skipping to change at line 106
if (strcmp(p, "lock=fcntl") == 0) if (strcmp(p, "lock=fcntl") == 0)
dict->lock_method = FILE_LOCK_METHOD_FCNTL; dict->lock_method = FILE_LOCK_METHOD_FCNTL;
else if (strcmp(p, "lock=flock") == 0) else if (strcmp(p, "lock=flock") == 0)
dict->lock_method = FILE_LOCK_METHOD_FLOCK; dict->lock_method = FILE_LOCK_METHOD_FLOCK;
else { else {
*error_r = t_strdup_printf("Invalid parameter: %s", p+1); *error_r = t_strdup_printf("Invalid parameter: %s", p+1);
i_free(dict); i_free(dict);
return -1; return -1;
} }
} }
dict->path = set->home_dir == NULL ? i_strdup(path) :
i_strdup(home_expand_tilde(path, set->home_dir)); /* keep the path for now, later in dict operations check if home_dir
should be prepended. */
dict->path = i_strdup(path);
dict->dict = *driver; dict->dict = *driver;
dict->hash_pool = pool_alloconly_create("file dict", 1024); dict->hash_pool = pool_alloconly_create("file dict", 1024);
hash_table_create(&dict->hash, dict->hash_pool, 0, str_hash, strcmp); hash_table_create(&dict->hash, dict->hash_pool, 0, str_hash, strcmp);
dict->fd = -1; dict->fd = -1;
*dict_r = &dict->dict; *dict_r = &dict->dict;
return 0; return 0;
} }
static void file_dict_deinit(struct dict *_dict) static void file_dict_deinit(struct dict *_dict)
{ {
struct file_dict *dict = (struct file_dict *)_dict; struct file_dict *dict = (struct file_dict *)_dict;
i_close_fd_path(&dict->fd, dict->path); i_close_fd_path(&dict->fd, dict->path);
hash_table_destroy(&dict->hash); hash_table_destroy(&dict->hash);
pool_unref(&dict->hash_pool); pool_unref(&dict->hash_pool);
i_free(dict->path); i_free(dict->path);
i_free(dict->home_dir);
i_free(dict); i_free(dict);
} }
static bool file_dict_need_refresh(struct file_dict *dict) static bool file_dict_need_refresh(struct file_dict *dict)
{ {
struct stat st1, st2; struct stat st1, st2;
if (dict->dict.iter_count > 0) { if (dict->dict.iter_count > 0) {
/* Change nothing while there are iterators or they can crash /* Change nothing while there are iterators or they can crash
because the hash table content recreated. */ because the hash table content recreated. */
skipping to change at line 200 skipping to change at line 224
value = str_tabunescape(p_strdup(dict->hash_pool, value)) ; value = str_tabunescape(p_strdup(dict->hash_pool, value)) ;
hash_table_update(dict->hash, key, value); hash_table_update(dict->hash, key, value);
} }
i_stream_destroy(&input); i_stream_destroy(&input);
} }
dict->refreshed = TRUE; dict->refreshed = TRUE;
return 0; return 0;
} }
static int file_dict_lookup(struct dict *_dict, pool_t pool, const char *key, static int file_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 file_dict *dict = (struct file_dict *)_dict; struct file_dict *dict = (struct file_dict *)_dict;
if (file_dict_ensure_path_home_dir(dict, set->home_dir, error_r) < 0)
return -1;
if (file_dict_refresh(dict, error_r) < 0) if (file_dict_refresh(dict, error_r) < 0)
return -1; return -1;
*value_r = p_strdup(pool, hash_table_lookup(dict->hash, key)); *value_r = p_strdup(pool, hash_table_lookup(dict->hash, key));
return *value_r == NULL ? 0 : 1; return *value_r == NULL ? 0 : 1;
} }
static struct dict_iterate_context * static struct dict_iterate_context *
file_dict_iterate_init(struct dict *_dict, const char *const *paths, file_dict_iterate_init(struct dict *_dict,
enum dict_iterate_flags flags) const struct dict_op_settings *set ATTR_UNUSED,
const char *path, enum dict_iterate_flags flags)
{ {
struct file_dict_iterate_context *ctx; struct file_dict_iterate_context *ctx;
struct file_dict *dict = (struct file_dict *)_dict; struct file_dict *dict = (struct file_dict *)_dict;
unsigned int i, path_count;
const char *error; const char *error;
pool_t pool; pool_t pool;
pool = pool_alloconly_create("file dict iterate", 256); pool = pool_alloconly_create("file dict iterate", 256);
ctx = p_new(pool, struct file_dict_iterate_context, 1); ctx = p_new(pool, struct file_dict_iterate_context, 1);
ctx->ctx.dict = _dict; ctx->ctx.dict = _dict;
ctx->pool = pool; ctx->pool = pool;
for (path_count = 0; paths[path_count] != NULL; path_count++) ; ctx->path = p_strdup(pool, path);
ctx->paths = p_new(pool, struct file_dict_iterate_path, path_count + 1); ctx->path_len = strlen(path);
for (i = 0; i < path_count; i++) {
ctx->paths[i].path = p_strdup(pool, paths[i]);
ctx->paths[i].len = strlen(paths[i]);
}
ctx->flags = flags; ctx->flags = flags;
if (file_dict_refresh(dict, &error) < 0) if (file_dict_ensure_path_home_dir(dict, set->home_dir, &error) < 0 ||
file_dict_refresh(dict, &error) < 0)
ctx->error = p_strdup(pool, error); ctx->error = p_strdup(pool, error);
ctx->iter = hash_table_iterate_init(dict->hash); ctx->iter = hash_table_iterate_init(dict->hash);
return &ctx->ctx; return &ctx->ctx;
} }
static const struct file_dict_iterate_path * static bool
file_dict_iterate_find_path(struct file_dict_iterate_context *ctx, file_dict_iterate_key_matches(struct file_dict_iterate_context *ctx,
const char *key) const char *key)
{ {
unsigned int i; if (strncmp(ctx->path, key, ctx->path_len) == 0)
return TRUE;
for (i = 0; ctx->paths[i].path != NULL; i++) { return FALSE;
if (strncmp(ctx->paths[i].path, key, ctx->paths[i].len) == 0)
return &ctx->paths[i];
}
return NULL;
} }
static bool file_dict_iterate(struct dict_iterate_context *_ctx, static bool file_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 file_dict_iterate_context *ctx = struct file_dict_iterate_context *ctx =
(struct file_dict_iterate_context *)_ctx; (struct file_dict_iterate_context *)_ctx;
const struct file_dict_iterate_path *path;
char *key, *value; char *key, *value;
while (hash_table_iterate(ctx->iter, while (hash_table_iterate(ctx->iter,
((struct file_dict *)_ctx->dict)->hash, ((struct file_dict *)_ctx->dict)->hash,
&key, &value)) { &key, &value)) {
path = file_dict_iterate_find_path(ctx, key); if (!file_dict_iterate_key_matches(ctx, key))
if (path == NULL)
continue; continue;
if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0) { if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) != 0) {
/* match everything */ /* match everything */
} else if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) { } else if ((ctx->flags & DICT_ITERATE_FLAG_EXACT_KEY) != 0) {
if (key[path->len] != '\0') if (key[ctx->path_len] != '\0')
continue; continue;
} else { } else {
if (strchr(key + path->len, '/') != NULL) if (strchr(key + ctx->path_len, '/') != NULL)
continue; continue;
} }
*key_r = key; *key_r = key;
ctx->values[0] = value; ctx->values[0] = value;
*values_r = ctx->values; *values_r = ctx->values;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
skipping to change at line 502 skipping to change at line 522
"creat(%s) failed: %m", dict->path); "creat(%s) failed: %m", dict->path);
} }
return -1; return -1;
} }
if (fd_copy_parent_dir_permissions(dict->path, dict->fd, if (fd_copy_parent_dir_permissions(dict->path, dict->fd,
dict->path, &error) < 0) dict->path, &error) < 0)
e_error(dict->dict.event, "%s", error); e_error(dict->dict.event, "%s", error);
} }
*lock_r = NULL; *lock_r = NULL;
struct file_lock_settings lock_set = {
.lock_method = dict->lock_method,
};
do { do {
file_lock_free(lock_r); file_lock_free(lock_r);
if (file_wait_lock(dict->fd, dict->path, F_WRLCK, if (file_wait_lock(dict->fd, dict->path, F_WRLCK, &lock_set,
dict->lock_method,
file_dict_dotlock_settings.timeout, file_dict_dotlock_settings.timeout,
lock_r) <= 0) { lock_r, &error) <= 0) {
*error_r = t_strdup_printf( *error_r = t_strdup_printf(
"file_wait_lock(%s) failed: %m", dict->path); "file_wait_lock(%s) failed: %s",
dict->path, error);
return -1; return -1;
} }
/* check again if we need to reopen the file because it was /* check again if we need to reopen the file because it was
just replaced */ just replaced */
} while ((ret = file_dict_open_latest(dict, error_r)) > 0); } while ((ret = file_dict_open_latest(dict, error_r)) > 0);
return ret < 0 ? -1 : 0; return ret < 0 ? -1 : 0;
} }
static int static int
skipping to change at line 536 skipping to change at line 559
const char *temp_path = NULL; const char *temp_path = NULL;
const char *error; const char *error;
struct hash_iterate_context *iter; struct hash_iterate_context *iter;
struct ostream *output; struct ostream *output;
char *key, *value; char *key, *value;
string_t *str; string_t *str;
int fd = -1; int fd = -1;
*atomic_inc_not_found_r = FALSE; *atomic_inc_not_found_r = FALSE;
if (file_dict_ensure_path_home_dir(dict, ctx->ctx.set.home_dir, error_r)
< 0)
return -1;
switch (dict->lock_method) { switch (dict->lock_method) {
case FILE_LOCK_METHOD_FCNTL: case FILE_LOCK_METHOD_FCNTL:
case FILE_LOCK_METHOD_FLOCK: case FILE_LOCK_METHOD_FLOCK:
if (file_dict_lock(dict, &lock, error_r) < 0) if (file_dict_lock(dict, &lock, error_r) < 0)
return -1; return -1;
temp_path = t_strdup_printf("%s.tmp", dict->path); temp_path = t_strdup_printf("%s.tmp", dict->path);
fd = creat(temp_path, 0600); fd = creat(temp_path, 0600);
if (fd == -1) { if (fd == -1) {
*error_r = t_strdup_printf( *error_r = t_strdup_printf(
"dict-file: creat(%s) failed: %m", temp_path); "dict-file: creat(%s) failed: %m", temp_path);
 End of changes. 24 change blocks. 
39 lines changed or deleted 66 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)