From 7b70cb1dbc448a35297bb6ae4595315b9947e0ce Mon Sep 17 00:00:00 2001 From: John Starich <johnstarich@johnstarich.com> Date: Sat, 11 Jul 2020 18:13:38 -0500 Subject: [PATCH] Fix MemMapFs.Chmod changing non-perm bits --- memmap.go | 22 ++++++++++++++++++---- memmap_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/memmap.go b/memmap.go index b7b1474..39b1e75 100644 --- a/memmap.go +++ b/memmap.go @@ -141,9 +141,7 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error { m.registerWithParent(item) m.mu.Unlock() - m.Chmod(name, perm|os.ModeDir) - - return nil + return m.unrestrictedChmod(name, perm|os.ModeDir) } func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error { @@ -240,7 +238,7 @@ func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, erro } } if chmod { - m.Chmod(name, perm) + return file, m.unrestrictedChmod(name, perm) } return file, nil } @@ -321,6 +319,22 @@ func (m *MemMapFs) Stat(name string) (os.FileInfo, error) { } func (m *MemMapFs) Chmod(name string, mode os.FileMode) error { + const chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod() + mode &= chmodBits + + m.mu.RLock() + f, ok := m.getData()[name] + m.mu.RUnlock() + if !ok { + return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound} + } + prevOtherBits := mem.GetFileInfo(f).Mode() & ^chmodBits + + mode = prevOtherBits | mode + return m.unrestrictedChmod(name, mode) +} + +func (m *MemMapFs) unrestrictedChmod(name string, mode os.FileMode) error { name = normalizePath(name) m.mu.RLock() diff --git a/memmap_test.go b/memmap_test.go index a88ea30..76a712d 100644 --- a/memmap_test.go +++ b/memmap_test.go @@ -472,3 +472,34 @@ func TestMemFsUnexpectedEOF(t *testing.T) { t.Fatal("Expected ErrUnexpectedEOF") } } + +func TestMemFsChmod(t *testing.T) { + t.Parallel() + + fs := NewMemMapFs() + const file = "/hello" + if err := fs.Mkdir(file, 0700); err != nil { + t.Fatal(err) + } + + info, err := fs.Stat(file) + if err != nil { + t.Fatal(err) + } + if info.Mode().String() != "drwx------" { + t.Fatal("mkdir failed to create a directory: mode =", info.Mode()) + } + + err = fs.Chmod(file, 0) + if err != nil { + t.Error("Failed to run chmod:", err) + } + + info, err = fs.Stat(file) + if err != nil { + t.Fatal(err) + } + if info.Mode().String() != "d---------" { + t.Error("chmod should not change file type. New mode =", info.Mode()) + } +}