github.com/maxnasonov/afero@v1.8.4/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 const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod() 29 30 type MemMapFs struct { 31 mu sync.RWMutex 32 data map[string]*mem.FileData 33 init sync.Once 34 } 35 36 func NewMemMapFs() Fs { 37 return &MemMapFs{} 38 } 39 40 func (m *MemMapFs) getData() map[string]*mem.FileData { 41 m.init.Do(func() { 42 m.data = make(map[string]*mem.FileData) 43 // Root should always exist, right? 44 // TODO: what about windows? 45 root := mem.CreateDir(FilePathSeparator) 46 mem.SetMode(root, os.ModeDir|0755) 47 m.data[FilePathSeparator] = root 48 }) 49 return m.data 50 } 51 52 func (*MemMapFs) Name() string { return "MemMapFS" } 53 54 func (m *MemMapFs) Create(name string) (File, error) { 55 name = normalizePath(name) 56 m.mu.Lock() 57 file := mem.CreateFile(name) 58 m.getData()[name] = file 59 m.registerWithParent(file, 0) 60 m.mu.Unlock() 61 return mem.NewFileHandle(file), nil 62 } 63 64 func (m *MemMapFs) unRegisterWithParent(fileName string) error { 65 f, err := m.lockfreeOpen(fileName) 66 if err != nil { 67 return err 68 } 69 parent := m.findParent(f) 70 if parent == nil { 71 log.Panic("parent of ", f.Name(), " is nil") 72 } 73 74 parent.Lock() 75 mem.RemoveFromMemDir(parent, f) 76 parent.Unlock() 77 return nil 78 } 79 80 func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData { 81 pdir, _ := filepath.Split(f.Name()) 82 pdir = filepath.Clean(pdir) 83 pfile, err := m.lockfreeOpen(pdir) 84 if err != nil { 85 return nil 86 } 87 return pfile 88 } 89 90 func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) { 91 if f == nil { 92 return 93 } 94 parent := m.findParent(f) 95 if parent == nil { 96 pdir := filepath.Dir(filepath.Clean(f.Name())) 97 err := m.lockfreeMkdir(pdir, perm) 98 if err != nil { 99 //log.Println("Mkdir error:", err) 100 return 101 } 102 parent, err = m.lockfreeOpen(pdir) 103 if err != nil { 104 //log.Println("Open after Mkdir error:", err) 105 return 106 } 107 } 108 109 parent.Lock() 110 mem.InitializeDir(parent) 111 mem.AddToMemDir(parent, f) 112 parent.Unlock() 113 } 114 115 func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error { 116 name = normalizePath(name) 117 x, ok := m.getData()[name] 118 if ok { 119 // Only return ErrFileExists if it's a file, not a directory. 120 i := mem.FileInfo{FileData: x} 121 if !i.IsDir() { 122 return ErrFileExists 123 } 124 } else { 125 item := mem.CreateDir(name) 126 mem.SetMode(item, os.ModeDir|perm) 127 m.getData()[name] = item 128 m.registerWithParent(item, perm) 129 } 130 return nil 131 } 132 133 func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { 134 perm &= chmodBits 135 name = normalizePath(name) 136 137 m.mu.RLock() 138 fd, ok := m.getData()[name] 139 m.mu.RUnlock() 140 if ok { 141 i := mem.FileInfo{FileData: fd} 142 if i.IsDir() { 143 return nil 144 } 145 return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists} 146 } 147 148 m.mu.Lock() 149 item := mem.CreateDir(name) 150 mem.SetMode(item, os.ModeDir|perm) 151 m.getData()[name] = item 152 m.registerWithParent(item, perm) 153 m.mu.Unlock() 154 155 return m.setFileMode(name, perm|os.ModeDir) 156 } 157 158 func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error { 159 err := m.Mkdir(path, perm) 160 if err != nil { 161 return err 162 } 163 return nil 164 } 165 166 // Handle some relative paths 167 func normalizePath(path string) string { 168 path = filepath.Clean(path) 169 170 switch path { 171 case ".": 172 return FilePathSeparator 173 case "..": 174 return FilePathSeparator 175 default: 176 return path 177 } 178 } 179 180 func (m *MemMapFs) Open(name string) (File, error) { 181 f, err := m.open(name) 182 if f != nil { 183 return mem.NewReadOnlyFileHandle(f), err 184 } 185 return nil, err 186 } 187 188 func (m *MemMapFs) openWrite(name string) (File, error) { 189 f, err := m.open(name) 190 if f != nil { 191 return mem.NewFileHandle(f), err 192 } 193 return nil, err 194 } 195 196 func (m *MemMapFs) open(name string) (*mem.FileData, error) { 197 name = normalizePath(name) 198 199 m.mu.RLock() 200 f, ok := m.getData()[name] 201 m.mu.RUnlock() 202 if !ok { 203 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileNotFound} 204 } 205 return f, nil 206 } 207 208 func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) { 209 name = normalizePath(name) 210 f, ok := m.getData()[name] 211 if ok { 212 return f, nil 213 } else { 214 return nil, ErrFileNotFound 215 } 216 } 217 218 func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { 219 perm &= chmodBits 220 chmod := false 221 file, err := m.openWrite(name) 222 if err == nil && (flag&os.O_EXCL > 0) { 223 return nil, &os.PathError{Op: "open", Path: name, Err: ErrFileExists} 224 } 225 if os.IsNotExist(err) && (flag&os.O_CREATE > 0) { 226 file, err = m.Create(name) 227 chmod = true 228 } 229 if err != nil { 230 return nil, err 231 } 232 if flag == os.O_RDONLY { 233 file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data()) 234 } 235 if flag&os.O_APPEND > 0 { 236 _, err = file.Seek(0, os.SEEK_END) 237 if err != nil { 238 file.Close() 239 return nil, err 240 } 241 } 242 if flag&os.O_TRUNC > 0 && flag&(os.O_RDWR|os.O_WRONLY) > 0 { 243 err = file.Truncate(0) 244 if err != nil { 245 file.Close() 246 return nil, err 247 } 248 } 249 if chmod { 250 return file, m.setFileMode(name, perm) 251 } 252 return file, nil 253 } 254 255 func (m *MemMapFs) Remove(name string) error { 256 name = normalizePath(name) 257 258 m.mu.Lock() 259 defer m.mu.Unlock() 260 261 if _, ok := m.getData()[name]; ok { 262 err := m.unRegisterWithParent(name) 263 if err != nil { 264 return &os.PathError{Op: "remove", Path: name, Err: err} 265 } 266 delete(m.getData(), name) 267 } else { 268 return &os.PathError{Op: "remove", Path: name, Err: os.ErrNotExist} 269 } 270 return nil 271 } 272 273 func (m *MemMapFs) RemoveAll(path string) error { 274 path = normalizePath(path) 275 m.mu.Lock() 276 m.unRegisterWithParent(path) 277 m.mu.Unlock() 278 279 m.mu.RLock() 280 defer m.mu.RUnlock() 281 282 for p := range m.getData() { 283 if p == path || strings.HasPrefix(p, path+FilePathSeparator) { 284 m.mu.RUnlock() 285 m.mu.Lock() 286 delete(m.getData(), p) 287 m.mu.Unlock() 288 m.mu.RLock() 289 } 290 } 291 return nil 292 } 293 294 func (m *MemMapFs) Rename(oldname, newname string) error { 295 oldname = normalizePath(oldname) 296 newname = normalizePath(newname) 297 298 if oldname == newname { 299 return nil 300 } 301 302 m.mu.RLock() 303 defer m.mu.RUnlock() 304 if _, ok := m.getData()[oldname]; ok { 305 m.mu.RUnlock() 306 m.mu.Lock() 307 m.unRegisterWithParent(oldname) 308 fileData := m.getData()[oldname] 309 delete(m.getData(), oldname) 310 mem.ChangeFileName(fileData, newname) 311 m.getData()[newname] = fileData 312 m.registerWithParent(fileData, 0) 313 m.mu.Unlock() 314 m.mu.RLock() 315 } else { 316 return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound} 317 } 318 return nil 319 } 320 321 func (m *MemMapFs) LstatIfPossible(name string) (os.FileInfo, bool, error) { 322 fileInfo, err := m.Stat(name) 323 return fileInfo, false, err 324 } 325 326 func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { 327 f, err := m.Open(name) 328 if err != nil { 329 return nil, err 330 } 331 fi := mem.GetFileInfo(f.(*mem.File).Data()) 332 return fi, nil 333 } 334 335 func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { 336 mode &= chmodBits 337 338 m.mu.RLock() 339 f, ok := m.getData()[name] 340 m.mu.RUnlock() 341 if !ok { 342 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} 343 } 344 prevOtherBits := mem.GetFileInfo(f).Mode() & ^chmodBits 345 346 mode = prevOtherBits | mode 347 return m.setFileMode(name, mode) 348 } 349 350 func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error { 351 name = normalizePath(name) 352 353 m.mu.RLock() 354 f, ok := m.getData()[name] 355 m.mu.RUnlock() 356 if !ok { 357 return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} 358 } 359 360 m.mu.Lock() 361 mem.SetMode(f, mode) 362 m.mu.Unlock() 363 364 return nil 365 } 366 367 func (m *MemMapFs) Chown(name string, uid, gid int) error { 368 name = normalizePath(name) 369 370 m.mu.RLock() 371 f, ok := m.getData()[name] 372 m.mu.RUnlock() 373 if !ok { 374 return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound} 375 } 376 377 mem.SetUID(f, uid) 378 mem.SetGID(f, gid) 379 380 return nil 381 } 382 383 func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error { 384 name = normalizePath(name) 385 386 m.mu.RLock() 387 f, ok := m.getData()[name] 388 m.mu.RUnlock() 389 if !ok { 390 return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound} 391 } 392 393 m.mu.Lock() 394 mem.SetModTime(f, mtime) 395 m.mu.Unlock() 396 397 return nil 398 } 399 400 func (m *MemMapFs) List() { 401 for _, x := range m.data { 402 y := mem.FileInfo{FileData: x} 403 fmt.Println(x.Name(), y.Size()) 404 } 405 }