mirror of
https://github.com/PeernetOfficial/Abstraction.git
synced 2026-07-21 21:07:49 +01:00
235 lines
4.2 KiB
Go
235 lines
4.2 KiB
Go
package fs
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
type memFS struct {
|
|
files map[string]*memFile
|
|
}
|
|
|
|
// Mem is a file system backed by memory.
|
|
var Mem FileSystem = &memFS{files: map[string]*memFile{}}
|
|
|
|
func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
|
|
if flag&os.O_APPEND != 0 {
|
|
// memFS doesn't support opening files in append-only mode.
|
|
// The database doesn't currently use O_APPEND.
|
|
return nil, errAppendModeNotSupported
|
|
}
|
|
f := fs.files[name]
|
|
if f == nil || (flag&os.O_TRUNC) != 0 {
|
|
f = &memFile{
|
|
name: name,
|
|
perm: perm, // Perm is saved to return it in Mode, but don't do anything else with it yet.
|
|
}
|
|
fs.files[name] = f
|
|
} else if !f.closed {
|
|
return nil, os.ErrExist
|
|
} else {
|
|
f.offset = 0
|
|
f.closed = false
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (fs *memFS) CreateLockFile(name string, perm os.FileMode) (LockFile, bool, error) {
|
|
_, exists := fs.files[name]
|
|
_, err := fs.OpenFile(name, 0, perm)
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
return fs.files[name], exists, nil
|
|
}
|
|
|
|
func (fs *memFS) Stat(name string) (os.FileInfo, error) {
|
|
if f, ok := fs.files[name]; ok {
|
|
return f, nil
|
|
}
|
|
return nil, os.ErrNotExist
|
|
}
|
|
|
|
func (fs *memFS) Remove(name string) error {
|
|
if _, ok := fs.files[name]; ok {
|
|
delete(fs.files, name)
|
|
return nil
|
|
}
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
func (fs *memFS) Rename(oldpath, newpath string) error {
|
|
if f, ok := fs.files[oldpath]; ok {
|
|
delete(fs.files, oldpath)
|
|
fs.files[newpath] = f
|
|
f.name = newpath
|
|
return nil
|
|
}
|
|
return os.ErrNotExist
|
|
}
|
|
|
|
func (fs *memFS) ReadDir(dir string) ([]os.FileInfo, error) {
|
|
dir = filepath.Clean(dir)
|
|
var fis []os.FileInfo
|
|
for name, f := range fs.files {
|
|
if filepath.Dir(name) == dir {
|
|
fis = append(fis, f)
|
|
}
|
|
}
|
|
return fis, nil
|
|
}
|
|
|
|
type memFile struct {
|
|
name string
|
|
perm os.FileMode
|
|
buf []byte
|
|
size int64
|
|
offset int64
|
|
closed bool
|
|
}
|
|
|
|
func (f *memFile) Close() error {
|
|
if f.closed {
|
|
return os.ErrClosed
|
|
}
|
|
f.closed = true
|
|
return nil
|
|
}
|
|
|
|
func (f *memFile) Unlock() error {
|
|
if err := f.Close(); err != nil {
|
|
return err
|
|
}
|
|
return Mem.Remove(f.name)
|
|
}
|
|
|
|
func (f *memFile) ReadAt(p []byte, off int64) (int, error) {
|
|
if f.closed {
|
|
return 0, os.ErrClosed
|
|
}
|
|
if off >= f.size {
|
|
return 0, io.EOF
|
|
}
|
|
n := int64(len(p))
|
|
if n > f.size-off {
|
|
copy(p, f.buf[off:])
|
|
return int(f.size - off), nil
|
|
}
|
|
copy(p, f.buf[off:off+n])
|
|
return int(n), nil
|
|
}
|
|
|
|
func (f *memFile) Read(p []byte) (int, error) {
|
|
n, err := f.ReadAt(p, f.offset)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
f.offset += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
func (f *memFile) WriteAt(p []byte, off int64) (int, error) {
|
|
if f.closed {
|
|
return 0, os.ErrClosed
|
|
}
|
|
n := int64(len(p))
|
|
if off+n > f.size {
|
|
f.truncate(off + n)
|
|
}
|
|
copy(f.buf[off:off+n], p)
|
|
return int(n), nil
|
|
}
|
|
|
|
func (f *memFile) Write(p []byte) (int, error) {
|
|
n, err := f.WriteAt(p, f.offset)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
f.offset += int64(n)
|
|
return n, err
|
|
}
|
|
|
|
func (f *memFile) Seek(offset int64, whence int) (int64, error) {
|
|
if f.closed {
|
|
return 0, os.ErrClosed
|
|
}
|
|
switch whence {
|
|
case io.SeekEnd:
|
|
f.offset = f.size + offset
|
|
case io.SeekStart:
|
|
f.offset = offset
|
|
case io.SeekCurrent:
|
|
f.offset += offset
|
|
}
|
|
return f.offset, nil
|
|
}
|
|
|
|
func (f *memFile) Stat() (os.FileInfo, error) {
|
|
if f.closed {
|
|
return f, os.ErrClosed
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
func (f *memFile) Sync() error {
|
|
if f.closed {
|
|
return os.ErrClosed
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *memFile) truncate(size int64) {
|
|
if size > f.size {
|
|
diff := int(size - f.size)
|
|
f.buf = append(f.buf, make([]byte, diff)...)
|
|
} else {
|
|
f.buf = f.buf[:size]
|
|
}
|
|
f.size = size
|
|
}
|
|
|
|
func (f *memFile) Truncate(size int64) error {
|
|
if f.closed {
|
|
return os.ErrClosed
|
|
}
|
|
f.truncate(size)
|
|
return nil
|
|
}
|
|
|
|
func (f *memFile) Name() string {
|
|
_, name := filepath.Split(f.name)
|
|
return name
|
|
}
|
|
|
|
func (f *memFile) Size() int64 {
|
|
return f.size
|
|
}
|
|
|
|
func (f *memFile) Mode() os.FileMode {
|
|
return f.perm
|
|
}
|
|
|
|
func (f *memFile) ModTime() time.Time {
|
|
return time.Now()
|
|
}
|
|
|
|
func (f *memFile) IsDir() bool {
|
|
return false
|
|
}
|
|
|
|
func (f *memFile) Sys() interface{} {
|
|
return nil
|
|
}
|
|
|
|
func (f *memFile) Slice(start int64, end int64) ([]byte, error) {
|
|
if f.closed {
|
|
return nil, os.ErrClosed
|
|
}
|
|
if end > f.size {
|
|
return nil, io.EOF
|
|
}
|
|
return f.buf[start:end], nil
|
|
}
|