Skip to content

Commit

Permalink
add option to have strict file creation behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
natebrennand committed Jul 25, 2022
1 parent 2a70f2b commit 46f9d51
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 13 deletions.
52 changes: 39 additions & 13 deletions memmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"
"strings"
"sync"
"syscall"
"time"

"github.com/spf13/afero/mem"
Expand All @@ -28,15 +29,30 @@ import (
const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod()

type MemMapFs struct {
mu sync.RWMutex
data map[string]*mem.FileData
init sync.Once
mu sync.RWMutex
data map[string]*mem.FileData
init sync.Once
strictDirectoryBehavior bool
}

type MemMapOption func(*MemMapFs)

func NewMemMapFsWithOptions(opts ...MemMapFs) Fs {
fs := &MemMapFs{}
for _, opt := range opts {
opt(fs)
}
return fs
}

func NewMemMapFs() Fs {
return &MemMapFs{}
}

func EnableStrictDirectories(m *MemMapFs) {
m.strictDirectoryBehavior = true
}

func (m *MemMapFs) getData() map[string]*mem.FileData {
m.init.Do(func() {
m.data = make(map[string]*mem.FileData)
Expand All @@ -56,9 +72,9 @@ func (m *MemMapFs) Create(name string) (File, error) {
m.mu.Lock()
file := mem.CreateFile(name)
m.getData()[name] = file
m.registerWithParent(file, 0)
err := m.registerWithParent(file, 0)
m.mu.Unlock()
return mem.NewFileHandle(file), nil
return mem.NewFileHandle(file), err
}

func (m *MemMapFs) unRegisterWithParent(fileName string) error {
Expand Down Expand Up @@ -87,29 +103,35 @@ func (m *MemMapFs) findParent(f *mem.FileData) *mem.FileData {
return pfile
}

func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) {
func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) error {
if f == nil {
return
return nil
}
parent := m.findParent(f)
if parent == nil {
if m.strictDirectoryBehavior {
return &os.PathError{Op: "open", Path: f.Name(), Err: syscall.ENOENT}
}

pdir := filepath.Dir(filepath.Clean(f.Name()))
log.Printf("creating %s", pdir)
err := m.lockfreeMkdir(pdir, perm)
if err != nil {
//log.Println("Mkdir error:", err)
return
return nil
}
parent, err = m.lockfreeOpen(pdir)
if err != nil {
//log.Println("Open after Mkdir error:", err)
return
return nil
}
}

parent.Lock()
mem.InitializeDir(parent)
mem.AddToMemDir(parent, f)
parent.Unlock()
return nil
}

func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
Expand All @@ -125,7 +147,7 @@ func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
m.getData()[name] = item
m.registerWithParent(item, perm)
return m.registerWithParent(item, perm)
}
return nil
}
Expand All @@ -145,9 +167,13 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
m.getData()[name] = item
m.registerWithParent(item, perm)
err := m.registerWithParent(item, perm)
m.mu.Unlock()

if err != nil {
return err
}

return m.setFileMode(name, perm|os.ModeDir)
}

Expand Down Expand Up @@ -308,13 +334,13 @@ func (m *MemMapFs) Rename(oldname, newname string) error {
delete(m.getData(), oldname)
mem.ChangeFileName(fileData, newname)
m.getData()[newname] = fileData
m.registerWithParent(fileData, 0)
err := m.registerWithParent(fileData, 0)
m.mu.Unlock()
m.mu.RLock()
return err
} else {
return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
}
return nil
}

func (m *MemMapFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
Expand Down
19 changes: 19 additions & 0 deletions memmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -692,3 +692,22 @@ func TestMemFsLstatIfPossible(t *testing.T) {
t.Fatalf("Function indicated lstat was called. This should never be true.")
}
}

func TestStrictDirectories(t *testing.T) {
t.Parallel()

fs := NewMemMapFsWithOptions(EnableStrictDirectories)

err := WriteFile(fs, "/bar/test.txt", []byte("hello, world"), 0777)
if err == nil {
t.Fatalf("Expected an error with strict directories")
}

if err := fs.Mkdir("bar", 0777); err != nil {
t.Fatalf("mkdir must function")
}

if err := WriteFile(fs, "/bar/test.txt", []byte("hello, world"), 0777); err != nil {
t.Fatalf("Expected no error with the directory created, recieved: %s", err)
}
}

0 comments on commit 46f9d51

Please sign in to comment.