golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/xattr_test.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build darwin || freebsd || linux || netbsd
     6  
     7  package unix_test
     8  
     9  import (
    10  	"os"
    11  	"path/filepath"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  
    16  	"golang.org/x/sys/unix"
    17  )
    18  
    19  func TestXattr(t *testing.T) {
    20  	chtmpdir(t)
    21  
    22  	f := "xattr1"
    23  	touch(t, f)
    24  
    25  	xattrName := "user.test"
    26  	xattrDataSet := "gopher"
    27  
    28  	err := unix.Setxattr(f, xattrName, []byte{}, 0)
    29  	if err == unix.ENOTSUP || err == unix.EOPNOTSUPP {
    30  		t.Skip("filesystem does not support extended attributes, skipping test")
    31  	} else if err != nil {
    32  		t.Fatalf("Setxattr: %v", err)
    33  	}
    34  
    35  	err = unix.Setxattr(f, xattrName, []byte(xattrDataSet), 0)
    36  	if err != nil {
    37  		t.Fatalf("Setxattr: %v", err)
    38  	}
    39  
    40  	// find size
    41  	size, err := unix.Listxattr(f, nil)
    42  	if err != nil {
    43  		t.Fatalf("Listxattr: %v", err)
    44  	}
    45  
    46  	if size <= 0 {
    47  		t.Fatalf("Listxattr returned an empty list of attributes")
    48  	}
    49  
    50  	buf := make([]byte, size)
    51  	read, err := unix.Listxattr(f, buf)
    52  	if err != nil {
    53  		t.Fatalf("Listxattr: %v", err)
    54  	}
    55  
    56  	xattrs := stringsFromByteSlice(buf[:read])
    57  
    58  	xattrWant := xattrName
    59  	if runtime.GOOS == "freebsd" {
    60  		// On FreeBSD, the namespace is stored separately from the xattr
    61  		// name and Listxattr doesn't return the namespace prefix.
    62  		xattrWant = strings.TrimPrefix(xattrWant, "user.")
    63  	}
    64  	found := false
    65  	for _, name := range xattrs {
    66  		if name == xattrWant {
    67  			found = true
    68  		}
    69  	}
    70  
    71  	if !found {
    72  		t.Errorf("Listxattr did not return previously set attribute '%s'", xattrName)
    73  	}
    74  
    75  	// find size
    76  	size, err = unix.Getxattr(f, xattrName, nil)
    77  	if err != nil {
    78  		t.Fatalf("Getxattr: %v", err)
    79  	}
    80  
    81  	if size <= 0 {
    82  		t.Fatalf("Getxattr returned an empty attribute")
    83  	}
    84  
    85  	xattrDataGet := make([]byte, size)
    86  	_, err = unix.Getxattr(f, xattrName, xattrDataGet)
    87  	if err != nil {
    88  		t.Fatalf("Getxattr: %v", err)
    89  	}
    90  
    91  	got := string(xattrDataGet)
    92  	if got != xattrDataSet {
    93  		t.Errorf("Getxattr: expected attribute value %s, got %s", xattrDataSet, got)
    94  	}
    95  
    96  	err = unix.Removexattr(f, xattrName)
    97  	if err != nil {
    98  		t.Fatalf("Removexattr: %v", err)
    99  	}
   100  
   101  	n := "nonexistent"
   102  	err = unix.Lsetxattr(n, xattrName, []byte(xattrDataSet), 0)
   103  	if err != unix.ENOENT {
   104  		t.Errorf("Lsetxattr: expected %v on non-existent file, got %v", unix.ENOENT, err)
   105  	}
   106  
   107  	_, err = unix.Lgetxattr(n, xattrName, nil)
   108  	if err != unix.ENOENT {
   109  		t.Errorf("Lgetxattr: %v", err)
   110  	}
   111  
   112  	s := "symlink1"
   113  	err = os.Symlink(n, s)
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  
   118  	err = unix.Lsetxattr(s, xattrName, []byte(xattrDataSet), 0)
   119  	if err != nil {
   120  		// Linux and Android doen't support xattrs on symlinks according
   121  		// to xattr(7), so just test that we get the proper error.
   122  		if (runtime.GOOS != "linux" && runtime.GOOS != "android") || err != unix.EPERM {
   123  			t.Fatalf("Lsetxattr: %v", err)
   124  		}
   125  	}
   126  }
   127  
   128  func TestFdXattr(t *testing.T) {
   129  	file, err := os.Create(filepath.Join(t.TempDir(), "TestFdXattr"))
   130  	if err != nil {
   131  		t.Fatal(err)
   132  	}
   133  	defer file.Close()
   134  
   135  	fd := int(file.Fd())
   136  	xattrName := "user.test"
   137  	xattrDataSet := "gopher"
   138  
   139  	err = unix.Fsetxattr(fd, xattrName, []byte(xattrDataSet), 0)
   140  	if err == unix.ENOTSUP || err == unix.EOPNOTSUPP {
   141  		t.Skip("filesystem does not support extended attributes, skipping test")
   142  	} else if err != nil {
   143  		t.Fatalf("Fsetxattr: %v", err)
   144  	}
   145  
   146  	// find size
   147  	size, err := unix.Flistxattr(fd, nil)
   148  	if err != nil {
   149  		t.Fatalf("Flistxattr: %v", err)
   150  	}
   151  
   152  	if size <= 0 {
   153  		t.Fatalf("Flistxattr returned an empty list of attributes")
   154  	}
   155  
   156  	buf := make([]byte, size)
   157  	read, err := unix.Flistxattr(fd, buf)
   158  	if err != nil {
   159  		t.Fatalf("Flistxattr: %v", err)
   160  	}
   161  
   162  	xattrs := stringsFromByteSlice(buf[:read])
   163  
   164  	xattrWant := xattrName
   165  	if runtime.GOOS == "freebsd" {
   166  		// On FreeBSD, the namespace is stored separately from the xattr
   167  		// name and Listxattr doesn't return the namespace prefix.
   168  		xattrWant = strings.TrimPrefix(xattrWant, "user.")
   169  	}
   170  	found := false
   171  	for _, name := range xattrs {
   172  		if name == xattrWant {
   173  			found = true
   174  		}
   175  	}
   176  
   177  	if !found {
   178  		t.Errorf("Flistxattr did not return previously set attribute '%s'", xattrName)
   179  	}
   180  
   181  	// find size
   182  	size, err = unix.Fgetxattr(fd, xattrName, nil)
   183  	if err != nil {
   184  		t.Fatalf("Fgetxattr: %v", err)
   185  	}
   186  
   187  	if size <= 0 {
   188  		t.Fatalf("Fgetxattr returned an empty attribute")
   189  	}
   190  
   191  	xattrDataGet := make([]byte, size)
   192  	_, err = unix.Fgetxattr(fd, xattrName, xattrDataGet)
   193  	if err != nil {
   194  		t.Fatalf("Fgetxattr: %v", err)
   195  	}
   196  
   197  	got := string(xattrDataGet)
   198  	if got != xattrDataSet {
   199  		t.Errorf("Fgetxattr: expected attribute value %s, got %s", xattrDataSet, got)
   200  	}
   201  
   202  	err = unix.Fremovexattr(fd, xattrName)
   203  	if err != nil {
   204  		t.Fatalf("Fremovexattr: %v", err)
   205  	}
   206  }