1 package zipfs
2
3 import (
4 "archive/zip"
5 "os"
6 "path/filepath"
7 "syscall"
8 "time"
9
10 "github.com/spf13/afero"
11 )
12
13 type Fs struct {
14 r *zip.Reader
15 files map[string]map[string]*zip.File
16 }
17
18 func splitpath(name string) (dir, file string) {
19 name = filepath.ToSlash(name)
20 if len(name) == 0 || name[0] != '/' {
21 name = "/" + name
22 }
23 name = filepath.Clean(name)
24 dir, file = filepath.Split(name)
25 dir = filepath.Clean(dir)
26 return
27 }
28
29 func New(r *zip.Reader) afero.Fs {
30 fs := &Fs{r: r, files: make(map[string]map[string]*zip.File)}
31 for _, file := range r.File {
32 d, f := splitpath(file.Name)
33 if _, ok := fs.files[d]; !ok {
34 fs.files[d] = make(map[string]*zip.File)
35 }
36 if _, ok := fs.files[d][f]; !ok {
37 fs.files[d][f] = file
38 }
39 if file.FileInfo().IsDir() {
40 dirname := filepath.Join(d, f)
41 if _, ok := fs.files[dirname]; !ok {
42 fs.files[dirname] = make(map[string]*zip.File)
43 }
44 }
45 }
46 return fs
47 }
48
49 func (fs *Fs) Create(name string) (afero.File, error) { return nil, syscall.EPERM }
50
51 func (fs *Fs) Mkdir(name string, perm os.FileMode) error { return syscall.EPERM }
52
53 func (fs *Fs) MkdirAll(path string, perm os.FileMode) error { return syscall.EPERM }
54
55 func (fs *Fs) Open(name string) (afero.File, error) {
56 d, f := splitpath(name)
57 if f == "" {
58 return &File{fs: fs, isdir: true}, nil
59 }
60 if _, ok := fs.files[d]; !ok {
61 return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
62 }
63 file, ok := fs.files[d][f]
64 if !ok {
65 return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
66 }
67 return &File{fs: fs, zipfile: file, isdir: file.FileInfo().IsDir()}, nil
68 }
69
70 func (fs *Fs) OpenFile(name string, flag int, perm os.FileMode) (afero.File, error) {
71 if flag != os.O_RDONLY {
72 return nil, syscall.EPERM
73 }
74 return fs.Open(name)
75 }
76
77 func (fs *Fs) Remove(name string) error { return syscall.EPERM }
78
79 func (fs *Fs) RemoveAll(path string) error { return syscall.EPERM }
80
81 func (fs *Fs) Rename(oldname, newname string) error { return syscall.EPERM }
82
83 type pseudoRoot struct{}
84
85 func (p *pseudoRoot) Name() string { return string(filepath.Separator) }
86 func (p *pseudoRoot) Size() int64 { return 0 }
87 func (p *pseudoRoot) Mode() os.FileMode { return os.ModeDir | os.ModePerm }
88 func (p *pseudoRoot) ModTime() time.Time { return time.Now() }
89 func (p *pseudoRoot) IsDir() bool { return true }
90 func (p *pseudoRoot) Sys() interface{} { return nil }
91
92 func (fs *Fs) Stat(name string) (os.FileInfo, error) {
93 d, f := splitpath(name)
94 if f == "" {
95 return &pseudoRoot{}, nil
96 }
97 if _, ok := fs.files[d]; !ok {
98 return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
99 }
100 file, ok := fs.files[d][f]
101 if !ok {
102 return nil, &os.PathError{Op: "stat", Path: name, Err: syscall.ENOENT}
103 }
104 return file.FileInfo(), nil
105 }
106
107 func (fs *Fs) Name() string { return "zipfs" }
108
109 func (fs *Fs) Chmod(name string, mode os.FileMode) error { return syscall.EPERM }
110
111 func (fs *Fs) Chown(name string, uid, gid int) error { return syscall.EPERM }
112
113 func (fs *Fs) Chtimes(name string, atime time.Time, mtime time.Time) error { return syscall.EPERM }
114
View as plain text