Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions tarfs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import (
)

type Fs struct {
files map[string]map[string]*File
files map[string]map[string]*fsEntry
}

type fsEntry struct {
h *tar.Header
data []byte
}

func splitpath(name string) (dir, file string) {
Expand All @@ -29,7 +34,7 @@ func splitpath(name string) (dir, file string) {
}

func New(t *tar.Reader) *Fs {
fs := &Fs{files: make(map[string]map[string]*File)}
fs := &Fs{files: make(map[string]map[string]*fsEntry)}
for {
hdr, err := t.Next()
if err == io.EOF {
Expand All @@ -41,7 +46,7 @@ func New(t *tar.Reader) *Fs {

d, f := splitpath(hdr.Name)
if _, ok := fs.files[d]; !ok {
fs.files[d] = make(map[string]*File)
fs.files[d] = make(map[string]*fsEntry)
}

var buf bytes.Buffer
Expand All @@ -54,27 +59,25 @@ func New(t *tar.Reader) *Fs {
panic("tarfs: size mismatch")
}

file := &File{
file := &fsEntry{
h: hdr,
data: bytes.NewReader(buf.Bytes()),
fs: fs,
data: buf.Bytes(),
}
fs.files[d][f] = file

}

if fs.files[afero.FilePathSeparator] == nil {
fs.files[afero.FilePathSeparator] = make(map[string]*File)
fs.files[afero.FilePathSeparator] = make(map[string]*fsEntry)
}
// Add a pseudoroot
fs.files[afero.FilePathSeparator][""] = &File{
fs.files[afero.FilePathSeparator][""] = &fsEntry{
h: &tar.Header{
Name: afero.FilePathSeparator,
Typeflag: tar.TypeDir,
Size: 0,
},
data: bytes.NewReader(nil),
fs: fs,
data: nil,
}

return fs
Expand All @@ -91,7 +94,11 @@ func (fs *Fs) Open(name string) (afero.File, error) {
return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT}
}

nf := *file
nf := File{
h: file.h,
data: bytes.NewReader(file.data),
fs: fs,
}

return &nf, nil
}
Expand Down
48 changes: 48 additions & 0 deletions tarfs/tarfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,54 @@ func TestReadAt(t *testing.T) {
}
}

func TestMultipleReads(t *testing.T) {
for _, f := range files {
if !f.exists {
continue
}

readFile := func(file afero.File) {
buf := make([]byte, 8)
n, err := file.Read(buf)
if f.isdir && (err != syscall.EISDIR) {
t.Errorf("%v got error %v, expected EISDIR", f.name, err)
} else if !f.isdir && (err != nil) {
if err != nil {
t.Errorf("%v: %v", f.name, err)
} else if n != 8 {
t.Errorf("%v: got %d read bytes, expected 8", f.name, n)
} else if string(buf) != f.content {
t.Errorf("%v: got <%s>, expected <%s>", f.name, f.content, string(buf))
}
}

_, err = io.ReadAll(file)
if f.isdir && (err != syscall.EISDIR) {
t.Errorf("%v got error %v, expected EISDIR", f.name, err)
} else if !f.isdir && (err != nil) {
t.Errorf("reading %v: %v", f.name, err)
}

err = file.Close()
if err != nil {
t.Errorf("closing %v: %v", f.name, err)
}
}

fileA, err := afs.Open(f.name)
if err != nil {
t.Fatalf("opening %v: %v", f.name, err)
}
fileB, err := afs.Open(f.name)
if err != nil {
t.Fatalf("opening %v: %v", f.name, err)
}

readFile(fileA)
readFile(fileB)
}
}

func TestSeek(t *testing.T) {
for _, f := range files {
if !f.exists {
Expand Down