diff options
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 } |