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()"); } }
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; }
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; }
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; }
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); }
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; }
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; }