Skip to content

Commit 0452cbf

Browse files
committed
1 parent 07ada12 commit 0452cbf

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
@@ -1289,11 +1289,32 @@ extension EXT4 {
12891289
left = left - rl
12901290
}
12911291

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

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

0 commit comments

Comments
 (0)