memfs - file_rw.go
1 package memfs
2
3 import (
4 "errors"
5 "io"
6 "io/fs"
7 "sync"
8 "time"
9 "unicode/utf8"
10 )
11
12 type inodeRW struct {
13 inode
14 mu sync.RWMutex
15 }
16
17 func (i *inodeRW) open(name string, mode opMode) (fs.File, error) {
18 i.mu.Lock()
19 defer i.mu.Unlock()
20
21 if mode&opRead > 0 && i.mode&0o444 == 0 || mode&opWrite > 0 && i.mode&0o222 == 0 {
22 return nil, fs.ErrPermission
23 }
24
25 return &File{
26 mu: &i.mu,
27 file: file{
28 name: name,
29 inode: &i.inode,
30 opMode: mode,
31 },
32 }, nil
33 }
34
35 func (i *inodeRW) bytes() ([]byte, error) {
36 i.mu.RLock()
37 defer i.mu.RUnlock()
38
39 bytes, err := i.inode.bytes()
40 if err != nil {
41 return nil, err
42 }
43
44 return append(make([]byte, 0, len(bytes)), bytes...), nil
45 }
46
47 func (i *inodeRW) setMode(mode fs.FileMode) {
48 i.mu.Lock()
49 defer i.mu.Unlock()
50
51 i.mode = i.mode&fs.ModeSymlink | mode
52 }
53
54 func (i *inodeRW) setTimes(_, mtime time.Time) {
55 i.mu.Lock()
56 defer i.mu.Unlock()
57
58 i.modtime = mtime
59 }
60
61 func (i *inodeRW) seal() directoryEntry {
62 i.mu.Lock()
63 defer i.mu.Unlock()
64
65 de := i.inode
66 i.inode = inode{}
67
68 return &de
69 }
70
71 func (i *inodeRW) Size() int64 {
72 i.mu.RLock()
73 defer i.mu.RUnlock()
74
75 return int64(len(i.data))
76 }
77
78 func (i *inodeRW) Type() fs.FileMode {
79 i.mu.RLock()
80 defer i.mu.RUnlock()
81
82 return i.mode
83 }
84
85 func (i *inodeRW) Mode() fs.FileMode {
86 i.mu.RLock()
87 defer i.mu.RUnlock()
88
89 return i.mode
90 }
91
92 func (i *inodeRW) ModTime() time.Time {
93 i.mu.RLock()
94 defer i.mu.RUnlock()
95
96 return i.modtime
97 }
98
99 // File represents an open file, that can be used for reading and writing
100 // (depending on how it was opened).
101 //
102 // The file locks when making any changes, and so can be safely used from
103 // multiple goroutines.
104 type File struct {
105 mu *sync.RWMutex
106 file
107 }
108
109 func (f *File) Read(p []byte) (int, error) {
110 f.mu.Lock()
111 defer f.mu.Unlock()
112
113 return f.file.Read(p)
114 }
115
116 func (f *File) ReadAt(p []byte, off int64) (int, error) {
117 f.mu.RLock()
118 defer f.mu.RUnlock()
119
120 return f.file.ReadAt(p, off)
121 }
122
123 func (f *File) ReadByte() (byte, error) {
124 f.mu.Lock()
125 defer f.mu.Unlock()
126
127 return f.file.ReadByte()
128 }
129
130 func (f *File) UnreadByte() error {
131 f.mu.Lock()
132 defer f.mu.Unlock()
133
134 return f.file.UnreadByte()
135 }
136
137 func (f *File) ReadRune() (rune, int, error) {
138 f.mu.Lock()
139 defer f.mu.Unlock()
140
141 return f.file.ReadRune()
142 }
143
144 func (f *File) UnreadRune() error {
145 f.mu.Lock()
146 defer f.mu.Unlock()
147
148 return f.file.UnreadRune()
149 }
150
151 func (f *File) WriteTo(w io.Writer) (int64, error) {
152 f.mu.Lock()
153 defer f.mu.Unlock()
154
155 if err := f.validTo("writeto", opRead, true); err != nil {
156 return 0, err
157 }
158
159 data := f.data[f.pos:]
160
161 n, err := w.Write(append(make([]byte, 0, len(data)), data...))
162 f.pos += int64(n)
163 f.lastRead = 0
164
165 return int64(n), err
166 }
167
168 func (f *File) Seek(offset int64, whence int) (int64, error) {
169 f.mu.Lock()
170 defer f.mu.Unlock()
171
172 return f.file.Seek(offset, whence)
173 }
174
175 func (f *File) Close() error {
176 f.mu.Lock()
177 defer f.mu.Unlock()
178
179 return f.file.Close()
180 }
181
182 func (f *File) grow(size int) {
183 if size > len(f.data) {
184 if size < cap(f.data) {
185 f.data = (f.data)[:size]
186 } else {
187 var newData []byte
188
189 const simpleGrowLimit = 512
190
191 if len(f.data) < simpleGrowLimit {
192 newData = make([]byte, size, size<<1)
193 } else {
194 const growShift = 2
195
196 newData = make([]byte, size, size+(size>>growShift))
197 }
198
199 copy(newData, f.data)
200 f.data = newData
201 }
202 }
203 }
204
205 func (f *File) Write(p []byte) (int, error) {
206 f.mu.Lock()
207 defer f.mu.Unlock()
208
209 if err := f.validTo("write", opWrite, false); err != nil {
210 return 0, err
211 }
212
213 f.grow(int(f.pos) + len(p))
214
215 n := copy(f.data[f.pos:], p)
216 f.pos += int64(n)
217 f.lastRead = 0
218 f.modtime = time.Now()
219
220 return n, nil
221 }
222
223 func (f *File) WriteAt(p []byte, off int64) (int, error) {
224 f.mu.Lock()
225 defer f.mu.Unlock()
226
227 if err := f.validTo("writeat", opWrite|opSeek, false); err != nil {
228 return 0, err
229 }
230
231 f.grow(int(off) + len(p))
232
233 n := copy(f.data[off:], p)
234 f.modtime = time.Now()
235
236 return n, nil
237 }
238
239 func (f *File) WriteString(str string) (int, error) {
240 f.mu.Lock()
241 defer f.mu.Unlock()
242
243 if err := f.validTo("writestring", opWrite, false); err != nil {
244 return 0, err
245 }
246
247 f.grow(int(f.pos) + len(str))
248
249 n := copy(f.data[f.pos:], str)
250 f.pos += int64(n)
251 f.lastRead = 0
252 f.modtime = time.Now()
253
254 return n, nil
255 }
256
257 func (f *File) WriteByte(c byte) error {
258 f.mu.Lock()
259 defer f.mu.Unlock()
260
261 if err := f.validTo("writebyte", opWrite, false); err != nil {
262 return err
263 }
264
265 f.grow(int(f.pos) + 1)
266
267 f.data[f.pos] = c
268 f.pos++
269 f.lastRead = 0
270 f.modtime = time.Now()
271
272 return nil
273 }
274
275 func (f *File) WriteRune(r rune) (int, error) {
276 f.mu.Lock()
277 defer f.mu.Unlock()
278
279 if err := f.validTo("writerune", opWrite, false); err != nil {
280 return 0, err
281 }
282
283 p := utf8.AppendRune([]byte{}, r)
284
285 f.grow(int(f.pos) + len(p))
286
287 n := copy(f.data[f.pos:], p)
288 f.pos += int64(n)
289 f.lastRead = 0
290 f.modtime = time.Now()
291
292 return n, nil
293 }
294
295 func (f *File) ReadFrom(r io.Reader) (int64, error) {
296 f.mu.Lock()
297 defer f.mu.Unlock()
298
299 if err := f.validTo("readfrom", opWrite, false); err != nil {
300 return 0, err
301 }
302
303 var count int64
304
305 for {
306 f.grow(int(f.pos + 1))
307
308 n, err := r.Read(f.data[f.pos:cap(f.data)])
309
310 count += int64(n)
311 f.pos += int64(n)
312 f.data = f.data[:f.pos]
313
314 if errors.Is(err, io.EOF) {
315 return count, nil
316 }
317
318 if err != nil {
319 return count, err
320 }
321 }
322 }
323
324 func (f *File) handleOpenMode(mode Mode) {
325 if mode&Truncate != 0 {
326 f.data = f.data[:0]
327 f.modtime = time.Now()
328 }
329
330 if mode&Append != 0 {
331 f.pos = int64(len(f.data))
332 }
333 }
334