diff options
author | Jakob Unterwurzacher | 2017-12-03 17:57:08 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2017-12-03 19:33:26 +0100 |
commit | 70bcf58a9bda5f95a3037fb785858f5d7ce3f930 (patch) | |
tree | 15122949d8adede1b6e8a68e7e2a2b19d42a1660 /internal/syscallcompat/getdents_other.go | |
parent | e33593d30d9dee6fd6b0e7c0d01832e478815d88 (diff) |
syscallcompat: convert Getdents to fd input, add emulation
Now that we have Fstatat we can use it in Getdents to
get rid of the path name.
Also, add an emulated version of getdents for MacOS. This allows
to drop the !HaveGetdents special cases from fusefrontend.
Modify the getdents test to test both native getdents and the emulated
version.
Diffstat (limited to 'internal/syscallcompat/getdents_other.go')
-rw-r--r-- | internal/syscallcompat/getdents_other.go | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/internal/syscallcompat/getdents_other.go b/internal/syscallcompat/getdents_other.go index 4ef5b8f..6d08a9b 100644 --- a/internal/syscallcompat/getdents_other.go +++ b/internal/syscallcompat/getdents_other.go @@ -1,17 +1,49 @@ -// +build !linux - package syscallcompat import ( - "log" + "os" + "syscall" + + "golang.org/x/sys/unix" "github.com/hanwen/go-fuse/fuse" ) -// HaveGetdents is true if we have a working implementation of Getdents -const HaveGetdents = false - -func Getdents(dir string) ([]fuse.DirEntry, error) { - log.Panic("only implemented on Linux") - return nil, nil +// emulateGetdents reads all directory entries from the open directory "fd" +// and returns them in a fuse.DirEntry slice. +func emulateGetdents(fd int) (out []fuse.DirEntry, err error) { + // os.File closes the fd in its finalizer. Duplicate the fd to not affect + // the original fd. + newFd, err := syscall.Dup(fd) + if err != nil { + return nil, err + } + f := os.NewFile(uintptr(newFd), "") + defer f.Close() + // Get all file names in the directory + names, err := f.Readdirnames(0) + if err != nil { + return nil, err + } + // Stat all of them and convert to fuse.DirEntry + out = make([]fuse.DirEntry, 0, len(names)) + for _, name := range names { + var st unix.Stat_t + err = Fstatat(fd, name, &st, unix.AT_SYMLINK_NOFOLLOW) + if err == syscall.ENOENT { + // File disappeared between readdir and stat. Pretend we did not + // see it. + continue + } + if err != nil { + return nil, err + } + newEntry := fuse.DirEntry{ + Name: name, + Mode: uint32(st.Mode) & syscall.S_IFMT, + Ino: st.Ino, + } + out = append(out, newEntry) + } + return out, nil } |