memfs - directory.go
1 package memfs
2
3 import (
4 "io"
5 "io/fs"
6 "time"
7 )
8
9 type directoryEntry interface {
10 IsDir() bool
11 ModTime() time.Time
12 Type() fs.FileMode
13 Mode() fs.FileMode
14 Size() int64
15 open(name string, mode opMode) (fs.File, error)
16 bytes() ([]byte, error)
17 setMode(fs.FileMode)
18 setTimes(time.Time, time.Time)
19 seal() directoryEntry
20 getEntry(string) (*dirEnt, error)
21 }
22
23 type dNode interface {
24 getEntry(string) (*dirEnt, error)
25 setEntry(*dirEnt) error
26 hasEntries() bool
27 getEntries() ([]fs.DirEntry, error)
28 removeEntry(string) error
29 Mode() fs.FileMode
30 }
31
32 type dirEnt struct {
33 directoryEntry
34 name string
35 }
36
37 func (d *dirEnt) Info() (fs.FileInfo, error) {
38 return d, nil
39 }
40
41 func (d *dirEnt) Name() string {
42 return d.name
43 }
44
45 func (d *dirEnt) Sys() any {
46 return d.directoryEntry
47 }
48
49 type dnode struct {
50 entries []*dirEnt
51 modtime time.Time
52 mode fs.FileMode
53 }
54
55 func (d *dnode) open(name string, _ opMode) (fs.File, error) {
56 if d.mode&0o444 == 0 {
57 return nil, fs.ErrPermission
58 }
59
60 return &directory{
61 dnode: d,
62 name: name,
63 }, nil
64 }
65
66 func (d *dnode) bytes() ([]byte, error) {
67 return nil, fs.ErrInvalid
68 }
69
70 func (d *dnode) getEntry(name string) (*dirEnt, error) {
71 if d.mode&0o444 == 0 {
72 return nil, fs.ErrPermission
73 }
74
75 for _, de := range d.entries {
76 if de.name == name {
77 return de, nil
78 }
79 }
80
81 return nil, fs.ErrNotExist
82 }
83
84 func (d *dnode) setEntry(de *dirEnt) error {
85 if d.mode&0o222 == 0 {
86 return fs.ErrPermission
87 }
88
89 d.entries = append(d.entries, de)
90 d.modtime = time.Now()
91
92 return nil
93 }
94
95 func (d *dnode) hasEntries() bool {
96 return len(d.entries) > 0
97 }
98
99 func (d *dnode) getEntries() ([]fs.DirEntry, error) {
100 if d.mode&0o444 == 0 {
101 return nil, fs.ErrPermission
102 }
103
104 dirs := make([]fs.DirEntry, len(d.entries))
105
106 for i := range d.entries {
107 dirs[i] = d.entries[i]
108 }
109
110 return dirs, nil
111 }
112
113 func (d *dnode) removeEntry(name string) error {
114 if d.mode&0o222 == 0 {
115 return fs.ErrPermission
116 }
117
118 for n, de := range d.entries {
119 if de.name == name {
120 d.entries = append(d.entries[:n], d.entries[n+1:]...)
121 d.modtime = time.Now()
122
123 return nil
124 }
125 }
126
127 return fs.ErrNotExist
128 }
129
130 func (d *dnode) setMode(mode fs.FileMode) {
131 d.mode = fs.ModeDir | mode
132 }
133
134 func (d *dnode) setTimes(_, mtime time.Time) {
135 d.modtime = mtime
136 }
137
138 func (d *dnode) seal() directoryEntry {
139 return d
140 }
141
142 type directory struct {
143 *dnode
144 name string
145 pos int
146 }
147
148 func (d *directory) Info() (fs.FileInfo, error) {
149 return d, nil
150 }
151
152 func (d *directory) Stat() (fs.FileInfo, error) {
153 return d, nil
154 }
155
156 func (d *directory) Read(_ []byte) (int, error) {
157 return 0, &fs.PathError{
158 Op: "read",
159 Path: d.name,
160 Err: fs.ErrInvalid,
161 }
162 }
163
164 func (d *directory) Close() error {
165 return nil
166 }
167
168 func (d *directory) ReadDir(n int) ([]fs.DirEntry, error) {
169 if d.mode&0o444 == 0 {
170 return nil, &fs.PathError{
171 Op: "readdir",
172 Path: d.name,
173 Err: fs.ErrPermission,
174 }
175 }
176
177 left := len(d.entries) - d.pos
178
179 m := n
180
181 if left < n || n <= 0 {
182 m = left
183 }
184
185 if m == 0 {
186 if n <= 0 {
187 return nil, nil
188 }
189
190 return nil, io.EOF
191 }
192
193 dirs := make([]fs.DirEntry, m)
194
195 for i := range dirs {
196 dirs[i] = d.entries[d.pos]
197 d.pos++
198 }
199
200 return dirs, nil
201 }
202
203 func (d *directory) Name() string {
204 return d.name
205 }
206
207 func (d *dnode) Size() int64 {
208 return 0
209 }
210
211 func (d *dnode) Type() fs.FileMode {
212 return d.mode.Type()
213 }
214
215 func (d *dnode) Mode() fs.FileMode {
216 return d.mode
217 }
218
219 func (d *dnode) ModTime() time.Time {
220 return d.modtime
221 }
222
223 func (d *dnode) IsDir() bool {
224 return true
225 }
226
227 func (d *directory) Sys() any {
228 return d
229 }
230