@@ -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