package btrfsitem import ( "fmt" "lukeshu.com/btrfs-tools/pkg/binstruct" "lukeshu.com/btrfs-tools/pkg/btrfs/internal" ) type FileExtent struct { // EXTENT_DATA=108 Generation internal.Generation `bin:"off=0x0, siz=0x8"` // transaction ID that created this extent RAMBytes int64 `bin:"off=0x8, siz=0x8"` // upper bound of what compressed data will decompress to // 32 bits describing the data encoding Compression CompressionType `bin:"off=0x10, siz=0x1"` Encryption uint8 `bin:"off=0x11, siz=0x1"` OtherEncoding uint16 `bin:"off=0x12, siz=0x2"` // reserved for later use Type FileExtentType `bin:"off=0x14, siz=0x1"` // inline data or real extent binstruct.End `bin:"off=0x15"` // only one of these, depending on .Type BodyInline []byte `bin:"-"` BodyReg struct { // Position within the device DiskByteNr int64 `bin:"off=0x0, siz=0x8"` DiskNumBytes int64 `bin:"off=0x8, siz=0x8"` // Position within the file Offset int64 `bin:"off=0x10, siz=0x8"` NumBytes int64 `bin:"off=0x18, siz=0x8"` binstruct.End `bin:"off=0x20"` } `bin:"-"` BodyPrealloc struct { // Position within the device DiskByteNr int64 `bin:"off=0x0, siz=0x8"` DiskNumBytes int64 `bin:"off=0x8, siz=0x8"` // Position within the file Offset int64 `bin:"off=0x10, siz=0x8"` NumBytes int64 `bin:"off=0x18, siz=0x8"` binstruct.End `bin:"off=0x20"` } `bin:"-"` } func (o *FileExtent) UnmarshalBinary(dat []byte) (int, error) { n, err := binstruct.UnmarshalWithoutInterface(dat, o) if err != nil { return n, err } switch o.Type { case FILE_EXTENT_INLINE: o.BodyInline = dat[n:] n += len(o.BodyInline) case FILE_EXTENT_REG: _n, err := binstruct.Unmarshal(dat[n:], &o.BodyReg) n += _n if err != nil { return n, err } case FILE_EXTENT_PREALLOC: _n, err := binstruct.Unmarshal(dat[n:], &o.BodyPrealloc) n += _n if err != nil { return n, err } default: return n, fmt.Errorf("unknown file extent type %v", o.Type) } return n, nil } func (o FileExtent) MarshalBinary() ([]byte, error) { dat, err := binstruct.MarshalWithoutInterface(o) if err != nil { return dat, err } switch o.Type { case FILE_EXTENT_INLINE: dat = append(dat, o.BodyInline...) case FILE_EXTENT_REG: bs, err := binstruct.Marshal(o.BodyReg) dat = append(dat, bs...) if err != nil { return dat, err } case FILE_EXTENT_PREALLOC: bs, err := binstruct.Marshal(o.BodyPrealloc) dat = append(dat, bs...) if err != nil { return dat, err } default: return dat, fmt.Errorf("unknown file extent type %v", o.Type) } return dat, nil } type FileExtentType uint8 const ( FILE_EXTENT_INLINE = FileExtentType(iota) FILE_EXTENT_REG FILE_EXTENT_PREALLOC ) func (fet FileExtentType) String() string { names := map[FileExtentType]string{ FILE_EXTENT_INLINE: "inline", FILE_EXTENT_REG: "regular", FILE_EXTENT_PREALLOC: "prealloc", } name, ok := names[fet] if !ok { name = "unknown" } return fmt.Sprintf("%d (%s)", fet, name) } type CompressionType uint8 const ( COMPRESS_NONE = CompressionType(iota) COMPRESS_ZLIB COMPRESS_LZO COMPRESS_ZSTD ) func (ct CompressionType) String() string { names := map[CompressionType]string{ COMPRESS_NONE: "none", COMPRESS_ZLIB: "zlib", COMPRESS_LZO: "lzo", COMPRESS_ZSTD: "zstd", } name, ok := names[ct] if !ok { name = "unknown" } return fmt.Sprintf("%d (%s)", ct, name) }