diff options
| author | Jakob Unterwurzacher | 2017-12-03 17:53:14 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2017-12-03 19:32:59 +0100 | 
| commit | e33593d30d9dee6fd6b0e7c0d01832e478815d88 (patch) | |
| tree | 5070656829a7215bd4fe01404f208798cd073a2b | |
| parent | 441e796e7034977c15dc9402a880ef4061b471a7 (diff) | |
syscallcompat: add Fstatat + emulation + test
Fstatat has recently been added to x/sys/unix. Make
it available for use in gocryptfs.
| -rw-r--r-- | internal/syscallcompat/emulate.go | 20 | ||||
| -rw-r--r-- | internal/syscallcompat/emulate_test.go | 35 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_darwin.go | 12 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 10 | 
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) +} | 
