diff --git a/file.go b/file.go index d9be4cd..b13ca39 100644 --- a/file.go +++ b/file.go @@ -597,12 +597,15 @@ func (file File) ListDirRecursiveChan(cancel <-chan error, patterns ...string) ( return files, errs } -func (file File) User() string { +func (file File) User() (string, error) { + if file == "" { + return "", ErrEmptyPath + } fileSystem, path := file.ParseRawURI() if fs, ok := fileSystem.(UserFileSystem); ok { return fs.User(path) } - return "" + return "", NewErrUnsupported(fileSystem, "User") } func (file File) SetUser(user string) error { @@ -616,12 +619,15 @@ func (file File) SetUser(user string) error { return NewErrUnsupported(fileSystem, "SetUser") } -func (file File) Group() string { +func (file File) Group() (string, error) { + if file == "" { + return "", ErrEmptyPath + } fileSystem, path := file.ParseRawURI() if fs, ok := fileSystem.(GroupFileSystem); ok { return fs.Group(path) } - return "" + return "", NewErrUnsupported(fileSystem, "Group") } func (file File) SetGroup(group string) error { diff --git a/filesystem.go b/filesystem.go index 63a131c..8f20273 100644 --- a/filesystem.go +++ b/filesystem.go @@ -235,14 +235,14 @@ type ExistsFileSystem interface { type UserFileSystem interface { FileSystem - User(filePath string) string + User(filePath string) (string, error) SetUser(filePath string, user string) error } type GroupFileSystem interface { FileSystem - Group(filePath string) string + Group(filePath string) (string, error) SetGroup(filePath string, group string) error } diff --git a/httpfs/httpfs.go b/httpfs/httpfs.go index 146b0df..1aa7cb2 100644 --- a/httpfs/httpfs.go +++ b/httpfs/httpfs.go @@ -171,14 +171,6 @@ func (f *HTTPFileSystem) ListDirInfo(ctx context.Context, dirPath string, callba return fs.NewErrUnsupported(f, "ListDirInfo") } -func (f *HTTPFileSystem) ListDirInfoRecursive(ctx context.Context, dirPath string, callback func(*fs.FileInfo) error, patterns []string) error { - return fs.NewErrUnsupported(f, "ListDirInfoRecursive") -} - -func (f *HTTPFileSystem) ListDirMax(ctx context.Context, dirPath string, max int, patterns []string) ([]fs.File, error) { - return nil, fs.NewErrUnsupported(f, "ListDirMax") -} - func (f *HTTPFileSystem) ReadAll(ctx context.Context, filePath string) (data []byte, err error) { if ctx.Err() != nil { return nil, ctx.Err() diff --git a/invalidfilesystem.go b/invalidfilesystem.go index e833fdb..e457860 100644 --- a/invalidfilesystem.go +++ b/invalidfilesystem.go @@ -139,16 +139,16 @@ func (InvalidFileSystem) SetPermissions(filePath string, perm Permissions) error return ErrInvalidFileSystem } -func (InvalidFileSystem) User(filePath string) string { - return "" +func (InvalidFileSystem) User(filePath string) (string, error) { + return "", ErrInvalidFileSystem } func (InvalidFileSystem) SetUser(filePath string, user string) error { return ErrInvalidFileSystem } -func (InvalidFileSystem) Group(filePath string) string { - return "" +func (InvalidFileSystem) Group(filePath string) (string, error) { + return "", ErrInvalidFileSystem } func (InvalidFileSystem) SetGroup(filePath string, group string) error { diff --git a/listdir_test.go b/listdir_test.go index 4818d1e..4ce7cff 100644 --- a/listdir_test.go +++ b/listdir_test.go @@ -7,7 +7,7 @@ import ( ) func Test_listDirMaxImpl(t *testing.T) { - bg := context.Background() + ctx := context.Background() errCtx, cancel := context.WithCancel(context.Background()) cancel() @@ -37,11 +37,11 @@ func Test_listDirMaxImpl(t *testing.T) { wantFiles []File wantErr bool }{ - {name: "-1", args: args{ctx: bg, max: -1, listDir: list("1", "2", "3")}, wantFiles: []File{"1", "2", "3"}}, - {name: "-1 no files", args: args{ctx: bg, max: -1, listDir: list()}, wantFiles: nil}, - {name: "0", args: args{ctx: bg, max: 0, listDir: list("1", "2", "3")}, wantFiles: nil}, - {name: "1", args: args{ctx: bg, max: 1, listDir: list("1", "2", "3")}, wantFiles: []File{"1"}}, - {name: "2", args: args{ctx: bg, max: 2, listDir: list("1", "2", "3")}, wantFiles: []File{"1", "2"}}, + {name: "-1", args: args{ctx: ctx, max: -1, listDir: list("1", "2", "3")}, wantFiles: []File{"1", "2", "3"}}, + {name: "-1 no files", args: args{ctx: ctx, max: -1, listDir: list()}, wantFiles: nil}, + {name: "0", args: args{ctx: ctx, max: 0, listDir: list("1", "2", "3")}, wantFiles: nil}, + {name: "1", args: args{ctx: ctx, max: 1, listDir: list("1", "2", "3")}, wantFiles: []File{"1"}}, + {name: "2", args: args{ctx: ctx, max: 2, listDir: list("1", "2", "3")}, wantFiles: []File{"1", "2"}}, {name: "context error", args: args{ctx: errCtx, max: -1, listDir: list("1", "2", "3")}, wantErr: true}, } diff --git a/localfilesystem.go b/localfilesystem.go index 57c68d4..ddaa337 100644 --- a/localfilesystem.go +++ b/localfilesystem.go @@ -410,30 +410,6 @@ func (local *LocalFileSystem) SetPermissions(filePath string, perm Permissions) return os.Chmod(filePath, mode) } -func (local *LocalFileSystem) User(filePath string) string { - filePath = expandTilde(filePath) - - panic("not implemented") -} - -func (local *LocalFileSystem) SetUser(filePath string, user string) error { - filePath = expandTilde(filePath) - - panic("not implemented") -} - -func (local *LocalFileSystem) Group(filePath string) string { - filePath = expandTilde(filePath) - - panic("not implemented") -} - -func (local *LocalFileSystem) SetGroup(filePath string, group string) error { - filePath = expandTilde(filePath) - - panic("not implemented") -} - func (local *LocalFileSystem) Touch(filePath string, perm []Permissions) error { if filePath == "" { return ErrEmptyPath diff --git a/localfilesystem_unix.go b/localfilesystem_unix.go index b111b7e..65311d3 100644 --- a/localfilesystem_unix.go +++ b/localfilesystem_unix.go @@ -1,7 +1,16 @@ +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris package fs +import ( + "fmt" + "os" + "os/user" + "strconv" + "syscall" +) + const localRoot = `/` var extraDirPermissions Permissions = AllExecute @@ -9,3 +18,81 @@ var extraDirPermissions Permissions = AllExecute func hasLocalFileAttributeHidden(path string) (bool, error) { return false, nil } + +func (local *LocalFileSystem) User(filePath string) (string, error) { + if filePath == "" { + return "", ErrEmptyPath + } + filePath = expandTilde(filePath) + + info, err := os.Stat(filePath) + if err != nil { + return "", err + } + stat, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return "", NewErrUnsupported(local, "User") + } + u, err := user.LookupId(fmt.Sprint(stat.Uid)) + if err != nil { + return "", err + } + return u.Username, nil +} + +func (local *LocalFileSystem) SetUser(filePath string, username string) error { + if filePath == "" { + return ErrEmptyPath + } + filePath = expandTilde(filePath) + + u, err := user.Lookup(username) + if err != nil { + return err + } + uid, err := strconv.Atoi(u.Uid) + if err != nil { + return err + } + return os.Chown(filePath, uid, -1) +} + +func (local *LocalFileSystem) Group(filePath string) (string, error) { + if filePath == "" { + return "", ErrEmptyPath + } + filePath = expandTilde(filePath) + + info, err := os.Stat(filePath) + if err != nil { + return "", err + } + stat, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return "", NewErrUnsupported(local, "Group") + } + g, err := user.LookupGroupId(fmt.Sprint(stat.Gid)) + if err != nil { + return "", err + } + return g.Name, nil +} + +func (local *LocalFileSystem) SetGroup(filePath string, group string) error { + filePath = expandTilde(filePath) + + if filePath == "" { + return ErrEmptyPath + } + filePath = expandTilde(filePath) + + g, err := user.LookupGroup(group) + if err != nil { + return err + } + gid, err := strconv.Atoi(g.Gid) + if err != nil { + return err + } + return os.Chown(filePath, -1, gid) +} diff --git a/memfilesystem.go b/memfilesystem.go index b63eb9b..78725a6 100644 --- a/memfilesystem.go +++ b/memfilesystem.go @@ -16,7 +16,7 @@ import ( ) var ( - _ fullyFeaturedFileSystem = new(MemFileSystem) + _ FileSystem = new(MemFileSystem) // memFileNode implements io/fs.FileInfo _ iofs.FileInfo = new(memFileInfo) @@ -217,8 +217,7 @@ func (fs *MemFileSystem) MakeAllDirs(dirPath string, perm []Permissions) error { // } // parentDir.Dir[pathParts[len(pathParts)-1]] = fs.newMemFileInfo(f, modified) - panic("todo") - + panic("TODO") } func (fs *MemFileSystem) IsReadOnly() bool { @@ -410,28 +409,20 @@ func (*MemFileSystem) ListDirInfo(ctx context.Context, dirPath string, callback return nil } -func (*MemFileSystem) ListDirInfoRecursive(ctx context.Context, dirPath string, callback func(*FileInfo) error, patterns []string) error { - return nil -} - -func (*MemFileSystem) ListDirMax(ctx context.Context, dirPath string, n int, patterns []string) (files []File, err error) { - return nil, nil -} - func (*MemFileSystem) SetPermissions(filePath string, perm Permissions) error { return nil } -func (*MemFileSystem) User(filePath string) string { - return "" +func (*MemFileSystem) User(filePath string) (string, error) { + return "", nil } func (*MemFileSystem) SetUser(filePath string, user string) error { return nil } -func (*MemFileSystem) Group(filePath string) string { - return "" +func (*MemFileSystem) Group(filePath string) (string, error) { + return "", nil } func (*MemFileSystem) SetGroup(filePath string, group string) error { diff --git a/readonlybase.go b/readonlybase.go index 106a0ee..f95d077 100644 --- a/readonlybase.go +++ b/readonlybase.go @@ -29,14 +29,10 @@ func (*ReadOnlyBase) SetPermissions(filePath string, perm Permissions) error { return ErrReadOnlyFileSystem } -func (*ReadOnlyBase) User(filePath string) string { return "" } - func (*ReadOnlyBase) SetUser(filePath string, user string) error { return ErrReadOnlyFileSystem } -func (*ReadOnlyBase) Group(filePath string) string { return "" } - func (*ReadOnlyBase) SetGroup(filePath string, group string) error { return ErrReadOnlyFileSystem } diff --git a/subfilesystem.go b/subfilesystem.go index e97cfe7..0aaab12 100644 --- a/subfilesystem.go +++ b/subfilesystem.go @@ -100,7 +100,7 @@ func (subfs *todoSubFileSystem) MatchAnyPattern(name string, patterns []string) } func (subfs *todoSubFileSystem) SplitDirAndName(filePath string) (dir, name string) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) VolumeName(filePath string) string { @@ -139,73 +139,73 @@ func (subfs *todoSubFileSystem) IsSymbolicLink(filePath string) bool { } func (subfs *todoSubFileSystem) ListDirInfo(ctx context.Context, dirPath string, callback func(*FileInfo) error, patterns []string) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) ListDirInfoRecursive(ctx context.Context, dirPath string, callback func(*FileInfo) error, patterns []string) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) ListDirMax(ctx context.Context, dirPath string, max int, patterns []string) (files []File, err error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) SetPermissions(filePath string, perm Permissions) error { - panic("not implemented") + panic("TODO") } -func (subfs *todoSubFileSystem) User(filePath string) string { - panic("not implemented") +func (subfs *todoSubFileSystem) User(filePath string) (string, error) { + panic("TODO") } func (subfs *todoSubFileSystem) SetUser(filePath string, user string) error { - panic("not implemented") + panic("TODO") } -func (subfs *todoSubFileSystem) Group(filePath string) string { - panic("not implemented") +func (subfs *todoSubFileSystem) Group(filePath string) (string, error) { + panic("TODO") } func (subfs *todoSubFileSystem) SetGroup(filePath string, group string) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) Touch(filePath string, perm []Permissions) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) MakeDir(filePath string, perm []Permissions) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) ReadAll(ctx context.Context, filePath string) ([]byte, error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) WriteAll(ctx context.Context, filePath string, data []byte, perm []Permissions) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) OpenReader(filePath string) (ReadCloser, error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) OpenWriter(filePath string, perm []Permissions) (WriteCloser, error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) OpenAppendWriter(filePath string, perm []Permissions) (WriteCloser, error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) OpenReadWriter(filePath string, perm []Permissions) (ReadWriteSeekCloser, error) { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) Truncate(filePath string, size int64) error { - panic("not implemented") + panic("TODO") } func (subfs *todoSubFileSystem) Remove(filePath string) error { - panic("not implemented") + panic("TODO") } diff --git a/zipfs/zipfs.go b/zipfs/zipfs.go index 3f87fae..6f7da9d 100644 --- a/zipfs/zipfs.go +++ b/zipfs/zipfs.go @@ -244,7 +244,7 @@ func (zipfs *ZipFileSystem) ListDirInfo(ctx context.Context, dirPath string, cal return fs.ErrWriteOnlyFileSystem } - panic("not implemented") + panic("TODO") } func (zipfs *ZipFileSystem) ListDirInfoRecursive(ctx context.Context, dirPath string, callback func(*fs.FileInfo) error, patterns []string) error {