1818// via direct writer calls, without staging an intermediate fs.FS.
1919//
2020// The single entry point is [Apply]. It handles all tar entry types (regular
21- // files, directories, symlinks, hard links, device nodes, FIFOs) and three
21+ // files, directories, symlinks, hard links, device nodes, FIFOs) and four
2222// whiteout strategies selectable via options:
2323//
2424// - Default (no option): translate AUFS/OCI whiteouts to overlayfs xattrs.
2727// Suitable for flat merged images where all layers are applied in sequence.
2828// - [WithPreserveWhiteouts]: keep .wh.* entries as plain files.
2929// Suitable for tooling that needs the raw tar content.
30+ // - [WithStripWhiteouts]: drop .wh.* entries entirely.
31+ // Suitable for the bottommost layer of a chain, where no lower layer
32+ // exists for a whiteout to hide.
3033//
3134// Tar-index mode is enabled by creating the [erofs.Writer] with
3235// [erofs.WithDataFile] pointing at a file that receives the raw tar bytes,
@@ -75,6 +78,9 @@ const (
7578 whiteoutMerge
7679 // whiteoutPreserve keeps whiteout entries as plain regular files.
7780 whiteoutPreserve
81+ // whiteoutStrip drops whiteout entries entirely: neither translated,
82+ // preserved, nor acted on.
83+ whiteoutStrip
7884)
7985
8086// config holds the parsed options for an Apply call.
@@ -106,6 +112,15 @@ func WithPreserveWhiteouts() Option {
106112 return func (c * config ) { c .whiteouts = whiteoutPreserve }
107113}
108114
115+ // WithStripWhiteouts makes Apply drop .wh.* and .wh..wh..opq entries
116+ // entirely: they are neither translated to overlayfs representation nor
117+ // preserved as plain files. Use this for the bottommost layer of a chain,
118+ // where no lower layer exists for a whiteout to hide, so the whiteout
119+ // carries no meaning.
120+ func WithStripWhiteouts () Option {
121+ return func (c * config ) { c .whiteouts = whiteoutStrip }
122+ }
123+
109124// WithTarIndexData enables tar-index mode.
110125//
111126// In tar-index mode Apply does not copy file payload bytes into the EROFS
@@ -148,6 +163,7 @@ type pendingLink struct {
148163//
149164// Use [WithMerge] to resolve whiteouts structurally instead (flat merged image).
150165// Use [WithPreserveWhiteouts] to keep whiteout entries as plain files.
166+ // Use [WithStripWhiteouts] to drop whiteout entries entirely.
151167//
152168// Hard links may appear in any order. Links whose targets have not yet appeared
153169// are queued and resolved as subsequent entries are processed. An unresolved
@@ -203,6 +219,8 @@ func Apply(w *erofs.Writer, r io.Reader, opts ...Option) error {
203219 if err := setOpaqueXattr (w , dir , hdr ); err != nil {
204220 return fmt .Errorf ("tarconv: opaque %s: %w" , dir , err )
205221 }
222+ case whiteoutStrip :
223+ // Nothing below this layer to hide; drop the marker.
206224 }
207225 } else {
208226 target := path .Join (dir , base [len (whiteoutPrefix ):])
@@ -228,6 +246,8 @@ func Apply(w *erofs.Writer, r io.Reader, opts ...Option) error {
228246 }
229247 pendingOrigin [dir ] = true
230248 }
249+ case whiteoutStrip :
250+ // Nothing below this layer to hide; drop the marker.
231251 }
232252 }
233253 // Drain any data bytes (whiteouts are zero-size in practice but be safe).
0 commit comments