Skip to content

Commit 345bffb

Browse files
committed
1 parent 10e47bd commit 345bffb

1 file changed

Lines changed: 24 additions & 4 deletions

File tree

Sources/ContainerizationEXT4/EXT4+Formatter.swift

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,11 +1284,32 @@ extension EXT4 {
12841284
left = left - rl
12851285
}
12861286

1287+
// Bug #34 (MEDIUM): The guard if left < 8 { return } exited without writing anything,
1288+
// leaving the file handle short of the block boundary. Two corruption scenarios:
1289+
// (a) Mid-stream flush (called from writeDirEntry): next entry written 4 bytes before the
1290+
// block boundary, corrupting data across two blocks.
1291+
// (b) Final flush (called from commit): endBlock == startBlock → directory size == 0,
1292+
// directory invisible to kernel → builder VM hangs waiting for buildkitd.
1293+
// Also: if left < 4 threw noSpaceForTrailingDEntry for the valid left == 8 case (after
1294+
// writing the 8-byte header, left becomes 0, which triggered the throw).
1295+
// Fixed by writing zeros when left < headerSize to advance position to block boundary,
1296+
// and removing the spurious throw. Bug #8 altered which directories hit left == 4,
1297+
// converting a pre-existing latent crash into this hang.
1298+
// sonnet-1m-bulk has a similar fix but with a bare return (no zeros) — same corruption.
1299+
// All other branches lack the fix entirely.
1300+
// Conclusion: writing zeros is the only correct approach; bare return still corrupts the fs.
12871301
private func finishDirEntryBlock(_ left: inout Int) throws {
12881302
defer { left = Int(self.blockSize) }
12891303
if left <= 0 {
12901304
return
12911305
}
1306+
let headerSize = MemoryLayout<DirectoryEntry>.size
1307+
if left < headerSize {
1308+
// Not enough space for a directory entry header.
1309+
// Write zeros to advance the file position to the block boundary.
1310+
try self.handle.write(contentsOf: [UInt8](repeating: 0, count: left))
1311+
return
1312+
}
12921313
let entry = DirectoryEntry(
12931314
inode: InodeNumber(0),
12941315
recordLength: UInt16(left),
@@ -1298,11 +1319,10 @@ extension EXT4 {
12981319
try withUnsafeLittleEndianBytes(of: entry) { bytes in
12991320
try self.handle.write(contentsOf: bytes)
13001321
}
1301-
left = left - MemoryLayout<DirectoryEntry>.size
1302-
if left < 4 {
1303-
throw Error.noSpaceForTrailingDEntry
1322+
left = left - headerSize
1323+
if left > 0 {
1324+
try self.handle.write(contentsOf: [UInt8](repeating: 0, count: left))
13041325
}
1305-
try self.handle.write(contentsOf: [UInt8](repeating: 0, count: Int(left)))
13061326
}
13071327

13081328
public enum Error: Swift.Error, CustomStringConvertible, Sendable, Equatable {

0 commit comments

Comments
 (0)