Explicitly close all AutoFiles that have been written

There is no way to report a close error from `AutoFile` destructor.
Such an error could be serious if the file has been written to because
it may mean the file is now corrupted (same as if write fails).

So, change all users of `AutoFile` that use it to write data to
explicitly close the file and handle a possible error.
This commit is contained in:
Vasil Dimov
2024-01-24 15:03:55 +01:00
parent a69c4098b2
commit 8bb34f07df
15 changed files with 121 additions and 38 deletions

View File

@@ -33,6 +33,7 @@
#include <util/fs.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/syserror.h>
#include <util/translation.h>
#include <validation.h>
@@ -941,13 +942,13 @@ bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationSt
return false;
}
// Open history file to append
AutoFile file{OpenUndoFile(pos)};
if (file.IsNull()) {
LogError("OpenUndoFile failed for %s while writing block undo", pos.ToString());
return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
}
{
// Open history file to append
AutoFile file{OpenUndoFile(pos)};
if (file.IsNull()) {
LogError("OpenUndoFile failed for %s while writing block undo", pos.ToString());
return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
}
BufferedWriter fileout{file};
// Write index header
@@ -960,8 +961,13 @@ bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationSt
// Write undo data & checksum
fileout << blockundo << hasher.GetHash();
}
// BufferedWriter will flush pending data to file when fileout goes out of scope.
}
fileout.flush(); // Make sure `AutoFile`/`BufferedWriter` go out of scope before we call `FlushUndoFile`
// Make sure that the file is closed before we call `FlushUndoFile`.
if (file.fclose() != 0) {
LogError("Failed to close block undo file %s: %s", pos.ToString(), SysErrorString(errno));
return FatalError(m_opts.notifications, state, _("Failed to close block undo file."));
}
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
@@ -1094,13 +1100,22 @@ FlatFilePos BlockManager::WriteBlock(const CBlock& block, int nHeight)
m_opts.notifications.fatalError(_("Failed to write block."));
return FlatFilePos();
}
BufferedWriter fileout{file};
{
BufferedWriter fileout{file};
// Write index header
fileout << GetParams().MessageStart() << block_size;
pos.nPos += STORAGE_HEADER_BYTES;
// Write block
fileout << TX_WITH_WITNESS(block);
}
if (file.fclose() != 0) {
LogError("Failed to close block file %s: %s", pos.ToString(), SysErrorString(errno));
m_opts.notifications.fatalError(_("Failed to close file when writing block."));
return FlatFilePos();
}
// Write index header
fileout << GetParams().MessageStart() << block_size;
pos.nPos += STORAGE_HEADER_BYTES;
// Write block
fileout << TX_WITH_WITNESS(block);
return pos;
}
@@ -1143,6 +1158,11 @@ static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
#endif
)};
xor_key_file << xor_key;
if (xor_key_file.fclose() != 0) {
throw std::runtime_error{strprintf("Error closing XOR key file %s: %s",
fs::PathToString(xor_key_path),
SysErrorString(errno))};
}
}
// If the user disabled the key, it must be zero.
if (!opts.use_xor && xor_key != decltype(xor_key){}) {