From 5f3e6ed2e624b80d5b6f587685de139057c1f682 Mon Sep 17 00:00:00 2001 From: Brad Arant Date: Mon, 7 Sep 2026 02:29:16 +0000 Subject: [PATCH] Log MailFolder save failures instead of failing silently std::ofstream does not throw on a failed open, so a permissions or disk-full problem writing .imapindex/.uidnext/.uidvalidity previously just... did not happen, with no trace anywhere. Confirmed live: the barant accounts inbox and Trash index files were root-owned mode 644 while the mail service runs as a non-root user, so every flag/counter persist attempt (marking a message \Seen, for instance) silently failed for weeks - the in-memory session reflected the change for that one connection, but nothing ever reached disk, so any fresh IMAP session saw the old state again. Ownership fixed directly on the affected files; this logs the failure mode so a recurrence is visible. --- MailFolder.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MailFolder.cpp b/MailFolder.cpp index c206ce8..45f004c 100644 --- a/MailFolder.cpp +++ b/MailFolder.cpp @@ -1,4 +1,5 @@ #include "MailFolder.h" +#include "Log.h" #include #include #include @@ -47,6 +48,15 @@ namespace mail { void writeCounterFile(const std::string &path, uint32_t value) { std::ofstream out(path, std::ios::trunc); out << value; + // ofstream doesn't throw on a failed open (e.g. a permissions + // problem, a full/read-only filesystem) - confirmed live: two + // pre-existing mailbox index files were root-owned mode 644 + // while the mail service runs as a non-root user, so every + // counter/flag persist attempt failed here completely silently + // for weeks. Logging it is the only way this becomes visible + // instead of just quietly not happening. + if (!out) + coreutils::Log(coreutils::LOG_EXCEPT) << "MailFolder: failed to write " << path << " - check ownership/permissions."; } } @@ -160,9 +170,15 @@ namespace mail { writeCounterFile(path + "/.uidvalidity", mUidValidity); writeCounterFile(path + "/.uidnext", mUidNext); std::ofstream out(path + "/.imapindex", std::ios::trunc); + if (!out) { + coreutils::Log(coreutils::LOG_EXCEPT) << "MailFolder: failed to open " << path << "/.imapindex for writing - flag/message changes will not persist. Check ownership/permissions."; + return; + } for (const Message &message : mMessages) out << message.fileName << " " << message.uid << " " << (long long)message.internalDate << " " << joinFlags(message.flags) << "\n"; + if (!out) + coreutils::Log(coreutils::LOG_EXCEPT) << "MailFolder: write to " << path << "/.imapindex failed partway through - index may be incomplete."; } uint32_t MailFolder::seq(uint32_t uid) const {