github.com/dennwc/btrfs@v0.0.0-20221026161108-3097362dc072/btrfs_tree.go (about)

     1  package btrfs
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  	"unsafe"
     7  )
     8  
     9  const (
    10  	_BTRFS_BLOCK_GROUP_TYPE_MASK = (blockGroupData |
    11  		blockGroupSystem |
    12  		blockGroupMetadata)
    13  	_BTRFS_BLOCK_GROUP_PROFILE_MASK = (blockGroupRaid0 |
    14  		blockGroupRaid1 |
    15  		blockGroupRaid5 |
    16  		blockGroupRaid6 |
    17  		blockGroupDup |
    18  		blockGroupRaid10)
    19  	_BTRFS_BLOCK_GROUP_MASK = _BTRFS_BLOCK_GROUP_TYPE_MASK | _BTRFS_BLOCK_GROUP_PROFILE_MASK
    20  )
    21  
    22  type rootRef struct {
    23  	DirID    objectID
    24  	Sequence uint64
    25  	Name     string
    26  }
    27  
    28  func (rootRef) btrfsSize() int { return 18 }
    29  
    30  func asUint64(p []byte) uint64 {
    31  	return *(*uint64)(unsafe.Pointer(&p[0]))
    32  }
    33  
    34  func asUint32(p []byte) uint32 {
    35  	return *(*uint32)(unsafe.Pointer(&p[0]))
    36  }
    37  
    38  func asUint16(p []byte) uint16 {
    39  	return *(*uint16)(unsafe.Pointer(&p[0]))
    40  }
    41  
    42  func asRootRef(p []byte) rootRef {
    43  	const sz = 18
    44  	// assuming that it is highly unsafe to have sizeof(struct) > len(data)
    45  	// (*btrfs_root_ref)(unsafe.Pointer(&p[0])) and sizeof(btrfs_root_ref) == 24
    46  	ref := rootRef{
    47  		DirID:    objectID(asUint64(p[0:])),
    48  		Sequence: asUint64(p[8:]),
    49  	}
    50  	if n := asUint16(p[16:]); n > 0 {
    51  		ref.Name = string(p[sz : sz+n : sz+n])
    52  	}
    53  	return ref
    54  }
    55  
    56  var treeKeyNames = map[treeKeyType]string{
    57  	inodeItemKey:          "inodeItem",
    58  	inodeRefKey:           "inodeRef",
    59  	inodeExtrefKey:        "inodeExtref",
    60  	xattrItemKey:          "xattrItemKey",
    61  	orphanItemKey:         "orphanItem",
    62  	dirLogItemKey:         "dirLogItem",
    63  	dirLogIndexKey:        "dirLogIndex",
    64  	dirItemKey:            "dirItem",
    65  	dirIndexKey:           "dirIndex",
    66  	extentDataKey:         "extentData",
    67  	extentCsumKey:         "extentCsum",
    68  	rootItemKey:           "rootItem",
    69  	rootBackrefKey:        "rootBackref",
    70  	rootRefKey:            "rootRef",
    71  	extentItemKey:         "extentItem",
    72  	metadataItemKey:       "metadataItem",
    73  	treeBlockRefKey:       "treeBlockRef",
    74  	extentDataRefKey:      "extentDataRef",
    75  	extentRefV0Key:        "extentRefV0",
    76  	sharedBlockRefKey:     "sharedBlockRef",
    77  	sharedDataRefKey:      "sharedDataRef",
    78  	blockGroupItemKey:     "blockGroupItem",
    79  	freeSpaceInfoKey:      "freeSpaceInfo",
    80  	freeSpaceExtentKey:    "freeSpaceExtent",
    81  	freeSpaceBitmapKey:    "freeSpaceBitmap",
    82  	devExtentKey:          "devExtent",
    83  	devItemKey:            "devItem",
    84  	chunkItemKey:          "chunkItem",
    85  	qgroupStatusKey:       "qgroupStatus",
    86  	qgroupInfoKey:         "qgroupInfo",
    87  	qgroupLimitKey:        "qgroupLimit",
    88  	qgroupRelationKey:     "qgroupRelation",
    89  	temporaryItemKey:      "temporaryItem",
    90  	persistentItemKey:     "persistentItem",
    91  	devReplaceKey:         "devReplace",
    92  	uuidKeySubvol:         "uuidKeySubvol",
    93  	uuidKeyReceivedSubvol: "uuidKeyReceivedSubvol",
    94  	stringItemKey:         "stringItem",
    95  }
    96  
    97  func (t treeKeyType) String() string {
    98  	if name, ok := treeKeyNames[t]; ok {
    99  		return name
   100  	}
   101  	return fmt.Sprintf("%#x", int(t))
   102  }
   103  
   104  // btrfs_disk_key_raw is a raw bytes for btrfs_disk_key structure
   105  type btrfs_disk_key_raw [17]byte
   106  
   107  func (p btrfs_disk_key_raw) Decode() diskKey {
   108  	return diskKey{
   109  		ObjectID: asUint64(p[0:]),
   110  		Type:     p[8],
   111  		Offset:   asUint64(p[9:]),
   112  	}
   113  }
   114  
   115  type diskKey struct {
   116  	ObjectID uint64
   117  	Type     byte
   118  	Offset   uint64
   119  }
   120  
   121  // btrfs_timespec_raw is a raw bytes for btrfs_timespec structure.
   122  type btrfs_timespec_raw [12]byte
   123  
   124  func (t btrfs_timespec_raw) Decode() time.Time {
   125  	sec, nsec := asUint64(t[0:]), asUint32(t[8:])
   126  	return time.Unix(int64(sec), int64(nsec))
   127  }
   128  
   129  // timeBlock is a raw set of bytes for 4 time fields.
   130  // It is used to keep correct alignment when accessing structures from btrfs.
   131  type timeBlock [4]btrfs_timespec_raw
   132  
   133  type btrfs_inode_item_raw struct {
   134  	generation  uint64
   135  	transid     uint64
   136  	size        uint64
   137  	nbytes      uint64
   138  	block_group uint64
   139  	nlink       uint32
   140  	uid         uint32
   141  	gid         uint32
   142  	mode        uint32
   143  	rdev        uint64
   144  	flags       uint64
   145  	sequence    uint64
   146  	_           [4]uint64 // reserved
   147  	// 	atime btrfs_timespec
   148  	// 	ctime btrfs_timespec
   149  	// 	mtime btrfs_timespec
   150  	// 	otime btrfs_timespec
   151  	times timeBlock
   152  }
   153  
   154  func (v btrfs_inode_item_raw) Decode() inodeItem {
   155  	return inodeItem{
   156  		Gen:        v.generation,
   157  		TransID:    v.transid,
   158  		Size:       v.size,
   159  		NBytes:     v.nbytes,
   160  		BlockGroup: v.block_group,
   161  		NLink:      v.nlink,
   162  		UID:        v.uid,
   163  		GID:        v.gid,
   164  		Mode:       v.mode,
   165  		RDev:       v.rdev,
   166  		Flags:      v.flags,
   167  		Sequence:   v.sequence,
   168  		ATime:      v.times[0].Decode(),
   169  		CTime:      v.times[1].Decode(),
   170  		MTime:      v.times[2].Decode(),
   171  		OTime:      v.times[3].Decode(),
   172  	}
   173  }
   174  
   175  type inodeItem struct {
   176  	Gen        uint64 // nfs style generation number
   177  	TransID    uint64 // transid that last touched this inode
   178  	Size       uint64
   179  	NBytes     uint64
   180  	BlockGroup uint64
   181  	NLink      uint32
   182  	UID        uint32
   183  	GID        uint32
   184  	Mode       uint32
   185  	RDev       uint64
   186  	Flags      uint64
   187  	Sequence   uint64 // modification sequence number for NFS
   188  	ATime      time.Time
   189  	CTime      time.Time
   190  	MTime      time.Time
   191  	OTime      time.Time
   192  }
   193  
   194  func asRootItem(p []byte) *btrfs_root_item_raw {
   195  	return (*btrfs_root_item_raw)(unsafe.Pointer(&p[0]))
   196  }
   197  
   198  type btrfs_root_item_raw [439]byte
   199  
   200  func (p btrfs_root_item_raw) Decode() rootItem {
   201  	const (
   202  		off2 = unsafe.Sizeof(btrfs_root_item_raw_p1{})
   203  		off3 = off2 + 23
   204  	)
   205  	p1 := (*btrfs_root_item_raw_p1)(unsafe.Pointer(&p[0]))
   206  	p2 := p[off2 : off2+23]
   207  	p2_k := (*btrfs_disk_key_raw)(unsafe.Pointer(&p[off2+4]))
   208  	p2_b := p2[4+17:]
   209  	p3 := (*btrfs_root_item_raw_p3)(unsafe.Pointer(&p[off3]))
   210  	return rootItem{
   211  		Inode:        p1.inode.Decode(),
   212  		Gen:          p1.generation,
   213  		RootDirID:    p1.root_dirid,
   214  		ByteNr:       p1.bytenr,
   215  		ByteLimit:    p1.byte_limit,
   216  		BytesUsed:    p1.bytes_used,
   217  		LastSnapshot: p1.last_snapshot,
   218  		Flags:        p1.flags,
   219  		// from here, Go structure become misaligned with C structure
   220  		Refs:         asUint32(p2[0:]),
   221  		DropProgress: p2_k.Decode(),
   222  		DropLevel:    p2_b[0],
   223  		Level:        p2_b[1],
   224  		// these fields are still misaligned by 1 bytes
   225  		// TODO(dennwc): it's a copy of Gen to check structure version; hide it maybe?
   226  		GenV2:        p3.generation_v2,
   227  		UUID:         p3.uuid,
   228  		ParentUUID:   p3.parent_uuid,
   229  		ReceivedUUID: p3.received_uuid,
   230  		CTransID:     p3.ctransid,
   231  		OTransID:     p3.otransid,
   232  		STransID:     p3.stransid,
   233  		RTransID:     p3.rtransid,
   234  		CTime:        p3.times[0].Decode(),
   235  		OTime:        p3.times[1].Decode(),
   236  		STime:        p3.times[2].Decode(),
   237  		RTime:        p3.times[3].Decode(),
   238  	}
   239  }
   240  
   241  type rootItem struct {
   242  	Inode        inodeItem
   243  	Gen          uint64
   244  	RootDirID    uint64
   245  	ByteNr       uint64
   246  	ByteLimit    uint64
   247  	BytesUsed    uint64
   248  	LastSnapshot uint64
   249  	Flags        uint64
   250  	Refs         uint32
   251  	DropProgress diskKey
   252  	DropLevel    uint8
   253  	Level        uint8
   254  	GenV2        uint64
   255  	UUID         UUID
   256  	ParentUUID   UUID
   257  	ReceivedUUID UUID
   258  	CTransID     uint64
   259  	OTransID     uint64
   260  	STransID     uint64
   261  	RTransID     uint64
   262  	CTime        time.Time
   263  	OTime        time.Time
   264  	STime        time.Time
   265  	RTime        time.Time
   266  }
   267  
   268  type btrfs_root_item_raw_p1 struct {
   269  	inode         btrfs_inode_item_raw
   270  	generation    uint64
   271  	root_dirid    uint64
   272  	bytenr        uint64
   273  	byte_limit    uint64
   274  	bytes_used    uint64
   275  	last_snapshot uint64
   276  	flags         uint64
   277  }
   278  type btrfs_root_item_raw_p2 struct {
   279  	refs          uint32
   280  	drop_progress btrfs_disk_key_raw
   281  	drop_level    uint8
   282  	level         uint8
   283  }
   284  type btrfs_root_item_raw_p3 struct {
   285  	generation_v2 uint64
   286  	uuid          UUID
   287  	parent_uuid   UUID
   288  	received_uuid UUID
   289  	ctransid      uint64
   290  	otransid      uint64
   291  	stransid      uint64
   292  	rtransid      uint64
   293  	// ctime btrfs_timespec
   294  	// otime btrfs_timespec
   295  	// stime btrfs_timespec
   296  	// rtime btrfs_timespec
   297  	times timeBlock
   298  	_     [8]uint64 // reserved
   299  }