Codebase list golang-github-pkg-xattr / upstream/0.4.3
Import upstream version 0.4.3 Debian Janitor 2 years ago
5 changed file(s) with 173 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
55
66 xattr
77 =====
8 Extended attribute support for Go (linux + darwin + freebsd + netbsd).
8 Extended attribute support for Go (linux + darwin + freebsd + netbsd + solaris).
99
1010 "Extended attributes are name:value pairs associated permanently with files and directories, similar to the environment strings associated with a process. An attribute may be defined or undefined. If it is defined, its value may be empty or non-empty." [See more...](https://en.wikipedia.org/wiki/Extended_file_attributes)
1111
0 // +build linux darwin
0 // +build linux darwin solaris
11
22 package xattr
33
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 }
0 // +build linux darwin freebsd netbsd
0 // +build linux darwin freebsd netbsd solaris
11
22 package xattr
33
146146 // Test that Get/LGet, Set/LSet etc operate as expected on symlinks. The
147147 // functions should behave differently when operating on a symlink.
148148 func TestSymlink(t *testing.T) {
149 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" {
150 t.Skipf("extended attributes aren't supported for symlinks on %s", runtime.GOOS)
151 }
149152 dir, err := ioutil.TempDir("", "")
150153 if err != nil {
151154 t.Fatal(err)
280283 if !ok {
281284 log.Panicf("cannot unpack err=%#v", err)
282285 }
283 return err2.Err.(syscall.Errno)
286 err3, ok := err2.Err.(syscall.Errno)
287 if !ok {
288 log.Panicf("cannot unpack err2=%#v", err2)
289 }
290 return err3
284291 }
285292
286293 // wrappers to adapt "F" variants to the test
0 // +build !linux,!freebsd,!netbsd,!darwin
0 // +build !linux,!freebsd,!netbsd,!darwin,!solaris
11
22 package xattr
33