1
2
3
4
5
6
7
8
9
10
11
12
13
14 package afero
15
16 import (
17 "fmt"
18 "io"
19
20 "log"
21 "os"
22 "path/filepath"
23
24 "sort"
25 "strings"
26 "sync"
27 "time"
28
29 "github.com/spf13/afero/mem"
30 )
31
32 const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky
33
34 type MemMapFs struct {
35 mu sync.RWMutex
36 data map[string]*mem.FileData
37 init sync.Once
38 }
39
40 func NewMemMapFs() Fs {
41 return &MemMapFs{}
42 }
43
44 func (m *MemMapFs) getData() map[string]*mem.FileData {
45 m.init.Do(func() {
46 m.data = make(map[string]*mem.FileData)
47
48
49 root := mem.CreateDir(FilePathSeparator)
50 mem.SetMode(root, os.ModeDir|0o755)
51 m.data[FilePathSeparator] = root
52 })
53 return m.data
54 }
55
56 func (*MemMapFs) Name() string { return "MemMapFS" }
57
58 func (m *MemMapFs) Create(name string) (File, error) {
59 name = normalizePath(name)
60 m.mu.Lock()
61 file := mem.CreateFile(name)
62 m.getData()[name] = file
63 m.registerWithParent(file, 0)
64 m.mu.Unlock()
65 return mem.NewFileHandle(file), nil
66 }
67
68 func (m *MemMapFs) unRegisterWithParent(fileName string) error {
69 f, err := m.lockfreeOpen(fileName)
70 if err != nil {
71 return err
72 }
73 parent := m.findParent(f)
74 if parent == nil {
75 log.Panic("parent of ", f.Name(), " is nil")
76 }
77
78 parent.Lock()
79 mem.RemoveFromMemDir(parent, f)
80 parent.Unlock()
81 return nil
82 }
83
84 func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData {
85 pdir, _ := filepath.Split(f.Name())
86 pdir = filepath.Clean(pdir)
87 pfile, err := m.lockfreeOpen(pdir)
88 if err != nil {
89 return nil
90 }
91 return pfile
92 }
93
94 func (m *MemMapFs) findDescendants(name string) []*mem.FileData {
95 fData := m.getData()
96 descendants := make([]*mem.FileData, 0, len(fData))
97 for p, dFile := range fData {
98 if strings.HasPrefix(p, name+FilePathSeparator) {
99 descendants = append(descendants, dFile)
100 }
101 }
102
103 sort.Slice(descendants, func(i, j int) bool {
104 cur := len(strings.Split(descendants[i].Name(), FilePathSeparator))
105 next := len(strings.Split(descendants[j].Name(), FilePathSeparator))
106 return cur < next
107 })
108
109 return descendants
110 }
111
112 func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) {
113 if f == nil {
114 return
115 }
116 parent := m.findParent(f)
117 if parent == nil {
118 pdir := filepath.Dir(filepath.Clean(f.Name()))
119 err := m.lockfreeMkdir(pdir, perm)
120 if err != nil {
121
122 return
123 }
124 parent, err = m.lockfreeOpen(pdir)
125 if err != nil {
126
127 return
128 }
129 }
130
131 parent.Lock()
132 mem.InitializeDir(parent)
133 mem.AddToMemDir(parent, f)
134 parent.Unlock()
135 }
136
137 func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
138 name = normalizePath(name)
139 x, ok := m.getData()[name]
140 if ok {
141
142 i := mem.FileInfo{FileData: x}
143 if !i.IsDir() {
144 return ErrFileExists
145 }
146 } else {
147 item := mem.CreateDir(name)
148 mem.SetMode(item, os.ModeDir|perm)
149 m.getData()[name] = item
150 m.registerWithParent(item, perm)
151 }
152 return nil
153 }
154
155 func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
156 perm &= chmodBits
157 name = normalizePath(name)
158
159 m.mu.RLock()
160 _, ok := m.getData()[name]
161 m.mu.RUnlock()
162 if ok {
163 return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
164 }
165
166 m.mu.Lock()
167
168 if _, ok := m.getData()[name]; ok {
169 m.mu.Unlock()
170 return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
171 }
172 item := mem.CreateDir(name)
173 mem.SetMode(item, os.ModeDir|perm)
174 m.getData()[name] = item
175 m.registerWithParent(item, perm)
176 m.mu.Unlock()
177
178 return m.setFileMode(name, perm|os.ModeDir)
179 }
180
181 func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
182 err := m.Mkdir(path, perm)
183 if err != nil {
184 if err.(*os.PathError).Err == ErrFileExists {
185 return nil
186 }
187 return err
188 }
189 return nil
190 }
191
192
193 func normalizePath(path string) string {
194 path = filepath.Clean(path)
195
196 switch path {
197 case ".":
198 return FilePathSeparator
199 case "..":
200 return FilePathSeparator
201 default:
202 return path
203 }
204 }
205
206 func (m *MemMapFs) Open(name string) (File, error) {
207 f, err := m.open(name)
208 if f != nil {
209 return mem.NewReadOnlyFileHandle(f), err
210 }
211 return nil, err
212 }
213
214 func (m *MemMapFs) openWrite(name string) (File, error) {
215 f, err := m.open(name)
216 if f != nil {
217 return mem.NewFileHandle(f), err
218 }
219 return nil, err
220 }
221
222 func (m *MemMapFs) open(name string) (*mem.FileData, error) {
223 name = normalizePath(name)
224
225 m.mu.RLock()
226 f, ok := m.getData()[name]
227 m.mu.RUnlock()
228 if !ok {
229 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound}
230 }
231 return f, nil
232 }
233
234 func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
235 name = normalizePath(name)
236 f, ok := m.getData()[name]
237 if ok {
238 return f, nil
239 } else {
240 return nil, ErrFileNotFound
241 }
242 }
243
244 func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
245 perm &= chmodBits
246 chmod := false
247 file, err := m.openWrite(name)
248 if err == nil && (flag&os.O_EXCL > 0) {
249 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists}
250 }
251 if os.IsNotExist(err) && (flag&os.O_CREATE > 0) {
252 file, err = m.Create(name)
253 chmod = true
254 }
255 if err != nil {
256 return nil, err
257 }
258 if flag == os.O_RDONLY {
259 file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
260 }
261 if flag&os.O_APPEND > 0 {
262 _, err = file.Seek(0, io.SeekEnd)
263 if err != nil {
264 file.Close()
265 return nil, err
266 }
267 }
268 if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 {
269 err = file.Truncate(0)
270 if err != nil {
271 file.Close()
272 return nil, err
273 }
274 }
275 if chmod {
276 return file, m.setFileMode(name, perm)
277 }
278 return file, nil
279 }
280
281 func (m *MemMapFs) Remove(name string) error {
282 name = normalizePath(name)
283
284 m.mu.Lock()
285 defer m.mu.Unlock()
286
287 if _, ok := m.getData()[name]; ok {
288 err := m.unRegisterWithParent(name)
289 if err != nil {
290 return &os.PathError{Op: "remove", Path: name, Err: err}
291 }
292 delete(m.getData(), name)
293 } else {
294 return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist}
295 }
296 return nil
297 }
298
299 func (m *MemMapFs) RemoveAll(path string) error {
300 path = normalizePath(path)
301 m.mu.Lock()
302 m.unRegisterWithParent(path)
303 m.mu.Unlock()
304
305 m.mu.RLock()
306 defer m.mu.RUnlock()
307
308 for p := range m.getData() {
309 if p == path || strings.HasPrefix(p, path+FilePathSeparator) {
310 m.mu.RUnlock()
311 m.mu.Lock()
312 delete(m.getData(), p)
313 m.mu.Unlock()
314 m.mu.RLock()
315 }
316 }
317 return nil
318 }
319
320 func (m *MemMapFs) Rename(oldname, newname string) error {
321 oldname = normalizePath(oldname)
322 newname = normalizePath(newname)
323
324 if oldname == newname {
325 return nil
326 }
327
328 m.mu.RLock()
329 defer m.mu.RUnlock()
330 if _, ok := m.getData()[oldname]; ok {
331 m.mu.RUnlock()
332 m.mu.Lock()
333 err := m.unRegisterWithParent(oldname)
334 if err != nil {
335 return err
336 }
337
338 fileData := m.getData()[oldname]
339 mem.ChangeFileName(fileData, newname)
340 m.getData()[newname] = fileData
341
342 err = m.renameDescendants(oldname, newname)
343 if err != nil {
344 return err
345 }
346
347 delete(m.getData(), oldname)
348
349 m.registerWithParent(fileData, 0)
350 m.mu.Unlock()
351 m.mu.RLock()
352 } else {
353 return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
354 }
355 return nil
356 }
357
358 func (m *MemMapFs) renameDescendants(oldname, newname string) error {
359 descendants := m.findDescendants(oldname)
360 removes := make([]string, 0, len(descendants))
361 for _, desc := range descendants {
362 descNewName := strings.Replace(desc.Name(), oldname, newname, 1)
363 err := m.unRegisterWithParent(desc.Name())
364 if err != nil {
365 return err
366 }
367
368 removes = append(removes, desc.Name())
369 mem.ChangeFileName(desc, descNewName)
370 m.getData()[descNewName] = desc
371
372 m.registerWithParent(desc, 0)
373 }
374 for _, r := range removes {
375 delete(m.getData(), r)
376 }
377
378 return nil
379 }
380
381 func (m *MemMapFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
382 fileInfo, err := m.Stat(name)
383 return fileInfo, false, err
384 }
385
386 func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
387 f, err := m.Open(name)
388 if err != nil {
389 return nil, err
390 }
391 fi := mem.GetFileInfo(f.(*mem.File).Data())
392 return fi, nil
393 }
394
395 func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
396 mode &= chmodBits
397
398 m.mu.RLock()
399 f, ok := m.getData()[name]
400 m.mu.RUnlock()
401 if !ok {
402 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
403 }
404 prevOtherBits := mem.GetFileInfo(f).Mode() & ^chmodBits
405
406 mode = prevOtherBits | mode
407 return m.setFileMode(name, mode)
408 }
409
410 func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error {
411 name = normalizePath(name)
412
413 m.mu.RLock()
414 f, ok := m.getData()[name]
415 m.mu.RUnlock()
416 if !ok {
417 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
418 }
419
420 m.mu.Lock()
421 mem.SetMode(f, mode)
422 m.mu.Unlock()
423
424 return nil
425 }
426
427 func (m *MemMapFs) Chown(name string, uid, gid int) error {
428 name = normalizePath(name)
429
430 m.mu.RLock()
431 f, ok := m.getData()[name]
432 m.mu.RUnlock()
433 if !ok {
434 return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound}
435 }
436
437 mem.SetUID(f, uid)
438 mem.SetGID(f, gid)
439
440 return nil
441 }
442
443 func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
444 name = normalizePath(name)
445
446 m.mu.RLock()
447 f, ok := m.getData()[name]
448 m.mu.RUnlock()
449 if !ok {
450 return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
451 }
452
453 m.mu.Lock()
454 mem.SetModTime(f, mtime)
455 m.mu.Unlock()
456
457 return nil
458 }
459
460 func (m *MemMapFs) List() {
461 for _, x := range m.data {
462 y := mem.FileInfo{FileData: x}
463 fmt.Println(x.Name(), y.Size())
464 }
465 }
466
View as plain text