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