// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build darwin freebsd linux netbsd package unix_test import ( "io/ioutil" "os" "runtime" "strings" "testing" "golang.org/x/sys/unix" ) func TestXattr(t *testing.T) { defer chtmpdir(t)() f := "xattr1" touch(t, f) xattrName := "user.test" xattrDataSet := "gopher" err := unix.Setxattr(f, xattrName, []byte{}, 0) if err == unix.ENOTSUP || err == unix.EOPNOTSUPP { t.Skip("filesystem does not support extended attributes, skipping test") } else if err != nil { t.Fatalf("Setxattr: %v", err) } err = unix.Setxattr(f, xattrName, []byte(xattrDataSet), 0) if err != nil { t.Fatalf("Setxattr: %v", err) } // find size size, err := unix.Listxattr(f, nil) if err != nil { t.Fatalf("Listxattr: %v", err) } if size <= 0 { t.Fatalf("Listxattr returned an empty list of attributes") } buf := make([]byte, size) read, err := unix.Listxattr(f, buf) if err != nil { t.Fatalf("Listxattr: %v", err) } xattrs := stringsFromByteSlice(buf[:read]) xattrWant := xattrName if runtime.GOOS == "freebsd" { // On FreeBSD, the namespace is stored separately from the xattr // name and Listxattr doesn't return the namespace prefix. xattrWant = strings.TrimPrefix(xattrWant, "user.") } found := false for _, name := range xattrs { if name == xattrWant { found = true } } if !found { t.Errorf("Listxattr did not return previously set attribute '%s'", xattrName) } // find size size, err = unix.Getxattr(f, xattrName, nil) if err != nil { t.Fatalf("Getxattr: %v", err) } if size <= 0 { t.Fatalf("Getxattr returned an empty attribute") } xattrDataGet := make([]byte, size) _, err = unix.Getxattr(f, xattrName, xattrDataGet) if err != nil { t.Fatalf("Getxattr: %v", err) } got := string(xattrDataGet) if got != xattrDataSet { t.Errorf("Getxattr: expected attribute value %s, got %s", xattrDataSet, got) } err = unix.Removexattr(f, xattrName) if err != nil { t.Fatalf("Removexattr: %v", err) } n := "nonexistent" err = unix.Lsetxattr(n, xattrName, []byte(xattrDataSet), 0) if err != unix.ENOENT { t.Errorf("Lsetxattr: expected %v on non-existent file, got %v", unix.ENOENT, err) } _, err = unix.Lgetxattr(n, xattrName, nil) if err != unix.ENOENT { t.Errorf("Lgetxattr: %v", err) } s := "symlink1" err = os.Symlink(n, s) if err != nil { t.Fatal(err) } err = unix.Lsetxattr(s, xattrName, []byte(xattrDataSet), 0) if err != nil { // Linux and Android doen't support xattrs on symlinks according // to xattr(7), so just test that we get the proper error. if (runtime.GOOS != "linux" && runtime.GOOS != "android") || err != unix.EPERM { t.Fatalf("Lsetxattr: %v", err) } } } func TestFdXattr(t *testing.T) { file, err := ioutil.TempFile("", "TestFdXattr") if err != nil { t.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() fd := int(file.Fd()) xattrName := "user.test" xattrDataSet := "gopher" err = unix.Fsetxattr(fd, xattrName, []byte(xattrDataSet), 0) if err == unix.ENOTSUP || err == unix.EOPNOTSUPP { t.Skip("filesystem does not support extended attributes, skipping test") } else if err != nil { t.Fatalf("Fsetxattr: %v", err) } // find size size, err := unix.Flistxattr(fd, nil) if err != nil { t.Fatalf("Flistxattr: %v", err) } if size <= 0 { t.Fatalf("Flistxattr returned an empty list of attributes") } buf := make([]byte, size) read, err := unix.Flistxattr(fd, buf) if err != nil { t.Fatalf("Flistxattr: %v", err) } xattrs := stringsFromByteSlice(buf[:read]) xattrWant := xattrName if runtime.GOOS == "freebsd" { // On FreeBSD, the namespace is stored separately from the xattr // name and Listxattr doesn't return the namespace prefix. xattrWant = strings.TrimPrefix(xattrWant, "user.") } found := false for _, name := range xattrs { if name == xattrWant { found = true } } if !found { t.Errorf("Flistxattr did not return previously set attribute '%s'", xattrName) } // find size size, err = unix.Fgetxattr(fd, xattrName, nil) if err != nil { t.Fatalf("Fgetxattr: %v", err) } if size <= 0 { t.Fatalf("Fgetxattr returned an empty attribute") } xattrDataGet := make([]byte, size) _, err = unix.Fgetxattr(fd, xattrName, xattrDataGet) if err != nil { t.Fatalf("Fgetxattr: %v", err) } got := string(xattrDataGet) if got != xattrDataSet { t.Errorf("Fgetxattr: expected attribute value %s, got %s", xattrDataSet, got) } err = unix.Fremovexattr(fd, xattrName) if err != nil { t.Fatalf("Fremovexattr: %v", err) } }