dict-file.c revision bdb0f594a5673a0c5a16b92dc49eb2a8a66bdace
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2008-2012 Dovecot authors, see the included COPYING file */
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen unsigned int len;
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen const char *key;
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen const char *str;
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen ARRAY_DEFINE(changes, struct file_dict_change);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic struct dotlock_settings file_dict_dotlock_settings = {
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic struct dict *file_dict_init(struct dict *driver, const char *uri,
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen const char *p;
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen /* no parameters */
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen i_error("dict file: Invalid parameter: %s", p+1);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen dict->hash_pool = pool_alloconly_create("file dict", 1024);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen dict->hash = hash_table_create(default_pool, dict->hash_pool, 0,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic void file_dict_deinit(struct dict *_dict)
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen struct file_dict *dict = (struct file_dict *)_dict;
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic bool file_dict_need_refresh(struct file_dict *dict)
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen /* file changed */
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainenstatic int file_dict_open_latest(struct file_dict *dict)
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen open_type = dict->lock_method == FILE_LOCK_METHOD_DOTLOCK ?
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainenstatic int file_dict_refresh(struct file_dict *dict)
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen input = i_stream_create_fd(dict->fd, (size_t)-1, FALSE);
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen while ((key = i_stream_read_next_line(input)) != NULL &&
bdb0f594a5673a0c5a16b92dc49eb2a8a66bdaceTimo Sirainen (value = i_stream_read_next_line(input)) != NULL) {
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic int file_dict_lookup(struct dict *_dict, pool_t pool,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen struct file_dict *dict = (struct file_dict *)_dict;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen *value_r = p_strdup(pool, hash_table_lookup(dict->hash, key));
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenfile_dict_iterate_init(struct dict *_dict, const char *const *paths,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen struct file_dict *dict = (struct file_dict *)_dict;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen unsigned int i, path_count;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen pool = pool_alloconly_create("file dict iterate", 256);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen ctx = p_new(pool, struct file_dict_iterate_context, 1);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen for (path_count = 0; paths[path_count] != NULL; path_count++) ;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen ctx->paths = p_new(pool, struct file_dict_iterate_path, path_count + 1);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen for (i = 0; i < path_count; i++) {
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen ctx->paths[i].path = p_strdup(pool, paths[i]);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen ctx->iter = hash_table_iterate_init(dict->hash);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenstatic const struct file_dict_iterate_path *
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenfile_dict_iterate_find_path(struct file_dict_iterate_context *ctx,
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen const char *key)
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen unsigned int i;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen for (i = 0; ctx->paths[i].path != NULL; i++) {
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen if (strncmp(ctx->paths[i].path, key, ctx->paths[i].len) == 0)
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic bool file_dict_iterate(struct dict_iterate_context *_ctx,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen while (hash_table_iterate(ctx->iter, &key, &value)) {
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen if ((ctx->flags & DICT_ITERATE_FLAG_RECURSE) == 0 &&
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic int file_dict_iterate_deinit(struct dict_iterate_context *_ctx)
dba8af1faaf9fd3957254bb6f2234b285f77096fTimo Sirainen pool = pool_alloconly_create("file dict transaction", 2048);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen ctx = p_new(pool, struct file_dict_transaction_context, 1);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic void file_dict_apply_changes(struct file_dict_transaction_context *ctx)
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen struct file_dict *dict = (struct file_dict *)ctx->ctx.dict;
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen const char *tmp;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen unsigned int new_len;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (hash_table_lookup_full(dict->hash, change->key,
3c63c219ae7854b4f1d44a671a65572aa242cbcfTimo Sirainen if (old_value == NULL || new_len > strlen(old_value))
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen /* fall through */
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainenfd_copy_stat_permissions(const struct stat *src_st,
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen ((src_st->st_mode & 0070) >> 3 != (src_st->st_mode & 0007))) {
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen /* group has different permissions from world.
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen preserve the group. */
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen if (fchown(dest_fd, (uid_t)-1, src_st->st_gid) < 0) {
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen if ((src_st->st_mode & 07777) != (dest_st.st_mode & 07777)) {
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen if (fchmod(dest_fd, src_st->st_mode & 07777) < 0) {
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainenstatic int fd_copy_permissions(int src_fd, const char *src_path,
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen return fd_copy_stat_permissions(&src_st, dest_fd, dest_path);
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainenfd_copy_parent_dir_permissions(const char *src_path, int dest_fd,
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen const char *src_dir, *p;
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen return fd_copy_stat_permissions(&src_st, dest_fd, dest_path);
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainenfile_dict_lock(struct file_dict *dict, struct file_lock **lock_r)
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen /* quota file doesn't exist yet, we need to create it */
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen fd = open(dict->path, O_CREAT | O_RDWR, 0600);
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen (void)fd_copy_parent_dir_permissions(dict->path, fd, dict->path);
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen if (file_wait_lock(dict->fd, dict->path, F_WRLCK,
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen i_error("file_wait_lock(%s) failed: %m", dict->path);
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen /* check again if we need to reopen the file because it was
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen just replaced */
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen } while ((ret = file_dict_open_latest(dict)) > 0);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic int file_dict_write_changes(struct file_dict_transaction_context *ctx)
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen struct file_dict *dict = (struct file_dict *)ctx->ctx.dict;
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen temp_path = t_strdup_printf("%s.tmp", dict->path);
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen i_error("file dict commit: creat(%s) failed: %m",
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen fd = file_dotlock_open(&file_dict_dotlock_settings, dict->path, 0,
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen i_error("file dict commit: file_dotlock_open(%s) failed: %m",
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen temp_path = file_dotlock_get_lock_path(dotlock);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen /* refresh once more now that we're locked */
b141c303bf09b6ae43e1eb4aac1e1a6b796b9d35Timo Sirainen /* preserve the permissions */
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen (void)fd_copy_permissions(dict->fd, dict->path, fd, temp_path);
e5ff2112aea089f3de2badf9b1635677791d1384Timo Sirainen /* get initial permissions from parent directory */
f739c92a9237db03327dc82e3792e39c160a1e4dTimo Sirainen (void)fd_copy_parent_dir_permissions(dict->path, fd, temp_path);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenfile_dict_transaction_commit(struct dict_transaction_context *_ctx,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic void file_dict_transaction_rollback(struct dict_transaction_context *_ctx)
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic void file_dict_set(struct dict_transaction_context *_ctx,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen change->value.str = p_strdup(ctx->pool, value);
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainenstatic void file_dict_unset(struct dict_transaction_context *_ctx,
e3fabe8d0faa9aab7cae2d0eee9653f581a3061dTimo Sirainen const char *key)