1
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18
19 package fs
20
21 import (
22 "context"
23 "encoding/base64"
24 "strings"
25 "sync"
26
27 "perkeep.org/pkg/blob"
28 "perkeep.org/pkg/schema"
29 "perkeep.org/pkg/search"
30
31 "bazil.org/fuse"
32 )
33
34
35
36 const xattrPrefix = "xattr:"
37
38
39
40 type xattr struct {
41 typeName string
42 fs *CamliFileSystem
43 permanode blob.Ref
44
45
46
47 mu *sync.Mutex
48
49
50
51
52 xattrs *map[string][]byte
53 }
54
55
56
57
58 func (x *xattr) load(p *search.DescribedPermanode) {
59 x.mu.Lock()
60 defer x.mu.Unlock()
61
62 *x.xattrs = map[string][]byte{}
63 for k, v := range p.Attr {
64 if strings.HasPrefix(k, xattrPrefix) {
65 name := k[len(xattrPrefix):]
66 val, err := base64.StdEncoding.DecodeString(v[0])
67 if err != nil {
68 Logger.Printf("Base64 decoding error on attribute %v: %v", name, err)
69 continue
70 }
71 (*x.xattrs)[name] = val
72 }
73 }
74 }
75
76 func (x *xattr) set(ctx context.Context, req *fuse.SetxattrRequest) error {
77 Logger.Printf("%s.setxattr(%q) -> %q", x.typeName, req.Name, req.Xattr)
78
79 claim := schema.NewSetAttributeClaim(x.permanode, xattrPrefix+req.Name,
80 base64.StdEncoding.EncodeToString(req.Xattr))
81 _, err := x.fs.client.UploadAndSignBlob(ctx, claim)
82 if err != nil {
83 Logger.Printf("Error setting xattr: %v", err)
84 return handleEIOorEINTR(err)
85 }
86
87 val := make([]byte, len(req.Xattr))
88 copy(val, req.Xattr)
89 x.mu.Lock()
90 (*x.xattrs)[req.Name] = val
91 x.mu.Unlock()
92
93 return nil
94 }
95
96 func (x *xattr) remove(ctx context.Context, req *fuse.RemovexattrRequest) error {
97 Logger.Printf("%s.Removexattr(%q)", x.typeName, req.Name)
98
99 claim := schema.NewDelAttributeClaim(x.permanode, xattrPrefix+req.Name, "")
100 _, err := x.fs.client.UploadAndSignBlob(ctx, claim)
101
102 if err != nil {
103 Logger.Printf("Error removing xattr: %v", err)
104 return handleEIOorEINTR(err)
105 }
106
107 x.mu.Lock()
108 delete(*x.xattrs, req.Name)
109 x.mu.Unlock()
110
111 return nil
112 }
113
114 func (x *xattr) get(req *fuse.GetxattrRequest, res *fuse.GetxattrResponse) error {
115 x.mu.Lock()
116 defer x.mu.Unlock()
117
118 val, found := (*x.xattrs)[req.Name]
119
120 if !found {
121 return fuse.ErrNoXattr
122 }
123
124 res.Xattr = val
125
126 return nil
127 }
128
129 func (x *xattr) list(req *fuse.ListxattrRequest, res *fuse.ListxattrResponse) error {
130 x.mu.Lock()
131 defer x.mu.Unlock()
132
133 for k := range *x.xattrs {
134 res.Xattr = append(res.Xattr, k...)
135 res.Xattr = append(res.Xattr, '\x00')
136 }
137 return nil
138 }