Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Chmod() method to File #357

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ io.Seeker
io.Writer
io.WriterAt

Chmod(mode os.FileMode) : error
Name() : string
Readdir(count int) : []os.FileInfo, error
Readdirnames(n int) : []string, error
Expand Down
1 change: 1 addition & 0 deletions afero.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ type File interface {
io.Writer
io.WriterAt

Chmod(mode os.FileMode) error
Name() string
Readdir(count int) ([]os.FileInfo, error)
Readdirnames(n int) ([]string, error)
Expand Down
5 changes: 5 additions & 0 deletions gcsfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package gcsfs

import (
"context"
"errors"
"fmt"
"io"
"log"
Expand Down Expand Up @@ -175,6 +176,10 @@ func (o *GcsFile) WriteAt(b []byte, off int64) (n int, err error) {
return written, err
}

func (o *GcsFile) Chmod(mode os.FileMode) error {
return errors.New("method Chmod is not implemented in GCS")
}

func (o *GcsFile) Name() string {
return filepath.FromSlash(o.resource.name)
}
Expand Down
4 changes: 4 additions & 0 deletions iofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ type fromIOFSFile struct {
name string
}

func (f fromIOFSFile) Chmod(mode os.FileMode) error {
return notImplemented("chmod", f.name)
}

func (f fromIOFSFile) ReadAt(p []byte, off int64) (n int, err error) {
readerAt, ok := f.File.(io.ReaderAt)
if !ok {
Expand Down
28 changes: 23 additions & 5 deletions mem/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import (
"time"
)

const FilePathSeparator = string(filepath.Separator)
const (
FilePathSeparator = string(filepath.Separator)

chmodBits = os.ModePerm | os.ModeSetuid | os.ModeSetgid | os.ModeSticky // Only a subset of bits are allowed to be changed. Documented under os.Chmod()
)

type File struct {
// atomic requires 64-bit alignment for struct field access
Expand Down Expand Up @@ -67,11 +71,20 @@ func (d *FileData) Name() string {
}

func CreateFile(name string) *FileData {
return &FileData{name: name, mode: os.ModeTemporary, modtime: time.Now()}
return &FileData{
name: name,
modtime: time.Now(),
}
}

func CreateDir(name string) *FileData {
return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()}
return &FileData{
name: name,
mode: os.ModeDir,
memDir: &DirMap{},
dir: true,
modtime: time.Now(),
}
}

func ChangeFileName(f *FileData, newname string) {
Expand All @@ -80,9 +93,9 @@ func ChangeFileName(f *FileData, newname string) {
f.Unlock()
}

func SetMode(f *FileData, mode os.FileMode) {
func Chmod(f *FileData, mode os.FileMode) {
f.Lock()
f.mode = mode
f.mode = (f.mode & ^chmodBits) | (mode & chmodBits)
f.Unlock()
}

Expand Down Expand Up @@ -131,6 +144,11 @@ func (f *File) Close() error {
return nil
}

func (f *File) Chmod(mode os.FileMode) error {
Chmod(f.fileData, mode)
return nil
}

func (f *File) Name() string {
return f.fileData.Name()
}
Expand Down
4 changes: 2 additions & 2 deletions mem/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ func TestFileDataModeRace(t *testing.T) {
t.Errorf("Failed to read correct value, was %v", s.Mode())
}

SetMode(&d, someOtherMode)
Chmod(&d, someOtherMode)
if s.Mode() != someOtherMode {
t.Errorf("Failed to set Mode, was %v", s.Mode())
}

go func() {
SetMode(&d, someMode)
Chmod(&d, someMode)
}()

if s.Mode() != someMode && s.Mode() != someOtherMode {
Expand Down
59 changes: 17 additions & 42 deletions memmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
"github.com/spf13/afero/mem"
)

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
Expand All @@ -43,7 +41,7 @@ func (m *MemMapFs) getData() map[string]*mem.FileData {
// Root should always exist, right?
// TODO: what about windows?
root := mem.CreateDir(FilePathSeparator)
mem.SetMode(root, os.ModeDir|0755)
mem.Chmod(root, 0755)
m.data[FilePathSeparator] = root
})
return m.data
Expand Down Expand Up @@ -123,15 +121,14 @@ func (m *MemMapFs) lockfreeMkdir(name string, perm os.FileMode) error {
}
} else {
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
mem.Chmod(item, perm)
m.getData()[name] = item
m.registerWithParent(item, perm)
}
return nil
}

func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
perm &= chmodBits
name = normalizePath(name)

m.mu.RLock()
Expand All @@ -143,12 +140,12 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {

m.mu.Lock()
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
mem.Chmod(item, perm)
m.getData()[name] = item
m.registerWithParent(item, perm)
m.mu.Unlock()

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

func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error {
Expand Down Expand Up @@ -215,7 +212,6 @@ func (m *MemMapFs) lockfreeOpen(name string) (*mem.FileData, error) {
}

func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
perm &= chmodBits
chmod := false
file, err := m.openWrite(name)
if err == nil && (flag&os.O_EXCL > 0) {
Expand Down Expand Up @@ -246,7 +242,7 @@ func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, erro
}
}
if chmod {
return file, m.setFileMode(name, perm)
m.Chmod(name, perm)
}
return file, nil
}
Expand Down Expand Up @@ -331,45 +327,30 @@ func (m *MemMapFs) Stat(name string) (os.FileInfo, error) {
return fi, nil
}

func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
mode &= chmodBits
func (m *MemMapFs) getFileData(name string) *mem.FileData {
name = normalizePath(name)

m.mu.RLock()
f, ok := m.getData()[name]
f := 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.setFileMode(name, mode)
return f
}

func (m *MemMapFs) setFileMode(name string, mode os.FileMode) error {
name = normalizePath(name)

m.mu.RLock()
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
func (m *MemMapFs) Chmod(name string, mode os.FileMode) error {
f := m.getFileData(name)
if f == nil {
return &os.PathError{Op: "chmod", Path: name, Err: ErrFileNotFound}
}

m.mu.Lock()
mem.SetMode(f, mode)
m.mu.Unlock()
mem.Chmod(f, mode)

return nil
}

func (m *MemMapFs) Chown(name string, uid, gid int) error {
name = normalizePath(name)

m.mu.RLock()
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
f := m.getFileData(name)
if f == nil {
return &os.PathError{Op: "chown", Path: name, Err: ErrFileNotFound}
}

Expand All @@ -380,18 +361,12 @@ func (m *MemMapFs) Chown(name string, uid, gid int) error {
}

func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error {
name = normalizePath(name)

m.mu.RLock()
f, ok := m.getData()[name]
m.mu.RUnlock()
if !ok {
f := m.getFileData(name)
if f == nil {
return &os.PathError{Op: "chtimes", Path: name, Err: ErrFileNotFound}
}

m.mu.Lock()
mem.SetModTime(f, mtime)
m.mu.Unlock()

return nil
}
Expand Down
26 changes: 23 additions & 3 deletions memmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@ func TestMemFsChmod(t *testing.T) {
t.Fatal("mkdir failed to create a directory: mode =", info.Mode())
}

err = fs.Chmod(file, 0)
err = fs.Chmod(file, os.ModeTemporary|0355)
if err != nil {
t.Error("Failed to run chmod:", err)
}
Expand All @@ -623,9 +623,29 @@ func TestMemFsChmod(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if info.Mode().String() != "d---------" {
t.Error("chmod should not change file type. New mode =", info.Mode())
if info.Mode().String() != "d-wxr-xr-x" {
t.Error("incorrect file mode after chmod:", info.Mode())
}

f, err := fs.Open(file)
if err != nil {
t.Error("failed to open file:", err)
}

err = f.Chmod(os.ModeNamedPipe | 0744)
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() != "drwxr--r--" {
t.Error("incorrect file mode after chmod:", info.Mode())
}

f.Close()
}

// can't use Mkdir to get around which permissions we're allowed to set
Expand Down
4 changes: 4 additions & 0 deletions regexpfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ func (f *RegexpFile) WriteAt(s []byte, o int64) (int, error) {
return f.f.WriteAt(s, o)
}

func (f *RegexpFile) Chmod(mode os.FileMode) error {
return f.f.Chmod(mode)
}

func (f *RegexpFile) Name() string {
return f.f.Name()
}
Expand Down
4 changes: 4 additions & 0 deletions sftpfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (f *File) Close() error {
return f.fd.Close()
}

func (f *File) Chmod(mode os.FileMode) error {
return f.fd.Chmod(mode)
}

func (f *File) Name() string {
return f.fd.Name()
}
Expand Down
4 changes: 4 additions & 0 deletions tarfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ func (f *File) Write(p []byte) (n int, err error) { return 0, syscall.EROFS }

func (f *File) WriteAt(p []byte, off int64) (n int, err error) { return 0, syscall.EROFS }

func (f *File) Chmod(mode os.FileMode) error {
return syscall.EROFS
}

func (f *File) Name() string {
return filepath.Join(splitpath(f.h.Name))
}
Expand Down
14 changes: 14 additions & 0 deletions unionFile.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ func (f *UnionFile) Close() error {
return BADFD
}

func (f *UnionFile) Chmod(mode os.FileMode) error {
if f.Layer != nil {
err := f.Layer.Chmod(mode)
if err == nil && f.Base != nil {
err = f.Base.Chmod(mode)
}
return err
}
if f.Base != nil {
return f.Base.Chmod(mode)
}
return BADFD
}

func (f *UnionFile) Read(s []byte) (int, error) {
if f.Layer != nil {
n, err := f.Layer.Read(s)
Expand Down
4 changes: 4 additions & 0 deletions zipfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ func (f *File) Write(p []byte) (n int, err error) { return 0, syscall.EPERM }

func (f *File) WriteAt(p []byte, off int64) (n int, err error) { return 0, syscall.EPERM }

func (f *File) Chmod(mode os.FileMode) error {
return syscall.EPERM
}

func (f *File) Name() string {
if f.zipfile == nil {
return string(filepath.Separator)
Expand Down