예제 #1
0
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;
}