mailbox-log.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "eacces-error.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mailbox-log.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <stdio.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <unistd.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <fcntl.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/stat.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen/* How often to reopen the log file to make sure that the changes are written
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen to the latest file. The main problem here is if the value is too high the
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen changes could be written to a file that was already rotated and deleted.
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen That wouldn't happen in any real world situations though, since the file
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen rotation time is probably measured in months or years. Still, each session
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen rarely writes anything here, so the value can just as well be a pretty small
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen one without any performance problems. */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#define MAILBOX_LOG_REOPEN_SECS (60)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#define MAILBOX_LOG_ROTATE_SIZE (1024*4)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainenstruct mailbox_log {
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen char *filepath, *filepath2;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen int fd;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen time_t open_timestamp;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen mode_t mode;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen gid_t gid;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen char *gid_origin;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen};
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainenstruct mailbox_log_iter {
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen struct mailbox_log *log;
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen int fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *filepath;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen struct mailbox_log_record buf[128];
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen unsigned int idx, count;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen uoff_t offset;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen bool failed;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen};
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void mailbox_log_close(struct mailbox_log *log);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstruct mailbox_log *mailbox_log_alloc(const char *path)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct mailbox_log *log;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen log = i_new(struct mailbox_log, 1);
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainen log->filepath = i_strdup(path);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen log->filepath2 = i_strconcat(path, ".2", NULL);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen log->mode = 0644;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen log->gid = (gid_t)-1;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen log->fd = -1;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return log;
ff7257145f317d6ca44a9402427bb74c34b999a9Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_log_free(struct mailbox_log **_log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen struct mailbox_log *log = *_log;
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen *_log = NULL;
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen mailbox_log_close(log);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_free(log->gid_origin);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_free(log->filepath);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_free(log->filepath2);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_free(log);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen}
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenstatic void mailbox_log_close(struct mailbox_log *log)
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_close_fd_path(&log->fd, log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainenvoid mailbox_log_set_permissions(struct mailbox_log *log, mode_t mode,
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen gid_t gid, const char *gid_origin)
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen log->mode = mode;
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen log->gid = gid;
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen i_free(log->gid_origin);
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen log->gid_origin = i_strdup(gid_origin);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int mailbox_log_open(struct mailbox_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mode_t old_mode;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(log->fd == -1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->open_timestamp = ioloop_time;
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen log->fd = open(log->filepath, O_RDWR | O_APPEND);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (log->fd != -1)
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen return 0;
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen /* try to create it */
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen old_mode = umask(0666 ^ log->mode);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen log->fd = open(log->filepath, O_RDWR | O_APPEND | O_CREAT, 0666);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen umask(old_mode);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen if (log->fd == -1) {
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen if (errno != EACCES)
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen i_error("creat(%s) failed: %m", log->filepath);
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen else
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_error("%s", eacces_error_get("creat", log->filepath));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fchown(log->fd, (uid_t)-1, log->gid) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno != EPERM)
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_error("fchown(%s) failed: %m", log->filepath);
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen else {
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen i_error("%s", eperm_error_get_chgrp("fchown",
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen log->filepath, log->gid,
c3b36993785d9567a63bdad1933031060c9460cfTimo Sirainen log->gid_origin));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic int mailbox_log_rotate_if_needed(struct mailbox_log *log)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct stat st;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (fstat(log->fd, &st) < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fstat(%s) failed: %m", log->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (st.st_size < MAILBOX_LOG_ROTATE_SIZE)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (rename(log->filepath, log->filepath2) < 0 && errno != ENOENT) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("rename(%s, %s) failed: %m",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen log->filepath, log->filepath2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mailbox_log_record_set_timestamp(struct mailbox_log_record *rec,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen time_t stamp)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cpu32_to_be_unaligned(stamp, rec->timestamp);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainentime_t mailbox_log_record_get_timestamp(const struct mailbox_log_record *rec)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen{
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return (time_t) be32_to_cpu_unaligned(rec->timestamp);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen}
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenint mailbox_log_append(struct mailbox_log *log,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen const struct mailbox_log_record *rec)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen{
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen struct stat st;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen ssize_t ret;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen /* we don't have to be too strict about appending to the latest log
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen file. the records' ordering doesn't matter and iteration goes
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen through both logs anyway. still, if there's a long running session
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen it shouldn't keep writing to a rotated log forever. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (log->open_timestamp/MAILBOX_LOG_REOPEN_SECS !=
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen ioloop_time/MAILBOX_LOG_REOPEN_SECS)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mailbox_log_close(log);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (log->fd == -1) {
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (mailbox_log_open(log) < 0)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen return -1;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_assert(log->fd != -1);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* We don't bother with locking, atomic appends will protect us.
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen If they don't (NFS), the worst that can happen is that a few
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen records get overwritten (because they're all the same size).
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen This whole log isn't supposed to be super-reliable anyway. */
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen ret = write(log->fd, rec, sizeof(*rec));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (ret < 0) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_error("write(%s) failed: %m", log->filepath);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen return -1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen } else if (ret != sizeof(*rec)) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_error("write(%s) wrote %d/%u bytes", log->filepath,
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen (int)ret, (unsigned int)sizeof(*rec));
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (fstat(log->fd, &st) == 0) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (ftruncate(log->fd, st.st_size - ret) < 0) {
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen i_error("ftruncate(%s) failed: %m",
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen log->filepath);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return -1;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen }
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)mailbox_log_rotate_if_needed(log);
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen return 0;
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen}
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool mailbox_log_iter_open_next(struct mailbox_log_iter *iter)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen i_close_fd_path(&iter->fd, iter->filepath);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (iter->filepath == NULL)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen iter->filepath = iter->log->filepath2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (iter->filepath == iter->log->filepath2)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter->filepath = iter->log->filepath;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter->fd = open(iter->filepath, O_RDONLY | O_APPEND);
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen if (iter->fd != -1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (errno == ENOENT) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (iter->filepath == iter->log->filepath2)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen return mailbox_log_iter_open_next(iter);
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen } else {
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen i_error("open(%s) failed: %m", iter->filepath);
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen iter->failed = TRUE;
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen }
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen return FALSE;
06fb99af33bd380b382d2d4f2994cf9a5bf0bbaeTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenstruct mailbox_log_iter *mailbox_log_iter_init(struct mailbox_log *log)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mailbox_log_iter *iter;
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter = i_new(struct mailbox_log_iter, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter->log = log;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen iter->fd = -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)mailbox_log_iter_open_next(iter);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return iter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenconst struct mailbox_log_record *
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenmailbox_log_iter_next(struct mailbox_log_iter *iter)
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen{
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen const struct mailbox_log_record *rec;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen uoff_t offset;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen ssize_t ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (iter->idx == iter->count) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (iter->fd == -1)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen return NULL;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
5529671faac3c5672a948be93091056736c7afffTimo Sirainen ret = pread(iter->fd, iter->buf, sizeof(iter->buf),
5529671faac3c5672a948be93091056736c7afffTimo Sirainen iter->offset);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen if (ret < 0) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen i_error("pread(%s) failed: %m", iter->filepath);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen iter->failed = TRUE;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return NULL;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (ret == 0) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (!mailbox_log_iter_open_next(iter))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen iter->idx = iter->count = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen iter->offset = 0;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen return mailbox_log_iter_next(iter);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen iter->idx = 0;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen iter->count = ret / sizeof(iter->buf[0]);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen iter->offset += iter->count * sizeof(iter->buf[0]);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen }
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen rec = &iter->buf[iter->idx++];
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (rec->type < MAILBOX_LOG_RECORD_DELETE_MAILBOX ||
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen rec->type > MAILBOX_LOG_RECORD_UNSUBSCRIBE) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen offset = iter->offset -
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen (iter->count - iter->idx) * sizeof(iter->buf[0]);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen i_error("Corrupted mailbox log %s at offset %"PRIuUOFF_T": "
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen "type=%d", iter->filepath, offset, rec->type);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unlink(iter->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return NULL;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mailbox_log_iter_deinit(struct mailbox_log_iter **_iter)
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mailbox_log_iter *iter = *_iter;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = iter->failed ? -1 : 0;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_iter = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_close_fd_path(&iter->fd, iter->filepath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(iter);
6d25922a089626f5535d51358e33d3337783a410Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen