bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void sdbox_file_init_paths(struct sdbox_file *file, const char *fname)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen i_strdup_printf("%s/%s", mailbox_get_path(box), fname);
d1808f883d0da0e9740616695618924e8278fce1Timo Sirainen file->file.cur_path = file->file.primary_path;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_ALT_MAILBOX,
686bc4ea97a86333316182865be3fcfe465a5827Timo Sirainen file->file.alt_path = i_strdup_printf("%s/%s", alt_path, fname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct dbox_file *sdbox_file_init(struct sdbox_mailbox *mbox, uint32_t uid)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fname = t_strdup_printf(SDBOX_MAIL_FILE_FORMAT, uid);
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen sdbox_file_init_paths(file, dbox_generate_tmp_filename());
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenstruct dbox_file *sdbox_file_create(struct sdbox_mailbox *mbox)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen file_create_fd(file, file->primary_path, FALSE);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)file;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint sdbox_file_get_attachments(struct dbox_file *file, const char **extrefs_r)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* read the metadata */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* corrupted file. we're deleting it anyway. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen line = dbox_file_metadata_get(file, DBOX_METADATA_EXT_REF);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* no attachments */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainensdbox_file_attachment_relpath(struct sdbox_file *file, const char *srcpath)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *p;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "sdbox attachment path in invalid format: %s", srcpath);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen p == NULL ? srcpath : t_strdup_until(srcpath, p),
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int sdbox_file_rename_attachments(struct sdbox_file *file)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_storage *storage = file->file.storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen array_foreach(&file->attachment_paths, pathp) T_BEGIN {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen src = t_strdup_printf("%s/%s", storage->attachment_dir, *pathp);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen dest = t_strdup_printf("%s/%s", storage->attachment_dir,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen src_file = fs_file_init(storage->attachment_fs, src,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen dest_file = fs_file_init(storage->attachment_fs, dest,
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&file->mbox->box, "%s",
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainenint sdbox_file_assign_uid(struct sdbox_file *file, uint32_t uid,
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen const char *p, *old_path, *dir, *new_fname, *new_path;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen new_fname = t_strdup_printf(SDBOX_MAIL_FILE_FORMAT, uid);
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen new_path = t_strdup_printf("%s/%s", dir, new_fname);
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen if (!ignore_if_exists && stat(new_path, &st) == 0) {
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen "sdbox: %s already exists, rebuilding index", new_path);
dbc6f14323a634ce39f15dd7fef9ee773551dcf0Timo Sirainen sdbox_set_mailbox_corrupted(&file->mbox->box);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi "rename(%s, %s) failed: %m",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (array_is_created(&file->attachment_paths)) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic int sdbox_file_unlink_aborted_save_attachments(struct sdbox_file *file)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_storage *storage = file->file.storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen array_foreach(&file->attachment_paths, pathp) T_BEGIN {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* we don't know if we aborted before renaming this attachment,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen so try deleting both source and dest path. the source paths
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen point to temporary files (not to source messages'
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen attachment paths), so it's safe to delete them. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = t_strdup_printf("%s/%s", storage->attachment_dir,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&file->mbox->box, "%s",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = t_strdup_printf("%s/%s", storage->attachment_dir,
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen fs_file = fs_file_init(fs, path, FS_OPEN_MODE_READONLY);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(&file->mbox->box, "%s",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint sdbox_file_unlink_aborted_save(struct sdbox_file *file)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "unlink(%s) failed: %m", file->file.cur_path);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (array_is_created(&file->attachment_paths)) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (sdbox_file_unlink_aborted_save_attachments(file) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint sdbox_file_create_fd(struct dbox_file *file, const char *path, bool parents)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct sdbox_file *sfile = (struct sdbox_file *)file;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen const struct mailbox_permissions *perm = mailbox_get_permissions(box);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen old_mask = umask(0666 & ~perm->file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (mkdir_parents_chgrp(dir, perm->dir_create_mode,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* try again */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen old_mask = umask(0666 & ~perm->file_create_mode);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
d4002fe1f64d25a792f76fb102ef7dc519cd4e24Martti Rannanjärvi mailbox_set_critical(box, "open(%s, O_CREAT) failed: %m", path);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } else if (perm->file_create_gid == (gid_t)-1) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* no group change */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen } else if (fchown(fd, (uid_t)-1, perm->file_create_gid) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "fchown(%s, -1, %ld) failed: %m",
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* continue anyway */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainenint sdbox_file_move(struct dbox_file *file, bool alt_path)
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen struct mail_storage *storage = &file->storage->storage;
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen const char *dest_dir, *temp_path, *dest_path, *p;
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen if (stat(file->cur_path, &st) < 0 && errno == ENOENT) {
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* already expunged/moved by another session */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen dest_path = !alt_path ? file->primary_path : file->alt_path;
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen temp_path = t_strdup_printf("%s/%s", dest_dir,
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* first copy the file. make sure to catch every possible error
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen since we really don't want to break the file. */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen out_fd = file->storage->v.file_create_fd(file, temp_path, TRUE);
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen output = o_stream_create_fd_file(out_fd, 0, FALSE);
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen mail_storage_set_critical(storage, "write(%s) failed: %s",
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER && ret == 0) {
cf77eee4f485c152886e12bc3aa288da81c68532Timo Sirainen /* preserve the original atime/mtime. this isn't necessary for Dovecot,
cf77eee4f485c152886e12bc3aa288da81c68532Timo Sirainen but could be useful for external reasons. */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* the temp file was successfully written. rename it now to the
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen destination file. the destination shouldn't exist, but if it does
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen its contents should be the same (except for maybe older metadata) */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen "rename(%s, %s) failed: %m", temp_path, dest_path);
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen if (storage->set->parsed_fsync_mode != FSYNC_MODE_NEVER) {
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen dbox_file_set_syscall_error(file, "unlink()");
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* configuration problem? revert the write */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* who knows what happened to the file. keep both just to be
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen sure both won't get deleted. */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen /* file was successfully moved - reopen it */
c2d2161296e2361f97ee48b70b168602157069e6Timo Sirainen "dbox_file_move(%s): reopening file failed", dest_path);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainensdbox_unlink_attachments(struct sdbox_file *sfile,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const ARRAY_TYPE(mail_attachment_extref) *extrefs)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct dbox_storage *storage = sfile->file.storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen path = sdbox_file_attachment_relpath(sfile, extref->path);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (index_attachment_delete(&storage->storage,
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenint sdbox_file_unlink_with_attachments(struct sdbox_file *sfile)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = sdbox_file_get_attachments(&sfile->file, &extrefs_line);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* no attachments */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen pool = pool_alloconly_create("sdbox attachments unlink", 1024);
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen if (!index_attachment_parse_extrefs(extrefs_line, pool, &extrefs)) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen i_warning("%s: Ignoring corrupted extref: %s",
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* try to delete the file first, so if it fails we don't have
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen missing attachments */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = dbox_file_unlink(&sfile->file)) >= 0)