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 }