// Copyright 2024 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. //go:build zos package unix_test import ( "os" "testing" "golang.org/x/sys/unix" ) func TestXattr(t *testing.T) { chtmpdir(t) f := "xattr1" touch(t, f) xattrName := "system.filetag" xattrDataSet := make([]byte, 4) xattrDataSet[0] = 0xFF xattrDataSet[1] = 0xFF xattrDataSet[2] = 0 xattrDataSet[3] = 0 err := unix.Setxattr(f, xattrName, 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 found := false for _, name := range xattrs { if name == xattrWant { found = true break } } 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([]byte(xattrDataGet)) if got != string(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) } //confirm xattr removed // find size size, err = unix.Listxattr(f, nil) if err != nil { t.Fatalf("Listxattr: %v", err) } if size != 0 { buf := make([]byte, size) read, err = unix.Listxattr(f, buf) if err != nil { t.Fatalf("Listxattr: %v", err) } xattrs = stringsFromByteSlice(buf[:read]) found = false for _, name := range xattrs { if name == xattrWant { found = true break } if found { t.Errorf("Removexattr failed to remove attribute '%s'", xattrName) } } } n := "nonexistent" err = unix.Lsetxattr(n, xattrName, xattrDataSet, 0) if err != unix.ENOENT { t.Errorf("Lsetxattr: expected %v on non-existent file, got %v", unix.ENODATA, err) } _, err = unix.Lgetxattr(f, n, nil) if err != unix.ENODATA { t.Errorf("Lgetxattr: %v", err) } _, err = unix.Lgetxattr(n, xattrName, nil) if err != unix.ENOENT { t.Errorf("Lgetxattr: %v", err) } } func TestFdXattr(t *testing.T) { file, err := os.CreateTemp("", "TestFdXattr") if err != nil { t.Fatal(err) } defer os.Remove(file.Name()) defer file.Close() fd := int(file.Fd()) xattrName := "system.filetag" xattrDataSet := make([]byte, 4) xattrDataSet[0] = 0xFF xattrDataSet[1] = 0xFF xattrDataSet[2] = 0 xattrDataSet[3] = 0 err = unix.Fsetxattr(fd, xattrName, 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 found := false for _, name := range xattrs { if name == xattrWant { found = true break } } 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([]byte(xattrDataGet)) if got != string(xattrDataSet) { t.Errorf("Getxattr: expected attribute value %s, got %s", xattrDataSet, got) } err = unix.Fremovexattr(fd, xattrName) if err != nil { t.Fatalf("Fremovexattr: %v", err) } //confirm xattr removed // find size size, err = unix.Flistxattr(fd, nil) if err != nil { t.Fatalf("Flistxattr: %v", err) } if size != 0 { buf := make([]byte, size) read, err = unix.Flistxattr(fd, buf) if err != nil { t.Fatalf("Flistxattr: %v", err) } xattrs = stringsFromByteSlice(buf[:read]) found = false for _, name := range xattrs { if name == xattrWant { found = true break } if found { t.Errorf("Fremovexattr failed to remove attribute '%s'", xattrName) } } } }