From b98d27f773d74059e92bd5d4169e1347eeb4a6d9 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 5 Jan 2026 01:42:29 +0900 Subject: [PATCH] internal/pkg: expand single directory tarball This enables much cleaner use of their output without giving up any meaningful data. Signed-off-by: Ophestra --- internal/pkg/dir_test.go | 40 ++++++++++++- internal/pkg/tar.go | 31 ++++++++-- internal/pkg/tar_test.go | 124 ++++++++++++++++++++++----------------- 3 files changed, 135 insertions(+), 60 deletions(-) diff --git a/internal/pkg/dir_test.go b/internal/pkg/dir_test.go index e91a953..da0dd37 100644 --- a/internal/pkg/dir_test.go +++ b/internal/pkg/dir_test.go @@ -202,6 +202,7 @@ func TestFlatten(t *testing.T) { "identifier": {Mode: fs.ModeDir | 0700}, "identifier/-P_1iw6yVq_letMHncqcExSE0bYcDhYI5OdY6b1wKASf-Corufvj__XTBUq2Qd2a": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/yJlSb2A3jxaMLuKqwp1GwHOguAHddS9MjygF9ICEeegKfRvgLPdPmNh8mva47f8o")}, + "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }, []pkg.FlatEntry{ {Mode: fs.ModeDir | 0700, Path: "."}, @@ -222,8 +223,45 @@ func TestFlatten(t *testing.T) { {Mode: fs.ModeDir | 0700, Path: "identifier"}, {Mode: fs.ModeSymlink | 0777, Path: "identifier/-P_1iw6yVq_letMHncqcExSE0bYcDhYI5OdY6b1wKASf-Corufvj__XTBUq2Qd2a", Data: []byte("../checksum/yJlSb2A3jxaMLuKqwp1GwHOguAHddS9MjygF9ICEeegKfRvgLPdPmNh8mva47f8o")}, + {Mode: fs.ModeDir | 0700, Path: "temp"}, {Mode: fs.ModeDir | 0700, Path: "work"}, - }, pkg.MustDecode("lmVlYEGNFkwGVpzzS8KYjGBVB6FCyPtk9ViX88zen0GgTKLgGqO6eFxb4dpcP6bR")}, + }, pkg.MustDecode("d14kfTvK8uyYIrMq-NUPGGIGmYKcFytmrsvEu5oXibVfmxhu7Y_dAt3rXpsHVSPM")}, + + {"sample tar expand step unpack", fstest.MapFS{ + ".": {Mode: fs.ModeDir | 0700}, + + "libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")}, + }, []pkg.FlatEntry{ + {Mode: fs.ModeDir | 0700, Path: "."}, + + {Mode: fs.ModeSymlink | 0777, Path: "libedac.so", Data: []byte("/proc/nonexistent/libedac.so")}, + }, pkg.MustDecode("rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC")}, + + {"sample tar expand", fstest.MapFS{ + ".": {Mode: fs.ModeDir | 0700}, + + "checksum": {Mode: fs.ModeDir | 0700}, + "checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC": {Mode: fs.ModeDir | 0500}, + "checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")}, + + "identifier": {Mode: fs.ModeDir | 0700}, + "identifier/-P_1iw6yVq_letMHncqcExSE0bYcDhYI5OdY6b1wKASf-Corufvj__XTBUq2Qd2a": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC")}, + + "temp": {Mode: fs.ModeDir | 0700}, + "work": {Mode: fs.ModeDir | 0700}, + }, []pkg.FlatEntry{ + {Mode: fs.ModeDir | 0700, Path: "."}, + + {Mode: fs.ModeDir | 0700, Path: "checksum"}, + {Mode: fs.ModeDir | 0500, Path: "checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC"}, + {Mode: fs.ModeSymlink | 0777, Path: "checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC/libedac.so", Data: []byte("/proc/nonexistent/libedac.so")}, + + {Mode: fs.ModeDir | 0700, Path: "identifier"}, + {Mode: fs.ModeSymlink | 0777, Path: "identifier/-P_1iw6yVq_letMHncqcExSE0bYcDhYI5OdY6b1wKASf-Corufvj__XTBUq2Qd2a", Data: []byte("../checksum/rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC")}, + + {Mode: fs.ModeDir | 0700, Path: "temp"}, + {Mode: fs.ModeDir | 0700, Path: "work"}, + }, pkg.MustDecode("tqrqx8Ig_l9jjDywovatvg3btS-6hf182Ofzpjcrj2148NhobE_Xb7wrYptZoXFD")}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/pkg/tar.go b/internal/pkg/tar.go index ac36cf9..f058d24 100644 --- a/internal/pkg/tar.go +++ b/internal/pkg/tar.go @@ -108,6 +108,10 @@ func (a *tarArtifact) Cure(work, temp *check.Absolute, loadData CacheDataFunc) ( } var madeDirectories []dirTargetPerm + if err = os.MkdirAll(temp.String(), 0700); err != nil { + return + } + var header *tar.Header r := tar.NewReader(tr) for header, err = r.Next(); err == nil; header, err = r.Next() { @@ -125,7 +129,7 @@ func (a *tarArtifact) Cure(work, temp *check.Absolute, loadData CacheDataFunc) ( case tar.TypeReg: var f *os.File if f, err = os.OpenFile( - work.Append(header.Name).String(), + temp.Append(header.Name).String(), os.O_CREATE|os.O_EXCL|os.O_WRONLY, header.FileInfo().Mode()&0400, ); err != nil { @@ -142,7 +146,7 @@ func (a *tarArtifact) Cure(work, temp *check.Absolute, loadData CacheDataFunc) ( case tar.TypeLink: if err = os.Link( header.Linkname, - work.Append(header.Name).String(), + temp.Append(header.Name).String(), ); err != nil { return } @@ -151,14 +155,14 @@ func (a *tarArtifact) Cure(work, temp *check.Absolute, loadData CacheDataFunc) ( case tar.TypeSymlink: if err = os.Symlink( header.Linkname, - work.Append(header.Name).String(), + temp.Append(header.Name).String(), ); err != nil { return } break case tar.TypeDir: - pathname := work.Append(header.Name) + pathname := temp.Append(header.Name) madeDirectories = append(madeDirectories, dirTargetPerm{ path: pathname, mode: header.FileInfo().Mode(), @@ -185,14 +189,29 @@ func (a *tarArtifact) Cure(work, temp *check.Absolute, loadData CacheDataFunc) ( if errors.Is(err, io.EOF) { err = nil } - if err == nil { for _, e := range madeDirectories { if err = os.Chmod(e.path.String(), e.mode&0500); err != nil { return } } - err = os.Chmod(work.String(), 0500) + } else { + return + } + + var entries []os.DirEntry + if entries, err = os.ReadDir(temp.String()); err != nil { + return + } + + if len(entries) == 1 && entries[0].IsDir() { + p := temp.Append(entries[0].Name()) + if err = os.Chmod(p.String(), 0700); err != nil { + return + } + err = os.Rename(p.String(), work.String()) + } else { + err = os.Rename(temp.String(), work.String()) } return } diff --git a/internal/pkg/tar_test.go b/internal/pkg/tar_test.go index feff9c1..604ef61 100644 --- a/internal/pkg/tar_test.go +++ b/internal/pkg/tar_test.go @@ -17,23 +17,48 @@ import ( func TestTar(t *testing.T) { t.Parallel() - testdataFsys := fstest.MapFS{ - ".": {Mode: fs.ModeDir | 0700}, + checkWithCache(t, []cacheTestCase{ + {"http", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { + checkTarHTTP(t, base, c, fstest.MapFS{ + ".": {Mode: fs.ModeDir | 0700}, - "checksum": {Mode: fs.ModeDir | 0700}, - "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0700}, - "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}}, - "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0700}, - "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0700}, - "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: 01000000777, Data: []byte("/proc/nonexistent/libedac.so")}, + "checksum": {Mode: fs.ModeDir | 0700}, + "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP": {Mode: fs.ModeDir | 0700}, + "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/check": {Mode: 0400, Data: []byte{0, 0}}, + "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib": {Mode: fs.ModeDir | 0700}, + "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/pkgconfig": {Mode: fs.ModeDir | 0700}, + "checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP/lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")}, - "identifier": {Mode: fs.ModeDir | 0700}, - "identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: 01000000777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")}, - "identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: 01000000777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")}, + "identifier": {Mode: fs.ModeDir | 0700}, + "identifier/HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")}, + "identifier/Zx5ZG9BAwegNT3zQwCySuI2ktCXxNgxirkGLFjW4FW06PtojYVaCdtEw8yuntPLa": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP")}, - "work": {Mode: fs.ModeDir | 0700}, - } + "work": {Mode: fs.ModeDir | 0700}, + }, pkg.MustDecode( + "yJlSb2A3jxaMLuKqwp1GwHOguAHddS9MjygF9ICEeegKfRvgLPdPmNh8mva47f8o", + )) + }, pkg.MustDecode("d14kfTvK8uyYIrMq-NUPGGIGmYKcFytmrsvEu5oXibVfmxhu7Y_dAt3rXpsHVSPM")}, + {"http expand", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { + checkTarHTTP(t, base, c, fstest.MapFS{ + ".": {Mode: fs.ModeDir | 0700}, + + "lib": {Mode: fs.ModeDir | 0700}, + "lib/libedac.so": {Mode: fs.ModeSymlink | 0777, Data: []byte("/proc/nonexistent/libedac.so")}, + }, pkg.MustDecode( + "rY9_cYWgGWgGI2efznu9RP6bPnjM6I5CHFY2nGysnlbPDdOx_iIaiGKYesmMARwC", + )) + }, pkg.MustDecode("tqrqx8Ig_l9jjDywovatvg3btS-6hf182Ofzpjcrj2148NhobE_Xb7wrYptZoXFD")}, + }) +} + +func checkTarHTTP( + t *testing.T, + base *check.Absolute, + c *pkg.Cache, + testdataFsys fs.FS, + wantChecksum pkg.Checksum, +) { var testdata string { var buf bytes.Buffer @@ -68,47 +93,40 @@ func TestTar(t *testing.T) { "testdata": {Data: []byte(testdata), Mode: 0400}, })) - checkWithCache(t, []cacheTestCase{ - {"http", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { - wantIdent := func() pkg.ID { - h := sha512.New384() - h.Write([]byte{byte(pkg.KindTar), 0, 0, 0, 0, 0, 0, 0}) - h.Write([]byte{pkg.TarGzip, 0, 0, 0, 0, 0, 0, 0}) - h.Write([]byte{byte(pkg.KindHTTPGet), 0, 0, 0, 0, 0, 0, 0}) - httpIdent := pkg.KindHTTPGet.Ident([]byte("file:///testdata")) - h.Write(httpIdent[:]) - return pkg.ID(h.Sum(nil)) - }() + wantIdent := func() pkg.ID { + h := sha512.New384() + h.Write([]byte{byte(pkg.KindTar), 0, 0, 0, 0, 0, 0, 0}) + h.Write([]byte{pkg.TarGzip, 0, 0, 0, 0, 0, 0, 0}) + h.Write([]byte{byte(pkg.KindHTTPGet), 0, 0, 0, 0, 0, 0, 0}) + httpIdent := pkg.KindHTTPGet.Ident([]byte("file:///testdata")) + h.Write(httpIdent[:]) + return pkg.ID(h.Sum(nil)) + }() - a := pkg.NewHTTPGetTar( - t.Context(), - &client, - "file:///testdata", - testdataChecksum, - pkg.TarGzip, - ) + a := pkg.NewHTTPGetTar( + t.Context(), + &client, + "file:///testdata", + testdataChecksum, + pkg.TarGzip, + ) - if id := pkg.Ident(a); id != wantIdent { - t.Fatalf("Ident: %s, want %s", pkg.Encode(id), pkg.Encode(wantIdent)) - } + if id := pkg.Ident(a); id != wantIdent { + t.Fatalf("Ident: %s, want %s", pkg.Encode(id), pkg.Encode(wantIdent)) + } - wantPathname := base.Append( - "identifier", - pkg.Encode(wantIdent), - ) - wantChecksum := pkg.MustDecode( - "yJlSb2A3jxaMLuKqwp1GwHOguAHddS9MjygF9ICEeegKfRvgLPdPmNh8mva47f8o", - ) - if pathname, checksum, err := c.Cure(a); err != nil { - t.Fatalf("Cure: error = %v", err) - } else if !pathname.Is(wantPathname) { - t.Fatalf("Cure: %q, want %q", pathname, wantPathname) - } else if checksum != wantChecksum { - t.Fatalf("Cure: %v", &pkg.ChecksumMismatchError{ - Got: checksum, - Want: wantChecksum, - }) - } - }, pkg.MustDecode("lmVlYEGNFkwGVpzzS8KYjGBVB6FCyPtk9ViX88zen0GgTKLgGqO6eFxb4dpcP6bR")}, - }) + wantPathname := base.Append( + "identifier", + pkg.Encode(wantIdent), + ) + if pathname, checksum, err := c.Cure(a); err != nil { + t.Fatalf("Cure: error = %v", err) + } else if !pathname.Is(wantPathname) { + t.Fatalf("Cure: %q, want %q", pathname, wantPathname) + } else if checksum != wantChecksum { + t.Fatalf("Cure: %v", &pkg.ChecksumMismatchError{ + Got: checksum, + Want: wantChecksum, + }) + } }