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