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 }