summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/btrfs-dbg/main.go5
-rw-r--r--cmd/btrfs-dbg/types.go38
-rw-r--r--pkg/binstruct/binstruct_test.go15
-rw-r--r--pkg/binstruct/l1.go49
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,