diff --git a/fs.go b/fs.go index b822ff3..653b4d3 100644 --- a/fs.go +++ b/fs.go @@ -132,12 +132,18 @@ type Symlink interface { Readlink(link string) (string, error) } -// Change abstract the FileInfo change related operations in a storage-agnostic -// interface as an extension to the Basic interface -type Change interface { +// Chmod abstracts the logic around changing file modes. +type Chmod interface { // Chmod changes the mode of the named file to mode. If the file is a // symbolic link, it changes the mode of the link's target. Chmod(name string, mode fs.FileMode) error +} + +// Change abstract the FileInfo change related operations in a storage-agnostic +// interface as an extension to the Basic interface +type Change interface { + Chmod + // Lchown changes the numeric uid and gid of the named file. If the file is // a symbolic link, it changes the uid and gid of the link itself. Lchown(name string, uid, gid int) error diff --git a/helper/chroot/chroot.go b/helper/chroot/chroot.go index b4b5b25..8966e17 100644 --- a/helper/chroot/chroot.go +++ b/helper/chroot/chroot.go @@ -228,6 +228,19 @@ func (fs *ChrootHelper) Readlink(link string) (string, error) { return string(os.PathSeparator) + target, nil } +func (fs *ChrootHelper) Chmod(path string, mode fs.FileMode) error { + fullpath, err := fs.underlyingPath(path) + if err != nil { + return err + } + + c, ok := fs.underlying.(billy.Chmod) + if !ok { + return errors.New("underlying fs does not implement billy.Chmod") + } + return c.Chmod(fullpath, mode) +} + func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) { fullpath, err := fs.underlyingPath(path) if err != nil { diff --git a/memfs/memory.go b/memfs/memory.go index ed45071..9ac8891 100644 --- a/memfs/memory.go +++ b/memfs/memory.go @@ -179,6 +179,10 @@ func (fs *Memory) Remove(filename string) error { return fs.s.Remove(filename) } +func (fs *Memory) Chmod(path string, mode gofs.FileMode) error { + return fs.s.Chmod(path, mode) +} + // Falls back to Go's filepath.Join, which works differently depending on the // OS where the code is being executed. func (fs *Memory) Join(elem ...string) string { diff --git a/memfs/storage.go b/memfs/storage.go index 4412980..051129f 100644 --- a/memfs/storage.go +++ b/memfs/storage.go @@ -222,6 +222,18 @@ func (s *storage) Remove(path string) error { return nil } +func (s *storage) Chmod(path string, mode fs.FileMode) error { + path = clean(path) + + f, has := s.Get(path) + if !has { + return os.ErrNotExist + } + + f.mode = mode + return nil +} + func clean(path string) string { return filepath.Clean(filepath.FromSlash(path)) } diff --git a/osfs/os_bound.go b/osfs/os_bound.go index 6f9b539..ccbb67d 100644 --- a/osfs/os_bound.go +++ b/osfs/os_bound.go @@ -223,6 +223,14 @@ func (fs *BoundOS) Readlink(link string) (string, error) { return os.Readlink(link) } +func (fs *BoundOS) Chmod(path string, mode fs.FileMode) error { + abspath, err := fs.abs(path) + if err != nil { + return err + } + return os.Chmod(abspath, mode) +} + // Chroot returns a new BoundOS filesystem, with the base dir set to the // result of joining the provided path with the underlying base dir. func (fs *BoundOS) Chroot(path string) (billy.Filesystem, error) { diff --git a/osfs/os_chroot.go b/osfs/os_chroot.go index 2cde299..f51e3ec 100644 --- a/osfs/os_chroot.go +++ b/osfs/os_chroot.go @@ -79,6 +79,10 @@ func (fs *ChrootOS) Remove(filename string) error { return os.Remove(filename) } +func (fs *ChrootOS) Chmod(path string, mode fs.FileMode) error { + return os.Chmod(path, mode) +} + func (fs *ChrootOS) TempFile(dir, prefix string) (billy.File, error) { if err := fs.createDir(dir + string(os.PathSeparator)); err != nil { return nil, err