示例#1
0
static int maildir_create_tmp(struct maildir_mailbox *mbox, const char *dir,
			      const char **fname_r)
{
	struct mailbox *box = &mbox->box;
	const struct mailbox_permissions *perm = mailbox_get_permissions(box);
	unsigned int prefix_len;
	const char *tmp_fname;
	string_t *path;
	mode_t old_mask;
	int fd;

	path = t_str_new(256);
	str_append(path, dir);
	str_append_c(path, '/');
	prefix_len = str_len(path);

	do {
		tmp_fname = maildir_filename_generate();
		str_truncate(path, prefix_len);
		str_append(path, tmp_fname);

		/* the generated filename is unique. the only reason why it
		   might return an existing filename is if the time moved
		   backwards. so we'll use O_EXCL anyway, although it's mostly
		   useless. */
		old_mask = umask(0777 & ~perm->file_create_mode);
		fd = open(str_c(path),
			  O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0777);
		umask(old_mask);
	} while (fd == -1 && errno == EEXIST);

	*fname_r = tmp_fname;
	if (fd == -1) {
		if (ENOQUOTA(errno)) {
			mail_storage_set_error(box->storage,
				MAIL_ERROR_NOQUOTA, MAIL_ERRSTR_NO_QUOTA);
		} else {
			mail_storage_set_critical(box->storage,
				"open(%s) failed: %m", str_c(path));
		}
	} else if (perm->file_create_gid != (gid_t)-1) {
		if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
			if (errno == EPERM) {
				mail_storage_set_critical(box->storage, "%s",
					eperm_error_get_chgrp("fchown",
						str_c(path),
						perm->file_create_gid,
						perm->file_create_gid_origin));
			} else {
				mail_storage_set_critical(box->storage,
					"fchown(%s) failed: %m", str_c(path));
			}
		}
	}

	return fd;
}
示例#2
0
文件: mail-copy.c 项目: Raffprta/core
bool mail_storage_copy_can_use_hardlink(struct mailbox *src,
					struct mailbox *dest)
{
	const struct mailbox_permissions *src_perm =
		mailbox_get_permissions(src);
	const struct mailbox_permissions *dest_perm =
		mailbox_get_permissions(dest);

	if (src_perm->file_uid != dest_perm->file_uid) {
		/* if we don't have read permissions, we can't hard link
		   (basically we'll catch 0600 files here) */
		if ((src_perm->file_create_mode & 0022) == 0)
			return FALSE;
	}

	return src_perm->file_create_mode == dest_perm->file_create_mode &&
		src_perm->file_create_gid == dest_perm->file_create_gid &&
		!dest->disable_reflink_copy_to;
}
示例#3
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;
}
示例#4
0
static int maildir_keywords_write_fd(struct maildir_keywords *mk,
				     const char *path, int fd)
{
	struct maildir_mailbox *mbox = mk->mbox;
	struct mailbox *box = &mbox->box;
	const struct mailbox_permissions *perm = mailbox_get_permissions(box);
	const char *const *keywords;
	unsigned int i, count;
	string_t *str;
	struct stat st;

	str = t_str_new(256);
	keywords = array_get(&mk->list, &count);
	for (i = 0; i < count; i++) {
		if (keywords[i] != NULL)
			str_printfa(str, "%u %s\n", i, keywords[i]);
	}
	if (write_full(fd, str_data(str), str_len(str)) < 0) {
		mail_storage_set_critical(mk->storage,
					  "write_full(%s) failed: %m", path);
		return -1;
	}

	if (fstat(fd, &st) < 0) {
		mail_storage_set_critical(mk->storage,
					  "fstat(%s) failed: %m", path);
		return -1;
	}

	if (st.st_gid != perm->file_create_gid &&
	    perm->file_create_gid != (gid_t)-1) {
		if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
			if (errno == EPERM) {
				mail_storage_set_critical(mk->storage, "%s",
					eperm_error_get_chgrp("fchown", path,
						perm->file_create_gid,
						perm->file_create_gid_origin));
			} else {
				mail_storage_set_critical(mk->storage,
					"fchown(%s) failed: %m", path);
			}
		}
	}

	/* mtime must grow every time */
	if (st.st_mtime <= mk->synced_mtime) {
		struct utimbuf ut;

		mk->synced_mtime = ioloop_time <= mk->synced_mtime ?
			mk->synced_mtime + 1 : ioloop_time;
		ut.actime = ioloop_time;
		ut.modtime = mk->synced_mtime;
		if (utime(path, &ut) < 0) {
			mail_storage_set_critical(mk->storage,
				"utime(%s) failed: %m", path);
			return -1;
		}
	}

	if (fsync(fd) < 0) {
		mail_storage_set_critical(mk->storage,
			"fsync(%s) failed: %m", path);
		return -1;
	}
	return 0;
}
示例#5
0
int index_storage_mailbox_open(struct mailbox *box, bool move_to_memory)
{
	struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
	enum mail_index_open_flags index_flags;
	int ret;

	i_assert(!box->opened);

	index_flags = ibox->index_flags;
	if (move_to_memory)
		ibox->index_flags &= ~MAIL_INDEX_OPEN_FLAG_CREATE;

	if (index_storage_mailbox_alloc_index(box) < 0)
		return -1;

	/* make sure mail_index_set_permissions() has been called */
	(void)mailbox_get_permissions(box);

	ret = mail_index_open(box->index, index_flags);
	if (ret <= 0 || move_to_memory) {
		if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
			i_assert(ret <= 0);
			mailbox_set_index_error(box);
			return -1;
		}

		if (mail_index_move_to_memory(box->index) < 0) {
			/* try opening once more. it should be created
			   directly into memory now. */
			if (mail_index_open_or_create(box->index,
						      index_flags) < 0)
				i_panic("in-memory index creation failed");
		}
	}
	if ((index_flags & MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY) != 0) {
		if (mail_index_is_in_memory(box->index)) {
			mail_storage_set_critical(box->storage,
				"Couldn't create index file");
			mail_index_close(box->index);
			return -1;
		}
	}

	if ((box->flags & MAILBOX_FLAG_OPEN_DELETED) == 0) {
		if (mail_index_is_deleted(box->index)) {
			mailbox_set_deleted(box);
			mail_index_close(box->index);
			return -1;
		}
	}

	box->cache = mail_index_get_cache(box->index);
	index_cache_register_defaults(box);
	box->view = mail_index_view_open(box->index);
	ibox->keyword_names = mail_index_get_keywords(box->index);
	ibox->vsize_hdr_ext_id =
		mail_index_ext_register(box->index, "hdr-vsize",
					sizeof(struct index_vsize_header), 0,
					sizeof(uint64_t));

	box->opened = TRUE;

	if ((box->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)
		mail_index_modseq_enable(box->index);

	index_thread_mailbox_opened(box);
	hook_mailbox_opened(box);
	return 0;
}