From bb73a2fb7678698353bb995754e8702caa2f6e0a Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 14 Jul 2022 04:45:48 -0600 Subject: wip ls-files --- lib/btrfs/btrfsitem/item_fileextent.go | 24 +++++++++++---------- lib/btrfs/btrfsitem/item_inode.go | 2 +- lib/btrfs/btrfsitem/item_inoderef.go | 36 +++++++++++++++++++++++++++++-- lib/btrfs/btrfsitem/items_gen.go | 4 ++-- lib/btrfs/io4_fs.go | 16 +++++++++----- lib/btrfsprogs/btrfsinspect/print_tree.go | 8 ++++--- 6 files changed, 66 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/btrfs/btrfsitem/item_fileextent.go b/lib/btrfs/btrfsitem/item_fileextent.go index a69c67a..b7e394e 100644 --- a/lib/btrfs/btrfsitem/item_fileextent.go +++ b/lib/btrfs/btrfsitem/item_fileextent.go @@ -28,20 +28,22 @@ type FileExtent struct { // EXTENT_DATA=108 binstruct.End `bin:"off=0x15"` // only one of these, depending on .Type - BodyInline []byte `bin:"-"` // .Type == FILE_EXTENT_INLINE - BodyExtent struct { // .Type == FILE_EXTENT_REG or FILE_EXTENT_PREALLOC - // Position and size of extent within the device - DiskByteNr btrfsvol.LogicalAddr `bin:"off=0x0, siz=0x8"` - DiskNumBytes btrfsvol.AddrDelta `bin:"off=0x8, siz=0x8"` + BodyInline []byte `bin:"-"` // .Type == FILE_EXTENT_INLINE + BodyExtent FileExtentExtent `bin:"-"` // .Type == FILE_EXTENT_REG or FILE_EXTENT_PREALLOC +} + +type FileExtentExtent struct { + // Position and size of extent within the device + DiskByteNr btrfsvol.LogicalAddr `bin:"off=0x0, siz=0x8"` + DiskNumBytes btrfsvol.AddrDelta `bin:"off=0x8, siz=0x8"` - // Position of data within the extent - Offset btrfsvol.AddrDelta `bin:"off=0x10, siz=0x8"` + // Position of data within the extent + Offset btrfsvol.AddrDelta `bin:"off=0x10, siz=0x8"` - // Decompressed/unencrypted size - NumBytes int64 `bin:"off=0x18, siz=0x8"` + // Decompressed/unencrypted size + NumBytes int64 `bin:"off=0x18, siz=0x8"` - binstruct.End `bin:"off=0x20"` - } `bin:"-"` + binstruct.End `bin:"off=0x20"` } func (o *FileExtent) UnmarshalBinary(dat []byte) (int, error) { diff --git a/lib/btrfs/btrfsitem/item_inode.go b/lib/btrfs/btrfsitem/item_inode.go index 27204f6..49b2031 100644 --- a/lib/btrfs/btrfsitem/item_inode.go +++ b/lib/btrfs/btrfsitem/item_inode.go @@ -14,7 +14,7 @@ type Inode struct { // INODE_ITEM=1 Generation internal.Generation `bin:"off=0x00, siz=0x08"` TransID int64 `bin:"off=0x08, siz=0x08"` Size int64 `bin:"off=0x10, siz=0x08"` // stat - NumBytes int64 `bin:"off=0x18, siz=0x08"` + NumBytes int64 `bin:"off=0x18, siz=0x08"` // allocated bytes, may be larger than size (or smaller if there are holes?) BlockGroup int64 `bin:"off=0x20, siz=0x08"` NLink int32 `bin:"off=0x28, siz=0x04"` // stat UID int32 `bin:"off=0x2C, siz=0x04"` // stat diff --git a/lib/btrfs/btrfsitem/item_inoderef.go b/lib/btrfs/btrfsitem/item_inoderef.go index b1eaf1b..083f19e 100644 --- a/lib/btrfs/btrfsitem/item_inoderef.go +++ b/lib/btrfs/btrfsitem/item_inoderef.go @@ -12,8 +12,40 @@ import ( ) // key.objectid = inode number of the file -// key.offset = inode number of the parent file -type InodeRef struct { // INODE_REF=12 +// key.offset = inode number of the parent directory +// +// Might have multiple entries if the same file has multiple hardlinks +// in the same directory. +type InodeRefs []InodeRef // INODE_REF=12 + +func (o *InodeRefs) UnmarshalBinary(dat []byte) (int, error) { + *o = nil + n := 0 + for n < len(dat) { + var ref InodeRef + _n, err := binstruct.Unmarshal(dat[n:], &ref) + n += _n + if err != nil { + return n, err + } + *o = append(*o, ref) + } + return n, nil +} + +func (o InodeRefs) MarshalBinary() ([]byte, error) { + var dat []byte + for _, ref := range o { + _dat, err := binstruct.Marshal(ref) + dat = append(dat, _dat...) + if err != nil { + return dat, err + } + } + return dat, nil +} + +type InodeRef struct { Index int64 `bin:"off=0x0, siz=0x8"` NameLen uint16 `bin:"off=0x8, siz=0x2"` // [ignored-when-writing] binstruct.End `bin:"off=0xa"` diff --git a/lib/btrfs/btrfsitem/items_gen.go b/lib/btrfs/btrfsitem/items_gen.go index 8573967..d21cd3e 100644 --- a/lib/btrfs/btrfsitem/items_gen.go +++ b/lib/btrfs/btrfsitem/items_gen.go @@ -57,7 +57,7 @@ var keytype2gotype = map[Type]reflect.Type{ FREE_SPACE_EXTENT_KEY: reflect.TypeOf(Empty{}), FREE_SPACE_INFO_KEY: reflect.TypeOf(FreeSpaceInfo{}), INODE_ITEM_KEY: reflect.TypeOf(Inode{}), - INODE_REF_KEY: reflect.TypeOf(InodeRef{}), + INODE_REF_KEY: reflect.TypeOf(InodeRefs{}), METADATA_ITEM_KEY: reflect.TypeOf(Metadata{}), ORPHAN_ITEM_KEY: reflect.TypeOf(Empty{}), PERSISTENT_ITEM_KEY: reflect.TypeOf(DevStats{}), @@ -91,7 +91,7 @@ func (FreeSpaceBitmap) isItem() {} func (FreeSpaceHeader) isItem() {} func (FreeSpaceInfo) isItem() {} func (Inode) isItem() {} -func (InodeRef) isItem() {} +func (InodeRefs) isItem() {} func (Metadata) isItem() {} func (Root) isItem() {} func (RootRef) isItem() {} diff --git a/lib/btrfs/io4_fs.go b/lib/btrfs/io4_fs.go index ad489c7..0ef922b 100644 --- a/lib/btrfs/io4_fs.go +++ b/lib/btrfs/io4_fs.go @@ -191,9 +191,15 @@ func (ret *Dir) populate() { for _, item := range ret.OtherItems { switch item.Key.ItemType { case btrfsitem.INODE_REF_KEY: + body := item.Body.(btrfsitem.InodeRefs) + if len(body) != 1 { + ret.Errs = append(ret.Errs, fmt.Errorf("INODE_REF item with %d entries on a directory", + len(body))) + continue + } ref := InodeRef{ Inode: ObjID(item.Key.Offset), - InodeRef: item.Body.(btrfsitem.InodeRef), + InodeRef: body[0], } if ret.DotDot != nil { if !reflect.DeepEqual(ref, *ret.DotDot) { @@ -336,13 +342,13 @@ func (ret *File) populate() { } pos += size } - if ret.InodeItem != nil && pos != ret.InodeItem.Size { - if ret.InodeItem.Size > pos { + if ret.InodeItem != nil && pos != ret.InodeItem.NumBytes { + if ret.InodeItem.NumBytes > pos { ret.Errs = append(ret.Errs, fmt.Errorf("extent gap from %v to %v", - pos, ret.InodeItem.Size)) + pos, ret.InodeItem.NumBytes)) } else { ret.Errs = append(ret.Errs, fmt.Errorf("extent mapped past end of file from %v to %v", - ret.InodeItem.Size, pos)) + ret.InodeItem.NumBytes, pos)) } } } diff --git a/lib/btrfsprogs/btrfsinspect/print_tree.go b/lib/btrfsprogs/btrfsinspect/print_tree.go index ff53953..d7eb6f3 100644 --- a/lib/btrfsprogs/btrfsinspect/print_tree.go +++ b/lib/btrfsprogs/btrfsinspect/print_tree.go @@ -135,9 +135,11 @@ func printTree(ctx context.Context, out io.Writer, fs *btrfs.FS, treeID btrfs.Ob fmt.Fprintf(out, "\t\tctime %v\n", fmtTime(body.CTime)) fmt.Fprintf(out, "\t\tmtime %v\n", fmtTime(body.MTime)) fmt.Fprintf(out, "\t\totime %v\n", fmtTime(body.OTime)) - case btrfsitem.InodeRef: - fmt.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", - body.Index, body.NameLen, body.Name) + case btrfsitem.InodeRefs: + for _, ref := range body { + fmt.Fprintf(out, "\t\tindex %v namelen %v name: %s\n", + ref.Index, ref.NameLen, ref.Name) + } //case btrfsitem.INODE_EXTREF_KEY: // // TODO case btrfsitem.DirEntry: -- cgit v1.2.3-2-g168b