equal
deleted
inserted
replaced
16 |
16 |
17 import ( |
17 import ( |
18 "bytes" |
18 "bytes" |
19 "errors" |
19 "errors" |
20 "io" |
20 "io" |
|
21 "io/fs" |
21 "os" |
22 "os" |
22 "path/filepath" |
23 "path/filepath" |
23 "sync" |
24 "sync" |
24 "sync/atomic" |
25 "sync/atomic" |
25 "time" |
26 "time" |
|
27 |
|
28 "github.com/spf13/afero/internal/common" |
26 ) |
29 ) |
27 |
30 |
28 const FilePathSeparator = string(filepath.Separator) |
31 const FilePathSeparator = string(filepath.Separator) |
|
32 |
|
33 var _ fs.ReadDirFile = &File{} |
29 |
34 |
30 type File struct { |
35 type File struct { |
31 // atomic requires 64-bit alignment for struct field access |
36 // atomic requires 64-bit alignment for struct field access |
32 at int64 |
37 at int64 |
33 readDirCount int64 |
38 readDirCount int64 |
69 func CreateFile(name string) *FileData { |
74 func CreateFile(name string) *FileData { |
70 return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()} |
75 return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()} |
71 } |
76 } |
72 |
77 |
73 func CreateDir(name string) *FileData { |
78 func CreateDir(name string) *FileData { |
74 return &FileData{name: name, memDir: &DirMap{}, dir: true} |
79 return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()} |
75 } |
80 } |
76 |
81 |
77 func ChangeFileName(f *FileData, newname string) { |
82 func ChangeFileName(f *FileData, newname string) { |
78 f.Lock() |
83 f.Lock() |
79 f.name = newname |
84 f.name = newname |
181 _, names[i] = filepath.Split(f.Name()) |
186 _, names[i] = filepath.Split(f.Name()) |
182 } |
187 } |
183 return names, err |
188 return names, err |
184 } |
189 } |
185 |
190 |
|
191 // Implements fs.ReadDirFile |
|
192 func (f *File) ReadDir(n int) ([]fs.DirEntry, error) { |
|
193 fi, err := f.Readdir(n) |
|
194 if err != nil { |
|
195 return nil, err |
|
196 } |
|
197 di := make([]fs.DirEntry, len(fi)) |
|
198 for i, f := range fi { |
|
199 di[i] = common.FileInfoDirEntry{FileInfo: f} |
|
200 } |
|
201 return di, nil |
|
202 } |
|
203 |
186 func (f *File) Read(b []byte) (n int, err error) { |
204 func (f *File) Read(b []byte) (n int, err error) { |
187 f.fileData.Lock() |
205 f.fileData.Lock() |
188 defer f.fileData.Unlock() |
206 defer f.fileData.Unlock() |
189 if f.closed == true { |
207 if f.closed { |
190 return 0, ErrFileClosed |
208 return 0, ErrFileClosed |
191 } |
209 } |
192 if len(b) > 0 && int(f.at) == len(f.fileData.data) { |
210 if len(b) > 0 && int(f.at) == len(f.fileData.data) { |
193 return 0, io.EOF |
211 return 0, io.EOF |
194 } |
212 } |
212 atomic.StoreInt64(&f.at, prev) |
230 atomic.StoreInt64(&f.at, prev) |
213 return |
231 return |
214 } |
232 } |
215 |
233 |
216 func (f *File) Truncate(size int64) error { |
234 func (f *File) Truncate(size int64) error { |
217 if f.closed == true { |
235 if f.closed { |
218 return ErrFileClosed |
236 return ErrFileClosed |
219 } |
237 } |
220 if f.readOnly { |
238 if f.readOnly { |
221 return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")} |
239 return &os.PathError{Op: "truncate", Path: f.fileData.name, Err: errors.New("file handle is read only")} |
222 } |
240 } |
234 setModTime(f.fileData, time.Now()) |
252 setModTime(f.fileData, time.Now()) |
235 return nil |
253 return nil |
236 } |
254 } |
237 |
255 |
238 func (f *File) Seek(offset int64, whence int) (int64, error) { |
256 func (f *File) Seek(offset int64, whence int) (int64, error) { |
239 if f.closed == true { |
257 if f.closed { |
240 return 0, ErrFileClosed |
258 return 0, ErrFileClosed |
241 } |
259 } |
242 switch whence { |
260 switch whence { |
243 case io.SeekStart: |
261 case io.SeekStart: |
244 atomic.StoreInt64(&f.at, offset) |
262 atomic.StoreInt64(&f.at, offset) |
249 } |
267 } |
250 return f.at, nil |
268 return f.at, nil |
251 } |
269 } |
252 |
270 |
253 func (f *File) Write(b []byte) (n int, err error) { |
271 func (f *File) Write(b []byte) (n int, err error) { |
254 if f.closed == true { |
272 if f.closed { |
255 return 0, ErrFileClosed |
273 return 0, ErrFileClosed |
256 } |
274 } |
257 if f.readOnly { |
275 if f.readOnly { |
258 return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")} |
276 return 0, &os.PathError{Op: "write", Path: f.fileData.name, Err: errors.New("file handle is read only")} |
259 } |
277 } |
328 return int64(len(s.data)) |
346 return int64(len(s.data)) |
329 } |
347 } |
330 |
348 |
331 var ( |
349 var ( |
332 ErrFileClosed = errors.New("File is closed") |
350 ErrFileClosed = errors.New("File is closed") |
333 ErrOutOfRange = errors.New("Out of range") |
351 ErrOutOfRange = errors.New("out of range") |
334 ErrTooLarge = errors.New("Too large") |
352 ErrTooLarge = errors.New("too large") |
335 ErrFileNotFound = os.ErrNotExist |
353 ErrFileNotFound = os.ErrNotExist |
336 ErrFileExists = os.ErrExist |
354 ErrFileExists = os.ErrExist |
337 ErrDestinationExists = os.ErrExist |
355 ErrDestinationExists = os.ErrExist |
338 ) |
356 ) |