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  }