...
1
2 package filter
3
4 import (
5 "fmt"
6 "io"
7 "net/http"
8 "os"
9 pathpkg "path"
10 "time"
11 )
12
13
14
15
16
17
18
19
20
21 type Func func(path string, fi os.FileInfo) bool
22
23
24
25 func Keep(source http.FileSystem, keep Func) http.FileSystem {
26 return &filterFS{source: source, keep: keep}
27 }
28
29
30
31 func Skip(source http.FileSystem, skip Func) http.FileSystem {
32 keep := func(path string, fi os.FileInfo) bool {
33 return !skip(path, fi)
34 }
35 return &filterFS{source: source, keep: keep}
36 }
37
38 type filterFS struct {
39 source http.FileSystem
40 keep Func
41 }
42
43 func (fs *filterFS) Open(path string) (http.File, error) {
44 f, err := fs.source.Open(path)
45 if err != nil {
46 return nil, err
47 }
48
49 fi, err := f.Stat()
50 if err != nil {
51 f.Close()
52 return nil, err
53 }
54
55 if !fs.keep(clean(path), fi) {
56
57 f.Close()
58 return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
59 }
60
61 if !fi.IsDir() {
62 return f, nil
63 }
64 defer f.Close()
65
66 fis, err := f.Readdir(0)
67 if err != nil {
68 return nil, err
69 }
70
71 var entries []os.FileInfo
72 for _, fi := range fis {
73 if !fs.keep(clean(pathpkg.Join(path, fi.Name())), fi) {
74
75 continue
76 }
77 entries = append(entries, fi)
78 }
79
80 return &dir{
81 name: fi.Name(),
82 entries: entries,
83 modTime: fi.ModTime(),
84 }, nil
85 }
86
87
88
89
90 func clean(path string) string {
91 return pathpkg.Clean("/" + path)
92 }
93
94
95 type dir struct {
96 name string
97 modTime time.Time
98 entries []os.FileInfo
99 pos int
100 }
101
102 func (d *dir) Read([]byte) (int, error) {
103 return 0, fmt.Errorf("cannot Read from directory %s", d.name)
104 }
105 func (d *dir) Close() error { return nil }
106 func (d *dir) Stat() (os.FileInfo, error) { return d, nil }
107
108 func (d *dir) Name() string { return d.name }
109 func (d *dir) Size() int64 { return 0 }
110 func (d *dir) Mode() os.FileMode { return 0755 | os.ModeDir }
111 func (d *dir) ModTime() time.Time { return d.modTime }
112 func (d *dir) IsDir() bool { return true }
113 func (d *dir) Sys() interface{} { return nil }
114
115 func (d *dir) Seek(offset int64, whence int) (int64, error) {
116 if offset == 0 && whence == io.SeekStart {
117 d.pos = 0
118 return 0, nil
119 }
120 return 0, fmt.Errorf("unsupported Seek in directory %s", d.name)
121 }
122
123 func (d *dir) Readdir(count int) ([]os.FileInfo, error) {
124 if d.pos >= len(d.entries) && count > 0 {
125 return nil, io.EOF
126 }
127 if count <= 0 || count > len(d.entries)-d.pos {
128 count = len(d.entries) - d.pos
129 }
130 e := d.entries[d.pos : d.pos+count]
131 d.pos += count
132 return e, nil
133 }
134
View as plain text