Commit b8a2eda4 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

nodefs: make everything compile on darwin

parent c6e7e60f
......@@ -12,7 +12,6 @@ import (
"time"
"github.com/hanwen/go-fuse/fuse"
"golang.org/x/sys/unix"
)
func errnoToStatus(errno syscall.Errno) fuse.Status {
......@@ -393,7 +392,7 @@ func (b *rawBridge) Rename(cancel <-chan struct{}, input *fuse.RenameIn, oldName
if mops, ok := p1.ops.(MutableDirOperations); ok {
errno := mops.Rename(&fuse.Context{Caller: input.Caller, Cancel: cancel}, oldName, p2.ops, newName, input.Flags)
if errno == 0 {
if input.Flags&unix.RENAME_EXCHANGE != 0 {
if input.Flags&RENAME_EXCHANGE != 0 {
p1.ExchangeChild(oldName, p2, newName)
} else {
p1.MvChild(oldName, p2, newName, true)
......
......@@ -17,3 +17,6 @@ func ToErrno(err error) syscall.Errno {
s := fuse.ToStatus(err)
return syscall.Errno(s)
}
// RENAME_EXCHANGE is a flag argument for renameat2()
const RENAME_EXCHANGE = 0x2
......@@ -11,7 +11,6 @@ import (
"syscall"
"github.com/hanwen/go-fuse/fuse"
"golang.org/x/sys/unix"
)
type loopbackRoot struct {
......@@ -135,7 +134,7 @@ func toLoopbackNode(op Operations) *loopbackNode {
func (n *loopbackNode) Rename(ctx context.Context, name string, newParent Operations, newName string, flags uint32) syscall.Errno {
newParentLoopback := toLoopbackNode(newParent)
if flags&unix.RENAME_EXCHANGE != 0 {
if flags&RENAME_EXCHANGE != 0 {
return n.renameExchange(name, newParentLoopback, newName)
}
......@@ -154,10 +153,10 @@ func (r *loopbackRoot) idFromStat(st *syscall.Stat_t) NodeAttr {
// device number of the root, so a loopback FS that does not
// encompass multiple mounts will reflect the inode numbers of
// the underlying filesystem
swapped := (st.Dev << 32) | (st.Dev >> 32)
swapped := (uint64(st.Dev) << 32) | (uint64(st.Dev) >> 32)
swappedRootDev := (r.rootDev << 32) | (r.rootDev >> 32)
return NodeAttr{
Mode: st.Mode,
Mode: uint32(st.Mode),
Gen: 1,
// This should work well for traditional backing FSes,
// not so much for other go-fuse FS-es
......@@ -279,24 +278,6 @@ func (n *loopbackNode) FGetAttr(ctx context.Context, f FileHandle, out *fuse.Att
return OK
}
func (n *loopbackNode) CopyFileRange(ctx context.Context, fhIn FileHandle,
offIn uint64, out *Inode, fhOut FileHandle, offOut uint64,
len uint64, flags uint64) (uint32, syscall.Errno) {
lfIn, ok := fhIn.(*loopbackFile)
if !ok {
return 0, syscall.ENOTSUP
}
lfOut, ok := fhOut.(*loopbackFile)
if !ok {
return 0, syscall.ENOTSUP
}
signedOffIn := int64(offIn)
signedOffOut := int64(offOut)
count, err := unix.CopyFileRange(lfIn.fd, &signedOffIn, lfOut.fd, &signedOffOut, int(len), int(flags))
return uint32(count), ToErrno(err)
}
// NewLoopback returns a root node for a loopback file system whose
// root is at the given root.
func NewLoopbackRoot(root string) (DirOperations, error) {
......@@ -308,7 +289,7 @@ func NewLoopbackRoot(root string) (DirOperations, error) {
n := &loopbackRoot{
root: root,
rootDev: st.Dev,
rootDev: uint64(st.Dev),
}
n.rootNode = n
return n, nil
......
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"context"
"syscall"
"time"
)
func (n *loopbackNode) GetXAttr(ctx context.Context, attr string, dest []byte) (uint32, syscall.Errno) {
return 0, syscall.ENOSYS
}
func (n *loopbackNode) SetXAttr(ctx context.Context, attr string, data []byte, flags uint32) syscall.Errno {
return syscall.ENOSYS
}
func (n *loopbackNode) RemoveXAttr(ctx context.Context, attr string) syscall.Errno {
return syscall.ENOSYS
}
func (n *loopbackNode) ListXAttr(ctx context.Context, dest []byte) (uint32, syscall.Errno) {
return 0, syscall.ENOSYS
}
func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newName string) syscall.Errno {
return syscall.ENOSYS
}
func (f *loopbackFile) utimens(a *time.Time, m *time.Time) syscall.Errno {
return syscall.ENOSYS // XXX
}
......@@ -59,3 +59,21 @@ func (n *loopbackNode) renameExchange(name string, newparent *loopbackNode, newN
return ToErrno(unix.Renameat2(fd1, name, fd2, newName, unix.RENAME_EXCHANGE))
}
func (n *loopbackNode) CopyFileRange(ctx context.Context, fhIn FileHandle,
offIn uint64, out *Inode, fhOut FileHandle, offOut uint64,
len uint64, flags uint64) (uint32, syscall.Errno) {
lfIn, ok := fhIn.(*loopbackFile)
if !ok {
return 0, syscall.ENOTSUP
}
lfOut, ok := fhOut.(*loopbackFile)
if !ok {
return 0, syscall.ENOTSUP
}
signedOffIn := int64(offIn)
signedOffOut := int64(offOut)
count, err := unix.CopyFileRange(lfIn.fd, &signedOffIn, lfOut.fd, &signedOffOut, int(len), int(flags))
return uint32(count), ToErrno(err)
}
// Copyright 2019 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package nodefs
import (
"bytes"
"io/ioutil"
"os"
"reflect"
"syscall"
"testing"
"github.com/kylelemons/godebug/pretty"
"golang.org/x/sys/unix"
)
func TestRenameExchange(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
tc.writeOrig("file", "hello", 0644)
tc.writeOrig("dir/file", "x", 0644)
f1, err := syscall.Open(tc.mntDir+"/", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 1: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dir", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 2: %v", err)
}
defer syscall.Close(f2)
var before1, before2 unix.Stat_t
if err := unix.Fstatat(f1, "file", &before1, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Fstatat(f2, "file", &before2, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Renameat2(f1, "file", f2, "file", unix.RENAME_EXCHANGE); err != nil {
t.Errorf("rename EXCHANGE: %v", err)
}
var after1, after2 unix.Stat_t
if err := unix.Fstatat(f1, "file", &after1, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Fstatat(f2, "file", &after2, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
clearCtime := func(s *unix.Stat_t) {
s.Ctim.Sec = 0
s.Ctim.Nsec = 0
}
clearCtime(&after1)
clearCtime(&after2)
clearCtime(&before2)
clearCtime(&before1)
if diff := pretty.Compare(after1, before2); diff != "" {
t.Errorf("after1, before2: %s", diff)
}
if !reflect.DeepEqual(after2, before1) {
t.Errorf("after2, before1: %#v, %#v", after2, before1)
}
}
func TestRenameNoOverwrite(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
tc.writeOrig("file", "hello", 0644)
tc.writeOrig("dir/file", "x", 0644)
f1, err := syscall.Open(tc.mntDir+"/", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 1: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dir", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 2: %v", err)
}
defer syscall.Close(f2)
if err := unix.Renameat2(f1, "file", f2, "file", unix.RENAME_NOREPLACE); err == nil {
t.Errorf("rename NOREPLACE succeeded")
} else if err != syscall.EEXIST {
t.Errorf("got %v (%T) want EEXIST", err, err)
}
}
func TestXAttr(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
tc.writeOrig("file", "", 0644)
buf := make([]byte, 1024)
attr := "user.xattrtest"
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err == syscall.ENOTSUP {
t.Skip("$TMP does not support xattrs. Rerun this test with a $TMPDIR override")
}
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err != syscall.ENODATA {
t.Fatalf("got %v want ENOATTR", err)
}
value := []byte("value")
if err := syscall.Setxattr(tc.mntDir+"/file", attr, value, 0); err != nil {
t.Fatalf("Setxattr: %v", err)
}
sz, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf)
if err != nil {
t.Fatalf("Getxattr: %v", err)
}
if bytes.Compare(buf[:sz], value) != 0 {
t.Fatalf("Getxattr got %q want %q", buf[:sz], value)
}
if err := syscall.Removexattr(tc.mntDir+"/file", attr); err != nil {
t.Fatalf("Removexattr: %v", err)
}
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err != syscall.ENODATA {
t.Fatalf("got %v want ENOATTR", err)
}
}
func TestCopyFileRange(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
tc.writeOrig("src", "01234567890123456789", 0644)
tc.writeOrig("dst", "abcdefghijabcdefghij", 0644)
f1, err := syscall.Open(tc.mntDir+"/src", syscall.O_RDONLY, 0)
if err != nil {
t.Fatalf("Open src: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dst", syscall.O_RDWR, 0)
if err != nil {
t.Fatalf("Open dst: %v", err)
}
defer syscall.Close(f2)
srcOff := int64(5)
dstOff := int64(7)
if sz, err := unix.CopyFileRange(f1, &srcOff, f2, &dstOff, 3, 0); err != nil || sz != 3 {
t.Fatalf("CopyFileRange: %d,%v", sz, err)
}
if err := syscall.Close(f1); err != nil {
t.Fatalf("Close src: %v", err)
}
if err := syscall.Close(f2); err != nil {
t.Fatalf("Close dst: %v", err)
}
c, err := ioutil.ReadFile(tc.mntDir + "/dst")
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
want := "abcdefg567abcdefghij"
got := string(c)
if got != want {
t.Errorf("got %q want %q", got, want)
}
}
......@@ -17,11 +17,8 @@ import (
"testing"
"time"
"golang.org/x/sys/unix"
"github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/internal/testutil"
"github.com/kylelemons/godebug/pretty"
)
type testCase struct {
......@@ -118,7 +115,7 @@ func TestBasic(t *testing.T) {
}
stat := fuse.ToStatT(fi)
if got, want := stat.Mode, uint32(fuse.S_IFREG|0644); got != want {
if got, want := uint32(stat.Mode), uint32(fuse.S_IFREG|0644); got != want {
t.Errorf("got mode %o, want %o", got, want)
}
......@@ -164,7 +161,7 @@ func TestFile(t *testing.T) {
}
stat := fuse.ToStatT(fi)
if got, want := stat.Mode, uint32(fuse.S_IFREG|0755); got != want {
if got, want := uint32(stat.Mode), uint32(fuse.S_IFREG|0755); got != want {
t.Errorf("Fstat: got mode %o, want %o", got, want)
}
......@@ -301,91 +298,6 @@ func TestRenameDestNoExist(t *testing.T) {
testRenameOverwrite(t, false)
}
func TestRenameNoOverwrite(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
tc.writeOrig("file", "hello", 0644)
tc.writeOrig("dir/file", "x", 0644)
f1, err := syscall.Open(tc.mntDir+"/", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 1: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dir", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 2: %v", err)
}
defer syscall.Close(f2)
if err := unix.Renameat2(f1, "file", f2, "file", unix.RENAME_NOREPLACE); err == nil {
t.Errorf("rename NOREPLACE succeeded")
} else if err != syscall.EEXIST {
t.Errorf("got %v (%T) want EEXIST", err, err)
}
}
func TestRenameExchange(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
if err := os.Mkdir(tc.origDir+"/dir", 0755); err != nil {
t.Fatalf("Mkdir: %v", err)
}
tc.writeOrig("file", "hello", 0644)
tc.writeOrig("dir/file", "x", 0644)
f1, err := syscall.Open(tc.mntDir+"/", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 1: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dir", syscall.O_DIRECTORY, 0)
if err != nil {
t.Fatalf("open 2: %v", err)
}
defer syscall.Close(f2)
var before1, before2 unix.Stat_t
if err := unix.Fstatat(f1, "file", &before1, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Fstatat(f2, "file", &before2, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Renameat2(f1, "file", f2, "file", unix.RENAME_EXCHANGE); err != nil {
t.Errorf("rename EXCHANGE: %v", err)
}
var after1, after2 unix.Stat_t
if err := unix.Fstatat(f1, "file", &after1, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
if err := unix.Fstatat(f2, "file", &after2, 0); err != nil {
t.Fatalf("Fstatat: %v", err)
}
clearCtime := func(s *unix.Stat_t) {
s.Ctim.Sec = 0
s.Ctim.Nsec = 0
}
clearCtime(&after1)
clearCtime(&after2)
clearCtime(&before2)
clearCtime(&before1)
if diff := pretty.Compare(after1, before2); diff != "" {
t.Errorf("after1, before2: %s", diff)
}
if !reflect.DeepEqual(after2, before1) {
t.Errorf("after2, before1: %#v, %#v", after2, before1)
}
}
func TestNlinkZero(t *testing.T) {
// xfstest generic/035.
tc := newTestCase(t, true, true)
......@@ -598,41 +510,6 @@ func TestStatFs(t *testing.T) {
}
}
func TestXAttr(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
tc.writeOrig("file", "", 0644)
buf := make([]byte, 1024)
attr := "user.xattrtest"
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err == syscall.ENOTSUP {
t.Skip("$TMP does not support xattrs. Rerun this test with a $TMPDIR override")
}
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err != syscall.ENODATA {
t.Fatalf("got %v want ENOATTR", err)
}
value := []byte("value")
if err := syscall.Setxattr(tc.mntDir+"/file", attr, value, 0); err != nil {
t.Fatalf("Setxattr: %v", err)
}
sz, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf)
if err != nil {
t.Fatalf("Getxattr: %v", err)
}
if bytes.Compare(buf[:sz], value) != 0 {
t.Fatalf("Getxattr got %q want %q", buf[:sz], value)
}
if err := syscall.Removexattr(tc.mntDir+"/file", attr); err != nil {
t.Fatalf("Removexattr: %v", err)
}
if _, err := syscall.Getxattr(tc.mntDir+"/file", attr, buf); err != syscall.ENODATA {
t.Fatalf("got %v want ENOATTR", err)
}
}
func TestGetAttrParallel(t *testing.T) {
// We grab a file-handle to provide to the API so rename+fstat
// can be handled correctly. Here, test that closing and
......@@ -679,45 +556,3 @@ func TestGetAttrParallel(t *testing.T) {
}
// XXX test mknod.
func TestCopyFileRange(t *testing.T) {
tc := newTestCase(t, true, true)
defer tc.Clean()
tc.writeOrig("src", "01234567890123456789", 0644)
tc.writeOrig("dst", "abcdefghijabcdefghij", 0644)
f1, err := syscall.Open(tc.mntDir+"/src", syscall.O_RDONLY, 0)
if err != nil {
t.Fatalf("Open src: %v", err)
}
defer syscall.Close(f1)
f2, err := syscall.Open(tc.mntDir+"/dst", syscall.O_RDWR, 0)
if err != nil {
t.Fatalf("Open dst: %v", err)
}
defer syscall.Close(f2)
srcOff := int64(5)
dstOff := int64(7)
if sz, err := unix.CopyFileRange(f1, &srcOff, f2, &dstOff, 3, 0); err != nil || sz != 3 {
t.Fatalf("CopyFileRange: %d,%v", sz, err)
}
if err := syscall.Close(f1); err != nil {
t.Fatalf("Close src: %v", err)
}
if err := syscall.Close(f2); err != nil {
t.Fatalf("Close dst: %v", err)
}
c, err := ioutil.ReadFile(tc.mntDir + "/dst")
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
want := "abcdefg567abcdefghij"
got := string(c)
if got != want {
t.Errorf("got %q want %q", got, want)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment