static void
mail_transaction_log_mark_corrupted(struct mail_transaction_log_file *file)
{
	unsigned int offset =
		offsetof(struct mail_transaction_log_header, indexid);
	int flags;

	if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file) ||
	    file->log->index->readonly)
		return;

	/* indexid=0 marks the log file as corrupted. we opened the file with
	   O_APPEND, and now we need to drop it for pwrite() to work (at least
	   in Linux) */
	flags = fcntl(file->fd, F_GETFL, 0);
	if (flags < 0) {
		mail_index_file_set_syscall_error(file->log->index,
			file->filepath, "fcntl(F_GETFL)");
		return;
	}
	if (fcntl(file->fd, F_SETFL, flags & ~O_APPEND) < 0) {
		mail_index_file_set_syscall_error(file->log->index,
			file->filepath, "fcntl(F_SETFL)");
		return;
	}
	if (pwrite_full(file->fd, &file->hdr.indexid,
			sizeof(file->hdr.indexid), offset) < 0) {
		mail_index_file_set_syscall_error(file->log->index,
						  file->filepath, "pwrite()");
	}
}
Esempio n. 2
0
static int mbox_fill_space(struct mbox_sync_context *sync_ctx,
			   uoff_t offset, uoff_t size)
{
	unsigned char space[1024];

	memset(space, ' ', sizeof(space));
	while (size > sizeof(space)) {
		if (pwrite_full(sync_ctx->write_fd, space,
				sizeof(space), offset) < 0) {
			mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
			return -1;
		}
		size -= sizeof(space);
	}

	if (pwrite_full(sync_ctx->write_fd, space, size, offset) < 0) {
		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
		return -1;
	}
	mbox_sync_file_updated(sync_ctx, TRUE);
	return 0;
}
/*
 * Actually write an image to the target device, eventually keeping a
 * DOS partition table on the device
 */
static int imx_bbu_write_device(struct imx_internal_bbu_handler *imx_handler,
		const char *devicefile, struct bbu_data *data,
		const void *buf, int image_len)
{
	int fd, ret, offset = 0;

	fd = open(devicefile, O_RDWR | O_CREAT);
	if (fd < 0)
		return fd;

	if (imx_handler->handler.flags & (IMX_BBU_FLAG_KEEP_HEAD |
	    IMX_BBU_FLAG_PARTITION_STARTS_AT_HEADER)) {
		image_len -= imx_handler->flash_header_offset;
		buf += imx_handler->flash_header_offset;
	}

	if (imx_handler->handler.flags & IMX_BBU_FLAG_KEEP_HEAD)
		offset += imx_handler->flash_header_offset;

	ret = imx_bbu_protect(fd, imx_handler, devicefile, offset,
			      image_len, 0);
	if (ret)
		goto err_close;

	if (imx_bbu_erase_required(imx_handler)) {
		pr_debug("%s: erasing %s from 0x%08x to 0x%08x\n", __func__,
				devicefile, offset, image_len);
		ret = erase(fd, image_len, offset);
		if (ret) {
			pr_err("erasing %s failed with %s\n", devicefile,
					strerror(-ret));
			goto err_close;
		}
	}

	ret = pwrite_full(fd, buf, image_len, offset);
	if (ret < 0) {
		pr_err("writing to %s failed with %s\n", devicefile,
		       strerror(-ret));
		goto err_close;
	}

	imx_bbu_protect(fd, imx_handler, devicefile, offset,
			image_len, 1);

err_close:
	close(fd);

	return ret < 0 ? ret : 0;
}
Esempio n. 4
0
uint32_t mailbox_uidvalidity_next(struct mailbox_list *list, const char *path)
{
	char buf[8+1];
	uint32_t cur_value;
	int fd, ret;

	fd = open(path, O_RDWR);
	if (fd == -1) {
		if (errno != ENOENT)
			i_error("open(%s) failed: %m", path);
		return mailbox_uidvalidity_next_rescan(list, path);
	}
	ret = read_full(fd, buf, sizeof(buf)-1);
	if (ret < 0) {
		i_error("read(%s) failed: %m", path);
		i_close_fd(&fd);
		return mailbox_uidvalidity_next_rescan(list, path);
	}
	buf[sizeof(buf)-1] = 0;
	if (ret == 0 || str_to_uint32_hex(buf, &cur_value) < 0 ||
	    cur_value == 0) {
		/* broken value */
		i_close_fd(&fd);
		return mailbox_uidvalidity_next_rescan(list, path);
	}

	/* we now have the current uidvalidity value that's hopefully correct */
	if (mailbox_uidvalidity_rename(path, &cur_value, FALSE) < 0) {
		i_close_fd(&fd);
		return mailbox_uidvalidity_next_rescan(list, path);
	}

	/* fast path succeeded. write the current value to the main
	   uidvalidity file. */
	if (i_snprintf(buf, sizeof(buf), "%08x", cur_value) < 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);
	return cur_value;
}
Esempio n. 5
0
static int
o_stream_temp_write_at(struct ostream_private *stream,
		       const void *data, size_t size, uoff_t offset)
{
	struct temp_ostream *tstream = (struct temp_ostream *)stream;

	if (tstream->fd == -1) {
		i_assert(stream->ostream.offset == tstream->buf->used);
		buffer_write(tstream->buf, offset, data, size);
		stream->ostream.offset = tstream->buf->used;
	} else {
		if (pwrite_full(tstream->fd, data, size, offset) < 0) {
			stream->ostream.stream_errno = errno;
			i_close_fd(&tstream->fd);
			return -1;
		}
		if (tstream->fd_size < offset + size)
			tstream->fd_size = offset + size;
	}
	return 0;
}
Esempio n. 6
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);
}
Esempio n. 7
0
static int mbox_sync_read_and_move(struct mbox_sync_context *sync_ctx,
                                   struct mbox_sync_mail_context *mail_ctx,
				   struct mbox_sync_mail *mails,
				   uint32_t seq, uint32_t idx, uint32_t padding,
				   off_t move_diff, uoff_t expunged_space,
				   uoff_t end_offset, bool first_nonexpunged)
{
	struct mbox_sync_mail_context new_mail_ctx;
	uoff_t offset, dest_offset;
	size_t need_space;

	if (mail_ctx == NULL) {
		if (mbox_sync_seek(sync_ctx, mails[idx].from_offset) < 0)
			return -1;

		mbox_sync_read_next(sync_ctx, &new_mail_ctx, mails, seq, idx,
				    expunged_space);
		mail_ctx = &new_mail_ctx;
	} else {
		i_assert(seq == mail_ctx->seq);
		if (mail_ctx->mail.space < 0)
			mail_ctx->mail.space = 0;
		i_stream_seek(sync_ctx->input, mail_ctx->body_offset);
	}

	if (mail_ctx->mail.space <= 0) {
		need_space = str_len(mail_ctx->header) - mail_ctx->mail.space -
			(mail_ctx->body_offset - mail_ctx->hdr_offset);
		if (need_space != (uoff_t)-mails[idx].space) {
			/* this check works only if we're doing the first
			   write, or if the file size was changed externally */
			mbox_sync_file_update_ext_modified(sync_ctx);

			mbox_sync_set_critical(sync_ctx,
				"seq=%u uid=%u uid_broken=%d "
				"originally needed %"PRIuUOFF_T
				" bytes, now needs %"PRIuSIZE_T" bytes",
				seq, mails[idx].uid, mails[idx].uid_broken,
				(uoff_t)-mails[idx].space, need_space);
		}
	}

	if (first_nonexpunged && expunged_space > 0) {
		/* move From-line (after parsing headers so we don't
		   overwrite them) */
		if (mbox_move(sync_ctx, mails[idx].from_offset - expunged_space,
			      mails[idx].from_offset,
			      mails[idx].offset - mails[idx].from_offset) < 0)
			return -1;
	}

	if (mails[idx].space == 0) {
		/* don't touch spacing */
	} else if (padding < (uoff_t)mail_ctx->mail.space) {
		mbox_sync_headers_remove_space(mail_ctx, mail_ctx->mail.space -
					       padding);
	} else {
		mbox_sync_headers_add_space(mail_ctx, padding -
					    mail_ctx->mail.space);
	}

	/* move the body of this message and headers of next message forward,
	   then write the headers */
	offset = sync_ctx->input->v_offset;
	dest_offset = offset + move_diff;
	i_assert(offset <= end_offset);
	if (mbox_move(sync_ctx, dest_offset, offset, end_offset - offset) < 0)
		return -1;

	/* the header may actually be moved backwards if there was expunged
	   space which we wanted to remove */
	i_assert(dest_offset >= str_len(mail_ctx->header));
	dest_offset -= str_len(mail_ctx->header);
	i_assert(dest_offset >= mails[idx].from_offset - expunged_space);
	if (pwrite_full(sync_ctx->write_fd, str_data(mail_ctx->header),
			str_len(mail_ctx->header), dest_offset) < 0) {
		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
		return -1;
	}
	mbox_sync_file_updated(sync_ctx, TRUE);

	if (sync_ctx->dest_first_mail) {
		mbox_sync_first_mail_written(mail_ctx, dest_offset);
		sync_ctx->dest_first_mail = FALSE;
	}

	mails[idx].offset = dest_offset +
		(mail_ctx->mail.offset - mail_ctx->hdr_offset);
	mails[idx].space = mail_ctx->mail.space;
	return 0;
}
Esempio n. 8
0
int mbox_sync_try_rewrite(struct mbox_sync_mail_context *ctx, off_t move_diff)
{
        struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
	size_t old_hdr_size, new_hdr_size;

	i_assert(sync_ctx->mbox->mbox_lock_type == F_WRLCK);

	old_hdr_size = ctx->body_offset - ctx->hdr_offset;
	new_hdr_size = str_len(ctx->header);

	if (new_hdr_size <= old_hdr_size) {
		/* add space. note that we must call add_space() even if we're
		   not adding anything so mail.offset gets fixed. */
		mbox_sync_headers_add_space(ctx, old_hdr_size - new_hdr_size);
	} else if (new_hdr_size > old_hdr_size) {
		/* try removing the space where we can */
		mbox_sync_headers_remove_space(ctx,
					       new_hdr_size - old_hdr_size);
		new_hdr_size = str_len(ctx->header);

		if (new_hdr_size <= old_hdr_size) {
			/* good, we removed enough. */
			i_assert(new_hdr_size == old_hdr_size);
		} else if (move_diff < 0 &&
			   new_hdr_size - old_hdr_size <= (uoff_t)-move_diff) {
			/* moving backwards - we can use the extra space from
			   it, just update expunged_space accordingly */
			i_assert(ctx->mail.space == 0);
			i_assert(sync_ctx->expunged_space >=
				 (off_t)(new_hdr_size - old_hdr_size));
			sync_ctx->expunged_space -= new_hdr_size - old_hdr_size;
		} else {
			/* couldn't get enough space */
			i_assert(ctx->mail.space == 0);
			ctx->mail.space =
				-(ssize_t)(new_hdr_size - old_hdr_size);
			return 0;
		}
	}

	i_assert(ctx->mail.space >= 0);

	if (ctx->header_first_change == (size_t)-1 && move_diff == 0) {
		/* no changes actually. we get here if index sync record told
		   us to do something that was already there */
		return 1;
	}

	if (move_diff != 0) {
		/* forget about partial write optimizations */
		ctx->header_first_change = 0;
		ctx->header_last_change = 0;
	}

	if (ctx->header_last_change != (size_t)-1 &&
	    ctx->header_last_change != 0)
		str_truncate(ctx->header, ctx->header_last_change);

	if (pwrite_full(sync_ctx->write_fd,
			str_data(ctx->header) + ctx->header_first_change,
			str_len(ctx->header) - ctx->header_first_change,
			ctx->hdr_offset + ctx->header_first_change +
			move_diff) < 0) {
		mbox_set_syscall_error(sync_ctx->mbox, "pwrite_full()");
		return -1;
	}

	if (sync_ctx->dest_first_mail &&
	    (ctx->imapbase_updated || ctx->sync_ctx->base_uid_last != 0)) {
		/* the position might have moved as a result of moving
		   whitespace */
		mbox_sync_first_mail_written(ctx, ctx->hdr_offset + move_diff);
	}

	mbox_sync_file_updated(sync_ctx, FALSE);
	return 1;
}