Skip to content

Commit 73f2b39

Browse files
committed
readlinkfs: implement go-apk fs.XattrFS interfaces
Signed-off-by: Ariadne Conill <[email protected]>
1 parent 7f8e196 commit 73f2b39

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

pkg/build/readlinkfs.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ import (
2020
"path/filepath"
2121

2222
apkofs "github.com/chainguard-dev/go-apk/pkg/fs"
23+
"golang.org/x/sys/unix"
2324
)
2425

2526
type rlfs struct {
27+
apkofs.XattrFS
28+
2629
base string
2730
f fs.FS
2831
}
@@ -43,6 +46,79 @@ func (f *rlfs) Stat(name string) (fs.FileInfo, error) {
4346
return os.Stat(filepath.Join(f.base, name))
4447
}
4548

49+
func (f *rlfs) SetXattr(path string, attr string, data []byte) error {
50+
return unix.Setxattr(filepath.Join(f.base, path), attr, data, 0)
51+
}
52+
53+
func (f *rlfs) GetXattr(path string, attr string) ([]byte, error) {
54+
realPath := filepath.Join(f.base, path)
55+
56+
size, err := unix.Getxattr(realPath, attr, nil)
57+
if err != nil {
58+
return []byte{}, err
59+
}
60+
61+
buf := make([]byte, size)
62+
_, err = unix.Getxattr(realPath, attr, buf)
63+
if err != nil {
64+
return []byte{}, err
65+
}
66+
67+
return buf, nil
68+
}
69+
70+
func (f *rlfs) RemoveXattr(path string, attr string) error {
71+
return unix.Removexattr(filepath.Join(f.base, path), attr)
72+
}
73+
74+
// stringsFromByteSlice converts a sequence of attributes to a []string.
75+
// On Linux, each entry is a NULL-terminated string.
76+
// Taken from golang.org/x/sys/unix/syscall_linux_test.go.
77+
func stringsFromByteSlice(buf []byte) []string {
78+
var result []string
79+
off := 0
80+
for i, b := range buf {
81+
if b == 0 {
82+
result = append(result, string(buf[off:i]))
83+
off = i + 1
84+
}
85+
}
86+
return result
87+
}
88+
89+
func (f *rlfs) ListXattrs(path string) (map[string][]byte, error) {
90+
realPath := filepath.Join(f.base, path)
91+
92+
size, err := unix.Listxattr(realPath, nil)
93+
if err != nil {
94+
return map[string][]byte{}, err
95+
}
96+
97+
// If the xattr list is empty, the size will be 0.
98+
if size <= 0 {
99+
return map[string][]byte{}, nil
100+
}
101+
102+
buf := make([]byte, size)
103+
read, err := unix.Listxattr(realPath, buf)
104+
if err != nil {
105+
return map[string][]byte{}, err
106+
}
107+
108+
xattrMap := map[string][]byte{}
109+
xattrNames := stringsFromByteSlice(buf[:read])
110+
for _, xattrName := range xattrNames {
111+
result, err := f.GetXattr(path, xattrName)
112+
if err != nil {
113+
return map[string][]byte{}, err
114+
}
115+
116+
xattrMap[xattrName] = result
117+
}
118+
119+
return xattrMap, nil
120+
}
121+
46122
func readlinkFS(dir string) apkofs.ReadLinkFS {
47123
return &rlfs{
48124
base: dir,

0 commit comments

Comments
 (0)