summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/btrfs/io4_fs.go6
-rw-r--r--lib/btrfsprogs/btrfsinspect/mount.go59
2 files changed, 62 insertions, 3 deletions
diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go
index d28e36f..65a7562 100644
--- a/lib/btrfs/io4_fs.go
+++ b/lib/btrfs/io4_fs.go
@@ -29,6 +29,7 @@ type BareInode struct {
type FullInode struct {
BareInode
+ XAttrs map[string]string
OtherItems []Item
}
@@ -133,6 +134,7 @@ func (sv *Subvolume) LoadFullInode(inode ObjID) (*FullInode, error) {
BareInode: BareInode{
Inode: inode,
},
+ XAttrs: make(map[string]string),
}
items, err := sv.FS.TreeSearchAll(sv.TreeID, func(key Key, _ uint32) int {
return containers.NativeCmp(inode, key.ObjectID)
@@ -154,6 +156,9 @@ func (sv *Subvolume) LoadFullInode(inode ObjID) (*FullInode, error) {
continue
}
val.InodeItem = &itemBody
+ case btrfsitem.XATTR_ITEM_KEY:
+ itemBody := item.Body.(btrfsitem.DirEntry)
+ val.XAttrs[string(itemBody.Name)] = string(itemBody.Data)
default:
val.OtherItems = append(val.OtherItems, item)
}
@@ -233,7 +238,6 @@ func (ret *Dir) populate() {
continue
}
ret.ChildrenByIndex[index] = entry
- //case btrfsitem.XATTR_ITEM_KEY:
default:
panic(fmt.Errorf("TODO: handle item type %v", item.Key.ItemType))
}
diff --git a/lib/btrfsprogs/btrfsinspect/mount.go b/lib/btrfsprogs/btrfsinspect/mount.go
index 05f3b9b..dbab7c7 100644
--- a/lib/btrfsprogs/btrfsinspect/mount.go
+++ b/lib/btrfsprogs/btrfsinspect/mount.go
@@ -411,9 +411,64 @@ func (sv *subvolume) ReadSymlink(_ context.Context, op *fuseops.ReadSymlinkOp) e
return nil
}
-func (sv *subvolume) GetXattr(_ context.Context, op *fuseops.GetXattrOp) error { return syscall.ENOSYS }
func (sv *subvolume) ListXattr(_ context.Context, op *fuseops.ListXattrOp) error {
- return syscall.ENOSYS
+ if op.Inode == fuseops.RootInodeID {
+ inode, err := sv.GetRootInode()
+ if err != nil {
+ return err
+ }
+ op.Inode = fuseops.InodeID(inode)
+ }
+
+ fullInode, err := sv.LoadFullInode(btrfs.ObjID(op.Inode))
+ if err != nil {
+ return err
+ }
+
+ size := 0
+ for name := range fullInode.XAttrs {
+ size += len(name) + 1
+ }
+ if len(op.Dst) < size {
+ return syscall.ERANGE
+ }
+
+ op.BytesRead = size
+ n := 0
+ for _, name := range maps.SortedKeys(fullInode.XAttrs) {
+ n += copy(op.Dst[n:], name)
+ op.Dst[n] = 0
+ n++
+ }
+ return nil
+}
+
+func (sv *subvolume) GetXattr(_ context.Context, op *fuseops.GetXattrOp) error {
+ if op.Inode == fuseops.RootInodeID {
+ inode, err := sv.GetRootInode()
+ if err != nil {
+ return err
+ }
+ op.Inode = fuseops.InodeID(inode)
+ }
+
+ fullInode, err := sv.LoadFullInode(btrfs.ObjID(op.Inode))
+ if err != nil {
+ return err
+ }
+
+ val, ok := fullInode.XAttrs[op.Name]
+ if !ok {
+ return syscall.ENODATA
+ }
+
+ if len(op.Dst) < len(val) {
+ return syscall.ERANGE
+ }
+
+ op.BytesRead = len(val)
+ copy(op.Dst, val)
+ return nil
}
func (sv *subvolume) Destroy() {}