static void test_compress_file(const char *in_path, const char *out_path) { const struct compression_handler *handler; struct istream *input, *file_input; struct ostream *output, *file_output; int fd_in, fd_out; struct sha1_ctxt sha1; unsigned char output_sha1[SHA1_RESULTLEN], input_sha1[SHA1_RESULTLEN]; const unsigned char *data; size_t size; ssize_t ret; handler = compression_lookup_handler_from_ext(out_path); if (handler == NULL) i_fatal("Can't detect compression algorithm from path %s", out_path); if (handler->create_ostream == NULL) i_fatal("Support not compiled in for %s", handler->name); /* write the compressed output file */ fd_in = open(in_path, O_RDONLY); if (fd_in == -1) i_fatal("open(%s) failed: %m", in_path); fd_out = open(out_path, O_TRUNC | O_CREAT | O_RDWR, 0600); if (fd_out == -1) i_fatal("creat(%s) failed: %m", out_path); sha1_init(&sha1); file_output = o_stream_create_fd_file(fd_out, 0, FALSE); output = handler->create_ostream(file_output, 1); input = i_stream_create_fd_autoclose(&fd_in, IO_BLOCK_SIZE); while (i_stream_read_data(input, &data, &size, 0) > 0) { sha1_loop(&sha1, data, size); o_stream_nsend(output, data, size); i_stream_skip(input, size); } if (o_stream_nfinish(output) < 0) { i_fatal("write(%s) failed: %s", out_path, o_stream_get_error(output)); } i_stream_destroy(&input); o_stream_destroy(&output); o_stream_destroy(&file_output); sha1_result(&sha1, output_sha1); /* verify that we can read the compressed file */ sha1_init(&sha1); file_input = i_stream_create_fd(fd_out, IO_BLOCK_SIZE, FALSE); input = handler->create_istream(file_input, FALSE); while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) { sha1_loop(&sha1, data, size); i_stream_skip(input, size); } i_stream_destroy(&input); i_stream_destroy(&file_input); sha1_result(&sha1, input_sha1); if (memcmp(input_sha1, output_sha1, sizeof(input_sha1)) != 0) i_fatal("Decompression couldn't get the original input"); i_close_fd(&fd_out); }
void dbox_save_end(struct dbox_save_context *ctx) { struct mail_save_data *mdata = &ctx->ctx.data; struct ostream *dbox_output = ctx->dbox_output; if (mdata->attach != NULL && !ctx->failed) { if (index_attachment_save_finish(&ctx->ctx) < 0) ctx->failed = TRUE; } if (o_stream_nfinish(mdata->output) < 0) { mail_storage_set_critical(ctx->ctx.transaction->box->storage, "write(%s) failed: %m", o_stream_get_name(mdata->output)); ctx->failed = TRUE; } if (mdata->output != dbox_output) { if (mdata->output != NULL) { /* e.g. zlib plugin had changed this */ o_stream_ref(dbox_output); o_stream_destroy(&mdata->output); mdata->output = dbox_output; } else { i_assert(ctx->failed); } } index_mail_cache_parse_deinit(ctx->ctx.dest_mail, ctx->ctx.data.received_date, !ctx->failed); }
static int mail_index_recreate(struct mail_index *index) { struct mail_index_map *map = index->map; struct ostream *output; unsigned int base_size; const char *path; int ret = 0, fd; i_assert(!MAIL_INDEX_IS_IN_MEMORY(index)); i_assert(map->hdr.indexid == index->indexid); i_assert((map->hdr.flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) == 0); i_assert(index->indexid != 0); fd = mail_index_create_tmp_file(index, index->filepath, &path); if (fd == -1) return -1; output = o_stream_create_fd_file(fd, 0, FALSE); o_stream_cork(output); base_size = I_MIN(map->hdr.base_header_size, sizeof(map->hdr)); o_stream_nsend(output, &map->hdr, base_size); o_stream_nsend(output, CONST_PTR_OFFSET(map->hdr_base, base_size), map->hdr.header_size - base_size); o_stream_nsend(output, map->rec_map->records, map->rec_map->records_count * map->hdr.record_size); o_stream_nflush(output); if (o_stream_nfinish(output) < 0) { mail_index_file_set_syscall_error(index, path, "write()"); ret = -1; } o_stream_destroy(&output); if (ret == 0 && index->fsync_mode != FSYNC_MODE_NEVER) { if (fdatasync(fd) < 0) { mail_index_file_set_syscall_error(index, path, "fdatasync()"); ret = -1; } } if (close(fd) < 0) { mail_index_file_set_syscall_error(index, path, "close()"); ret = -1; } if ((index->flags & MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS) != 0) (void)mail_index_create_backup(index); if (ret == 0 && rename(path, index->filepath) < 0) { mail_index_set_error(index, "rename(%s, %s) failed: %m", path, index->filepath); ret = -1; } if (ret < 0) i_unlink(path); return ret; }
static void test_write_read_v2(void) { test_begin("test_write_read_v2"); unsigned char payload[IO_BLOCK_SIZE*10]; const unsigned char *ptr; size_t pos = 0, siz; random_fill_weak(payload, IO_BLOCK_SIZE*10); buffer_t *buf = buffer_create_dynamic(default_pool, sizeof(payload)); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "aes-256-gcm-sha256", test_v1_kp.pub, IO_STREAM_ENC_INTEGRITY_AEAD); o_stream_nsend(os_2, payload, sizeof(payload)); test_assert(o_stream_nfinish(os_2) == 0); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); o_stream_unref(&os); o_stream_unref(&os_2); struct istream *is = test_istream_create_data(buf->data, buf->used); /* test regression where read fails due to incorrect behaviour when buffer is full before going to decrypt code */ i_stream_set_max_buffer_size(is, 8192); i_stream_read(is); struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv); size_t offset = 0; test_istream_set_size(is, 0); test_istream_set_allow_eof(is, FALSE); while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) { if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); test_assert_idx(pos + siz <= sizeof(payload), pos); if (pos + siz > sizeof(payload)) break; test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos); i_stream_skip(is_2, siz); pos += siz; } test_assert(is_2->stream_errno == 0); if (is_2->stream_errno != 0) i_debug("error: %s", i_stream_get_error(is_2)); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
static void rawlog_proxy_destroy(struct rawlog_proxy *proxy) { if (proxy->in_output != NULL) { o_stream_uncork(proxy->in_output); if (o_stream_nfinish(proxy->in_output) < 0) { i_error("write(in) failed: %s", o_stream_get_error(proxy->in_output)); } o_stream_destroy(&proxy->in_output); } if (proxy->out_output != NULL) { o_stream_uncork(proxy->out_output); if (o_stream_nfinish(proxy->out_output) < 0) { i_error("write(out) failed: %s", o_stream_get_error(proxy->out_output)); } o_stream_destroy(&proxy->out_output); } if (proxy->client_io != NULL) io_remove(&proxy->client_io); if (proxy->server_io != NULL) io_remove(&proxy->server_io); if (proxy->to_flush != NULL) timeout_remove(&proxy->to_flush); o_stream_destroy(&proxy->client_output); o_stream_destroy(&proxy->server_output); if (close(proxy->client_in_fd) < 0) i_error("close(client_in_fd) failed: %m"); if (close(proxy->client_out_fd) < 0) i_error("close(client_out_fd) failed: %m"); if (close(proxy->server_fd) < 0) i_error("close(server_fd) failed: %m"); i_free(proxy); io_loop_stop(ioloop); }
static void test_write_read_v1_short(void) { test_begin("test_write_read_v1_short"); unsigned char payload[1]; const unsigned char *ptr; size_t pos = 0, siz; random_fill_weak(payload, 1); buffer_t *buf = buffer_create_dynamic(default_pool, 64); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v2_kp.pub, IO_STREAM_ENC_VERSION_1); o_stream_nsend(os_2, payload, sizeof(payload)); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); test_assert(os_2->stream_errno == 0); test_assert(o_stream_nfinish(os_2) == 0); test_assert(os_2->stream_errno == 0); o_stream_unref(&os); o_stream_unref(&os_2); struct istream *is = test_istream_create_data(buf->data, buf->used); struct istream *is_2 = i_stream_create_decrypt(is, test_v2_kp.priv); size_t offset = 0; test_istream_set_allow_eof(is, FALSE); test_istream_set_size(is, 0); while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) { if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); test_assert_idx(pos + siz <= sizeof(payload), pos); if (pos + siz > sizeof(payload)) break; test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos); i_stream_skip(is_2, siz); pos += siz; } test_assert(is_2->stream_errno == 0); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
static void auth_worker_send_reply(struct auth_worker_client *client, struct auth_request *request, string_t *str) { time_t cmd_duration = time(NULL) - client->cmd_start; const char *p; if (worker_restart_request) o_stream_nsend_str(client->output, "RESTART\n"); o_stream_nsend(client->output, str_data(str), str_len(str)); if (o_stream_nfinish(client->output) < 0 && request != NULL && cmd_duration > AUTH_WORKER_WARN_DISCONNECTED_LONG_CMD_SECS) { p = strchr(str_c(str), '\t'); p = p == NULL ? "BUG" : t_strcut(p+1, '\t'); i_warning("Auth master disconnected us while handling " "request for %s for %ld secs (result=%s)", request->user, (long)cmd_duration, p); } }
static void test_write_read_v1_empty(void) { const unsigned char *ptr; size_t siz; test_begin("test_write_read_v1_empty"); buffer_t *buf = buffer_create_dynamic(default_pool, 64); struct ostream *os = o_stream_create_buffer(buf); struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v1_kp.pub, IO_STREAM_ENC_VERSION_1); test_assert(o_stream_nfinish(os_2) == 0); if (os_2->stream_errno != 0) i_debug("error: %s", o_stream_get_error(os_2)); o_stream_unref(&os); o_stream_unref(&os_2); /* this should've been enough */ struct istream *is = test_istream_create_data(buf->data, buf->used); struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv); /* read should not fail */ test_istream_set_allow_eof(is, FALSE); test_istream_set_size(is, 0); size_t offset = 0; ssize_t ret; while ((ret = i_stream_read_data(is_2, &ptr, &siz, 0)) >= 0) { test_assert(ret == 0); if (offset == buf->used) test_istream_set_allow_eof(is, TRUE); else test_istream_set_size(is, ++offset); }; test_assert(is_2->stream_errno == 0); if (is_2->stream_errno != 0) i_debug("error: %s", i_stream_get_error(is_2)); i_stream_unref(&is); i_stream_unref(&is_2); buffer_free(&buf); test_end(); }
void sieve_tool_dump_binary_to (struct sieve_binary *sbin, const char *filename, bool hexdump) { struct ostream *dumpstream; if ( filename == NULL ) return; dumpstream = sieve_tool_open_output_stream(filename); if ( dumpstream != NULL ) { if ( hexdump ) (void) sieve_hexdump(sbin, dumpstream); else (void) sieve_dump(sbin, dumpstream, FALSE); if (o_stream_nfinish(dumpstream) < 0) { i_fatal("write(%s) failed: %s", filename, o_stream_get_error(dumpstream)); } o_stream_destroy(&dumpstream); } else { i_fatal("Failed to create stream for sieve code dump."); } }
static int astream_part_finish(struct attachment_istream *astream, const char **error_r) { struct attachment_istream_part *part = &astream->part; struct istream_attachment_info info; struct istream *input; struct ostream *output; string_t *digest_str; const unsigned char *data; size_t size; int ret = 0; if (o_stream_nfinish(part->temp_output) < 0) { *error_r = t_strdup_printf("write(%s) failed: %s", o_stream_get_name(part->temp_output), o_stream_get_error(part->temp_output)); return -1; } memset(&info, 0, sizeof(info)); info.start_offset = astream->part.start_offset; /* base64_bytes contains how many valid base64 bytes there are so far. if the base64 ends properly, it'll specify how much of the MIME part is saved as an attachment. the rest of the data (typically linefeeds) is added back to main stream */ info.encoded_size = part->base64_bytes; /* get the hash before base64-decoder resets it */ digest_str = t_str_new(128); hash_format_write(astream->set.hash_format, digest_str); info.hash = str_c(digest_str); /* if it looks like we can decode base64 without any data loss, do it and write the decoded data to another temp file. */ if (!part->base64_failed) { if (part->base64_state == BASE64_STATE_0 && part->base64_bytes > 0) { /* there is no trailing LF or '=' characters, but it's not completely empty */ part->base64_state = BASE64_STATE_EOM; } if (part->base64_state == BASE64_STATE_EOM) { /* base64 data looks ok. */ if (astream_decode_base64(astream) < 0) part->base64_failed = TRUE; } else { part->base64_failed = TRUE; } } /* open attachment output file */ info.part = astream->cur_part; if (!part->base64_failed) { info.base64_blocks_per_line = part->base64_line_blocks; info.base64_have_crlf = part->base64_have_crlf; /* base64-decoder updated the hash, use it */ str_truncate(digest_str, 0); hash_format_write(astream->set.hash_format, digest_str); info.hash = str_c(digest_str); } else { /* couldn't decode base64, so write the entire MIME part as attachment */ info.encoded_size = part->temp_output->offset; } if (astream->set.open_attachment_ostream(&info, &output, error_r, astream->context) < 0) return -1; /* copy data to attachment from temp file */ input = i_stream_create_fd(part->temp_fd, IO_BLOCK_SIZE); while (i_stream_read_more(input, &data, &size) > 0) { o_stream_nsend(output, data, size); i_stream_skip(input, size); } if (input->stream_errno != 0) { *error_r = t_strdup_printf("read(%s) failed: %s", i_stream_get_name(input), i_stream_get_error(input)); ret = -1; } i_stream_destroy(&input); if (astream->set.close_attachment_ostream(output, ret == 0, error_r, astream->context) < 0) ret = -1; return ret; }
static int astream_decode_base64(struct attachment_istream *astream) { struct attachment_istream_part *part = &astream->part; buffer_t *extra_buf = NULL; struct istream *input, *base64_input; struct ostream *output; const unsigned char *data; size_t size; ssize_t ret; buffer_t *buf; int outfd; bool failed = FALSE; if (part->base64_bytes < astream->set.min_size || part->temp_output->offset > part->base64_bytes + BASE64_ATTACHMENT_MAX_EXTRA_BYTES) { /* only a small part of the MIME part is base64-encoded. */ return -1; } if (part->base64_line_blocks == 0) { /* only one line of base64 */ part->base64_line_blocks = part->cur_base64_blocks; i_assert(part->base64_line_blocks > 0); } /* decode base64 data and write it to another temp file */ outfd = astream->set.open_temp_fd(astream->context); if (outfd == -1) return -1; buf = buffer_create_dynamic(default_pool, 1024); input = i_stream_create_fd(part->temp_fd, IO_BLOCK_SIZE); base64_input = i_stream_create_limit(input, part->base64_bytes); output = o_stream_create_fd_file(outfd, 0, FALSE); o_stream_cork(output); hash_format_reset(astream->set.hash_format); size_t bytes_needed = 1; while ((ret = i_stream_read_bytes(base64_input, &data, &size, bytes_needed)) > 0) { buffer_set_used_size(buf, 0); if (base64_decode(data, size, &size, buf) < 0) { i_error("istream-attachment: BUG: " "Attachment base64 data unexpectedly broke"); failed = TRUE; break; } i_stream_skip(base64_input, size); o_stream_nsend(output, buf->data, buf->used); hash_format_loop(astream->set.hash_format, buf->data, buf->used); bytes_needed = i_stream_get_data_size(base64_input) + 1; } if (ret != -1) { i_assert(failed); } else if (base64_input->stream_errno != 0) { i_error("istream-attachment: read(%s) failed: %s", i_stream_get_name(base64_input), i_stream_get_error(base64_input)); failed = TRUE; } if (o_stream_nfinish(output) < 0) { i_error("istream-attachment: write(%s) failed: %s", o_stream_get_name(output), o_stream_get_error(output)); failed = TRUE; } buffer_free(&buf); i_stream_unref(&base64_input); o_stream_unref(&output); if (input->v_offset != part->temp_output->offset && !failed) { /* write the rest of the data to the message stream */ extra_buf = buffer_create_dynamic(default_pool, 1024); while ((ret = i_stream_read_more(input, &data, &size)) > 0) { buffer_append(extra_buf, data, size); i_stream_skip(input, size); } i_assert(ret == -1); if (input->stream_errno != 0) { i_error("istream-attachment: read(%s) failed: %s", i_stream_get_name(input), i_stream_get_error(input)); failed = TRUE; } } i_stream_unref(&input); if (failed) { i_close_fd(&outfd); return -1; } /* successfully wrote it. switch to using it. */ o_stream_destroy(&part->temp_output); i_close_fd(&part->temp_fd); part->temp_fd = outfd; if (extra_buf != NULL) { stream_add_data(astream, extra_buf->data, extra_buf->used); buffer_free(&extra_buf); } return 0; }
int subsfile_set_subscribed(struct mailbox_list *list, const char *path, const char *temp_prefix, const char *name, bool set) { const struct mail_storage_settings *mail_set = list->mail_set; struct dotlock_settings dotlock_set; struct dotlock *dotlock; struct mailbox_permissions perm; const char *line, *dir, *fname, *escaped_name; struct istream *input = NULL; struct ostream *output; int fd_in, fd_out; enum mailbox_list_path_type type; bool found, changed = FALSE, failed = FALSE; unsigned int version = 2; if (strcasecmp(name, "INBOX") == 0) name = "INBOX"; memset(&dotlock_set, 0, sizeof(dotlock_set)); dotlock_set.use_excl_lock = mail_set->dotlock_use_excl; dotlock_set.nfs_flush = mail_set->mail_nfs_storage; dotlock_set.temp_prefix = temp_prefix; dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT; dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT; mailbox_list_get_root_permissions(list, &perm); fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); if (fd_out == -1 && errno == ENOENT) { /* directory hasn't been created yet. */ type = list->set.control_dir != NULL ? MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_DIR; fname = strrchr(path, '/'); if (fname != NULL) { dir = t_strdup_until(path, fname); if (mailbox_list_mkdir_root(list, dir, type) < 0) return -1; } fd_out = file_dotlock_open_group(&dotlock_set, path, 0, perm.file_create_mode, perm.file_create_gid, perm.file_create_gid_origin, &dotlock); } if (fd_out == -1) { if (errno == EAGAIN) { mailbox_list_set_error(list, MAIL_ERROR_TEMP, "Timeout waiting for subscription file lock"); } else { subswrite_set_syscall_error(list, "file_dotlock_open()", path); } return -1; } fd_in = nfs_safe_open(path, O_RDONLY); if (fd_in == -1 && errno != ENOENT) { subswrite_set_syscall_error(list, "open()", path); file_dotlock_delete(&dotlock); return -1; } if (fd_in != -1) { input = i_stream_create_fd_autoclose(&fd_in, list->mailbox_name_max_length+1); i_stream_set_return_partial_line(input, TRUE); subsfile_list_read_header(list, input, &version); } found = FALSE; output = o_stream_create_fd_file(fd_out, 0, FALSE); o_stream_cork(output); if (version >= 2) o_stream_send_str(output, version2_header); if (version < 2 || name[0] == '\0') escaped_name = name; else { const char *const *tmp; char separators[2]; string_t *str = t_str_new(64); separators[0] = mailbox_list_get_hierarchy_sep(list); separators[1] = '\0'; tmp = t_strsplit(name, separators); str_append_tabescaped(str, *tmp); for (tmp++; *tmp != NULL; tmp++) { str_append_c(str, '\t'); str_append_tabescaped(str, *tmp); } escaped_name = str_c(str); } if (input != NULL) { while ((line = next_line(list, path, input, &failed, FALSE)) != NULL) { if (strcmp(line, escaped_name) == 0) { found = TRUE; if (!set) { changed = TRUE; continue; } } o_stream_nsend_str(output, line); o_stream_nsend(output, "\n", 1); } i_stream_destroy(&input); } if (!failed && set && !found) { /* append subscription */ line = t_strconcat(escaped_name, "\n", NULL); o_stream_nsend_str(output, line); changed = TRUE; } if (changed && !failed) { if (o_stream_nfinish(output) < 0) { subswrite_set_syscall_error(list, "write()", path); failed = TRUE; } else if (mail_set->parsed_fsync_mode != FSYNC_MODE_NEVER) { if (fsync(fd_out) < 0) { subswrite_set_syscall_error(list, "fsync()", path); failed = TRUE; } } } else { o_stream_ignore_last_errors(output); } o_stream_destroy(&output); if (failed || !changed) { if (file_dotlock_delete(&dotlock) < 0) { subswrite_set_syscall_error(list, "file_dotlock_delete()", path); failed = TRUE; } } else { enum dotlock_replace_flags flags = DOTLOCK_REPLACE_FLAG_VERIFY_OWNER; if (file_dotlock_replace(&dotlock, flags) < 0) { subswrite_set_syscall_error(list, "file_dotlock_replace()", path); failed = TRUE; } } return failed ? -1 : (changed ? 1 : 0); }
static int maildir_save_finish_real(struct mail_save_context *_ctx) { struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx; struct mail_storage *storage = &ctx->mbox->storage->storage; const char *path; off_t real_size; uoff_t size; int output_errno; ctx->last_save_finished = TRUE; if (ctx->failed && ctx->fd == -1) { /* tmp file creation failed */ return -1; } path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->tmp_name, NULL); if (!ctx->failed && o_stream_nfinish(_ctx->data.output) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } ctx->failed = TRUE; } if (_ctx->data.save_date != (time_t)-1) { /* we can't change ctime, but we can add the date to cache */ struct index_mail *mail = (struct index_mail *)_ctx->dest_mail; uint32_t t = _ctx->data.save_date; index_mail_cache_add(mail, MAIL_CACHE_SAVE_DATE, &t, sizeof(t)); } if (maildir_save_finish_received_date(ctx, path) < 0) ctx->failed = TRUE; if (ctx->cur_dest_mail != NULL) { index_mail_cache_parse_deinit(ctx->cur_dest_mail, ctx->ctx.data.received_date, !ctx->failed); } i_stream_unref(&ctx->input); /* remember the size in case we want to add it to filename */ ctx->file_last->size = _ctx->data.output->offset; if (ctx->cur_dest_mail == NULL || mail_get_virtual_size(ctx->cur_dest_mail, &ctx->file_last->vsize) < 0) ctx->file_last->vsize = (uoff_t)-1; output_errno = _ctx->data.output->last_failed_errno; o_stream_destroy(&_ctx->data.output); if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER && !ctx->failed) { if (fsync(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "fsync(%s) failed: %m", path); } ctx->failed = TRUE; } } real_size = lseek(ctx->fd, 0, SEEK_END); if (real_size == (off_t)-1) { mail_storage_set_critical(storage, "lseek(%s) failed: %m", path); } else if (real_size != (off_t)ctx->file_last->size && (!maildir_filename_get_size(ctx->file_last->dest_basename, MAILDIR_EXTRA_FILE_SIZE, &size) || size != ctx->file_last->size)) { /* e.g. zlib plugin was used. the "physical size" must be in the maildir filename, since stat() will return wrong size */ ctx->file_last->preserve_filename = FALSE; /* preserve the GUID if needed */ if (ctx->file_last->guid == NULL) ctx->file_last->guid = ctx->file_last->dest_basename; /* reset the base name as well, just in case there's a ,W=vsize */ ctx->file_last->dest_basename = ctx->file_last->tmp_name; } if (close(ctx->fd) < 0) { if (!mail_storage_set_error_from_errno(storage)) { mail_storage_set_critical(storage, "close(%s) failed: %m", path); } ctx->failed = TRUE; } ctx->fd = -1; if (ctx->failed) { /* delete the tmp file */ i_unlink_if_exists(path); errno = output_errno; if (ENOQUOTA(errno)) { mail_storage_set_error(storage, MAIL_ERROR_NOQUOTA, MAIL_ERRSTR_NO_QUOTA); } else if (errno != 0) { mail_storage_set_critical(storage, "write(%s) failed: %m", path); } maildir_save_remove_last_filename(ctx); return -1; } ctx->file_last = NULL; return 0; }