github.com/hanwen/go-fuse@v1.0.0/fuse/pathfs/xattr_test.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build linux 6 7 package pathfs 8 9 import ( 10 "bytes" 11 "os" 12 "path/filepath" 13 "testing" 14 15 "github.com/hanwen/go-fuse/fuse" 16 "github.com/hanwen/go-fuse/fuse/nodefs" 17 "github.com/hanwen/go-fuse/internal/testutil" 18 ) 19 20 var xattrGolden = map[string][]byte{ 21 "user.attr1": []byte("val1"), 22 "user.attr2": []byte("val2")} 23 var xattrFilename = "filename" 24 25 type XAttrTestFs struct { 26 filename string 27 attrs map[string][]byte 28 29 FileSystem 30 } 31 32 func NewXAttrFs(nm string, m map[string][]byte) *XAttrTestFs { 33 x := &XAttrTestFs{ 34 filename: nm, 35 attrs: make(map[string][]byte, len(m)), 36 FileSystem: NewDefaultFileSystem(), 37 } 38 39 for k, v := range m { 40 x.attrs[k] = v 41 } 42 return x 43 } 44 45 func (fs *XAttrTestFs) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { 46 a := &fuse.Attr{} 47 if name == "" || name == "/" { 48 a.Mode = fuse.S_IFDIR | 0700 49 return a, fuse.OK 50 } 51 if name == fs.filename { 52 a.Mode = fuse.S_IFREG | 0600 53 return a, fuse.OK 54 } 55 return nil, fuse.ENOENT 56 } 57 58 func (fs *XAttrTestFs) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status { 59 if name != fs.filename { 60 return fuse.ENOENT 61 } 62 dest := make([]byte, len(data)) 63 copy(dest, data) 64 fs.attrs[attr] = dest 65 return fuse.OK 66 } 67 68 func (fs *XAttrTestFs) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) { 69 if name != fs.filename { 70 return nil, fuse.ENOENT 71 } 72 v, ok := fs.attrs[attr] 73 if !ok { 74 return nil, fuse.ENOATTR 75 } 76 return v, fuse.OK 77 } 78 79 func (fs *XAttrTestFs) ListXAttr(name string, context *fuse.Context) (data []string, code fuse.Status) { 80 if name != fs.filename { 81 return nil, fuse.ENOENT 82 } 83 84 for k := range fs.attrs { 85 data = append(data, k) 86 } 87 return data, fuse.OK 88 } 89 90 func (fs *XAttrTestFs) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status { 91 if name != fs.filename { 92 return fuse.ENOENT 93 } 94 _, ok := fs.attrs[attr] 95 if !ok { 96 return fuse.ENOATTR 97 } 98 delete(fs.attrs, attr) 99 return fuse.OK 100 } 101 102 func readXAttr(p, a string) (val []byte, err error) { 103 val = make([]byte, 1024) 104 return getXAttr(p, a, val) 105 } 106 107 func xattrTestCase(t *testing.T, nm string, m map[string][]byte) (mountPoint string, cleanup func()) { 108 xfs := NewXAttrFs(nm, m) 109 mountPoint = testutil.TempDir() 110 111 nfs := NewPathNodeFs(xfs, nil) 112 state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), 113 &nodefs.Options{Debug: VerboseTest()}) 114 if err != nil { 115 t.Fatalf("MountRoot failed: %v", err) 116 } 117 118 go state.Serve() 119 return mountPoint, func() { 120 state.Unmount() 121 os.RemoveAll(mountPoint) 122 } 123 } 124 125 func TestXAttrNoAttrs(t *testing.T) { 126 nm := xattrFilename 127 mountPoint, clean := xattrTestCase(t, nm, make(map[string][]byte)) 128 defer clean() 129 130 mounted := filepath.Join(mountPoint, nm) 131 attrs, err := listXAttr(mounted) 132 if err != nil { 133 t.Error("Unexpected ListXAttr error", err) 134 } 135 136 if len(attrs) > 0 { 137 t.Errorf("ListXAttr(%s) = %s, want empty slice", mounted, attrs) 138 } 139 } 140 141 func TestXAttrNoExist(t *testing.T) { 142 nm := xattrFilename 143 mountPoint, clean := xattrTestCase(t, nm, xattrGolden) 144 defer clean() 145 146 mounted := filepath.Join(mountPoint, nm) 147 _, err := os.Lstat(mounted) 148 if err != nil { 149 t.Error("Unexpected stat error", err) 150 } 151 152 val, err := readXAttr(mounted, "noexist") 153 if err == nil { 154 t.Error("Expected GetXAttr error", val) 155 } 156 } 157 158 func TestXAttrRead(t *testing.T) { 159 nm := xattrFilename 160 mountPoint, clean := xattrTestCase(t, nm, xattrGolden) 161 defer clean() 162 163 mounted := filepath.Join(mountPoint, nm) 164 attrs, err := listXAttr(mounted) 165 readback := make(map[string][]byte) 166 if err != nil { 167 t.Error("Unexpected ListXAttr error", err) 168 } else { 169 for _, a := range attrs { 170 val, err := readXAttr(mounted, a) 171 if err != nil { 172 t.Errorf("GetXAttr(%q) failed: %v", a, err) 173 } 174 readback[a] = val 175 } 176 } 177 178 if len(readback) != len(xattrGolden) { 179 t.Error("length mismatch", xattrGolden, readback) 180 } else { 181 for k, v := range readback { 182 if bytes.Compare(xattrGolden[k], v) != 0 { 183 t.Error("val mismatch", k, v, xattrGolden[k]) 184 } 185 } 186 } 187 188 err = sysSetxattr(mounted, "third", []byte("value"), 0) 189 if err != nil { 190 t.Error("Setxattr error", err) 191 } 192 val, err := readXAttr(mounted, "third") 193 if err != nil || string(val) != "value" { 194 t.Error("Read back set xattr:", err, string(val)) 195 } 196 197 sysRemovexattr(mounted, "third") 198 val, err = readXAttr(mounted, "third") 199 if fuse.ToStatus(err) != fuse.ENOATTR { 200 t.Error("Data not removed?", err, val) 201 } 202 }