xattr_test.go 4.6 KB

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