diff options
-rw-r--r-- | cmd/btrfs-dbg/main.go | 5 | ||||
-rw-r--r-- | cmd/btrfs-dbg/types.go | 38 | ||||
-rw-r--r-- | pkg/binstruct/binstruct_test.go | 15 | ||||
-rw-r--r-- | pkg/binstruct/l1.go | 49 |
4 files changed, 94 insertions, 13 deletions
diff --git a/cmd/btrfs-dbg/main.go b/cmd/btrfs-dbg/main.go index d6c9c68..0990378 100644 --- a/cmd/btrfs-dbg/main.go +++ b/cmd/btrfs-dbg/main.go @@ -43,6 +43,11 @@ func Main(imgfilename string) (err error) { spew.DisablePointerAddresses = true spew.Dump(superblocks[0].data) + sum, err := superblocks[0].data.CalculateChecksum() + if err != nil { + return err + } + fmt.Printf("calculated sum: %x\n", sum) return nil } diff --git a/cmd/btrfs-dbg/types.go b/cmd/btrfs-dbg/types.go index 699f1a2..3cd348d 100644 --- a/cmd/btrfs-dbg/types.go +++ b/cmd/btrfs-dbg/types.go @@ -1,8 +1,11 @@ package main import ( + "encoding/binary" "encoding/hex" + "hash/crc32" "strings" + "time" "lukeshu.com/btrfs-tools/pkg/binstruct" ) @@ -11,6 +14,7 @@ type ( PhysicalAddr int64 LogicalAddr int64 ObjID int64 + CSum [0x20]byte UUID [16]byte ) @@ -25,8 +29,32 @@ func (uuid UUID) String() string { }, "-") } +func crc32c(data []byte) CSum { + sum := crc32.Update(0xFFFFFFFF, crc32.MakeTable(0x1EDC6F41), data) + var buf CSum + binary.LittleEndian.PutUint32(buf[:], sum) + return buf +} + +type Key struct { + ObjectID ObjID `bin:"off=0, siz=8, desc=Object ID. Each tree has its own set of Object IDs."` + ItemType uint8 `bin:"off=8, siz=1, desc=Item type."` + Offset uint64 `bin:"off=9, siz=8, desc=Offset. The meaning depends on the item type."` + binstruct.End `bin:"off=11"` +} + +type Time struct { + Sec int64 `bin:"off=0, siz=8, desc=Number of seconds since 1970-01-01T00:00:00Z."` + NSec uint64 `bin:"off=8, siz=4, desc=Number of nanoseconds since the beginning of the second."` + binstruct.End `bin:"off=c"` +} + +func (t Time) ToStd() time.Time { + return time.Unix(t.Sec, int64(t.NSec)) +} + type Superblock struct { - Checksum [0x20]byte `bin:"off=0, siz=20, desc=Checksum of everything past this field (from 20 to 1000)"` + Checksum CSum `bin:"off=0, siz=20, desc=Checksum of everything past this field (from 20 to 1000)"` FSUUID UUID `bin:"off=20, siz=10, desc=FS UUID"` Self PhysicalAddr `bin:"off=30, siz=8, desc=physical address of this block (different for mirrors)"` Flags uint64 `bin:"off=38, siz=8, desc=flags"` @@ -74,6 +102,14 @@ type Superblock struct { binstruct.End `bin:"off=1000"` } +func (sb Superblock) CalculateChecksum() (CSum, error) { + data, err := binstruct.Marshal(sb) + if err != nil { + return CSum{}, err + } + return crc32c(data[0x20:]), nil +} + type DevItem struct { DeviceID uint64 `bin:"off=0, siz=8, desc=device id"` diff --git a/pkg/binstruct/binstruct_test.go b/pkg/binstruct/binstruct_test.go index 33a2f0a..fc7eab4 100644 --- a/pkg/binstruct/binstruct_test.go +++ b/pkg/binstruct/binstruct_test.go @@ -10,6 +10,7 @@ import ( func TestSmoke(t *testing.T) { type UUID [16]byte + type PhysicalAddr int64 type DevItem struct { DeviceID uint64 `bin:"off=0, siz=8, desc=device id"` @@ -33,17 +34,23 @@ func TestSmoke(t *testing.T) { binstruct.End `bin:"off=62"` } type TestType struct { - Magic [5]byte `bin:"off=0,siz=5"` - Dev DevItem `bin:"off=5,siz=62"` + Magic [5]byte `bin:"off=0,siz=5"` + Dev DevItem `bin:"off=5,siz=62"` + Addr PhysicalAddr `bin:"off=67, siz=8"` - binstruct.End `bin:"off=67"` + binstruct.End `bin:"off=6F"` } input := TestType{} copy(input.Magic[:], "mAgIc") input.Dev.DeviceID = 12 + input.Addr = 0xBEEF bs, err := binstruct.Marshal(input) assert.NoError(t, err) - assert.True(t, len(bs) == 0x67, "len(bs)=0x%x", len(bs)) + assert.True(t, len(bs) == 0x6F, "len(bs)=0x%x", len(bs)) + + var output TestType + assert.NoError(t, binstruct.Unmarshal(bs, &output)) + assert.Equal(t, input, output) } diff --git a/pkg/binstruct/l1.go b/pkg/binstruct/l1.go index e76e7d0..d90ecba 100644 --- a/pkg/binstruct/l1.go +++ b/pkg/binstruct/l1.go @@ -6,12 +6,35 @@ import ( "reflect" ) +type Marshaler interface { + MarshalBinary() []byte + UnmarshalBinary([]byte) + BinarySize() int64 +} + type handler interface { Unmarshal(dat []byte) interface{} Marshal(val interface{}) []byte Size() int64 } +type extHandler struct { + typ reflect.Type +} + +func (_ extHandler) Marshal(val interface{}) []byte { + return val.(Marshaler).MarshalBinary() +} +func (e extHandler) Unmarshal(dat []byte) interface{} { + val := reflect.New(e.typ).Elem().Interface().(Marshaler) + val.UnmarshalBinary(dat) + return val +} +func (e extHandler) Size() int64 { + val := reflect.New(e.typ).Elem().Interface().(Marshaler) + return val.BinarySize() +} + type primitive struct { unmarshal func(dat []byte) interface{} marshal func(val interface{}) []byte @@ -24,7 +47,17 @@ func (p primitive) Size() int64 { return p.size } var _ handler = primitive{} +func convert[T any](in interface{}) T { + var dstTyp T + return reflect.ValueOf(in).Convert(reflect.TypeOf(dstTyp)).Interface().(T) +} + func genHandler(typ reflect.Type) (handler, error) { + if _, ok := reflect.New(typ).Elem().Interface().(Marshaler); ok { + return extHandler{ + typ: typ, + }, nil + } switch typ.Kind() { case reflect.Invalid: // invalid return nil, fmt.Errorf("unsupported kind: %s: %v", typ.Kind(), typ) @@ -41,7 +74,7 @@ func genHandler(typ reflect.Type) (handler, error) { case reflect.Uint8: return primitive{ unmarshal: func(dat []byte) interface{} { return dat[0] }, - marshal: func(val interface{}) []byte { return []byte{val.(uint8)} }, + marshal: func(val interface{}) []byte { return []byte{convert[uint8](val)} }, size: 1, }, nil case reflect.Uint16: @@ -49,7 +82,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return binary.LittleEndian.Uint16(dat) }, marshal: func(val interface{}) []byte { var buf [2]byte - binary.LittleEndian.PutUint16(buf[:], val.(uint16)) + binary.LittleEndian.PutUint16(buf[:], convert[uint16](val)) return buf[:] }, size: 2, @@ -59,7 +92,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return binary.LittleEndian.Uint32(dat) }, marshal: func(val interface{}) []byte { var buf [4]byte - binary.LittleEndian.PutUint32(buf[:], val.(uint32)) + binary.LittleEndian.PutUint32(buf[:], convert[uint32](val)) return buf[:] }, size: 4, @@ -69,7 +102,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return binary.LittleEndian.Uint64(dat) }, marshal: func(val interface{}) []byte { var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], val.(uint64)) + binary.LittleEndian.PutUint64(buf[:], convert[uint64](val)) return buf[:] }, size: 8, @@ -79,7 +112,7 @@ func genHandler(typ reflect.Type) (handler, error) { case reflect.Int8: return primitive{ unmarshal: func(dat []byte) interface{} { return int8(dat[0]) }, - marshal: func(val interface{}) []byte { return []byte{uint8(val.(int8))} }, + marshal: func(val interface{}) []byte { return []byte{uint8(convert[int8](val))}}, size: 1, }, nil case reflect.Int16: @@ -87,7 +120,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return int16(binary.LittleEndian.Uint16(dat)) }, marshal: func(val interface{}) []byte { var buf [2]byte - binary.LittleEndian.PutUint16(buf[:], uint16(val.(int16))) + binary.LittleEndian.PutUint16(buf[:], uint16(convert[int16](val))) return buf[:] }, size: 2, @@ -97,7 +130,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return int32(binary.LittleEndian.Uint32(dat)) }, marshal: func(val interface{}) []byte { var buf [4]byte - binary.LittleEndian.PutUint32(buf[:], uint32(val.(int32))) + binary.LittleEndian.PutUint32(buf[:], uint32(convert[int32](val))) return buf[:] }, size: 4, @@ -107,7 +140,7 @@ func genHandler(typ reflect.Type) (handler, error) { unmarshal: func(dat []byte) interface{} { return int64(binary.LittleEndian.Uint64(dat)) }, marshal: func(val interface{}) []byte { var buf [8]byte - binary.LittleEndian.PutUint64(buf[:], uint64(val.(int64))) + binary.LittleEndian.PutUint64(buf[:], uint64(convert[int64](val))) return buf[:] }, size: 8, |