+
+
+/*-------------------------------------------------------------------------------
+Routine: BTZeroUnusedNodes
+
+Function: Write zeros to all nodes in the B-tree that are not currently in use.
+-------------------------------------------------------------------------------*/
+int
+BTZeroUnusedNodes(FCB *filePtr)
+{
+ int err;
+ vnode_t vp;
+ BTreeControlBlockPtr btreePtr;
+ BlockDescriptor mapNode;
+ buf_t bp;
+ u_int32_t nodeNumber;
+ u_int16_t *mapPtr, *pos;
+ u_int16_t mapSize, size;
+ u_int16_t mask;
+ u_int16_t bitNumber;
+ u_int16_t word;
+ int numWritten;
+
+ vp = FTOV(filePtr);
+ btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
+ bp = NULL;
+ nodeNumber = 0;
+ mapNode.buffer = nil;
+ mapNode.blockHeader = nil;
+ numWritten = 0;
+
+ /* Iterate over map nodes. */
+ while (true)
+ {
+ err = GetMapNode (btreePtr, &mapNode, &mapPtr, &mapSize);
+ if (err)
+ {
+ err = MacToVFSError(err);
+ goto ErrorExit;
+ }
+
+ pos = mapPtr;
+ size = mapSize;
+ size >>= 1; /* convert to number of 16-bit words */
+
+ /* Iterate over 16-bit words in the map record. */
+ while (size--)
+ {
+ if (*pos != 0xFFFF) /* Anything free in this word? */
+ {
+ word = SWAP_BE16(*pos);
+
+ /* Iterate over bits in the word. */
+ for (bitNumber = 0, mask = 0x8000;
+ bitNumber < 16;
+ ++bitNumber, mask >>= 1)
+ {
+ if (word & mask)
+ continue; /* This node is in use. */
+
+ if (nodeNumber + bitNumber >= btreePtr->totalNodes)
+ {
+ /* We've processed all of the nodes. */
+ goto done;
+ }
+
+ /*
+ * Get a buffer full of zeros and write it to the unused
+ * node. Since we'll probably be writing a lot of nodes,
+ * bypass the journal (to avoid a transaction that's too
+ * big). Instead, this behaves more like clearing out
+ * nodes when extending a B-tree (eg., ClearBTNodes).
+ */
+ bp = buf_getblk(vp, nodeNumber + bitNumber, btreePtr->nodeSize, 0, 0, BLK_META);
+ if (bp == NULL)
+ {
+ printf("hfs: BTZeroUnusedNodes: unable to read node %u\n", nodeNumber + bitNumber);
+ err = EIO;
+ goto ErrorExit;
+ }
+
+ if (buf_flags(bp) & B_LOCKED) {
+ /*
+ * This node is already part of a transaction and will be written when
+ * the transaction is committed, so don't write it here. If we did, then
+ * we'd hit a panic in hfs_vnop_bwrite because the B_LOCKED bit is still set.
+ */
+ buf_brelse(bp);
+ continue;
+ }
+
+ buf_clear(bp);
+ buf_markaged(bp);
+
+ /*
+ * Try not to hog the buffer cache. Wait for the write
+ * every 32 nodes. If VNOP_BWRITE reports an error, bail out and bubble
+ * it up to the function calling us. If we tried to update a read-only
+ * mount on read-only media, for example, catching the error will let
+ * us alert the callers of this function that they should maintain
+ * the mount in read-only mode.
+
+ */
+ ++numWritten;
+ if (numWritten % 32 == 0) {
+ err = VNOP_BWRITE(bp);
+ if (err) {
+ goto ErrorExit;
+ }
+ }
+ else {
+ buf_bawrite(bp);
+ }
+ }
+ }
+
+ /* Go to the next word in the bitmap */
+ ++pos;
+ nodeNumber += 16;
+ }
+ }
+
+ErrorExit:
+done:
+ (void) ReleaseNode(btreePtr, &mapNode);
+
+ return err;
+}