diff options
-rw-r--r-- | lib/btrfs/io4_fs.go | 6 | ||||
-rw-r--r-- | lib/btrfsprogs/btrfsinspect/mount.go | 59 |
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() {} |