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 }