From 275e17bc7619831e5bbeb86c4234cf18c27d4877 Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 31 Aug 2021 23:08:07 -0300 Subject: [PATCH] feat: support links inside archives (#2436) Signed-off-by: Carlos Alexandro Becker --- pkg/archive/targz/targz.go | 9 ++++++++- pkg/archive/targz/targz_test.go | 13 +++++++++++++ pkg/archive/tarxz/tarxz.go | 11 +++++++++-- pkg/archive/tarxz/tarxz_test.go | 13 +++++++++++++ pkg/archive/testdata/link.txt | 1 + pkg/archive/testdata/regular.txt | 0 pkg/archive/zip/zip.go | 2 +- pkg/archive/zip/zip_test.go | 13 +++++++++++++ 8 files changed, 58 insertions(+), 4 deletions(-) create mode 120000 pkg/archive/testdata/link.txt create mode 100644 pkg/archive/testdata/regular.txt diff --git a/pkg/archive/targz/targz.go b/pkg/archive/targz/targz.go index 67a3dea3ef5..c468fe8703b 100644 --- a/pkg/archive/targz/targz.go +++ b/pkg/archive/targz/targz.go @@ -43,7 +43,7 @@ func (a Archive) Add(f config.File) error { return err } defer file.Close() - info, err := file.Stat() + info, err := os.Lstat(f.Source) // #nosec if err != nil { return err } @@ -66,6 +66,13 @@ func (a Archive) Add(f config.File) error { header.Gid = 0 header.Gname = f.Info.Group } + if info.Mode()&os.ModeSymlink != 0 { + target, err := os.Readlink(f.Source) + if err != nil { + return err + } + header.Linkname = target + } if err = a.tw.WriteHeader(header); err != nil { return err } diff --git a/pkg/archive/targz/targz_test.go b/pkg/archive/targz/targz_test.go index 39163a4ecf8..7488ae8f708 100644 --- a/pkg/archive/targz/targz_test.go +++ b/pkg/archive/targz/targz_test.go @@ -50,6 +50,14 @@ func TestTarGzFile(t *testing.T) { Source: "../testdata/sub1/sub2/subfoo.txt", Destination: "sub1/sub2/subfoo.txt", })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/regular.txt", + Destination: "regular.txt", + })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/link.txt", + Destination: "link.txt", + })) require.NoError(t, archive.Close()) require.Error(t, archive.Add(config.File{ @@ -84,6 +92,9 @@ func TestTarGzFile(t *testing.T) { ex := next.FileInfo().Mode() | 0o111 require.Equal(t, next.FileInfo().Mode().String(), ex.String()) } + if next.Name == "link.txt" { + require.Equal(t, next.Linkname, "regular.txt") + } } require.Equal(t, []string{ "foo.txt", @@ -92,6 +103,8 @@ func TestTarGzFile(t *testing.T) { "sub1/executable", "sub1/sub2", "sub1/sub2/subfoo.txt", + "regular.txt", + "link.txt", }, paths) } diff --git a/pkg/archive/tarxz/tarxz.go b/pkg/archive/tarxz/tarxz.go index e36040b5322..845793e24df 100644 --- a/pkg/archive/tarxz/tarxz.go +++ b/pkg/archive/tarxz/tarxz.go @@ -42,7 +42,7 @@ func (a Archive) Add(f config.File) error { return err } defer file.Close() - info, err := file.Stat() + info, err := os.Lstat(f.Source) // #nosec if err != nil { return err } @@ -65,10 +65,17 @@ func (a Archive) Add(f config.File) error { header.Gid = 0 header.Gname = f.Info.Group } + if info.Mode()&os.ModeSymlink != 0 { + target, err := os.Readlink(f.Source) + if err != nil { + return err + } + header.Linkname = target + } if err = a.tw.WriteHeader(header); err != nil { return err } - if info.IsDir() { + if info.IsDir() || info.Mode()&os.ModeSymlink != 0 { return nil } _, err = io.Copy(a.tw, file) diff --git a/pkg/archive/tarxz/tarxz_test.go b/pkg/archive/tarxz/tarxz_test.go index 3ac68a75523..59125beafed 100644 --- a/pkg/archive/tarxz/tarxz_test.go +++ b/pkg/archive/tarxz/tarxz_test.go @@ -50,6 +50,14 @@ func TestTarXzFile(t *testing.T) { Source: "../testdata/sub1/sub2/subfoo.txt", Destination: "sub1/sub2/subfoo.txt", })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/regular.txt", + Destination: "regular.txt", + })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/link.txt", + Destination: "link.txt", + })) require.NoError(t, archive.Close()) require.Error(t, archive.Add(config.File{ @@ -83,6 +91,9 @@ func TestTarXzFile(t *testing.T) { ex := next.FileInfo().Mode() | 0o111 require.Equal(t, next.FileInfo().Mode().String(), ex.String()) } + if next.Name == "link.txt" { + require.Equal(t, next.Linkname, "regular.txt") + } } require.Equal(t, []string{ "foo.txt", @@ -91,6 +102,8 @@ func TestTarXzFile(t *testing.T) { "sub1/executable", "sub1/sub2", "sub1/sub2/subfoo.txt", + "regular.txt", + "link.txt", }, paths) } diff --git a/pkg/archive/testdata/link.txt b/pkg/archive/testdata/link.txt new file mode 120000 index 00000000000..397e10770b6 --- /dev/null +++ b/pkg/archive/testdata/link.txt @@ -0,0 +1 @@ +regular.txt \ No newline at end of file diff --git a/pkg/archive/testdata/regular.txt b/pkg/archive/testdata/regular.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/pkg/archive/zip/zip.go b/pkg/archive/zip/zip.go index 89dcf56659d..8dc3a5d564e 100644 --- a/pkg/archive/zip/zip.go +++ b/pkg/archive/zip/zip.go @@ -39,7 +39,7 @@ func (a Archive) Add(f config.File) error { return err } defer file.Close() - info, err := file.Stat() + info, err := os.Lstat(f.Source) // #nosec if err != nil { return err } diff --git a/pkg/archive/zip/zip_test.go b/pkg/archive/zip/zip_test.go index 49428fb6b98..7a2ca85e709 100644 --- a/pkg/archive/zip/zip_test.go +++ b/pkg/archive/zip/zip_test.go @@ -48,6 +48,14 @@ func TestZipFile(t *testing.T) { Source: "../testdata/sub1/sub2/subfoo.txt", Destination: "sub1/sub2/subfoo.txt", })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/regular.txt", + Destination: "regular.txt", + })) + require.NoError(t, archive.Add(config.File{ + Source: "../testdata/link.txt", + Destination: "link.txt", + })) require.NoError(t, archive.Close()) require.Error(t, archive.Add(config.File{ @@ -75,12 +83,17 @@ func TestZipFile(t *testing.T) { ex := zf.Mode() | 0o111 require.Equal(t, zf.Mode().String(), ex.String()) } + if zf.Name == "link.txt" { + require.True(t, zf.FileInfo().Mode()&os.ModeSymlink != 0) + } } require.Equal(t, []string{ "foo.txt", "sub1/bar.txt", "sub1/executable", "sub1/sub2/subfoo.txt", + "regular.txt", + "link.txt", }, paths) }