int mdbox_file_create_fd(struct dbox_file *file, const char *path, bool parents) { struct mdbox_file *mfile = (struct mdbox_file *)file; struct mdbox_map *map = mfile->storage->map; struct mailbox_permissions perm; mode_t old_mask; const char *p, *dir; int fd; mailbox_list_get_root_permissions(map->root_list, &perm); old_mask = umask(0666 & ~perm.file_create_mode); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); umask(old_mask); if (fd == -1 && errno == ENOENT && parents && (p = strrchr(path, '/')) != NULL) { dir = t_strdup_until(path, p); if (mailbox_list_mkdir_root(map->root_list, dir, path != file->alt_path ? MAILBOX_LIST_PATH_TYPE_DIR : MAILBOX_LIST_PATH_TYPE_ALT_DIR) < 0) { mail_storage_copy_list_error(&file->storage->storage, map->root_list); return -1; } /* try again */ old_mask = umask(0666 & ~perm.file_create_mode); fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666); umask(old_mask); } if (fd == -1) { mail_storage_set_critical(&file->storage->storage, "open(%s, O_CREAT) failed: %m", path); } else if (perm.file_create_gid == (gid_t)-1) { /* no group change */ } else if (fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) { if (errno == EPERM) { mail_storage_set_critical(&file->storage->storage, "%s", eperm_error_get_chgrp("fchown", path, perm.file_create_gid, perm.file_create_gid_origin)); } else { mail_storage_set_critical(&file->storage->storage, "fchown(%s, -1, %ld) failed: %m", path, (long)perm.file_create_gid); } /* continue anyway */ } return fd; }
static int mailbox_list_index_index_open(struct mailbox_list *list) { struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(list); const struct mail_storage_settings *set = list->mail_set; struct mailbox_permissions perm; enum mail_index_open_flags index_flags; unsigned int lock_timeout; if (ilist->opened) return 0; if (mailbox_list_mkdir_missing_index_root(list) < 0) return -1; index_flags = mail_storage_settings_to_index_flags(set); if (strcmp(list->name, MAILBOX_LIST_NAME_INDEX) == 0) { /* LAYOUT=index. this is the only location for the mailbox data, so we must never move it into memory. */ index_flags |= MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY; } lock_timeout = set->mail_max_lock_timeout == 0 ? UINT_MAX : set->mail_max_lock_timeout; mailbox_list_get_root_permissions(list, &perm); mail_index_set_permissions(ilist->index, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin); mail_index_set_lock_method(ilist->index, set->parsed_lock_method, lock_timeout); if (mail_index_open_or_create(ilist->index, index_flags) < 0) { if (mail_index_move_to_memory(ilist->index) < 0) { /* try opening once more. it should be created directly into memory now, except if it fails with LAYOUT=index backend. */ if (mail_index_open_or_create(ilist->index, index_flags) < 0) { mailbox_list_set_internal_error(list); return -1; } } } ilist->opened = TRUE; return 0; }
static void mailbox_uidvalidity_write(struct mailbox_list *list, const char *path, uint32_t uid_validity) { char buf[8+1]; int fd; struct mailbox_permissions perm; mode_t old_mask; mailbox_list_get_root_permissions(list, &perm); old_mask = umask(0666 & ~perm.file_create_mode); fd = open(path, O_RDWR | O_CREAT, 0666); umask(old_mask); if (fd == -1) { i_error("open(%s) failed: %m", path); return; } if (perm.file_create_gid != (gid_t)-1 && fchown(fd, (uid_t)-1, perm.file_create_gid) < 0) { if (errno == EPERM) { i_error("%s", eperm_error_get_chgrp("fchown", path, perm.file_create_gid, perm.file_create_gid_origin)); } else { i_error("fchown(%s, -1, %ld) failed: %m", path, (long)perm.file_create_gid); } } if (i_snprintf(buf, sizeof(buf), "%08x", uid_validity) < 0) i_unreached(); if (pwrite_full(fd, buf, strlen(buf), 0) < 0) i_error("write(%s) failed: %m", path); if (close(fd) < 0) i_error("close(%s) failed: %m", path); }
int subsfile_set_subscribed(struct mailbox_list *list, const char *path, const char *temp_prefix, const char *name, bool set) { const struct mail_storage_settings *mail_set = list->mail_set; struct dotlock_settings dotlock_set; struct dotlock *dotlock; struct mailbox_permissions perm; const char *line, *dir, *fname, *escaped_name; struct istream *input = NULL; struct ostream *output; int fd_in, fd_out; enum mailbox_list_path_type type; bool found, changed = FALSE, failed = FALSE; unsigned int version = 2; if (strcasecmp(name, "INBOX") == 0) name = "INBOX"; memset(&dotlock_set, 0, sizeof(dotlock_set)); dotlock_set.use_excl_lock = mail_set->dotlock_use_excl; dotlock_set.nfs_flush = mail_set->mail_nfs_storage; dotlock_set.temp_prefix = temp_prefix; dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT; dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT; mailbox_list_get_root_permissions(list, &perm); fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); if (fd_out == -1 && errno == ENOENT) { /* directory hasn't been created yet. */ type = list->set.control_dir != NULL ? MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR; fname = strrchr(path, '/'); if (fname != NULL) { dir = t_strdup_until(path, fname); if (mailbox_list_mkdir_root(list, dir, type) < 0) return -1; } fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); } if (fd_out == -1) { if (errno == EAGAIN) { mailbox_list_set_error(list, MAIL_ERROR_TEMP, "Timeout waiting for subscription file lock"); } else { subswrite_set_syscall_error(list, "file_dotlock_open()", path); } return -1; } fd_in = nfs_safe_open(path, O_RDONLY); if (fd_in == -1 && errno != ENOENT) { subswrite_set_syscall_error(list, "open()", path); file_dotlock_delete(&dotlock); return -1; } if (fd_in != -1) { input = i_stream_create_fd_autoclose(&fd_in, list->mailbox_name_max_length+1); i_stream_set_return_partial_line(input, TRUE); subsfile_list_read_header(list, input, &version); } found = FALSE; output = o_stream_create_fd_file(fd_out, 0, FALSE); o_stream_cork(output); if (version >= 2) o_stream_send_str(output, version2_header); if (version < 2 || name[0] == '\0') escaped_name = name; else { const char *const *tmp; char separators[2]; string_t *str = t_str_new(64); separators[0] = mailbox_list_get_hierarchy_sep(list); separators[1] = '\0'; tmp = t_strsplit(name, separators); str_append_tabescaped(str, *tmp); for (tmp++; *tmp != NULL; tmp++) { str_append_c(str, '\t'); str_append_tabescaped(str, *tmp); } escaped_name = str_c(str); } if (input != NULL) { while ((line = next_line(list, path, input, &failed, FALSE)) != NULL) { if (strcmp(line, escaped_name) == 0) { found = TRUE; if (!set) { changed = TRUE; continue; } } o_stream_nsend_str(output, line); o_stream_nsend(output, "\n", 1); } i_stream_destroy(&input); } if (!failed && set && !found) { /* append subscription */ line = t_strconcat(escaped_name, "\n", NULL); o_stream_nsend_str(output, line); changed = TRUE; } if (changed && !failed) { if (o_stream_nfinish(output) < 0) { subswrite_set_syscall_error(list, "write()", path); failed = TRUE; } else if (mail_set->parsed_fsync_mode != FSYNC_MODE_NEVER) { if (fsync(fd_out) < 0) { subswrite_set_syscall_error(list, "fsync()", path); failed = TRUE; } } } else { o_stream_ignore_last_errors(output); } o_stream_destroy(&output); if (failed || !changed) { if (file_dotlock_delete(&dotlock) < 0) { subswrite_set_syscall_error(list, "file_dotlock_delete()", path); failed = TRUE; } } else { enum dotlock_replace_flags flags = DOTLOCK_REPLACE_FLAG_VERIFY_OWNER; if (file_dotlock_replace(&dotlock, flags) < 0) { subswrite_set_syscall_error(list, "file_dotlock_replace()", path); failed = TRUE; } } return failed ? -1 : (changed ? 1 : 0); }
static int mdbox_map_open_internal(struct mdbox_map *map, bool create_missing) { enum mail_index_open_flags open_flags; struct mailbox_permissions perm; int ret = 0; if (map->view != NULL) { /* already opened */ return 1; } mailbox_list_get_root_permissions(map->root_list, &perm); mail_index_set_permissions(map->index, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin); open_flags = MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY | mail_storage_settings_to_index_flags(MAP_STORAGE(map)->set); if (create_missing) { if ((ret = mdbox_map_mkdir_storage(map)) < 0) return -1; if (ret > 0) { /* storage/ directory already existed. the index should exist also. */ } else { open_flags |= MAIL_INDEX_OPEN_FLAG_CREATE; } } ret = mail_index_open(map->index, open_flags); if (ret == 0 && create_missing) { /* storage/ already existed, but indexes didn't. we'll need to take extra steps to make sure we won't overwrite any m.* files that may already exist. */ map->verify_existing_file_ids = TRUE; open_flags |= MAIL_INDEX_OPEN_FLAG_CREATE; ret = mail_index_open(map->index, open_flags); } if (ret < 0) { mail_storage_set_internal_error(MAP_STORAGE(map)); mail_index_reset_error(map->index); return -1; } if (ret == 0) { /* index not found - for now just return failure */ i_assert(!create_missing); return 0; } map->view = mail_index_view_open(map->index); mdbox_map_cleanup(map); if (mail_index_get_header(map->view)->uid_validity == 0) { if (mdbox_map_generate_uid_validity(map) < 0 || mdbox_map_refresh(map) < 0) { mail_storage_set_internal_error(MAP_STORAGE(map)); mail_index_reset_error(map->index); mail_index_close(map->index); return -1; } } return 1; }