github.com/millerlogic/afero@v1.1.1/memmap.go (about) 1 // Copyright © 2014 Steve Francia <spf@spf13.com>. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package afero 15 16 import ( 17 "fmt" 18 "log" 19 "os" 20 "path/filepath" 21 "strings" 22 "sync" 23 "time" 24 25 "github.com/spf13/afero/mem" 26 ) 27 28 type MemMapFs struct { 29 mu sync.RWMutex 30 data map[string]*mem.FileData 31 init sync.Once 32 } 33 34 func NewMemMapFs() Fs { 35 return &MemMapFs{} 36 } 37 38 func (m *MemMapFs) getData() map[string]*mem.FileData { 39 m.init.Do(func() { 40 m.data = make(map[string]*mem.FileData) 41 // Root should always exist, right? 42 // TODO: what about windows? 43 m.data[FilePathSeparator] = mem.CreateDir(FilePathSeparator) 44 }) 45 return m.data 46 } 47 48 func (*MemMapFs) Name() string { return "MemMapFS" } 49 50 func (m *MemMapFs) Create(name string) (File, error) { 51 name = normalizePath(name) 52 m.mu.Lock() 53 file := mem.CreateFile(name) 54 m.getData()[name] = file 55 m.registerWithParent(file) 56 m.mu.Unlock() 57 return mem.NewFileHandle(file), nil 58 } 59 60 func (m *MemMapFs) unRegisterWithParent(fileName string) error { 61 f, err := m.lockfreeOpen(fileName) 62 if err != nil { 63 return err 64 } 65 parent := m.findParent(f) 66 if parent == nil { 67 log.Panic("parent of ", f.Name(), " is nil") 68 } 69 70 parent.Lock() 71 mem.RemoveFromMemDir(parent, f) 72 parent.Unlock() 73 return nil 74 } 75 76 func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData { 77 pdir, _ := filepath.Split(f.Name()) 78 pdir = filepath.Clean(pdir) 79 pfile, err := m.lockfreeOpen(pdir) 80 if err != nil { 81 return nil 82 } 83 return pfile 84 } 85 86 func (m *MemMapFs) registerWithParent(f *mem.FileData) { 87 if f == nil { 88 return 89 } 90 parent := m.findParent(f) 91 if parent == nil { 92 pdir := filepath.Dir(filepath.Clean(f.Name())) 93 err := m.lockfreeMkdir(pdir, 0777) 94 if err != nil { 95 //log.Println("Mkdir error:", err) 96 return 97 } 98 parent, err = m.lockfreeOpen(pdir) 99 if err != nil { 100 //log.Println("Open after Mkdir error:", err) 101 return 102 } 103 } 104 105 parent.Lock() 106 mem.InitializeDir(parent) 107 mem.AddToMemDir(parent, f) 108 parent.Unlock() 109 } 110 111 func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { 112 name = normalizePath(name) 113 x, ok := m.getData()[name] 114 if ok { 115 // Only return ErrFileExists if it's a file, not a directory. 116 i := mem.FileInfo{FileData: x} 117 if !i.IsDir() { 118 return ErrFileExists 119 } 120 } else { 121 item := mem.CreateDir(name) 122 m.getData()[name] = item 123 m.registerWithParent(item) 124 } 125 return nil 126 } 127 128 func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { 129 name = normalizePath(name) 130 131 m.mu.RLock() 132 _, ok := m.getData()[name] 133 m.mu.RUnlock() 134 if ok { 135 return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists} 136 } 137 138 m.mu.Lock() 139 item := mem.CreateDir(name) 140 m.getData()[name] = item 141 m.registerWithParent(item) 142 m.mu.Unlock() 143 144 m.Chmod(name, perm|os.ModeDir) 145 146 return nil 147 } 148 149 func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error { 150 err := m.Mkdir(path, perm) 151 if err != nil { 152 if err.(*os.PathError).Err == ErrFileExists { 153 return nil 154 } 155 return err 156 } 157 return nil 158 } 159 160 // Handle some relative paths 161 func normalizePath(path string) string { 162 path = filepath.Clean(path) 163 164 switch path { 165 case ".": 166 return FilePathSeparator 167 case "..": 168 return FilePathSeparator 169 default: 170 return path 171 } 172 } 173 174 func (m *MemMapFs) Open(name string) (File, error) { 175 f, err := m.open(name) 176 if f != nil { 177 return mem.NewReadOnlyFileHandle(f), err 178 } 179 return nil, err 180 } 181 182 func (m *MemMapFs) openWrite(name string) (File, error) { 183 f, err := m.open(name) 184 if f != nil { 185 return mem.NewFileHandle(f), err 186 } 187 return nil, err 188 } 189 190 func (m *MemMapFs) open(name string) (*mem.FileData, error) { 191 name = normalizePath(name) 192 193 m.mu.RLock() 194 f, ok := m.getData()[name] 195 m.mu.RUnlock() 196 if !ok { 197 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound} 198 } 199 return f, nil 200 } 201 202 func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) { 203 name = normalizePath(name) 204 f, ok := m.getData()[name] 205 if ok { 206 return f, nil 207 } else { 208 return nil, ErrFileNotFound 209 } 210 } 211 212 func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { 213 chmod := false 214 file, err := m.openWrite(name) 215 if os.IsNotExist(err) && (flag&os.O_CREATE > 0) { 216 file, err = m.Create(name) 217 chmod = true 218 } 219 if err != nil { 220 return nil, err 221 } 222 if flag == os.O_RDONLY { 223 file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data()) 224 } 225 if flag&os.O_APPEND > 0 { 226 _, err = file.Seek(0, os.SEEK_END) 227 if err != nil { 228 file.Close() 229 return nil, err 230 } 231 } 232 if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 { 233 err = file.Truncate(0) 234 if err != nil { 235 file.Close() 236 return nil, err 237 } 238 } 239 if chmod { 240 m.Chmod(name, perm) 241 } 242 return file, nil 243 } 244 245 func (m *MemMapFs) Remove(name string) error { 246 name = normalizePath(name) 247 248 m.mu.Lock() 249 defer m.mu.Unlock() 250 251 if _, ok := m.getData()[name]; ok { 252 err := m.unRegisterWithParent(name) 253 if err != nil { 254 return &os.PathError{Op: "remove", Path: name, Err: err} 255 } 256 delete(m.getData(), name) 257 } else { 258 return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist} 259 } 260 return nil 261 } 262 263 func (m *MemMapFs) RemoveAll(path string) error { 264 path = normalizePath(path) 265 m.mu.Lock() 266 m.unRegisterWithParent(path) 267 m.mu.Unlock() 268 269 m.mu.RLock() 270 defer m.mu.RUnlock() 271 272 for p, _ := range m.getData() { 273 if strings.HasPrefix(p, path) { 274 m.mu.RUnlock() 275 m.mu.Lock() 276 delete(m.getData(), p) 277 m.mu.Unlock() 278 m.mu.RLock() 279 } 280 } 281 return nil 282 } 283 284 func (m *MemMapFs) Rename(oldname, newname string) error { 285 oldname = normalizePath(oldname) 286 newname = normalizePath(newname) 287 288 if oldname == newname { 289 return nil 290 } 291 292 m.mu.RLock() 293 defer m.mu.RUnlock() 294 if _, ok := m.getData()[oldname]; ok { 295 m.mu.RUnlock() 296 m.mu.Lock() 297 m.unRegisterWithParent(oldname) 298 fileData := m.getData()[oldname] 299 delete(m.getData(), oldname) 300 mem.ChangeFileName(fileData, newname) 301 m.getData()[newname] = fileData 302 m.registerWithParent(fileData) 303 m.mu.Unlock() 304 m.mu.RLock() 305 } else { 306 return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound} 307 } 308 return nil 309 } 310 311 func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { 312 f, err := m.Open(name) 313 if err != nil { 314 return nil, err 315 } 316 fi := mem.GetFileInfo(f.(*mem.File).Data()) 317 return fi, nil 318 } 319 320 func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { 321 name = normalizePath(name) 322 323 m.mu.RLock() 324 f, ok := m.getData()[name] 325 m.mu.RUnlock() 326 if !ok { 327 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} 328 } 329 330 m.mu.Lock() 331 mem.SetMode(f, mode) 332 m.mu.Unlock() 333 334 return nil 335 } 336 337 func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { 338 name = normalizePath(name) 339 340 m.mu.RLock() 341 f, ok := m.getData()[name] 342 m.mu.RUnlock() 343 if !ok { 344 return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound} 345 } 346 347 m.mu.Lock() 348 mem.SetModTime(f, mtime) 349 m.mu.Unlock() 350 351 return nil 352 } 353 354 func (m *MemMapFs) List() { 355 for _, x := range m.data { 356 y := mem.FileInfo{FileData: x} 357 fmt.Println(x.Name(), y.Size()) 358 } 359 } 360 361 // func debugMemMapList(fs Fs) { 362 // if x, ok := fs.(*MemMapFs); ok { 363 // x.List() 364 // } 365 // }