@@ -20,9 +20,12 @@ import (
20
20
"path/filepath"
21
21
22
22
apkofs "github.com/chainguard-dev/go-apk/pkg/fs"
23
+ "golang.org/x/sys/unix"
23
24
)
24
25
25
26
type rlfs struct {
27
+ apkofs.XattrFS
28
+
26
29
base string
27
30
f fs.FS
28
31
}
@@ -43,6 +46,79 @@ func (f *rlfs) Stat(name string) (fs.FileInfo, error) {
43
46
return os .Stat (filepath .Join (f .base , name ))
44
47
}
45
48
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
+
46
122
func readlinkFS (dir string ) apkofs.ReadLinkFS {
47
123
return & rlfs {
48
124
base : dir ,
0 commit comments