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