Пример #1
0
static void mbox_file_fix_atime(struct mbox_mailbox *mbox)
{
	struct utimbuf buf;
	struct stat st;

	if (mbox->box.recent_flags_count > 0 &&
	    (mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) == 0 &&
	    mbox->mbox_fd != -1 && !mbox_is_backend_readonly(mbox)) {
		/* we've seen recent messages which we want to keep recent.
		   keep file's atime lower than mtime so \Marked status
		   gets shown while listing */
		if (fstat(mbox->mbox_fd, &st) < 0) {
			mbox_set_syscall_error(mbox, "fstat()");
			return;
		}
		if (st.st_atime >= st.st_mtime) {
			buf.modtime = st.st_mtime;
			buf.actime = buf.modtime - 1;
			/* EPERM can happen with shared mailboxes */
			if (utime(mailbox_get_path(&mbox->box), &buf) < 0 &&
			    errno != EPERM)
				mbox_set_syscall_error(mbox, "utime()");
		}
	}
}
Пример #2
0
static void mbox_mailbox_close(struct mailbox *box)
{
	struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
	const struct mail_index_header *hdr;
	enum mbox_sync_flags sync_flags = 0;

	if (mbox->mbox_stream != NULL &&
	    istream_raw_mbox_is_corrupted(mbox->mbox_stream)) {
		/* clear the corruption by forcing a full resync */
		sync_flags |= MBOX_SYNC_UNDIRTY | MBOX_SYNC_FORCE_SYNC;
	}

	if (box->view != NULL) {
		hdr = mail_index_get_header(box->view);
		if ((hdr->flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0 &&
		    !mbox_is_backend_readonly(mbox)) {
			/* we've done changes to mbox which haven't been
			   written yet. do it now. */
			sync_flags |= MBOX_SYNC_REWRITE;
		}
	}
	if (sync_flags != 0 && !mbox->invalid_mbox_file)
		(void)mbox_sync(mbox, sync_flags);

	if (mbox->mbox_global_lock_id != 0)
		mbox_unlock(mbox, mbox->mbox_global_lock_id);
	if (mbox->keep_lock_to != NULL)
		timeout_remove(&mbox->keep_lock_to);

        mbox_file_close(mbox);
	if (mbox->mbox_file_stream != NULL)
		i_stream_destroy(&mbox->mbox_file_stream);

	index_storage_mailbox_close(box);
}
Пример #3
0
int mbox_file_open_stream(struct mbox_mailbox *mbox)
{
	if (mbox->mbox_stream != NULL)
		return 0;

	if (mbox->mbox_file_stream != NULL) {
		/* read-only mbox stream */
		i_assert(mbox->mbox_fd == -1 && mbox_is_backend_readonly(mbox));
	} else {
		if (mbox->mbox_fd == -1) {
			if (mbox_file_open(mbox) < 0)
				return -1;
		}

		if (mbox->mbox_writeonly) {
			mbox->mbox_file_stream =
				i_stream_create_from_data("", 0);
		} else {
			mbox->mbox_file_stream =
				i_stream_create_fd(mbox->mbox_fd,
						   MBOX_READ_BLOCK_SIZE);
			i_stream_set_init_buffer_size(mbox->mbox_file_stream,
						      MBOX_READ_BLOCK_SIZE);
		}
		i_stream_set_name(mbox->mbox_file_stream,
				  mailbox_get_path(&mbox->box));
	}

	mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream);
	if (mbox->mbox_lock_type != F_UNLCK)
		istream_raw_mbox_set_locked(mbox->mbox_stream);
	return 0;
}
Пример #4
0
int mbox_file_open(struct mbox_mailbox *mbox)
{
	struct stat st;
	int fd;

	i_assert(mbox->mbox_fd == -1);

	if (mbox->mbox_file_stream != NULL) {
		/* read-only mbox stream */
		i_assert(mbox_is_backend_readonly(mbox));
		return 0;
	}

	fd = open(mailbox_get_path(&mbox->box),
		  mbox_is_backend_readonly(mbox) ? O_RDONLY : O_RDWR);
	if (fd == -1 && errno == EACCES && !mbox->backend_readonly) {
		mbox->backend_readonly = TRUE;
		fd = open(mailbox_get_path(&mbox->box), O_RDONLY);
	}

	if (fd == -1) {
		mbox_set_syscall_error(mbox, "open()");
		return -1;
	}

	if (fstat(fd, &st) < 0) {
		mbox_set_syscall_error(mbox, "fstat()");
		i_close_fd(&fd);
		return -1;
	}

	mbox->mbox_writeonly = S_ISFIFO(st.st_mode);
	mbox->mbox_fd = fd;
	mbox->mbox_dev = st.st_dev;
	mbox->mbox_ino = st.st_ino;
	return 0;
}
Пример #5
0
static bool mbox_storage_is_readonly(struct mailbox *box)
{
	struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;

	if (index_storage_is_readonly(box))
		return TRUE;

	if (mbox_is_backend_readonly(mbox)) {
		/* return read-only only if there are no private flags
		   (that are stored in index files) */
		if (mailbox_get_private_flags_mask(box) == 0)
			return TRUE;
	}
	return FALSE;
}
Пример #6
0
void mbox_file_close_stream(struct mbox_mailbox *mbox)
{
	/* if we read anything, fix the atime if needed */
	mbox_file_fix_atime(mbox);

	if (mbox->mbox_stream != NULL)
		i_stream_destroy(&mbox->mbox_stream);

	if (mbox->mbox_file_stream != NULL) {
		if (mbox->mbox_fd == -1) {
			/* read-only mbox stream */
			i_assert(mbox_is_backend_readonly(mbox));
			i_stream_seek(mbox->mbox_file_stream, 0);
		} else {
			i_stream_destroy(&mbox->mbox_file_stream);
		}
	}
}
Пример #7
0
static int
mbox_save_init_file(struct mbox_save_context *ctx,
		    struct mbox_transaction_context *t, bool want_mail)
{
	struct mailbox_transaction_context *_t = &t->t;
	struct mbox_mailbox *mbox = ctx->mbox;
	struct mail_storage *storage = &mbox->storage->storage;
	bool empty = FALSE;
	int ret;

	if (mbox_is_backend_readonly(ctx->mbox)) {
		mail_storage_set_error(storage, MAIL_ERROR_PERM,
				       "Read-only mbox");
		return -1;
	}

	if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 ||
	    ctx->ctx.data.uid != 0)
		want_mail = TRUE;

	if (ctx->append_offset == (uoff_t)-1) {
		/* first appended mail in this transaction */
		if (t->write_lock_id == 0) {
			if (mbox_lock(mbox, F_WRLCK, &t->write_lock_id) <= 0)
				return -1;
		}

		if (mbox->mbox_fd == -1) {
			if (mbox_file_open(mbox) < 0)
				return -1;
		}

		/* update mbox_sync_dirty state */
		ret = mbox_sync_has_changed_full(mbox, TRUE, &empty);
		if (ret < 0)
			return -1;
		if (!want_mail && ret == 0) {
			/* we're not required to assign UIDs for the appended
			   mails immediately. do it only if it doesn't require
			   syncing. */
			mbox_save_init_sync(_t);
		}
	}

	if (!ctx->synced && (want_mail || empty)) {
		/* we'll need to assign UID for the mail immediately. */
		if (mbox_sync(mbox, 0) < 0)
			return -1;
		mbox_save_init_sync(_t);
	}

	/* the syncing above could have changed the append offset */
	if (ctx->append_offset == (uoff_t)-1) {
		if (mbox_seek_to_end(ctx, &ctx->append_offset) < 0)
			return -1;

		ctx->output = o_stream_create_fd_file(mbox->mbox_fd,
						      ctx->append_offset,
						      FALSE);
		o_stream_cork(ctx->output);
	}
	return 0;
}