mirror of https://github.com/spf13/afero.git
Fix #317
This commit is contained in:
parent
100c9a6d7b
commit
0ec4cd15a0
|
@ -13,6 +13,7 @@ import (
|
||||||
type File struct {
|
type File struct {
|
||||||
fs *Fs
|
fs *Fs
|
||||||
zipfile *zip.File
|
zipfile *zip.File
|
||||||
|
pseudodir *pseudoDir
|
||||||
reader io.ReadCloser
|
reader io.ReadCloser
|
||||||
offset int64
|
offset int64
|
||||||
isdir, closed bool
|
isdir, closed bool
|
||||||
|
@ -106,6 +107,9 @@ func (f *File) WriteAt(p []byte, off int64) (n int, err error) { return 0, sysca
|
||||||
|
|
||||||
func (f *File) Name() string {
|
func (f *File) Name() string {
|
||||||
if f.zipfile == nil {
|
if f.zipfile == nil {
|
||||||
|
if f.pseudodir != nil {
|
||||||
|
return f.pseudodir.path
|
||||||
|
}
|
||||||
return string(filepath.Separator)
|
return string(filepath.Separator)
|
||||||
}
|
}
|
||||||
return filepath.Join(splitpath(f.zipfile.Name))
|
return filepath.Join(splitpath(f.zipfile.Name))
|
||||||
|
@ -128,8 +132,12 @@ func (f *File) Readdir(count int) (fi []os.FileInfo, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, zipfile := range zipfiles {
|
for d, zipfile := range zipfiles {
|
||||||
fi = append(fi, zipfile.FileInfo())
|
if zipfile == nil {
|
||||||
|
fi = append(fi, pseudoDir{d})
|
||||||
|
} else {
|
||||||
|
fi = append(fi, zipfile.FileInfo())
|
||||||
|
}
|
||||||
if count > 0 && len(fi) >= count {
|
if count > 0 && len(fi) >= count {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -153,6 +161,9 @@ func (f *File) Readdirnames(count int) (names []string, err error) {
|
||||||
|
|
||||||
func (f *File) Stat() (os.FileInfo, error) {
|
func (f *File) Stat() (os.FileInfo, error) {
|
||||||
if f.zipfile == nil {
|
if f.zipfile == nil {
|
||||||
|
if f.pseudodir != nil {
|
||||||
|
return f.pseudodir, nil
|
||||||
|
}
|
||||||
return &pseudoRoot{}, nil
|
return &pseudoRoot{}, nil
|
||||||
}
|
}
|
||||||
return f.zipfile.FileInfo(), nil
|
return f.zipfile.FileInfo(), nil
|
||||||
|
|
36
zipfs/fs.go
36
zipfs/fs.go
|
@ -42,6 +42,21 @@ func New(r *zip.Reader) afero.Fs {
|
||||||
fs.files[dirname] = make(map[string]*zip.File)
|
fs.files[dirname] = make(map[string]*zip.File)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dv := d
|
||||||
|
for {
|
||||||
|
d, f = splitpath(dv)
|
||||||
|
if _, ok := fs.files[d]; !ok {
|
||||||
|
fs.files[d] = make(map[string]*zip.File)
|
||||||
|
}
|
||||||
|
if f == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, ok := fs.files[d][f]; !ok {
|
||||||
|
fs.files[d][f] = nil
|
||||||
|
}
|
||||||
|
dv = d
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
@ -64,6 +79,13 @@ func (fs *Fs) Open(name string) (afero.File, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
|
return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
|
||||||
}
|
}
|
||||||
|
if file == nil {
|
||||||
|
return &File{
|
||||||
|
fs: fs,
|
||||||
|
pseudodir: &pseudoDir{path: filepath.Join(d, f)},
|
||||||
|
isdir: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
return &File{fs: fs, zipfile: file, isdir: file.FileInfo().IsDir()}, nil
|
return &File{fs: fs, zipfile: file, isdir: file.FileInfo().IsDir()}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +111,17 @@ func (p *pseudoRoot) ModTime() time.Time { return time.Now() }
|
||||||
func (p *pseudoRoot) IsDir() bool { return true }
|
func (p *pseudoRoot) IsDir() bool { return true }
|
||||||
func (p *pseudoRoot) Sys() interface{} { return nil }
|
func (p *pseudoRoot) Sys() interface{} { return nil }
|
||||||
|
|
||||||
|
type pseudoDir struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi pseudoDir) Name() string { return filepath.Base(fi.path) }
|
||||||
|
func (fi pseudoDir) Size() int64 { return 0 }
|
||||||
|
func (fi pseudoDir) IsDir() bool { return true }
|
||||||
|
func (fi pseudoDir) ModTime() time.Time { return time.Now() }
|
||||||
|
func (fi pseudoDir) Mode() os.FileMode { return os.ModeDir | os.ModePerm }
|
||||||
|
func (fi pseudoDir) Sys() interface{} { return nil }
|
||||||
|
|
||||||
func (fs *Fs) Stat(name string) (os.FileInfo, error) {
|
func (fs *Fs) Stat(name string) (os.FileInfo, error) {
|
||||||
d, f := splitpath(name)
|
d, f := splitpath(name)
|
||||||
if f == "" {
|
if f == "" {
|
||||||
|
@ -101,6 +134,9 @@ func (fs *Fs) Stat(name string) (os.FileInfo, error) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
|
return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
|
||||||
}
|
}
|
||||||
|
if file == nil {
|
||||||
|
return pseudoDir{name}, nil
|
||||||
|
}
|
||||||
return file.FileInfo(), nil
|
return file.FileInfo(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -1,12 +1,13 @@
|
||||||
package zipfs
|
package zipfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/spf13/afero"
|
|
||||||
|
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
|
"io/fs"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestZipFS(t *testing.T) {
|
func TestZipFS(t *testing.T) {
|
||||||
|
@ -101,3 +102,62 @@ func TestZipFS(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestZipFsNoDirEntry(t *testing.T) {
|
||||||
|
zrc, err := zip.OpenReader("testdata/no_dir_entry.zip")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
zfs := New(&zrc.Reader)
|
||||||
|
|
||||||
|
// Test Walk
|
||||||
|
expected := map[string]bool{
|
||||||
|
"": true,
|
||||||
|
"sub": true,
|
||||||
|
"sub/testDir2": true,
|
||||||
|
"sub/testDir2/testFile": false,
|
||||||
|
"testDir1": true,
|
||||||
|
"testDir1/testFile": false,
|
||||||
|
}
|
||||||
|
err = afero.Walk(zfs, "", func(path string, info fs.FileInfo, err error) error {
|
||||||
|
path = filepath.ToSlash(path)
|
||||||
|
if isDir, ok := expected[path]; ok {
|
||||||
|
if isDir != info.IsDir() {
|
||||||
|
t.Error("file", path, "isDir:", info.IsDir(), "but expected:", isDir)
|
||||||
|
}
|
||||||
|
delete(expected, path)
|
||||||
|
} else {
|
||||||
|
t.Error("Unexpected file", path, "isDir:", info.IsDir())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if len(expected) > 0 {
|
||||||
|
t.Errorf("Files %v is not found in zip", expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test ReadDir
|
||||||
|
dir, err := afero.ReadDir(zfs, "/")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expected = map[string]bool{
|
||||||
|
"sub": true,
|
||||||
|
"testDir1": true,
|
||||||
|
}
|
||||||
|
for _, d := range dir {
|
||||||
|
if isDir, ok := expected[d.Name()]; ok {
|
||||||
|
if isDir != d.IsDir() {
|
||||||
|
t.Error("file", d.Name(), "isDir:", d.IsDir(), "but expected:", isDir)
|
||||||
|
}
|
||||||
|
delete(expected, d.Name())
|
||||||
|
} else {
|
||||||
|
t.Error("Unexpected file", d.Name(), "isDir:", d.IsDir())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(expected) > 0 {
|
||||||
|
t.Errorf("Files %v is not found in zip", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue