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