mirror of
https://github.com/dennwc/btrfs
synced 2025-01-23 07:43:54 +00:00
251 lines
5.8 KiB
Go
251 lines
5.8 KiB
Go
package btrfs
|
|
|
|
import (
|
|
"time"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
_BTRFS_BLOCK_GROUP_TYPE_MASK = (blockGroupData |
|
|
blockGroupSystem |
|
|
blockGroupMetadata)
|
|
_BTRFS_BLOCK_GROUP_PROFILE_MASK = (blockGroupRaid0 |
|
|
blockGroupRaid1 |
|
|
blockGroupRaid5 |
|
|
blockGroupRaid6 |
|
|
blockGroupDup |
|
|
blockGroupRaid10)
|
|
_BTRFS_BLOCK_GROUP_MASK = _BTRFS_BLOCK_GROUP_TYPE_MASK | _BTRFS_BLOCK_GROUP_PROFILE_MASK
|
|
)
|
|
|
|
type rootRef struct {
|
|
DirID objectID
|
|
Sequence uint64
|
|
Name string
|
|
}
|
|
|
|
func (rootRef) btrfsSize() int { return 18 }
|
|
|
|
func asUint64(p []byte) uint64 {
|
|
return *(*uint64)(unsafe.Pointer(&p[0]))
|
|
}
|
|
|
|
func asUint32(p []byte) uint32 {
|
|
return *(*uint32)(unsafe.Pointer(&p[0]))
|
|
}
|
|
|
|
func asUint16(p []byte) uint16 {
|
|
return *(*uint16)(unsafe.Pointer(&p[0]))
|
|
}
|
|
|
|
func asRootRef(p []byte) rootRef {
|
|
const sz = 18
|
|
// assuming that it is highly unsafe to have sizeof(struct) > len(data)
|
|
// (*btrfs_root_ref)(unsafe.Pointer(&p[0])) and sizeof(btrfs_root_ref) == 24
|
|
ref := rootRef{
|
|
DirID: objectID(asUint64(p[0:])),
|
|
Sequence: asUint64(p[8:]),
|
|
}
|
|
if n := asUint16(p[16:]); n > 0 {
|
|
ref.Name = string(p[sz : sz+n : sz+n])
|
|
}
|
|
return ref
|
|
}
|
|
|
|
// btrfs_disk_key_raw is a raw bytes for btrfs_disk_key structure
|
|
type btrfs_disk_key_raw [17]byte
|
|
|
|
func (p btrfs_disk_key_raw) Decode() diskKey {
|
|
return diskKey{
|
|
ObjectID: asUint64(p[0:]),
|
|
Type: p[8],
|
|
Offset: asUint64(p[9:]),
|
|
}
|
|
}
|
|
|
|
type diskKey struct {
|
|
ObjectID uint64
|
|
Type byte
|
|
Offset uint64
|
|
}
|
|
|
|
// btrfs_timespec_raw is a raw bytes for btrfs_timespec structure.
|
|
type btrfs_timespec_raw [12]byte
|
|
|
|
func (t btrfs_timespec_raw) Decode() time.Time {
|
|
sec, nsec := asUint64(t[0:]), asUint32(t[8:])
|
|
return time.Unix(int64(sec), int64(nsec))
|
|
}
|
|
|
|
// timeBlock is a raw set of bytes for 4 time fields.
|
|
// It is used to keep correct alignment when accessing structures from btrfs.
|
|
type timeBlock [4]btrfs_timespec_raw
|
|
|
|
type btrfs_inode_item_raw struct {
|
|
generation uint64
|
|
transid uint64
|
|
size uint64
|
|
nbytes uint64
|
|
block_group uint64
|
|
nlink uint32
|
|
uid uint32
|
|
gid uint32
|
|
mode uint32
|
|
rdev uint64
|
|
flags uint64
|
|
sequence uint64
|
|
_ [4]uint64 // reserved
|
|
// atime btrfs_timespec
|
|
// ctime btrfs_timespec
|
|
// mtime btrfs_timespec
|
|
// otime btrfs_timespec
|
|
times timeBlock
|
|
}
|
|
|
|
func (v btrfs_inode_item_raw) Decode() inodeItem {
|
|
return inodeItem{
|
|
Gen: v.generation,
|
|
TransID: v.transid,
|
|
Size: v.size,
|
|
NBytes: v.nbytes,
|
|
BlockGroup: v.block_group,
|
|
NLink: v.nlink,
|
|
UID: v.uid,
|
|
GID: v.gid,
|
|
Mode: v.mode,
|
|
RDev: v.rdev,
|
|
Flags: v.flags,
|
|
Sequence: v.sequence,
|
|
ATime: v.times[0].Decode(),
|
|
CTime: v.times[1].Decode(),
|
|
MTime: v.times[2].Decode(),
|
|
OTime: v.times[3].Decode(),
|
|
}
|
|
}
|
|
|
|
type inodeItem struct {
|
|
Gen uint64 // nfs style generation number
|
|
TransID uint64 // transid that last touched this inode
|
|
Size uint64
|
|
NBytes uint64
|
|
BlockGroup uint64
|
|
NLink uint32
|
|
UID uint32
|
|
GID uint32
|
|
Mode uint32
|
|
RDev uint64
|
|
Flags uint64
|
|
Sequence uint64 // modification sequence number for NFS
|
|
ATime time.Time
|
|
CTime time.Time
|
|
MTime time.Time
|
|
OTime time.Time
|
|
}
|
|
|
|
func asRootItem(p []byte) *btrfs_root_item_raw {
|
|
return (*btrfs_root_item_raw)(unsafe.Pointer(&p[0]))
|
|
}
|
|
|
|
type btrfs_root_item_raw [439]byte
|
|
|
|
func (p btrfs_root_item_raw) Decode() rootItem {
|
|
const (
|
|
off2 = unsafe.Sizeof(btrfs_root_item_raw_p1{})
|
|
off3 = off2 + 23
|
|
)
|
|
p1 := (*btrfs_root_item_raw_p1)(unsafe.Pointer(&p[0]))
|
|
p2 := p[off2 : off2+23]
|
|
p2_k := (*btrfs_disk_key_raw)(unsafe.Pointer(&p[off2+4]))
|
|
p2_b := p2[4+17:]
|
|
p3 := (*btrfs_root_item_raw_p3)(unsafe.Pointer(&p[off3]))
|
|
return rootItem{
|
|
Inode: p1.inode.Decode(),
|
|
Gen: p1.generation,
|
|
RootDirID: p1.root_dirid,
|
|
ByteNr: p1.bytenr,
|
|
ByteLimit: p1.byte_limit,
|
|
BytesUsed: p1.bytes_used,
|
|
LastSnapshot: p1.last_snapshot,
|
|
Flags: p1.flags,
|
|
// from here, Go structure become misaligned with C structure
|
|
Refs: asUint32(p2[0:]),
|
|
DropProgress: p2_k.Decode(),
|
|
DropLevel: p2_b[0],
|
|
Level: p2_b[1],
|
|
// these fields are still misaligned by 1 bytes
|
|
// TODO(dennwc): it's a copy of Gen to check structure version; hide it maybe?
|
|
GenV2: p3.generation_v2,
|
|
UUID: p3.uuid,
|
|
ParentUUID: p3.parent_uuid,
|
|
ReceivedUUID: p3.received_uuid,
|
|
CTransID: p3.ctransid,
|
|
OTransID: p3.otransid,
|
|
STransID: p3.stransid,
|
|
RTransID: p3.rtransid,
|
|
CTime: p3.times[0].Decode(),
|
|
OTime: p3.times[1].Decode(),
|
|
STime: p3.times[2].Decode(),
|
|
RTime: p3.times[3].Decode(),
|
|
}
|
|
}
|
|
|
|
type rootItem struct {
|
|
Inode inodeItem
|
|
Gen uint64
|
|
RootDirID uint64
|
|
ByteNr uint64
|
|
ByteLimit uint64
|
|
BytesUsed uint64
|
|
LastSnapshot uint64
|
|
Flags uint64
|
|
Refs uint32
|
|
DropProgress diskKey
|
|
DropLevel uint8
|
|
Level uint8
|
|
GenV2 uint64
|
|
UUID UUID
|
|
ParentUUID UUID
|
|
ReceivedUUID UUID
|
|
CTransID uint64
|
|
OTransID uint64
|
|
STransID uint64
|
|
RTransID uint64
|
|
CTime time.Time
|
|
OTime time.Time
|
|
STime time.Time
|
|
RTime time.Time
|
|
}
|
|
|
|
type btrfs_root_item_raw_p1 struct {
|
|
inode btrfs_inode_item_raw
|
|
generation uint64
|
|
root_dirid uint64
|
|
bytenr uint64
|
|
byte_limit uint64
|
|
bytes_used uint64
|
|
last_snapshot uint64
|
|
flags uint64
|
|
}
|
|
type btrfs_root_item_raw_p2 struct {
|
|
refs uint32
|
|
drop_progress btrfs_disk_key_raw
|
|
drop_level uint8
|
|
level uint8
|
|
}
|
|
type btrfs_root_item_raw_p3 struct {
|
|
generation_v2 uint64
|
|
uuid UUID
|
|
parent_uuid UUID
|
|
received_uuid UUID
|
|
ctransid uint64
|
|
otransid uint64
|
|
stransid uint64
|
|
rtransid uint64
|
|
// ctime btrfs_timespec
|
|
// otime btrfs_timespec
|
|
// stime btrfs_timespec
|
|
// rtime btrfs_timespec
|
|
times timeBlock
|
|
_ [8]uint64 // reserved
|
|
}
|