-
Notifications
You must be signed in to change notification settings - Fork 29
/
xattr_linux.go
142 lines (122 loc) · 3.26 KB
/
xattr_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//go:build linux
// +build linux
package xattr
import (
"os"
"syscall"
"golang.org/x/sys/unix"
)
const (
// XATTR_SUPPORTED will be true if the current platform is supported
XATTR_SUPPORTED = true
XATTR_CREATE = unix.XATTR_CREATE
XATTR_REPLACE = unix.XATTR_REPLACE
// ENOATTR is not exported by the syscall package on Linux, because it is
// an alias for ENODATA. We export it here so it is available on all
// our supported platforms.
ENOATTR = syscall.ENODATA
)
// On Linux, FUSE and CIFS filesystems can return EINTR for interrupted system
// calls. This function works around this by retrying system calls until they
// stop returning EINTR.
//
// See https://github.com/golang/go/commit/6b420169d798c7ebe733487b56ea5c3fa4aab5ce.
func ignoringEINTR(fn func() error) (err error) {
for {
err = fn()
if err != unix.EINTR {
break
}
}
return err
}
func getxattr(path string, name string, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Getxattr(path, name, data)
return err
})
return r, err
}
func lgetxattr(path string, name string, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Lgetxattr(path, name, data)
return err
})
return r, err
}
func fgetxattr(f *os.File, name string, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Fgetxattr(int(f.Fd()), name, data)
return err
})
return r, err
}
func setxattr(path string, name string, data []byte, flags int) error {
return ignoringEINTR(func() (err error) {
return unix.Setxattr(path, name, data, flags)
})
}
func lsetxattr(path string, name string, data []byte, flags int) error {
return ignoringEINTR(func() (err error) {
return unix.Lsetxattr(path, name, data, flags)
})
}
func fsetxattr(f *os.File, name string, data []byte, flags int) error {
return ignoringEINTR(func() (err error) {
return unix.Fsetxattr(int(f.Fd()), name, data, flags)
})
}
func removexattr(path string, name string) error {
return ignoringEINTR(func() (err error) {
return unix.Removexattr(path, name)
})
}
func lremovexattr(path string, name string) error {
return ignoringEINTR(func() (err error) {
return unix.Lremovexattr(path, name)
})
}
func fremovexattr(f *os.File, name string) error {
return ignoringEINTR(func() (err error) {
return unix.Fremovexattr(int(f.Fd()), name)
})
}
func listxattr(path string, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Listxattr(path, data)
return err
})
return r, err
}
func llistxattr(path string, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Llistxattr(path, data)
return err
})
return r, err
}
func flistxattr(f *os.File, data []byte) (int, error) {
var r int
err := ignoringEINTR(func() (err error) {
r, err = unix.Flistxattr(int(f.Fd()), data)
return err
})
return r, err
}
// stringsFromByteSlice converts a sequence of attributes to a []string.
// On Darwin and Linux, each entry is a NULL-terminated string.
func stringsFromByteSlice(buf []byte) (result []string) {
offset := 0
for index, b := range buf {
if b == 0 {
result = append(result, string(buf[offset:index]))
offset = index + 1
}
}
return
}