Skip to content

wclayer: fix sparse file logical size - #2926

Open
Dawei Wei (rzlink) wants to merge 1 commit into
microsoft:mainfrom
rzlink:fix/wclayer-sparse-logical-size
Open

wclayer: fix sparse file logical size#2926
Dawei Wei (rzlink) wants to merge 1 commit into
microsoft:mainfrom
rzlink:fix/wclayer-sparse-logical-size

Conversation

@rzlink

@rzlink Dawei Wei (rzlink) commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Prevent Windows container layer export from writing an all-hole sparse file as a zero-byte tar entry, which truncates the file's contents on export.

A sparse file can have a nonzero logical size without allocated data—for example, a 1 MiB file containing only zeroes. In this case the first BackupData stream reports size zero even though the file's logical EOF is 1 MiB.

findBackupStreamSize previously used that BackupData size directly. The resulting zero size was passed to the tar writer, so the exported entry was treated as empty and the file was restored truncated.

Keep the existing fast path for non-sparse files and sparse files with inline data. For a sparse BackupData stream with no inline data, derive the logical size from BackupSparseBlock records instead: the terminal zero-length block's
offset marks logical EOF, and allocated blocks satisfy offset+size <= logical size, so the maximum end position is the logical size.

Add regression coverage for regular files and sparse files with empty, all-hole, single-range, and multi-range layouts.

Context

Reported downstream in Docker/Moby as moby/moby#53464: building or committing a Windows image whose layer contains an NTFS sparse file fails.

That failure has two independent causes in two libraries:

  • This PR (hcsshim): the logical size of an all-hole sparse file is computed as 0, truncating its contents on export.
  • go-winio (microsoft/go-winio#375): the seekable export path rejects BackupSparseBlock records with unknown stream ID 9.

The two fixes are complementary. This change touches only findBackupStreamSize and uses existing go-winio APIs, so it builds, tests, and merges independently of go-winio#375. Once that PR lands and is tagged, a follow-up will bump the go-winio dependency here so a tagged hcsshim release carries the complete end-to-end fix.

Testing

  • go test ./internal/wclayer

Derive a sparse file's logical size from sparse block streams when BackupData has no inline data.

Add regression coverage for normal and sparse files.

Signed-off-by: Dawei Wei <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant