diff --git a/src/extract.go b/src/extract.go index 59ef0ac..e3b3a6f 100644 --- a/src/extract.go +++ b/src/extract.go @@ -145,6 +145,9 @@ func ExtractTar(ctx context.Context, reader io.Reader, oldManifest *Manifest) (* return nil, UnresolvedRefError{missing} } + // Ensure parent directories exist for all entries. + EnsureLeadingDirectories(manifest) + logc.Printf(ctx, "reuse: %s recycled, %s transferred\n", datasize.ByteSize(dataBytesRecycled).HR(), @@ -226,6 +229,9 @@ func ExtractZip(ctx context.Context, reader io.Reader, oldManifest *Manifest) (* return nil, UnresolvedRefError{missing} } + // Ensure parent directories exist for all entries. + EnsureLeadingDirectories(manifest) + logc.Printf(ctx, "reuse: %s recycled, %s transferred\n", datasize.ByteSize(dataBytesRecycled).HR(), @@ -234,3 +240,4 @@ func ExtractZip(ctx context.Context, reader io.Reader, oldManifest *Manifest) (* return manifest, nil } + diff --git a/src/manifest.go b/src/manifest.go index b5c6df2..024db67 100644 --- a/src/manifest.go +++ b/src/manifest.go @@ -144,6 +144,20 @@ func AddProblem(manifest *Manifest, pathName, format string, args ...any) error return fmt.Errorf("%s: %s", pathName, cause) } +// EnsureLeadingDirectories adds directory entries for any parent directories +// that are implicitly referenced by files in the manifest but don't have +// explicit directory entries. (This can be the case if an archive is created +// via globs rather than including a whole directory.) +func EnsureLeadingDirectories(manifest *Manifest) { + for name := range manifest.Contents { + for dir := path.Dir(name); dir != "." && dir != ""; dir = path.Dir(dir) { + if _, exists := manifest.Contents[dir]; !exists { + AddDirectory(manifest, dir) + } + } + } +} + func GetProblemReport(manifest *Manifest) []string { var report []string for _, problem := range manifest.Problems {