static int maildir_keywords_commit(struct maildir_keywords *mk) { const struct mailbox_permissions *perm; struct dotlock *dotlock; const char *lock_path; mode_t old_mask; int i, fd; mk->synced = FALSE; if (!mk->changed || mk->mbox == NULL) return 0; lock_path = t_strconcat(mk->path, ".lock", NULL); i_unlink_if_exists(lock_path); perm = mailbox_get_permissions(&mk->mbox->box); for (i = 0;; i++) { /* we could just create the temp file directly, but doing it this ways avoids potential problems with overwriting contents in malicious symlinks */ old_mask = umask(0777 & ~perm->file_create_mode); fd = file_dotlock_open(&mk->dotlock_settings, mk->path, DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock); umask(old_mask); if (fd != -1) break; if (errno != ENOENT || i == MAILDIR_DELETE_RETRY_COUNT) { mail_storage_set_critical(mk->storage, "file_dotlock_open(%s) failed: %m", mk->path); return -1; } /* the control dir doesn't exist. create it unless the whole mailbox was just deleted. */ if (!maildir_set_deleted(&mk->mbox->box)) return -1; } if (maildir_keywords_write_fd(mk, lock_path, fd) < 0) { file_dotlock_delete(&dotlock); return -1; } if (file_dotlock_replace(&dotlock, 0) < 0) { mail_storage_set_critical(mk->storage, "file_dotlock_replace(%s) failed: %m", mk->path); return -1; } mk->changed = FALSE; return 0; }
int mail_transaction_log_file_create(struct mail_transaction_log_file *file, bool reset) { struct mail_index *index = file->log->index; struct dotlock_settings new_dotlock_set; struct dotlock *dotlock; mode_t old_mask; int fd, ret; i_assert(!MAIL_INDEX_IS_IN_MEMORY(index)); if (file->log->index->readonly) { mail_index_set_error(index, "Can't create log file %s: Index is read-only", file->filepath); return -1; } mail_transaction_log_get_dotlock_set(file->log, &new_dotlock_set); new_dotlock_set.lock_suffix = LOG_NEW_DOTLOCK_SUFFIX; /* With dotlocking we might already have path.lock created, so this filename has to be different. */ old_mask = umask(index->mode ^ 0666); fd = file_dotlock_open(&new_dotlock_set, file->filepath, 0, &dotlock); umask(old_mask); if (fd == -1) { log_file_set_syscall_error(file, "file_dotlock_open()"); return -1; } mail_index_fchown(index, fd, file_dotlock_get_lock_path(dotlock)); /* either fd gets used or the dotlock gets deleted and returned fd is for the existing file */ ret = mail_transaction_log_file_create2(file, fd, reset, &dotlock); if (ret < 0) { if (dotlock != NULL) file_dotlock_delete(&dotlock); return -1; } return ret; }