xattrs_linux.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package system
  2. import (
  3. "syscall"
  4. "unsafe"
  5. )
  6. var _zero uintptr
  7. // Returns the size of xattrs and nil error
  8. // Requires path, takes allocated []byte or nil as last argument
  9. func Llistxattr(path string, dest []byte) (size int, err error) {
  10. pathBytes, err := syscall.BytePtrFromString(path)
  11. if err != nil {
  12. return -1, err
  13. }
  14. var newpathBytes unsafe.Pointer
  15. if len(dest) > 0 {
  16. newpathBytes = unsafe.Pointer(&dest[0])
  17. } else {
  18. newpathBytes = unsafe.Pointer(&_zero)
  19. }
  20. _size, _, errno := syscall.Syscall6(syscall.SYS_LLISTXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(newpathBytes), uintptr(len(dest)), 0, 0, 0)
  21. size = int(_size)
  22. if errno != 0 {
  23. return -1, errno
  24. }
  25. return size, nil
  26. }
  27. // Returns a []byte slice if the xattr is set and nil otherwise
  28. // Requires path and its attribute as arguments
  29. func Lgetxattr(path string, attr string) ([]byte, error) {
  30. var sz int
  31. pathBytes, err := syscall.BytePtrFromString(path)
  32. if err != nil {
  33. return nil, err
  34. }
  35. attrBytes, err := syscall.BytePtrFromString(attr)
  36. if err != nil {
  37. return nil, err
  38. }
  39. // Start with a 128 length byte array
  40. sz = 128
  41. dest := make([]byte, sz)
  42. destBytes := unsafe.Pointer(&dest[0])
  43. _sz, _, errno := syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
  44. switch {
  45. case errno == syscall.ENODATA:
  46. return nil, errno
  47. case errno == syscall.ENOTSUP:
  48. return nil, errno
  49. case errno == syscall.ERANGE:
  50. // 128 byte array might just not be good enough,
  51. // A dummy buffer is used ``uintptr(0)`` to get real size
  52. // of the xattrs on disk
  53. _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(unsafe.Pointer(nil)), uintptr(0), 0, 0)
  54. sz = int(_sz)
  55. if sz < 0 {
  56. return nil, errno
  57. }
  58. dest = make([]byte, sz)
  59. destBytes := unsafe.Pointer(&dest[0])
  60. _sz, _, errno = syscall.Syscall6(syscall.SYS_LGETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(destBytes), uintptr(len(dest)), 0, 0)
  61. if errno != 0 {
  62. return nil, errno
  63. }
  64. case errno != 0:
  65. return nil, errno
  66. }
  67. sz = int(_sz)
  68. return dest[:sz], nil
  69. }
  70. func Lsetxattr(path string, attr string, data []byte, flags int) error {
  71. pathBytes, err := syscall.BytePtrFromString(path)
  72. if err != nil {
  73. return err
  74. }
  75. attrBytes, err := syscall.BytePtrFromString(attr)
  76. if err != nil {
  77. return err
  78. }
  79. var dataBytes unsafe.Pointer
  80. if len(data) > 0 {
  81. dataBytes = unsafe.Pointer(&data[0])
  82. } else {
  83. dataBytes = unsafe.Pointer(&_zero)
  84. }
  85. _, _, errno := syscall.Syscall6(syscall.SYS_LSETXATTR, uintptr(unsafe.Pointer(pathBytes)), uintptr(unsafe.Pointer(attrBytes)), uintptr(dataBytes), uintptr(len(data)), uintptr(flags), 0)
  86. if errno != 0 {
  87. return errno
  88. }
  89. return nil
  90. }