|
0 |
// +build solaris
|
|
1 |
|
|
2 |
package xattr
|
|
3 |
|
|
4 |
import (
|
|
5 |
"os"
|
|
6 |
"syscall"
|
|
7 |
|
|
8 |
"golang.org/x/sys/unix"
|
|
9 |
)
|
|
10 |
|
|
11 |
const (
|
|
12 |
// XATTR_SUPPORTED will be true if the current platform is supported
|
|
13 |
XATTR_SUPPORTED = true
|
|
14 |
|
|
15 |
XATTR_CREATE = 0x1
|
|
16 |
XATTR_REPLACE = 0x2
|
|
17 |
|
|
18 |
// ENOATTR is not exported by the syscall package on Linux, because it is
|
|
19 |
// an alias for ENODATA. We export it here so it is available on all
|
|
20 |
// our supported platforms.
|
|
21 |
ENOATTR = syscall.ENODATA
|
|
22 |
)
|
|
23 |
|
|
24 |
func getxattr(path string, name string, data []byte) (int, error) {
|
|
25 |
fd, err := unix.Open(path, unix.O_RDONLY, 0)
|
|
26 |
if err != nil {
|
|
27 |
return 0, err
|
|
28 |
}
|
|
29 |
defer func() {
|
|
30 |
_ = unix.Close(fd)
|
|
31 |
}()
|
|
32 |
return fgetxattr(os.NewFile(uintptr(fd), path), name, data)
|
|
33 |
}
|
|
34 |
|
|
35 |
func lgetxattr(path string, name string, data []byte) (int, error) {
|
|
36 |
return 0, unix.ENOTSUP
|
|
37 |
}
|
|
38 |
|
|
39 |
func fgetxattr(f *os.File, name string, data []byte) (int, error) {
|
|
40 |
fd, err := unix.Openat(int(f.Fd()), name, unix.O_RDONLY|unix.O_XATTR, 0)
|
|
41 |
if err != nil {
|
|
42 |
return 0, err
|
|
43 |
}
|
|
44 |
defer func() {
|
|
45 |
_ = unix.Close(fd)
|
|
46 |
}()
|
|
47 |
return unix.Read(fd, data)
|
|
48 |
}
|
|
49 |
|
|
50 |
func setxattr(path string, name string, data []byte, flags int) error {
|
|
51 |
fd, err := unix.Open(path, unix.O_RDONLY, 0)
|
|
52 |
if err != nil {
|
|
53 |
return err
|
|
54 |
}
|
|
55 |
if err = fsetxattr(os.NewFile(uintptr(fd), path), name, data, flags); err != nil {
|
|
56 |
_ = unix.Close(fd)
|
|
57 |
return err
|
|
58 |
}
|
|
59 |
return unix.Close(fd)
|
|
60 |
}
|
|
61 |
|
|
62 |
func lsetxattr(path string, name string, data []byte, flags int) error {
|
|
63 |
return unix.ENOTSUP
|
|
64 |
}
|
|
65 |
|
|
66 |
func fsetxattr(f *os.File, name string, data []byte, flags int) error {
|
|
67 |
mode := unix.O_WRONLY | unix.O_XATTR
|
|
68 |
if flags&XATTR_REPLACE != 0 {
|
|
69 |
mode |= unix.O_TRUNC
|
|
70 |
} else if flags&XATTR_CREATE != 0 {
|
|
71 |
mode |= unix.O_CREAT | unix.O_EXCL
|
|
72 |
} else {
|
|
73 |
mode |= unix.O_CREAT | unix.O_TRUNC
|
|
74 |
}
|
|
75 |
fd, err := unix.Openat(int(f.Fd()), name, mode, 0666)
|
|
76 |
if err != nil {
|
|
77 |
return err
|
|
78 |
}
|
|
79 |
if _, err = unix.Write(fd, data); err != nil {
|
|
80 |
_ = unix.Close(fd)
|
|
81 |
return err
|
|
82 |
}
|
|
83 |
return unix.Close(fd)
|
|
84 |
}
|
|
85 |
|
|
86 |
func removexattr(path string, name string) error {
|
|
87 |
fd, err := unix.Open(path, unix.O_RDONLY|unix.O_XATTR, 0)
|
|
88 |
if err != nil {
|
|
89 |
return err
|
|
90 |
}
|
|
91 |
defer func() {
|
|
92 |
_ = unix.Close(fd)
|
|
93 |
}()
|
|
94 |
return fremovexattr(os.NewFile(uintptr(fd), path), name)
|
|
95 |
}
|
|
96 |
|
|
97 |
func lremovexattr(path string, name string) error {
|
|
98 |
return unix.ENOTSUP
|
|
99 |
}
|
|
100 |
|
|
101 |
func fremovexattr(f *os.File, name string) error {
|
|
102 |
fd, err := unix.Openat(int(f.Fd()), ".", unix.O_XATTR, 0)
|
|
103 |
if err != nil {
|
|
104 |
return err
|
|
105 |
}
|
|
106 |
defer func() {
|
|
107 |
_ = unix.Close(fd)
|
|
108 |
}()
|
|
109 |
return unix.Unlinkat(fd, name, 0)
|
|
110 |
}
|
|
111 |
|
|
112 |
func listxattr(path string, data []byte) (int, error) {
|
|
113 |
fd, err := unix.Open(path, unix.O_RDONLY, 0)
|
|
114 |
if err != nil {
|
|
115 |
return 0, err
|
|
116 |
}
|
|
117 |
defer func() {
|
|
118 |
_ = unix.Close(fd)
|
|
119 |
}()
|
|
120 |
return flistxattr(os.NewFile(uintptr(fd), path), data)
|
|
121 |
}
|
|
122 |
|
|
123 |
func llistxattr(path string, data []byte) (int, error) {
|
|
124 |
return 0, unix.ENOTSUP
|
|
125 |
}
|
|
126 |
|
|
127 |
func flistxattr(f *os.File, data []byte) (int, error) {
|
|
128 |
fd, err := unix.Openat(int(f.Fd()), ".", unix.O_RDONLY|unix.O_XATTR, 0)
|
|
129 |
if err != nil {
|
|
130 |
return 0, err
|
|
131 |
}
|
|
132 |
defer func() {
|
|
133 |
_ = unix.Close(fd)
|
|
134 |
}()
|
|
135 |
names, err := os.NewFile(uintptr(fd), f.Name()).Readdirnames(-1)
|
|
136 |
if err != nil {
|
|
137 |
return 0, err
|
|
138 |
}
|
|
139 |
var buf []byte
|
|
140 |
for _, name := range names {
|
|
141 |
buf = append(buf, append([]byte(name), '\000')...)
|
|
142 |
}
|
|
143 |
if data == nil {
|
|
144 |
return len(buf), nil
|
|
145 |
}
|
|
146 |
return copy(data, buf), nil
|
|
147 |
}
|
|
148 |
|
|
149 |
// stringsFromByteSlice converts a sequence of attributes to a []string.
|
|
150 |
// On Darwin and Linux, each entry is a NULL-terminated string.
|
|
151 |
func stringsFromByteSlice(buf []byte) (result []string) {
|
|
152 |
offset := 0
|
|
153 |
for index, b := range buf {
|
|
154 |
if b == 0 {
|
|
155 |
result = append(result, string(buf[offset:index]))
|
|
156 |
offset = index + 1
|
|
157 |
}
|
|
158 |
}
|
|
159 |
return
|
|
160 |
}
|