summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/syscallcompat/emulate.go20
-rw-r--r--internal/syscallcompat/emulate_test.go35
-rw-r--r--internal/syscallcompat/sys_darwin.go12
-rw-r--r--internal/syscallcompat/sys_linux.go10
4 files changed, 77 insertions, 0 deletions
diff --git a/internal/syscallcompat/emulate.go b/internal/syscallcompat/emulate.go
index 96776e2..e5aeae7 100644
--- a/internal/syscallcompat/emulate.go
+++ b/internal/syscallcompat/emulate.go
@@ -210,3 +210,23 @@ func emulateMkdirat(dirfd int, path string, mode uint32) (err error) {
}
return syscall.Mkdir(path, mode)
}
+
+// emulateFstatat emulates the syscall for platforms that don't have it
+// in the kernel (darwin).
+func emulateFstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
+ if !filepath.IsAbs(path) {
+ chdirMutex.Lock()
+ defer chdirMutex.Unlock()
+ cwd, err := syscall.Open(".", syscall.O_RDONLY, 0)
+ if err != nil {
+ return err
+ }
+ defer syscall.Close(cwd)
+ err = syscall.Fchdir(dirfd)
+ if err != nil {
+ return err
+ }
+ defer syscall.Fchdir(cwd)
+ }
+ return unix.Lstat(path, stat)
+}
diff --git a/internal/syscallcompat/emulate_test.go b/internal/syscallcompat/emulate_test.go
index 9b45672..c259778 100644
--- a/internal/syscallcompat/emulate_test.go
+++ b/internal/syscallcompat/emulate_test.go
@@ -256,3 +256,38 @@ func TestEmulateMkdirat(t *testing.T) {
t.Fatalf("mkdirat did not create a directory")
}
}
+
+func TestEmulateFstatat(t *testing.T) {
+ var st unix.Stat_t
+ // stat a normal file (size 3)
+ f, err := os.Create(tmpDir + "/fstatat")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = f.Write([]byte("foo"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
+ err = emulateFstatat(tmpDirFd, "fstatat", &st, unix.AT_SYMLINK_NOFOLLOW)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if st.Size != 3 {
+ t.Errorf("wrong file size: %d", st.Size)
+ }
+ // stat a symlink and check that the size matches the length of the
+ // symlink target. This proves that we have stat'ed the symlink itself.
+ err = os.Symlink(tmpDir+"/fstatat", tmpDir+"/fstatatSymlink")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = emulateFstatat(tmpDirFd, "fstatatSymlink", &st, unix.AT_SYMLINK_NOFOLLOW)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expectedSize := int64(len(tmpDir + "/fstatat"))
+ if st.Size != expectedSize {
+ t.Errorf("symlink size: expected=%d, got=%d", expectedSize, st.Size)
+ }
+}
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index 6238940..7f2c541 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -3,6 +3,10 @@ package syscallcompat
import (
"log"
"syscall"
+
+ "golang.org/x/sys/unix"
+
+ "github.com/hanwen/go-fuse/fuse"
)
// Sorry, fallocate is not available on OSX at all and
@@ -60,3 +64,11 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
func Mkdirat(dirfd int, path string, mode uint32) (err error) {
return emulateMkdirat(dirfd, path, mode)
}
+
+func Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
+ return emulateFstatat(dirfd, path, stat, flags)
+}
+
+func Getdents(fd int) ([]fuse.DirEntry, error) {
+ return emulateGetdents(fd)
+}
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index 0e03143..fb8d8b3 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -105,3 +105,13 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
func Mkdirat(dirfd int, path string, mode uint32) (err error) {
return syscall.Mkdirat(dirfd, path, mode)
}
+
+// Fstatat syscall.
+func Fstatat(dirfd int, path string, stat *unix.Stat_t, flags int) (err error) {
+ // Why would we ever want to call this without AT_SYMLINK_NOFOLLOW?
+ if flags&unix.AT_SYMLINK_NOFOLLOW == 0 {
+ tlog.Warn.Printf("Fstatat: adding missing AT_SYMLINK_NOFOLLOW flag")
+ flags |= unix.AT_SYMLINK_NOFOLLOW
+ }
+ return unix.Fstatat(dirfd, path, stat, flags)
+}