1
2
3
4
5 package fstest
6
7 import (
8 "io"
9 "io/fs"
10 "path"
11 "sort"
12 "strings"
13 "time"
14 )
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 type MapFS map[string]*MapFile
34
35
36 type MapFile struct {
37 Data []byte
38 Mode fs.FileMode
39 ModTime time.Time
40 Sys interface{}
41 }
42
43 var _ fs.FS = MapFS(nil)
44 var _ fs.File = (*openMapFile)(nil)
45
46
47 func (fsys MapFS) Open(name string) (fs.File, error) {
48 if !fs.ValidPath(name) {
49 return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
50 }
51 file := fsys[name]
52 if file != nil && file.Mode&fs.ModeDir == 0 {
53
54 return &openMapFile{name, mapFileInfo{path.Base(name), file}, 0}, nil
55 }
56
57
58
59
60
61 var list []mapFileInfo
62 var elem string
63 var need = make(map[string]bool)
64 if name == "." {
65 elem = "."
66 for fname, f := range fsys {
67 i := strings.Index(fname, "/")
68 if i < 0 {
69 list = append(list, mapFileInfo{fname, f})
70 } else {
71 need[fname[:i]] = true
72 }
73 }
74 } else {
75 elem = name[strings.LastIndex(name, "/")+1:]
76 prefix := name + "/"
77 for fname, f := range fsys {
78 if strings.HasPrefix(fname, prefix) {
79 felem := fname[len(prefix):]
80 i := strings.Index(felem, "/")
81 if i < 0 {
82 list = append(list, mapFileInfo{felem, f})
83 } else {
84 need[fname[len(prefix):len(prefix)+i]] = true
85 }
86 }
87 }
88
89
90
91 if file == nil && list == nil && len(need) == 0 {
92 return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
93 }
94 }
95 for _, fi := range list {
96 delete(need, fi.name)
97 }
98 for name := range need {
99 list = append(list, mapFileInfo{name, &MapFile{Mode: fs.ModeDir}})
100 }
101 sort.Slice(list, func(i, j int) bool {
102 return list[i].name < list[j].name
103 })
104
105 if file == nil {
106 file = &MapFile{Mode: fs.ModeDir}
107 }
108 return &mapDir{name, mapFileInfo{elem, file}, list, 0}, nil
109 }
110
111
112
113
114
115
116
117 type fsOnly struct{ fs.FS }
118
119 func (fsys MapFS) ReadFile(name string) ([]byte, error) {
120 return fs.ReadFile(fsOnly{fsys}, name)
121 }
122
123 func (fsys MapFS) Stat(name string) (fs.FileInfo, error) {
124 return fs.Stat(fsOnly{fsys}, name)
125 }
126
127 func (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error) {
128 return fs.ReadDir(fsOnly{fsys}, name)
129 }
130
131 func (fsys MapFS) Glob(pattern string) ([]string, error) {
132 return fs.Glob(fsOnly{fsys}, pattern)
133 }
134
135 type noSub struct {
136 MapFS
137 }
138
139 func (noSub) Sub() {}
140
141 func (fsys MapFS) Sub(dir string) (fs.FS, error) {
142 return fs.Sub(noSub{fsys}, dir)
143 }
144
145
146 type mapFileInfo struct {
147 name string
148 f *MapFile
149 }
150
151 func (i *mapFileInfo) Name() string { return i.name }
152 func (i *mapFileInfo) Size() int64 { return int64(len(i.f.Data)) }
153 func (i *mapFileInfo) Mode() fs.FileMode { return i.f.Mode }
154 func (i *mapFileInfo) Type() fs.FileMode { return i.f.Mode.Type() }
155 func (i *mapFileInfo) ModTime() time.Time { return i.f.ModTime }
156 func (i *mapFileInfo) IsDir() bool { return i.f.Mode&fs.ModeDir != 0 }
157 func (i *mapFileInfo) Sys() interface{} { return i.f.Sys }
158 func (i *mapFileInfo) Info() (fs.FileInfo, error) { return i, nil }
159
160
161 type openMapFile struct {
162 path string
163 mapFileInfo
164 offset int64
165 }
166
167 func (f *openMapFile) Stat() (fs.FileInfo, error) { return &f.mapFileInfo, nil }
168
169 func (f *openMapFile) Close() error { return nil }
170
171 func (f *openMapFile) Read(b []byte) (int, error) {
172 if f.offset >= int64(len(f.f.Data)) {
173 return 0, io.EOF
174 }
175 if f.offset < 0 {
176 return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid}
177 }
178 n := copy(b, f.f.Data[f.offset:])
179 f.offset += int64(n)
180 return n, nil
181 }
182
183 func (f *openMapFile) Seek(offset int64, whence int) (int64, error) {
184 switch whence {
185 case 0:
186
187 case 1:
188 offset += f.offset
189 case 2:
190 offset += int64(len(f.f.Data))
191 }
192 if offset < 0 || offset > int64(len(f.f.Data)) {
193 return 0, &fs.PathError{Op: "seek", Path: f.path, Err: fs.ErrInvalid}
194 }
195 f.offset = offset
196 return offset, nil
197 }
198
199 func (f *openMapFile) ReadAt(b []byte, offset int64) (int, error) {
200 if offset < 0 || offset > int64(len(f.f.Data)) {
201 return 0, &fs.PathError{Op: "read", Path: f.path, Err: fs.ErrInvalid}
202 }
203 n := copy(b, f.f.Data[offset:])
204 if n < len(b) {
205 return n, io.EOF
206 }
207 return n, nil
208 }
209
210
211 type mapDir struct {
212 path string
213 mapFileInfo
214 entry []mapFileInfo
215 offset int
216 }
217
218 func (d *mapDir) Stat() (fs.FileInfo, error) { return &d.mapFileInfo, nil }
219 func (d *mapDir) Close() error { return nil }
220 func (d *mapDir) Read(b []byte) (int, error) {
221 return 0, &fs.PathError{Op: "read", Path: d.path, Err: fs.ErrInvalid}
222 }
223
224 func (d *mapDir) ReadDir(count int) ([]fs.DirEntry, error) {
225 n := len(d.entry) - d.offset
226 if n == 0 && count > 0 {
227 return nil, io.EOF
228 }
229 if count > 0 && n > count {
230 n = count
231 }
232 list := make([]fs.DirEntry, n)
233 for i := range list {
234 list[i] = &d.entry[d.offset+i]
235 }
236 d.offset += n
237 return list, nil
238 }
239
View as plain text