xattr.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // +build linux darwin
  2. package sysx
  3. import (
  4. "bytes"
  5. "syscall"
  6. "golang.org/x/sys/unix"
  7. )
  8. // Listxattr calls syscall listxattr and reads all content
  9. // and returns a string array
  10. func Listxattr(path string) ([]string, error) {
  11. return listxattrAll(path, unix.Listxattr)
  12. }
  13. // Removexattr calls syscall removexattr
  14. func Removexattr(path string, attr string) (err error) {
  15. return unix.Removexattr(path, attr)
  16. }
  17. // Setxattr calls syscall setxattr
  18. func Setxattr(path string, attr string, data []byte, flags int) (err error) {
  19. return unix.Setxattr(path, attr, data, flags)
  20. }
  21. // Getxattr calls syscall getxattr
  22. func Getxattr(path, attr string) ([]byte, error) {
  23. return getxattrAll(path, attr, unix.Getxattr)
  24. }
  25. // LListxattr lists xattrs, not following symlinks
  26. func LListxattr(path string) ([]string, error) {
  27. return listxattrAll(path, unix.Llistxattr)
  28. }
  29. // LRemovexattr removes an xattr, not following symlinks
  30. func LRemovexattr(path string, attr string) (err error) {
  31. return unix.Lremovexattr(path, attr)
  32. }
  33. // LSetxattr sets an xattr, not following symlinks
  34. func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
  35. return unix.Lsetxattr(path, attr, data, flags)
  36. }
  37. // LGetxattr gets an xattr, not following symlinks
  38. func LGetxattr(path, attr string) ([]byte, error) {
  39. return getxattrAll(path, attr, unix.Lgetxattr)
  40. }
  41. const defaultXattrBufferSize = 5
  42. type listxattrFunc func(path string, dest []byte) (int, error)
  43. func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
  44. var p []byte // nil on first execution
  45. for {
  46. n, err := listFunc(path, p) // first call gets buffer size.
  47. if err != nil {
  48. return nil, err
  49. }
  50. if n > len(p) {
  51. p = make([]byte, n)
  52. continue
  53. }
  54. p = p[:n]
  55. ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
  56. var entries []string
  57. for _, p := range ps {
  58. s := string(p)
  59. if s != "" {
  60. entries = append(entries, s)
  61. }
  62. }
  63. return entries, nil
  64. }
  65. }
  66. type getxattrFunc func(string, string, []byte) (int, error)
  67. func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
  68. p := make([]byte, defaultXattrBufferSize)
  69. for {
  70. n, err := getFunc(path, attr, p)
  71. if err != nil {
  72. if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
  73. p = make([]byte, len(p)*2) // this can't be ideal.
  74. continue // try again!
  75. }
  76. return nil, err
  77. }
  78. // realloc to correct size and repeat
  79. if n > len(p) {
  80. p = make([]byte, n)
  81. continue
  82. }
  83. return p[:n], nil
  84. }
  85. }