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  }