}
static int
-dbox_file_seek_append_pos(struct dbox_file *file, uoff_t append_offset)
+dbox_file_seek_append_pos(struct dbox_file *file, uoff_t *append_offset_r)
{
struct stat st;
- i_assert(append_offset != 0);
-
if (file->file_version != DBOX_VERSION ||
file->msg_header_size != sizeof(struct dbox_message_header)) {
/* created by an incompatible version, can't append */
dbox_file_set_syscall_error(file, "fstat()");
return -1;
}
- if ((uoff_t)st.st_size != append_offset) {
- /* not end of file? either previous write crashed or map index
- got broken. play it safe and resync everything. */
- dbox_file_set_corrupted(file, "file size (%"PRIuUOFF_T
- ") not expected (%"PRIuUOFF_T")",
- st.st_size, append_offset);
- return 0;
- }
+ *append_offset_r = st.st_size;
file->output = o_stream_create_fd_file(file->fd, 0, FALSE);
- o_stream_seek(file->output, append_offset);
+ o_stream_seek(file->output, st.st_size);
return 1;
}
-int dbox_file_get_append_stream(struct dbox_file *file, uoff_t last_msg_offset,
- uoff_t last_msg_size, struct ostream **stream_r)
+int dbox_file_get_append_stream(struct dbox_file *file, uoff_t *append_offset_r,
+ struct ostream **stream_r)
{
int ret;
} else if (file->output == NULL) {
i_assert(file->lock != NULL || file->single_mbox != NULL);
- ret = dbox_file_seek_append_pos(file, last_msg_offset +
- last_msg_size);
+ ret = dbox_file_seek_append_pos(file, append_offset_r);
if (ret <= 0)
return ret;
}
void dbox_file_cancel_append(struct dbox_file *file, uoff_t append_offset)
{
- if (ftruncate(file->fd, append_offset) < 0)
- dbox_file_set_syscall_error(file, "ftruncate()");
+ (void)o_stream_flush(file->output);
- o_stream_seek(file->output, append_offset);
+ if (file->output->offset != append_offset) {
+ if (ftruncate(file->fd, append_offset) < 0)
+ dbox_file_set_syscall_error(file, "ftruncate()");
+ o_stream_seek(file->output, append_offset);
+ }
}
int dbox_file_flush_append(struct dbox_file *file)
/* Returns TRUE if mail_size bytes can be appended to the file. */
bool dbox_file_can_append(struct dbox_file *file, uoff_t mail_size);
-/* Get output stream for appending a new message. last_msg_offset points to
- the beginning of the last message in the file, or 0 for new files. Returns
- 1 if ok, 0 if file can't be appended to (old file version or corruption)
- or -1 if error. */
-int dbox_file_get_append_stream(struct dbox_file *file, uoff_t last_msg_offset,
- uoff_t last_msg_size,
+/* Get output stream for appending a new message. Returns 1 if ok, 0 if file
+ can't be appended to (old file version or corruption) or -1 if error. */
+int dbox_file_get_append_stream(struct dbox_file *file, uoff_t *append_offset_r,
struct ostream **stream_r);
/* Returns the next offset for append a message. dbox_file_get_append_stream()
must have been called for this file already at least once. */
{
struct dbox_map *map = ctx->map;
struct dbox_storage *storage = map->storage;
- const struct mail_index_header *hdr;
struct dbox_file *file;
struct stat st;
- uint32_t seq, tmp_file_id;
- uoff_t tmp_offset, tmp_size, last_msg_offset, last_msg_size, new_size;
+ uoff_t append_offset;
bool deleted, file_too_old = FALSE;
int ret;
if (errno != ENOENT)
i_error("stat(%s) failed: %m", file->current_path);
/* the file was unlinked between opening and locking it. */
- } else if (dbox_map_refresh(map) == 0) {
- /* now that the file is locked and map is refreshed, make sure
- we still have the last msg's offset. we have to go through
- the whole map, because existing messages may have already
- been appended to this file. */
- last_msg_offset = 0;
- hdr = mail_index_get_header(map->view);
- for (seq = 1; seq <= hdr->messages_count; seq++) {
- if (dbox_map_lookup_seq(map, seq, &tmp_file_id,
- &tmp_offset, &tmp_size) < 0)
- break;
- if (tmp_file_id == file->file_id &&
- last_msg_offset < tmp_offset) {
- last_msg_offset = tmp_offset;
- last_msg_size = tmp_size;
- }
- }
-
- new_size = last_msg_offset + last_msg_size + mail_size;
- if (seq > hdr->messages_count && last_msg_offset > 0 &&
- new_size <= storage->rotate_size &&
- dbox_file_get_append_stream(file, last_msg_offset,
- last_msg_size, output_r) > 0) {
- /* success */
- *file_r = file;
- return TRUE;
- }
+ } else if (dbox_file_get_append_stream(file, &append_offset,
+ output_r) <= 0) {
+ /* couldn't append to this file */
+ } else if (append_offset + mail_size > storage->rotate_size) {
+ /* file was too large after all */
+ dbox_file_cancel_append(file, append_offset);
+ } else {
+ /* success */
+ *file_r = file;
+ return TRUE;
}
/* failure */
append_offset = dbox_file_get_next_append_offset(files[i-1]);
if (append_offset + mail_size <= map->storage->rotate_size &&
- dbox_file_get_append_stream(files[i-1], 0, 0,
+ dbox_file_get_append_stream(files[i-1], &append_offset,
output_r) > 0) {
*file_r = files[i-1];
*existing_r = TRUE;
{
struct dbox_file *file = NULL;
struct dbox_map_append *append;
+ uoff_t append_offset;
bool existing;
int ret;
file = ctx->map->storage->rotate_size == 0 ?
dbox_file_init_single(ctx->mbox, 0) :
dbox_file_init_multi(ctx->map->storage, 0);
- ret = dbox_file_get_append_stream(file, 0, 0, output_r);
+ ret = dbox_file_get_append_stream(file, &append_offset,
+ output_r);
if (ret <= 0) {
i_assert(ret < 0);
(void)unlink(file->current_path);