Lines Matching refs:file

1 /* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
11 #include "file-lock.h"
12 #include "file-dotlock.h"
17 #include "dbox-file.h"
44 void dbox_file_set_syscall_error(struct dbox_file *file, const char *function)
46 mail_storage_set_critical(&file->storage->storage,
47 "%s failed for file %s: %m",
48 function, file->cur_path);
51 void dbox_file_set_corrupted(struct dbox_file *file, const char *reason, ...)
56 mail_storage_set_critical(&file->storage->storage,
57 "Corrupted dbox file %s (around offset=%"PRIuUOFF_T"): %s",
58 file->cur_path, file->input == NULL ? 0 : file->input->v_offset,
62 file->storage->v.set_file_corrupted(file);
65 void dbox_file_init(struct dbox_file *file)
67 file->refcount = 1;
68 file->fd = -1;
69 file->cur_offset = (uoff_t)-1;
70 file->cur_path = file->primary_path;
73 void dbox_file_free(struct dbox_file *file)
75 i_assert(file->refcount == 0);
77 pool_unref(&file->metadata_pool);
78 dbox_file_close(file);
79 i_free(file->primary_path);
80 i_free(file->alt_path);
81 i_free(file);
86 struct dbox_file *file = *_file;
90 i_assert(file->refcount > 0);
91 if (--file->refcount == 0)
92 file->storage->v.file_unrefed(file);
95 static int dbox_file_parse_header(struct dbox_file *file, const char *line)
101 file->file_version = *line - '0';
103 (file->file_version != 1 && file->file_version != DBOX_VERSION)) {
104 dbox_file_set_corrupted(file, "Invalid dbox version");
110 file->msg_header_size = 0;
121 if (str_to_uint_hex(value, &file->msg_header_size) < 0) {
122 dbox_file_set_corrupted(file, "Invalid message header size");
128 dbox_file_set_corrupted(file, "Invalid create time stamp");
131 file->create_time = (time_t)time;
137 if (file->msg_header_size == 0) {
138 dbox_file_set_corrupted(file, "Missing message header size");
144 static int dbox_file_read_header(struct dbox_file *file)
150 i_stream_seek(file->input, 0);
151 line = i_stream_read_next_line(file->input);
153 if (file->input->stream_errno == 0) {
154 dbox_file_set_corrupted(file,
155 "EOF while reading file header");
159 dbox_file_set_syscall_error(file, "read()");
162 hdr_size = file->input->v_offset;
164 ret = dbox_file_parse_header(file, line) < 0 ? 0 : 1;
167 file->file_header_size = hdr_size;
171 static int dbox_file_open_fd(struct dbox_file *file, bool try_altpath)
178 path = file->primary_path;
179 while ((file->fd = open(path, flags)) == -1) {
185 mail_storage_set_critical(&file->storage->storage,
190 if (file->alt_path == NULL || alt || !try_altpath) {
196 path = file->alt_path;
199 file->cur_path = path;
203 static int dbox_file_open_full(struct dbox_file *file, bool try_altpath,
209 if (file->input != NULL)
212 if (file->fd == -1) {
214 ret = dbox_file_open_fd(file, try_altpath);
226 fd = file->fd;
227 file->input = i_stream_create_fd_autoclose(&fd, DBOX_READ_BLOCK_SIZE);
228 i_stream_set_name(file->input, file->cur_path);
229 i_stream_set_init_buffer_size(file->input, DBOX_READ_BLOCK_SIZE);
230 return dbox_file_read_header(file);
233 int dbox_file_open(struct dbox_file *file, bool *deleted_r)
235 return dbox_file_open_full(file, TRUE, deleted_r);
238 int dbox_file_open_primary(struct dbox_file *file, bool *notfound_r)
240 return dbox_file_open_full(file, FALSE, notfound_r);
243 int dbox_file_stat(struct dbox_file *file, struct stat *st_r)
248 if (dbox_file_is_open(file)) {
249 if (fstat(file->fd, st_r) < 0) {
250 mail_storage_set_critical(&file->storage->storage,
251 "fstat(%s) failed: %m", file->cur_path);
258 path = file->primary_path;
261 mail_storage_set_critical(&file->storage->storage,
266 if (file->alt_path == NULL || alt) {
272 path = file->alt_path;
275 file->cur_path = path;
279 int dbox_file_header_write(struct dbox_file *file, struct ostream *output)
289 file->file_version = DBOX_VERSION;
290 file->file_header_size = str_len(hdr);
291 file->msg_header_size = sizeof(struct dbox_message_header);
295 void dbox_file_close(struct dbox_file *file)
297 dbox_file_unlock(file);
298 if (file->input != NULL) {
301 i_stream_unref(&file->input);
302 file->fd = -1;
303 } else if (file->fd != -1) {
304 if (close(file->fd) < 0)
305 dbox_file_set_syscall_error(file, "close()");
306 file->fd = -1;
308 file->cur_offset = (uoff_t)-1;
311 int dbox_file_try_lock(struct dbox_file *file)
315 i_assert(file->fd != -1);
318 ret = file_try_lock(file->fd, file->cur_path, F_WRLCK,
319 FILE_LOCK_METHOD_FLOCK, &file->lock);
321 mail_storage_set_critical(&file->storage->storage,
322 "file_try_lock(%s) failed: %m", file->cur_path);
325 ret = file_dotlock_create(&dotlock_set, file->cur_path,
326 DOTLOCK_CREATE_FLAG_NONBLOCK, &file->lock);
328 mail_storage_set_critical(&file->storage->storage,
329 "file_dotlock_create(%s) failed: %m", file->cur_path);
335 void dbox_file_unlock(struct dbox_file *file)
337 i_assert(!file->appending || file->lock == NULL);
339 if (file->lock != NULL) {
341 file_unlock(&file->lock);
343 file_dotlock_delete(&file->lock);
346 if (file->input != NULL)
347 i_stream_sync(file->input);
350 int dbox_file_read_mail_header(struct dbox_file *file, uoff_t *physical_size_r)
357 ret = i_stream_read_bytes(file->input, &data, &size,
358 file->msg_header_size);
360 if (file->input->stream_errno == 0) {
361 /* EOF, broken offset or file truncated */
362 dbox_file_set_corrupted(file, "EOF reading msg header "
364 size, file->msg_header_size);
367 dbox_file_set_syscall_error(file, "read()");
370 memcpy(&hdr, data, I_MIN(sizeof(hdr), file->msg_header_size));
373 dbox_file_set_corrupted(file, "msg header has bad magic value");
377 if (data[file->msg_header_size-1] != '\n') {
378 dbox_file_set_corrupted(file, "msg header doesn't end with LF");
387 int dbox_file_seek(struct dbox_file *file, uoff_t offset)
392 i_assert(file->input != NULL);
395 offset = file->file_header_size;
397 if (offset != file->cur_offset) {
398 i_stream_seek(file->input, offset);
399 ret = dbox_file_read_mail_header(file, &size);
402 file->cur_offset = offset;
403 file->cur_physical_size = size;
405 i_stream_seek(file->input, offset + file->msg_header_size);
410 dbox_file_seek_next_at_metadata(struct dbox_file *file, uoff_t *offset)
416 i_stream_seek(file->input, *offset);
417 if ((ret = dbox_file_metadata_skip_header(file)) <= 0)
421 buf_size = i_stream_get_max_buffer_size(file->input);
422 i_stream_set_max_buffer_size(file->input, (size_t)-1);
423 while ((line = i_stream_read_next_line(file->input)) != NULL) {
429 i_stream_set_max_buffer_size(file->input, buf_size);
430 *offset = file->input->v_offset;
434 void dbox_file_seek_rewind(struct dbox_file *file)
436 file->cur_offset = (uoff_t)-1;
439 int dbox_file_seek_next(struct dbox_file *file, uoff_t *offset_r, bool *last_r)
444 i_assert(file->input != NULL);
446 if (file->cur_offset == (uoff_t)-1) {
447 /* first mail. we may not have read the file at all yet,
451 offset = file->cur_offset + file->msg_header_size +
452 file->cur_physical_size;
453 if ((ret = dbox_file_seek_next_at_metadata(file, &offset)) <= 0) {
454 *offset_r = file->cur_offset;
457 if (i_stream_read_eof(file->input)) {
466 ret = dbox_file_seek(file, offset);
468 *offset_r = file->file_header_size;
472 struct dbox_file_append_context *dbox_file_append_init(struct dbox_file *file)
476 i_assert(!file->appending);
478 file->appending = TRUE;
481 ctx->file = file;
482 if (file->fd != -1) {
483 ctx->output = o_stream_create_fd_file(file->fd, 0, FALSE);
484 o_stream_set_name(ctx->output, file->cur_path);
496 i_assert(ctx->file->appending);
503 if (ftruncate(ctx->file->fd, ctx->last_checkpoint_offset) < 0) {
504 dbox_file_set_syscall_error(ctx->file, "ftruncate()");
509 ctx->file->appending = FALSE;
517 struct dbox_file *file = ctx->file;
520 i_assert(ctx->file->appending);
525 } else if (ctx->first_append_offset == file->file_header_size) {
527 if (unlink(file->cur_path) < 0)
528 dbox_file_set_syscall_error(file, "unlink()");
533 if (ftruncate(file->fd, ctx->first_append_offset) < 0)
534 dbox_file_set_syscall_error(file, "ftruncate()");
543 dbox_file_close(file);
544 file->appending = FALSE;
549 struct mail_storage *storage = &ctx->file->storage->storage;
556 dbox_file_set_syscall_error(ctx->file, "write()");
561 if (ftruncate(ctx->file->fd, ctx->last_checkpoint_offset) < 0) {
562 dbox_file_set_syscall_error(ctx->file, "ftruncate()");
566 dbox_file_set_syscall_error(ctx->file, "lseek()");
572 if (fdatasync(ctx->file->fd) < 0) {
573 dbox_file_set_syscall_error(ctx->file, "fdatasync()");
589 struct dbox_file *file = ctx->file;
593 /* file creation had failed */
598 file anymore. */
602 if (file->file_version == 0) {
603 /* newly created file, write the file header */
604 if (dbox_file_header_write(file, ctx->output) < 0) {
605 dbox_file_set_syscall_error(file, "write()");
612 /* file has existing mails */
613 if (file->file_version != DBOX_VERSION ||
614 file->msg_header_size != sizeof(struct dbox_message_header)) {
620 /* first append to existing file. seek to eof first. */
621 if (fstat(file->fd, &st) < 0) {
622 dbox_file_set_syscall_error(file, "fstat()");
625 if (st.st_size < file->msg_header_size) {
626 dbox_file_set_corrupted(file,
627 "dbox file size too small");
631 dbox_file_set_syscall_error(file, "lseek()");
639 int dbox_file_metadata_skip_header(struct dbox_file *file)
646 ret = i_stream_read_bytes(file->input, &data, &size,
649 if (file->input->stream_errno == 0) {
651 dbox_file_set_corrupted(file,
655 dbox_file_set_syscall_error(file, "read()");
662 dbox_file_set_corrupted(file,
666 i_stream_skip(file->input, sizeof(metadata_hdr));
671 dbox_file_metadata_read_at(struct dbox_file *file, uoff_t metadata_offset)
677 if (file->metadata_pool != NULL)
678 p_clear(file->metadata_pool);
680 file->metadata_pool =
683 p_array_init(&file->metadata, file->metadata_pool, 16);
685 i_stream_seek(file->input, metadata_offset);
686 if ((ret = dbox_file_metadata_skip_header(file)) <= 0)
690 buf_size = i_stream_get_max_buffer_size(file->input);
692 i_stream_set_max_buffer_size(file->input, (size_t)-1);
693 while ((line = i_stream_read_next_line(file->input)) != NULL) {
699 line = p_strdup(file->metadata_pool, line);
700 array_append(&file->metadata, &line, 1);
702 i_stream_set_max_buffer_size(file->input, buf_size);
704 dbox_file_set_corrupted(file, "missing end-of-metadata line");
708 int dbox_file_metadata_read(struct dbox_file *file)
713 i_assert(file->cur_offset != (uoff_t)-1);
715 if (file->metadata_read_offset == file->cur_offset)
718 metadata_offset = file->cur_offset + file->msg_header_size +
719 file->cur_physical_size;
720 ret = dbox_file_metadata_read_at(file, metadata_offset);
724 file->metadata_read_offset = file->cur_offset;
728 const char *dbox_file_metadata_get(struct dbox_file *file,
734 metadata = array_get(&file->metadata, &count);
742 uoff_t dbox_file_get_plaintext_size(struct dbox_file *file)
747 i_assert(file->metadata_read_offset == file->cur_offset);
750 value = dbox_file_metadata_get(file, DBOX_METADATA_PHYSICAL_SIZE);
755 return file->cur_physical_size;
773 int dbox_file_unlink(struct dbox_file *file)
778 path = file->primary_path;
781 mail_storage_set_critical(&file->storage->storage,
785 if (file->alt_path == NULL || alt) {
791 path = file->alt_path;