Skip to content

Commit 8745bcb

Browse files
committed
fix(tarfs): ReadFile follow hardlinks
Signed-off-by: Brad Lugo <[email protected]>
1 parent 762e6a4 commit 8745bcb

File tree

4 files changed

+105
-3
lines changed

4 files changed

+105
-3
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ require (
5555
github.com/prometheus/common v0.48.0 // indirect
5656
github.com/prometheus/procfs v0.12.0 // indirect
5757
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
58+
github.com/stretchr/objx v0.5.0 // indirect
5859
go.opentelemetry.io/otel/metric v1.24.0 // indirect
5960
golang.org/x/mod v0.16.0 // indirect
6061
google.golang.org/protobuf v1.33.0 // indirect

go.sum

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,17 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
172172
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
173173
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
174174
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
175-
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
176175
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
176+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
177+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
178+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
177179
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
178180
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
179181
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
180182
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
181183
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
184+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
185+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
182186
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
183187
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
184188
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=

pkg/tarfs/tarfs.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,10 +457,28 @@ func (f *FS) ReadFile(name string) ([]byte, error) {
457457
if err != nil {
458458
return nil, err
459459
}
460-
if i.h.FileInfo().Mode().Type()&fs.ModeSymlink != 0 {
460+
461+
typ := i.h.FileInfo().Mode().Type()
462+
var r *tar.Reader
463+
switch {
464+
case typ.IsRegular() && i.h.Typeflag != tar.TypeLink:
465+
r = tar.NewReader(io.NewSectionReader(f.r, i.off, i.sz))
466+
case typ.IsRegular() && i.h.Typeflag == tar.TypeLink:
467+
tgt, err := f.getInode(op, i.h.Linkname)
468+
if err != nil {
469+
return nil, err
470+
}
471+
r = tar.NewReader(io.NewSectionReader(f.r, tgt.off, tgt.sz))
472+
case typ&fs.ModeSymlink != 0: // typ.IsSymlink()
461473
return f.ReadFile(i.h.Linkname)
474+
default:
475+
// Pretend all other kinds of files don't exist.
476+
return nil, &fs.PathError{
477+
Op: op,
478+
Path: name,
479+
Err: fs.ErrExist,
480+
}
462481
}
463-
r := tar.NewReader(io.NewSectionReader(f.r, i.off, i.sz))
464482
if _, err := r.Next(); err != nil {
465483
return nil, &fs.PathError{
466484
Op: op,

pkg/tarfs/tarfs_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,85 @@ func TestSymlinks(t *testing.T) {
460460
}))
461461
}
462462

463+
func TestReadFile(t *testing.T) {
464+
type tarfsFile struct {
465+
Header tar.Header
466+
Data []byte
467+
}
468+
469+
tmp := t.TempDir()
470+
run := func(openErr bool, tarfsFiles []tarfsFile, chk func(*testing.T, *FS)) func(*testing.T) {
471+
return func(t *testing.T) {
472+
t.Helper()
473+
// This is a perfect candidate for using test.GenerateFixture, but
474+
// creates an import cycle.
475+
f, err := os.Create(filepath.Join(tmp, path.Base(t.Name())))
476+
if err != nil {
477+
t.Fatal(err)
478+
}
479+
defer f.Close()
480+
481+
tw := tar.NewWriter(f)
482+
for _, tarfsFile := range tarfsFiles {
483+
h := tarfsFile.Header
484+
h.Size = int64(len(tarfsFile.Data))
485+
h.Format = tar.FormatGNU
486+
if err := tw.WriteHeader(&h); err != nil {
487+
t.Error(err)
488+
}
489+
_, err := tw.Write(tarfsFile.Data)
490+
if err != nil {
491+
t.Error(err)
492+
}
493+
}
494+
if err := tw.Close(); err != nil {
495+
t.Error(err)
496+
}
497+
498+
sys, err := New(f)
499+
t.Log(err)
500+
if (err != nil) != openErr {
501+
t.Fail()
502+
}
503+
504+
if chk != nil {
505+
chk(t, sys)
506+
}
507+
}
508+
}
509+
510+
t.Run("Hardlink", func(t *testing.T) {
511+
originalData := []byte(`Hello, World!`)
512+
abData := make([]byte, len(originalData))
513+
copy(abData, originalData)
514+
515+
run(false, []tarfsFile{
516+
{
517+
Header: tar.Header{Name: `a/`},
518+
},
519+
{
520+
Header: tar.Header{Name: `a/b`},
521+
Data: abData,
522+
},
523+
{
524+
Header: tar.Header{
525+
Name: `a/c`,
526+
Typeflag: tar.TypeLink,
527+
Linkname: `a/b`,
528+
},
529+
},
530+
}, func(t *testing.T, sys *FS) {
531+
acFile, err := sys.ReadFile("a/c")
532+
if err != nil {
533+
t.Errorf("error while opening file: %v", err)
534+
}
535+
if !bytes.Equal(originalData, acFile) {
536+
t.Errorf("unexpected \"%s\", got \"%s\"", originalData, acFile)
537+
}
538+
})
539+
})
540+
}
541+
463542
func TestKnownLayers(t *testing.T) {
464543
ents, err := os.ReadDir(`testdata/known`)
465544
if err != nil {

0 commit comments

Comments
 (0)