Skip to content
Closed
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
26 changes: 20 additions & 6 deletions fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,14 @@ func New() (http.FileSystem, error) {
files["/"+zipFile.Name] = f
}
for fn := range files {
dn := path.Dir(fn)
if _, ok := files[dn]; !ok {
files[dn] = file{FileInfo: dirInfo{dn}, fs: fs}
// go up directories recursively in order to care deep directory
for dn := path.Dir(fn); dn != fn; {
if _, ok := files[dn]; !ok {
files[dn] = file{FileInfo: dirInfo{dn}, fs: fs}
} else {
break
}
fn, dn = dn, path.Dir(dn)
}
}
return fs, nil
Expand All @@ -84,7 +89,7 @@ type dirInfo struct {
name string
}

func (di dirInfo) Name() string { return di.name }
func (di dirInfo) Name() string { return path.Base(di.name) }
func (di dirInfo) Size() int64 { return 0 }
func (di dirInfo) Mode() os.FileMode { return 0755 | os.ModeDir }
func (di dirInfo) ModTime() time.Time { return time.Time{} }
Expand Down Expand Up @@ -158,9 +163,18 @@ func (f *httpFile) Readdir(count int) ([]os.FileInfo, error) {
if !f.isDir {
return fis, nil
}
prefix := f.Name()
di, ok := f.FileInfo.(dirInfo)
if !ok {
return nil, fmt.Errorf("failed to draw dirInfo from *httpFile: %q", f.Name())
}
prefix := di.name // absolute path name
for fn, f := range f.file.fs.files {
if strings.HasPrefix(fn, prefix) && len(fn) > len(prefix) {
rel := strings.TrimPrefix(fn, prefix)
rel = strings.TrimPrefix(rel, "/")
// pick up only the entries just under the directory and
// do not follow grandchild.
if strings.HasPrefix(fn, prefix) && len(fn) > len(prefix) &&
!strings.Contains(rel, "/") {
fis = append(fis, f.FileInfo)
}
}
Expand Down
75 changes: 74 additions & 1 deletion fs/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ import (
"bytes"
"io/ioutil"
"os"
"path"
"path/filepath"
"reflect"
"sort"
"strings"
"sync"
"testing"
Expand All @@ -41,6 +43,8 @@ func TestOpen(t *testing.T) {
pixelGifHeader := mustFileHeader("../testdata/image/pixel.gif")
indexHTMLHeader := mustFileHeader("../testdata/index/index.html")
subdirIndexHTMLHeader := mustFileHeader("../testdata/index/sub_dir/index.html")
deepAHTMLHeader := mustFileHeader("../testdata/deep/a")
deepCHTMLHeader := mustFileHeader("../testdata/deep/aa/bb/c")
tests := []struct {
description string
zipData string
Expand Down Expand Up @@ -115,6 +119,43 @@ func TestOpen(t *testing.T) {
},
},
},
{
description: "listed all sub directories in deep directory",
zipData: mustZipTree("../testdata/deep"),
wantFiles: map[string]wantFile{
"/a": {
data: mustReadFile("../testdata/deep/a"),
isDir: false,
modTime: deepAHTMLHeader.ModTime(),
mode: deepAHTMLHeader.Mode(),
name: deepAHTMLHeader.Name,
size: int64(deepAHTMLHeader.UncompressedSize64),
},
"/aa/bb/c": {
data: mustReadFile("../testdata/deep/aa/bb/c"),
isDir: false,
modTime: deepCHTMLHeader.ModTime(),
mode: deepCHTMLHeader.Mode(),
name: deepCHTMLHeader.Name,
size: int64(deepCHTMLHeader.UncompressedSize64),
},
"/": {
isDir: true,
mode: os.ModeDir | 0755,
name: "/",
},
"/aa": {
isDir: true,
mode: os.ModeDir | 0755,
name: "/aa",
},
"/aa/bb": {
isDir: true,
mode: os.ModeDir | 0755,
name: "/aa/bb",
},
},
},
}
for _, tc := range tests {
t.Run(tc.description, func(t *testing.T) {
Expand Down Expand Up @@ -155,7 +196,7 @@ func TestOpen(t *testing.T) {
if got, want := stat.Mode(), wantFile.mode; got != want {
t.Errorf("Mode(%v) = %v; want %v", name, got, want)
}
if got, want := stat.Name(), wantFile.name; got != want {
if got, want := stat.Name(), path.Base(wantFile.name); got != want {
t.Errorf("Name(%v) = %v; want %v", name, got, want)
}
if got, want := stat.Size(), wantFile.size; got != want {
Expand All @@ -166,6 +207,38 @@ func TestOpen(t *testing.T) {
}
}

func TestWalk(t *testing.T) {
Register(mustZipTree("../testdata/deep"))
fs, err := New()
if err != nil {
t.Errorf("New() = %v", err)
return
}
var files []string
err = Walk(fs, "/", func(path string, fi os.FileInfo, err error) error {
if err != nil {
return err
}
files = append(files, path)
return nil
})
if err != nil {
t.Errorf("Walk(fs, /) = %v", err)
return
}
expect := []string{
"/",
"/a",
"/aa",
"/aa/bb",
"/aa/bb/c",
}
sort.Strings(files)
if !reflect.DeepEqual(files, expect) {
t.Errorf("something went wrong\ngot: %v\nexpect: %v", files, expect)
}
}

// Test that calling Open by many goroutines concurrently continues
// to return the expected result.
func TestOpen_Parallel(t *testing.T) {
Expand Down
Empty file added testdata/deep/a
Empty file.
Empty file added testdata/deep/aa/bb/c
Empty file.