mail-index-compress.c revision 3c7a9aa32ddc1a930a75681a6c3cafb8d10fe810
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "write-full.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "mail-index.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-data.h"
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen#include "mail-index-util.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen#include <stdio.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenint mail_index_compress(MailIndex *index)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen MailIndexRecord *rec, *hole_rec, *end_rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen size_t fsize;
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen if (index->header->first_hole_position == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we don't need to compress after all. shouldn't happen.. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->header->flags &= ~MAIL_INDEX_FLAG_CACHE_FIELDS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (!mail_index_verify_hole_range(index))
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen return FALSE;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* if we get interrupted, the whole index is probably corrupted.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so keep rebuild-flag on while doing this */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mail_index_fmsync(index, sizeof(MailIndexHeader)))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* first actually compress the data */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen end_rec = (MailIndexRecord *) ((char *) index->mmap_base +
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen index->mmap_length);
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen hole_rec = (MailIndexRecord *) ((char *) index->mmap_base +
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen index->header->first_hole_position);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen rec = hole_rec + index->header->first_hole_records;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen while (rec < end_rec) {
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen if (rec->uid != 0) {
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen memcpy(hole_rec, rec, sizeof(MailIndexRecord));
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen hole_rec++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec++;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* truncate the file to get rid of the extra records */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen fsize = (size_t) ((char *) hole_rec - (char *) index->mmap_base);
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen if (ftruncate(index->fd, (off_t)fsize) == -1) {
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen index_set_error(index, "ftruncate() failed for %s: %m",
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen index->filepath);
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen return FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen /* update headers */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen index->header->first_hole_position = 0;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen index->header->first_hole_records = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* make sure the whole file is synced before removing rebuild-flag */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!mail_index_fmsync(index, fsize))
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen index->header->flags &= ~(MAIL_INDEX_FLAG_CACHE_FIELDS |
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen MAIL_INDEX_FLAG_REBUILD);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return TRUE;
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen}
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int mail_index_copy_data(MailIndex *index, int fd, const char *path)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen MailIndexDataHeader data_hdr;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen MailIndexRecord *rec;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen unsigned char *mmap_data;
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen size_t mmap_data_size;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen uoff_t offset;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen mmap_data = mail_index_data_get_mmaped(index->data, &mmap_data_size);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mmap_data == NULL)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* write data header */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen memset(&data_hdr, 0, sizeof(data_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen data_hdr.indexid = index->indexid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (write_full(fd, &data_hdr, sizeof(data_hdr)) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_set_error(index, "Error writing to temp index data "
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen "%s: %m", path);
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen return FALSE;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen }
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen /* no we'll begin the actual moving. keep rebuild-flag on
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen while doing it. */
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen index->header->flags |= MAIL_INDEX_FLAG_REBUILD;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen if (!mail_index_fmsync(index, sizeof(MailIndexHeader)))
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return FALSE;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen offset = sizeof(data_hdr);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen rec = index->lookup(index, 1);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen while (rec != NULL) {
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (rec->data_position + rec->data_size > mmap_data_size) {
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen index_set_error(index, "Error in index file %s: "
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen "data_position+data_size points "
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen "outside file", index->filepath);
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return FALSE;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (write_full(fd, mmap_data + rec->data_position,
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen rec->data_size) < 0) {
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen index_set_error(index, "Error writing to temp index "
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen "data %s: %m", path);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen return FALSE;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen rec->data_position = offset;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen offset += rec->data_size;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec = index->next(index, rec);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return TRUE;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen}
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainenint mail_index_compress_data(MailIndex *index)
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen{
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen const char *temppath, *datapath;
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen int fd;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen /* write the data into temporary file updating the offsets in index
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen while doing it. if we fail (especially if out of disk space/quota)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen we'll simply fail and index is rebuilt later */
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return FALSE;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen fd = mail_index_create_temp_file(index, &temppath);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (fd == -1)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen return FALSE;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (!mail_index_copy_data(index, fd, temppath)) {
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen (void)close(fd);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen (void)unlink(temppath);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return FALSE;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* now, close the old data file and rename the temp file into
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen new data file */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen mail_index_data_free(index->data);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen (void)close(fd);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen datapath = t_strconcat(index->filepath, DATA_FILE_PREFIX, NULL);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (rename(temppath, datapath) < 0) {
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen index_set_error(index, "rename(%s, %s) failed: %m",
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen temppath, datapath);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return FALSE;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen }
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* make sure the whole file is synced before removing rebuild-flag */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (!mail_index_fmsync(index, index->mmap_length))
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return FALSE;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen index->header->flags &= ~(MAIL_INDEX_FLAG_CACHE_FIELDS |
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen MAIL_INDEX_FLAG_REBUILD);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen return mail_index_data_open(index);
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen