11 * Functions to scan through the extents overflow file, grabbing
12 * overflow extents for the special files.
16 * Given an extent record, return the logical block address (in the volume)
17 * for the requested block offset into the file. It returns 0 if it can't
21 FindBlock(HFSPlusExtentRecord
*erp
, unsigned int blockNum
)
24 unsigned int base
= 0;
25 HFSPlusExtentDescriptor
*ep
= &(*erp
)[0];
28 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
29 if (ep
->startBlock
== 0 || ep
->blockCount
== 0)
31 if ((base
+ S32(ep
->blockCount
)) > blockNum
) {
32 lba
= S32(ep
->startBlock
) + (blockNum
- base
);
35 base
+= S32(ep
->blockCount
);
42 * Get the given node from the extents-overflow file. Returns -1 on error, and
46 GetNode(DeviceInfo_t
*devp
, HFSPlusVolumeHeader
*hp
, int nodeNum
, int blocksPerNode
, void *nodePtr
)
49 unsigned char *ptr
, *endPtr
;
51 HFSPlusExtentRecord
*erp
= &hp
->extentsFile
.extents
;
54 endPtr
= ptr
+ (blocksPerNode
* S32(hp
->blockSize
));
55 offset
= nodeNum
* blocksPerNode
;
58 * We have two block sizes to consider here. The device blocksize, and the
61 while (ptr
< endPtr
) {
67 lba
= FindBlock(erp
, offset
);
69 warnx("Cannot find block %u in extents overflow file", offset
);
72 lba
= lba
* S32(hp
->blockSize
);
73 for (i
= 0; i
< S32(hp
->blockSize
) / devp
->blockSize
; i
++) {
74 // printf("Trying to get block %lld\n", lba + i);
75 rv
= GetBlock(devp
, lba
+ (i
* devp
->blockSize
), ptr
);
77 warnx("Cannot read block %u in extents overflow file", lba
+ i
);
80 ptr
+= devp
->blockSize
;
90 * Scan through an extentes overflow node, looking for File ID's less than
91 * the first user file ID. For each one it finds, it adds the extents to
92 * the volume structure list. It returns the number of the next node
93 * (which will be 0 when we've hit the end of the list); it also returns 0
94 * when it encounters a CNID larger than the system files'.
97 ScanNode(VolumeObjects_t
*vop
, uint8_t *nodePtr
, size_t nodeSize
, off_t blockSize
)
100 BTNodeDescriptor
*descp
;
103 HFSPlusExtentKey
*keyp
;
104 HFSPlusExtentRecord
*datap
;
108 descp
= (BTNodeDescriptor
*)nodePtr
;
110 if (descp
->kind
!= kBTLeafNode
)
113 numRecords
= S16(descp
->numRecords
);
114 offsetPtr
= (u_int16_t
*)((uint8_t*)nodePtr
+ nodeSize
);
116 retval
= S32(descp
->fLink
);
117 for (indx
= 1; indx
<= numRecords
; indx
++) {
118 int recOffset
= S16(offsetPtr
[-indx
]);
119 recp
= nodePtr
+ recOffset
;
120 if (recp
> (nodePtr
+ nodeSize
)) {
121 return -1; // Corrupt node
123 keyp
= (HFSPlusExtentKey
*)recp
;
124 datap
= (HFSPlusExtentRecord
*)(recp
+ sizeof(HFSPlusExtentKey
));
125 // printf("Node index #%d: fileID = %u\n", indx, S32(keyp->fileID));
126 if (S32(keyp
->fileID
) >= kHFSFirstUserCatalogNodeID
) {
127 if (debug
) printf("Done scanning extents overflow file\n");
132 for (i
= 0; i
< kHFSPlusExtentDensity
; i
++) {
133 off_t start
= S32((*datap
)[i
].startBlock
) * (off_t
)blockSize
;
134 off_t len
= S32((*datap
)[i
].blockCount
) * (off_t
)blockSize
;
136 AddExtent(vop
, start
, len
);
145 * Given a volme structure list, scan through the extents overflow file
146 * looking for system-file extents (those with a CNID < 16). If useAltHdr
147 * is set, it'll use the extents overflow descriptor in the alternate header.
150 ScanExtents(VolumeObjects_t
*vop
, int useAltHdr
)
154 char buffer
[vop
->devp
->blockSize
];
156 BTNodeDescriptor desc
;
159 HFSPlusVolumeHeader
*hp
;
160 HFSPlusExtentRecord
*erp
;
164 void *nodePtr
= NULL
;
165 unsigned int nodeNum
= 0;
167 hp
= useAltHdr
? &vop
->vdp
->altHeader
: & vop
->vdp
->priHeader
;
168 vBlockSize
= S32(hp
->blockSize
);
170 rv
= GetBlock(vop
->devp
, S32(hp
->extentsFile
.extents
[0].startBlock
) * vBlockSize
, buffer
);
172 warnx("Cannot get btree header node for extents file for %s header", useAltHdr
? "alternate" : "primary");
176 headerNode
= (struct RootNode
*)buffer
;
178 if (headerNode
->desc
.kind
!= kBTHeaderNode
) {
179 warnx("Root node is not a header node (%x)", headerNode
->desc
.kind
);
183 tBlockSize
= S16(headerNode
->header
.nodeSize
);
184 blocksPerNode
= tBlockSize
/ vBlockSize
;
186 nodePtr
= malloc(tBlockSize
);
187 if (nodePtr
== NULL
) {
188 warn("cannot allocate buffer for node");
191 nodeNum
= S32(headerNode
->header
.firstLeafNode
);
193 if (debug
) printf("nodenum = %u\n", nodeNum
);
196 * Iterate through the leaf nodes.
198 while (nodeNum
!= 0) {
199 if (debug
) printf("Getting node %u\n", nodeNum
);
201 rv
= GetNode(vop
->devp
, hp
, nodeNum
, blocksPerNode
, nodePtr
);
203 warnx("Cannot get node %u", nodeNum
);
207 nodeNum
= ScanNode(vop
, nodePtr
, tBlockSize
, vBlockSize
);