Close package fs review findings: readRange bounds, picker ext, non-ASCII tests
Cap readRange's allocation and reject size_t overflow instead of truncating; re-append .rsbank when the export picker omits it; add cafe coverage for writeFileExclusive and writeLandedFile; loop write() on EINTR.
This commit is contained in:
@@ -293,11 +293,22 @@ static void testWriteFileExclusiveRefusesAnOccupiedPath() {
|
||||
CHECK(writeFileExclusive(path, PayloadBuffer(mine)));
|
||||
CHECK(readAll(path) == mine);
|
||||
// The create IS the check: a second call cannot replace the first file's bytes.
|
||||
// (this pins the refusal, not O_EXCL's atomicity — a genuine race isn't portable)
|
||||
CHECK(!writeFileExclusive(path, PayloadBuffer(patternBytes(9, 8))));
|
||||
CHECK(readAll(path) == mine);
|
||||
CHECK(!writeFileExclusive("pkg_io_excl_empty.bin", PayloadBuffer{}));
|
||||
CHECK(!exists("pkg_io_excl_empty.bin"));
|
||||
removeQuietly(path);
|
||||
|
||||
// writeFileExclusive is the one call site using the wstring()/c_str() Windows
|
||||
// open form rather than the fstream(fs::path) overload every other test here
|
||||
// exercises — the only conversion whose reversion this file would otherwise miss.
|
||||
const std::string cafePath = "pkg_io_excl_caf\xC3\xA9.bin";
|
||||
const std::vector<std::uint8_t> cafeBytes = patternBytes(6, 4);
|
||||
CHECK(writeFileExclusive(cafePath, PayloadBuffer(cafeBytes)));
|
||||
CHECK(readAll(cafePath) == cafeBytes);
|
||||
CHECK(!writeFileExclusive(cafePath, PayloadBuffer(patternBytes(3, 9))));
|
||||
removeQuietly(cafePath);
|
||||
}
|
||||
|
||||
static void testListFolderFileNames() {
|
||||
|
||||
@@ -22,7 +22,7 @@ static int g_fail = 0;
|
||||
|
||||
// The journal records absolute paths, so every expectation is built the same way.
|
||||
static std::string scratch(const std::string& name) {
|
||||
return (fs::current_path() / utf8Path(name)).u8string();
|
||||
return pathToUtf8(fs::current_path() / utf8Path(name));
|
||||
}
|
||||
|
||||
static std::vector<std::uint8_t> patternBytes(std::size_t n, std::uint8_t seed) {
|
||||
@@ -64,6 +64,18 @@ static void testLandRecordsOnSuccessOnly() {
|
||||
CHECK(!exists(path)); // the recorded path denoted the file we asked for
|
||||
}
|
||||
|
||||
static void testLandNonAsciiPathRoundTripsAsUtf8() {
|
||||
// The fs::absolute -> u8string round trip at writeLandedFile is otherwise
|
||||
// untested with a non-ASCII path.
|
||||
LandedFileJournal journal;
|
||||
const std::string path = scratch("rb_caf\xC3\xA9.bin");
|
||||
const std::vector<std::uint8_t> bytes = patternBytes(16, 2);
|
||||
CHECK(journal.writeLandedFile(path, PayloadBuffer(bytes)));
|
||||
CHECK(readAll(path) == bytes);
|
||||
journal.rollback();
|
||||
CHECK(!exists(path));
|
||||
}
|
||||
|
||||
static void testRelativeInputIsRecordedAbsolute() {
|
||||
// The hazard: a bare name recorded verbatim, then a CWD change, and rollback
|
||||
// unlinks whatever now sits at that name in the new directory.
|
||||
@@ -169,6 +181,7 @@ static void testIndexCommitDisarmsRollback() {
|
||||
|
||||
int main() {
|
||||
testLandRecordsOnSuccessOnly();
|
||||
testLandNonAsciiPathRoundTripsAsUtf8();
|
||||
testRelativeInputIsRecordedAbsolute();
|
||||
testExistingDestinationRefusedUntouched();
|
||||
testEmptyPayloadRefused();
|
||||
|
||||
Reference in New Issue
Block a user