github.com/sunvim/utils@v0.1.0/fs/mem.go (about)

     1  package fs
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path/filepath"
     7  	"time"
     8  )
     9  
    10  type memFS struct {
    11  	files map[string]*memFile
    12  }
    13  
    14  // Mem is a file system backed by memory.
    15  var Mem FileSystem = &memFS{files: map[string]*memFile{}}
    16  
    17  func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
    18  	if flag&os.O_APPEND != 0 {
    19  		// memFS doesn't support opening files in append-only mode.
    20  		// The database doesn't currently use O_APPEND.
    21  		return nil, errAppendModeNotSupported
    22  	}
    23  	f := fs.files[name]
    24  	if f == nil || (flag&os.O_TRUNC) != 0 {
    25  		f = &memFile{
    26  			name: name,
    27  			perm: perm, // Perm is saved to return it in Mode, but don't do anything else with it yet.
    28  		}
    29  		fs.files[name] = f
    30  	} else if !f.closed {
    31  		return nil, os.ErrExist
    32  	} else {
    33  		f.offset = 0
    34  		f.closed = false
    35  	}
    36  	return f, nil
    37  }
    38  
    39  func (fs *memFS) CreateLockFile(name string, perm os.FileMode) (LockFile, bool, error) {
    40  	_, exists := fs.files[name]
    41  	_, err := fs.OpenFile(name, 0, perm)
    42  	if err != nil {
    43  		return nil, false, err
    44  	}
    45  	return fs.files[name], exists, nil
    46  }
    47  
    48  func (fs *memFS) Stat(name string) (os.FileInfo, error) {
    49  	if f, ok := fs.files[name]; ok {
    50  		return f, nil
    51  	}
    52  	return nil, os.ErrNotExist
    53  }
    54  
    55  func (fs *memFS) Remove(name string) error {
    56  	if _, ok := fs.files[name]; ok {
    57  		delete(fs.files, name)
    58  		return nil
    59  	}
    60  	return os.ErrNotExist
    61  }
    62  
    63  func (fs *memFS) Rename(oldpath, newpath string) error {
    64  	if f, ok := fs.files[oldpath]; ok {
    65  		delete(fs.files, oldpath)
    66  		fs.files[newpath] = f
    67  		f.name = newpath
    68  		return nil
    69  	}
    70  	return os.ErrNotExist
    71  }
    72  
    73  func (fs *memFS) ReadDir(dir string) ([]os.FileInfo, error) {
    74  	dir = filepath.Clean(dir)
    75  	var fis []os.FileInfo
    76  	for name, f := range fs.files {
    77  		if filepath.Dir(name) == dir {
    78  			fis = append(fis, f)
    79  		}
    80  	}
    81  	return fis, nil
    82  }
    83  
    84  type memFile struct {
    85  	name   string
    86  	perm   os.FileMode
    87  	buf    []byte
    88  	size   int64
    89  	offset int64
    90  	closed bool
    91  }
    92  
    93  func (f *memFile) Close() error {
    94  	if f.closed {
    95  		return os.ErrClosed
    96  	}
    97  	f.closed = true
    98  	return nil
    99  }
   100  
   101  func (f *memFile) Unlock() error {
   102  	if err := f.Close(); err != nil {
   103  		return err
   104  	}
   105  	return Mem.Remove(f.name)
   106  }
   107  
   108  func (f *memFile) ReadAt(p []byte, off int64) (int, error) {
   109  	if f.closed {
   110  		return 0, os.ErrClosed
   111  	}
   112  	if off >= f.size {
   113  		return 0, io.EOF
   114  	}
   115  	n := int64(len(p))
   116  	if n > f.size-off {
   117  		copy(p, f.buf[off:])
   118  		return int(f.size - off), nil
   119  	}
   120  	copy(p, f.buf[off:off+n])
   121  	return int(n), nil
   122  }
   123  
   124  func (f *memFile) Read(p []byte) (int, error) {
   125  	n, err := f.ReadAt(p, f.offset)
   126  	if err != nil {
   127  		return n, err
   128  	}
   129  	f.offset += int64(n)
   130  	return n, err
   131  }
   132  
   133  func (f *memFile) WriteAt(p []byte, off int64) (int, error) {
   134  	if f.closed {
   135  		return 0, os.ErrClosed
   136  	}
   137  	n := int64(len(p))
   138  	if off+n > f.size {
   139  		f.truncate(off + n)
   140  	}
   141  	copy(f.buf[off:off+n], p)
   142  	return int(n), nil
   143  }
   144  
   145  func (f *memFile) Write(p []byte) (int, error) {
   146  	n, err := f.WriteAt(p, f.offset)
   147  	if err != nil {
   148  		return n, err
   149  	}
   150  	f.offset += int64(n)
   151  	return n, err
   152  }
   153  
   154  func (f *memFile) Seek(offset int64, whence int) (int64, error) {
   155  	if f.closed {
   156  		return 0, os.ErrClosed
   157  	}
   158  	switch whence {
   159  	case io.SeekEnd:
   160  		f.offset = f.size + offset
   161  	case io.SeekStart:
   162  		f.offset = offset
   163  	case io.SeekCurrent:
   164  		f.offset += offset
   165  	}
   166  	return f.offset, nil
   167  }
   168  
   169  func (f *memFile) Stat() (os.FileInfo, error) {
   170  	if f.closed {
   171  		return f, os.ErrClosed
   172  	}
   173  	return f, nil
   174  }
   175  
   176  func (f *memFile) Sync() error {
   177  	if f.closed {
   178  		return os.ErrClosed
   179  	}
   180  	return nil
   181  }
   182  
   183  func (f *memFile) truncate(size int64) {
   184  	if size > f.size {
   185  		diff := int(size - f.size)
   186  		f.buf = append(f.buf, make([]byte, diff)...)
   187  	} else {
   188  		f.buf = f.buf[:size]
   189  	}
   190  	f.size = size
   191  }
   192  
   193  func (f *memFile) Truncate(size int64) error {
   194  	if f.closed {
   195  		return os.ErrClosed
   196  	}
   197  	f.truncate(size)
   198  	return nil
   199  }
   200  
   201  func (f *memFile) Name() string {
   202  	_, name := filepath.Split(f.name)
   203  	return name
   204  }
   205  
   206  func (f *memFile) Size() int64 {
   207  	return f.size
   208  }
   209  
   210  func (f *memFile) Mode() os.FileMode {
   211  	return f.perm
   212  }
   213  
   214  func (f *memFile) ModTime() time.Time {
   215  	return time.Now()
   216  }
   217  
   218  func (f *memFile) IsDir() bool {
   219  	return false
   220  }
   221  
   222  func (f *memFile) Sys() interface{} {
   223  	return nil
   224  }
   225  
   226  func (f *memFile) Slice(start int64, end int64) ([]byte, error) {
   227  	if f.closed {
   228  		return nil, os.ErrClosed
   229  	}
   230  	if end > f.size {
   231  		return nil, io.EOF
   232  	}
   233  	return f.buf[start:end], nil
   234  }