-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfs.go
More file actions
104 lines (93 loc) · 2.6 KB
/
fs.go
File metadata and controls
104 lines (93 loc) · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package fsconvert
import (
"io/fs"
"sync"
"testing/fstest"
"time"
)
// FS is a simple structure implementing io/fs's FS interface
// It is implemented as a MapFS (from testing/fstest) but with locks
// to be able to have concurrent reads and writes
type FS struct {
mutex sync.RWMutex
mapFS fstest.MapFS
}
type file struct {
mutex *sync.RWMutex
mapFile fs.File
}
// Open opens the named file.
func (fsys FS) Open(name string) (fs.File, error) {
fsys.mutex.RLock()
defer fsys.mutex.RUnlock()
f, err := fsys.mapFS.Open(name)
return file{mutex: &fsys.mutex, mapFile: f}, err
}
// ReadDir opens the named directory and returns a list of
// directory entries sorted by filename.
func (fsys FS) ReadDir(name string) ([]fs.DirEntry, error) {
fsys.mutex.RLock()
defer fsys.mutex.RUnlock()
de, err := fsys.mapFS.ReadDir(name)
return de, err
}
func (f file) Stat() (fs.FileInfo, error) {
f.mutex.RLock()
fi, err := f.mapFile.Stat()
f.mutex.RUnlock()
return fi, err
}
func (f file) Read(b []byte) (int, error) {
f.mutex.RLock()
defer f.mutex.RUnlock()
n, err := f.mapFile.Read(b)
return n, err
}
func (f file) Close() error {
f.mutex.RLock()
defer f.mutex.RUnlock()
err := f.mapFile.Close()
return err
}
// Remove removes the named file or (empty) directory.
// It may return nil, even if the name does not exist
// or cannot be removed (because it belongs to a non-empty directory)
func (fsys *FS) Remove(name string) error {
if !fs.ValidPath(name) {
return &fs.PathError{Op: "remove", Path: name, Err: fs.ErrNotExist}
}
fsys.mutex.Lock()
defer fsys.mutex.Unlock()
delete(fsys.mapFS, name)
return nil
}
// WriteFile creates or overwrites the named file with the specified
// data and permissions.
func (fsys *FS) WriteFile(name string, data []byte, perm fs.FileMode) error {
if !fs.ValidPath(name) {
return &fs.PathError{Op: "WriteFile", Path: name, Err: fs.ErrNotExist}
}
mapFile := fstest.MapFile{Data: data, Mode: perm, ModTime: time.Now()}
fsys.mutex.Lock()
defer fsys.mutex.Unlock()
if fsys.mapFS == nil {
fsys.mapFS = make(fstest.MapFS)
}
fsys.mapFS[name] = &mapFile
return nil
}
// AppendFile appends data to the already existing named file.
func (fsys *FS) AppendFile(name string, data []byte) error {
if !fs.ValidPath(name) {
return &fs.PathError{Op: "AppendFile", Path: name, Err: fs.ErrNotExist}
}
fsys.mutex.Lock()
defer fsys.mutex.Unlock()
if fsys.mapFS == nil || fsys.mapFS[name] == nil {
return &fs.PathError{Op: "AppendFile", Path: name, Err: fs.ErrNotExist}
}
mapFile := fsys.mapFS[name]
mapFile.Data = append(mapFile.Data, data...)
mapFile.ModTime = time.Now()
return nil
}