diff --git a/.gitmodules b/.gitmodules index ff3fc66a..e7526dbb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,9 +37,6 @@ [submodule "vendor/github.com/shirou/gopsutil"] path = vendor/github.com/shirou/gopsutil url = https://github.com/shirou/gopsutil/ -[submodule "vendor/github.com/kahing/go-xattr"] - path = vendor/github.com/kahing/go-xattr - url = https://github.com/kahing/go-xattr [submodule "vendor/github.com/kardianos/osext"] path = vendor/github.com/kardianos/osext url = https://github.com/kardianos/osext diff --git a/api/common/panic_logger.go b/api/common/panic_logger.go index 4d1d27ae..8312c21d 100644 --- a/api/common/panic_logger.go +++ b/api/common/panic_logger.go @@ -52,6 +52,10 @@ func (fs FusePanicLogger) SetInodeAttributes(ctx context.Context, op *fuseops.Se defer LogPanic(&err) return fs.Fs.SetInodeAttributes(ctx, op) } +func (fs FusePanicLogger) Fallocate(ctx context.Context, op *fuseops.FallocateOp) (err error) { + defer LogPanic(&err) + return fs.Fs.Fallocate(ctx, op) +} func (fs FusePanicLogger) ForgetInode(ctx context.Context, op *fuseops.ForgetInodeOp) (err error) { defer LogPanic(&err) return fs.Fs.ForgetInode(ctx, op) diff --git a/internal/goofys.go b/internal/goofys.go index 7747e464..80e7df20 100644 --- a/internal/goofys.go +++ b/internal/goofys.go @@ -443,12 +443,14 @@ func (fs *Goofys) GetXattr(ctx context.Context, op.BytesRead = len(value) - if len(op.Dst) < op.BytesRead { - return syscall.ERANGE - } else { + if len(op.Dst) != 0 { + if len(op.Dst) < op.BytesRead { + return syscall.ERANGE + } + copy(op.Dst, value) - return } + return } func (fs *Goofys) ListXattr(ctx context.Context, @@ -474,7 +476,7 @@ func (fs *Goofys) ListXattr(ctx context.Context, op.BytesRead += nlen } - if ncopied < op.BytesRead { + if len(op.Dst) != 0 && ncopied < op.BytesRead { err = syscall.ERANGE } diff --git a/internal/goofys_test.go b/internal/goofys_test.go index 40d7f24e..c1d34464 100644 --- a/internal/goofys_test.go +++ b/internal/goofys_test.go @@ -48,7 +48,7 @@ import ( "github.com/Azure/go-autorest/autorest/azure" azureauth "github.com/Azure/go-autorest/autorest/azure/auth" - "github.com/kahing/go-xattr" + "golang.org/x/sys/unix" "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" @@ -1620,6 +1620,10 @@ func (s *GoofysTest) runFuseTest(t *C, mountPoint string, umount bool, cmdArgs . defer s.umount(t, mountPoint) } + // if command starts with ./ or ../ then we are executing a + // relative path and cannot do chdir + chdir := cmdArgs[0][0] != '.' + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) cmd.Env = append(cmd.Env, os.Environ()...) cmd.Env = append(cmd.Env, "FAST=true") @@ -1635,6 +1639,16 @@ func (s *GoofysTest) runFuseTest(t *C, mountPoint string, umount bool, cmdArgs . cmd.Stderr = w } + if chdir { + oldCwd, err := os.Getwd() + t.Assert(err, IsNil) + + err = os.Chdir(mountPoint) + t.Assert(err, IsNil) + + defer os.Chdir(oldCwd) + } + err := cmd.Run() t.Assert(err, IsNil) } @@ -2097,8 +2111,7 @@ func (s *GoofysTest) TestXAttrGet(t *C) { t.Assert(names, DeepEquals, []string{"s3.etag", "s3.storage-class", "user.name"}) _, err = file1.GetXattr("user.foobar") - // xattr.IsNotExist seems broken on recent version of macOS - t.Assert(err, Equals, syscall.ENODATA) + t.Assert(err, Equals, unix.ENODATA) if checkETag { value, err := file1.GetXattr("s3.etag") @@ -2114,6 +2127,10 @@ func (s *GoofysTest) TestXAttrGet(t *C) { dir1, err := s.LookUpInode(t, "dir1") t.Assert(err, IsNil) + names, err = dir1.ListXattr() + t.Assert(err, IsNil) + t.Assert(len(names), Equals, 0) + // list dir1 to populate file3 in cache, then get file3's xattr lookup := fuseops.LookUpInodeOp{ Parent: fuseops.RootInodeID, @@ -2309,6 +2326,73 @@ func (s *GoofysTest) TestXAttrRemove(t *C) { t.Assert(err, Equals, syscall.ENODATA) } +func (s *GoofysTest) TestXAttrFuse(t *C) { + if _, ok := s.cloud.(*ADLv1); ok { + t.Skip("ADLv1 doesn't support metadata") + } + + _, checkETag := s.cloud.Delegate().(*S3Backend) + + //fuseLog.Level = logrus.DebugLevel + mountPoint := "/tmp/mnt" + s.fs.bucket + s.mount(t, mountPoint) + defer s.umount(t, mountPoint) + + expectedXattrs := "s3.etag\x00s3.storage-class\x00user.name\x00" + var buf [1024]byte + + // error if size is too small (but not zero) + _, err := unix.Listxattr(mountPoint+"/file1", buf[:1]) + t.Assert(err, Equals, unix.ERANGE) + + // 0 len buffer means interogate the size of buffer + nbytes, err := unix.Listxattr(mountPoint+"/file1", nil) + t.Assert(err, Equals, nil) + t.Assert(nbytes, Equals, len(expectedXattrs)) + + nbytes, err = unix.Listxattr(mountPoint+"/file1", buf[:nbytes]) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, len(expectedXattrs)) + t.Assert(string(buf[:nbytes]), Equals, expectedXattrs) + + _, err = unix.Getxattr(mountPoint+"/file1", "user.name", buf[:1]) + t.Assert(err, Equals, unix.ERANGE) + + nbytes, err = unix.Getxattr(mountPoint+"/file1", "user.name", nil) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, 9) + + nbytes, err = unix.Getxattr(mountPoint+"/file1", "user.name", buf[:nbytes]) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, 9) + t.Assert(string(buf[:nbytes]), Equals, "file1+/#\x00") + + // dir1 has no xattrs + nbytes, err = unix.Listxattr(mountPoint+"/dir1", nil) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, 0) + + nbytes, err = unix.Listxattr(mountPoint+"/dir1", buf[:1]) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, 0) + + if checkETag { + _, err = unix.Getxattr(mountPoint+"/file1", "s3.etag", buf[:1]) + t.Assert(err, Equals, unix.ERANGE) + + nbytes, err = unix.Getxattr(mountPoint+"/file1", "s3.etag", nil) + t.Assert(err, IsNil) + // 32 bytes md5 plus quotes + t.Assert(nbytes, Equals, 34) + + nbytes, err = unix.Getxattr(mountPoint+"/file1", "s3.etag", buf[:nbytes]) + t.Assert(err, IsNil) + t.Assert(nbytes, Equals, 34) + t.Assert(string(buf[:nbytes]), Equals, + "\"826e8142e6baabe8af779f5f490cf5f5\"") + } +} + func (s *GoofysTest) TestXAttrSet(t *C) { if _, ok := s.cloud.(*ADLv1); ok { t.Skip("ADLv1 doesn't support metadata") @@ -2317,13 +2401,13 @@ func (s *GoofysTest) TestXAttrSet(t *C) { in, err := s.LookUpInode(t, "file1") t.Assert(err, IsNil) - err = in.SetXattr("user.bar", []byte("hello"), xattr.REPLACE) + err = in.SetXattr("user.bar", []byte("hello"), unix.XATTR_REPLACE) t.Assert(err, Equals, syscall.ENODATA) - err = in.SetXattr("user.bar", []byte("hello"), xattr.CREATE) + err = in.SetXattr("user.bar", []byte("hello"), unix.XATTR_CREATE) t.Assert(err, IsNil) - err = in.SetXattr("user.bar", []byte("hello"), xattr.CREATE) + err = in.SetXattr("user.bar", []byte("hello"), unix.XATTR_CREATE) t.Assert(err, Equals, syscall.EEXIST) in, err = s.LookUpInode(t, "file1") @@ -2335,7 +2419,7 @@ func (s *GoofysTest) TestXAttrSet(t *C) { value = []byte("file1+%/#\x00") - err = in.SetXattr("user.bar", value, xattr.REPLACE) + err = in.SetXattr("user.bar", value, unix.XATTR_REPLACE) t.Assert(err, IsNil) in, err = s.LookUpInode(t, "file1") @@ -2361,10 +2445,18 @@ func (s *GoofysTest) TestXAttrSet(t *C) { t.Assert(value2, DeepEquals, value) t.Assert(string(value2), DeepEquals, "world") - err = in.SetXattr("s3.bar", []byte("hello"), xattr.CREATE) + err = in.SetXattr("s3.bar", []byte("hello"), unix.XATTR_CREATE) t.Assert(err, Equals, syscall.EPERM) } +func (s *GoofysTest) TestPythonCopyTree(t *C) { + mountPoint := "/tmp/mnt" + s.fs.bucket + + s.runFuseTest(t, mountPoint, true, "python", "-c", + "import shutil; shutil.copytree('dir2', 'dir5')", + mountPoint) +} + func (s *GoofysTest) TestCreateRenameBeforeCloseFuse(t *C) { if s.azurite { // Azurite returns 400 when copy source doesn't exist diff --git a/internal/handles.go b/internal/handles.go index f5b49043..c31fbc38 100644 --- a/internal/handles.go +++ b/internal/handles.go @@ -28,6 +28,7 @@ import ( "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fuseops" + "golang.org/x/sys/unix" "github.com/sirupsen/logrus" ) @@ -344,12 +345,12 @@ func (inode *Inode) getXattrMap(name string, userOnly bool) ( if userOnly { return nil, "", syscall.EACCES } else { - return nil, "", syscall.ENODATA + return nil, "", unix.ENODATA } } if meta == nil { - return nil, "", syscall.ENODATA + return nil, "", unix.ENODATA } return @@ -390,11 +391,11 @@ func (inode *Inode) SetXattr(name string, value []byte, flags uint32) error { if flags != 0x0 { _, ok := meta[name] - if flags == 0x1 { + if flags == unix.XATTR_CREATE { if ok { return syscall.EEXIST } - } else if flags == 0x2 { + } else if flags == unix.XATTR_REPLACE { if !ok { return syscall.ENODATA } diff --git a/vendor/github.com/jacobsa/fuse b/vendor/github.com/jacobsa/fuse index cb66eea2..374cf420 160000 --- a/vendor/github.com/jacobsa/fuse +++ b/vendor/github.com/jacobsa/fuse @@ -1 +1 @@ -Subproject commit cb66eea2377fb365bbeb3055585db6e9ea3e8226 +Subproject commit 374cf4208103e8c7a7bb70af2acf459772c05d0a diff --git a/vendor/github.com/kahing/go-xattr b/vendor/github.com/kahing/go-xattr deleted file mode 160000 index 257c199c..00000000 --- a/vendor/github.com/kahing/go-xattr +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 257c199cd6482799d85890abdd2ecb28b721fcc4