]> git.saurik.com Git - apple/xnu.git/blame - bsd/hfs/hfscommon/BTree/BTreeScanner.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / BTree / BTreeScanner.c
CommitLineData
14353aa8 1/*
91447636 2 * Copyright (c) 1996-2005 Apple Computer, Inc. All rights reserved.
14353aa8
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
14353aa8 11 *
37839358
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14353aa8
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
14353aa8
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 *
22 * @(#)BTreeScanner.c
23 */
24#include <sys/kernel.h>
55e303ae 25#include "../../hfs_endian.h"
14353aa8
A
26
27#include "../headers/BTreeScanner.h"
28
29static int FindNextLeafNode( BTScanState *scanState, Boolean avoidIO );
30static int ReadMultipleNodes( BTScanState *scanState );
31
32
33//_________________________________________________________________________________
34//
35// Routine: BTScanNextRecord
36//
37// Purpose: Return the next leaf record in a scan.
38//
39// Inputs:
40// scanState Scanner's current state
41// avoidIO If true, don't do any I/O to refill the buffer
42//
43// Outputs:
44// key Key of found record (points into buffer)
45// data Data of found record (points into buffer)
46// dataSize Size of data in found record
47//
48// Result:
49// noErr Found a valid record
50// btNotFound No more records
51// ??? Needed to do I/O to get next node, but avoidIO set
52//
53// Notes:
54// This routine returns pointers to the found record's key and data. It
55// does not copy the key or data to a caller-supplied buffer (like
56// GetBTreeRecord would). The caller must not modify the key or data.
57//_________________________________________________________________________________
58
59int BTScanNextRecord( BTScanState * scanState,
60 Boolean avoidIO,
61 void * * key,
62 void * * data,
63 u_int32_t * dataSize )
64{
65 int err;
66 u_int16_t dataSizeShort;
67
68 err = noErr;
69
70 //
71 // If this is the first call, there won't be any nodes in the buffer, so go
72 // find the first first leaf node (if any).
73 //
74 if ( scanState->nodesLeftInBuffer == 0 )
75 {
76 err = FindNextLeafNode( scanState, avoidIO );
77 }
78
79 while ( err == noErr )
80 {
81 // See if we have a record in the current node
82 err = GetRecordByIndex( scanState->btcb, scanState->currentNodePtr,
83 scanState->recordNum, (KeyPtr *) key,
84 (UInt8 **) data, &dataSizeShort );
85
86 if ( err == noErr )
87 {
88 ++scanState->recordsFound;
89 ++scanState->recordNum;
90 if (dataSize != NULL)
91 *dataSize = dataSizeShort;
92 return noErr;
93 }
94 else if (err > 0)
95 {
96 // We didn't get the node through the cache, so we can't invalidate it.
97 //XXX Should we do something else to avoid seeing the same record again?
98 return err;
99 }
100
101 // We're done with the current node. See if we've returned all the records
102 if ( scanState->recordsFound >= scanState->btcb->leafRecords )
103 {
104 return btNotFound;
105 }
106
107 // Move to the first record of the next leaf node
108 scanState->recordNum = 0;
109 err = FindNextLeafNode( scanState, avoidIO );
110 }
111
112 //
113 // If we got an EOF error from FindNextLeafNode, then there are no more leaf
114 // records to be found.
115 //
116 if ( err == fsEndOfIterationErr )
117 err = btNotFound;
118
119 return err;
120
121} /* BTScanNextRecord */
122
123
124//_________________________________________________________________________________
125//
126// Routine: FindNextLeafNode
127//
128// Purpose: Point to the next leaf node in the buffer. Read more nodes
129// into the buffer if needed (and allowed).
130//
131// Inputs:
132// scanState Scanner's current state
133// avoidIO If true, don't do any I/O to refill the buffer
134//
135// Result:
136// noErr Found a valid record
137// fsEndOfIterationErr No more nodes in file
138// ??? Needed to do I/O to get next node, but avoidIO set
139//_________________________________________________________________________________
140
141static int FindNextLeafNode( BTScanState *scanState, Boolean avoidIO )
142{
3a60a9f5
A
143 int err;
144 BlockDescriptor block;
145 FileReference fref;
14353aa8
A
146
147 err = noErr; // Assume everything will be OK
148
149 while ( 1 )
150 {
151 if ( scanState->nodesLeftInBuffer == 0 )
152 {
153 // Time to read some more nodes into the buffer
154 if ( avoidIO )
155 {
156 return fsBTTimeOutErr;
157 }
158 else
159 {
160 // read some more nodes into buffer
161 err = ReadMultipleNodes( scanState );
162 if ( err != noErr )
163 break;
164 }
165 }
166 else
167 {
168 // Adjust the node counters and point to the next node in the buffer
169 ++scanState->nodeNum;
170 --scanState->nodesLeftInBuffer;
171
172 // If we've looked at all nodes in the tree, then we're done
173 if ( scanState->nodeNum >= scanState->btcb->totalNodes )
174 return fsEndOfIterationErr;
175
176 if ( scanState->nodesLeftInBuffer == 0 )
177 {
178 scanState->recordNum = 0;
179 continue;
180 }
181
182 (u_int8_t *) scanState->currentNodePtr += scanState->btcb->nodeSize;
183 }
184
55e303ae 185 /* Fake a BlockDescriptor */
3a60a9f5 186 block.blockHeader = NULL; /* No buffer cache buffer */
55e303ae 187 block.buffer = scanState->currentNodePtr;
3a60a9f5 188 block.blockNum = scanState->nodeNum;
55e303ae
A
189 block.blockSize = scanState->btcb->nodeSize;
190 block.blockReadFromDisk = 1;
191 block.isModified = 0;
192
193 fref = scanState->btcb->fileRefNum;
194
3a60a9f5
A
195 /* This node was read from disk, so it must be swapped/checked. */
196 err = hfs_swap_BTNode(&block, fref, kSwapBTNodeBigToHost);
197 if ( err != noErr ) {
198 printf("FindNextLeafNode: Error from hfs_swap_BTNode (node %u)\n", scanState->nodeNum);
14353aa8
A
199 continue;
200 }
3a60a9f5 201
14353aa8
A
202 if ( scanState->currentNodePtr->kind == kBTLeafNode )
203 break;
204 }
205
206 return err;
207
208} /* FindNextLeafNode */
209
210
211//_________________________________________________________________________________
212//
213// Routine: ReadMultipleNodes
214//
215// Purpose: Read one or more nodes into the buffer.
216//
217// Inputs:
218// theScanStatePtr Scanner's current state
219//
220// Result:
221// noErr One or nodes were read
222// fsEndOfIterationErr No nodes left in file, none in buffer
223//_________________________________________________________________________________
224
225static int ReadMultipleNodes( BTScanState *theScanStatePtr )
226{
227 int myErr = E_NONE;
228 BTreeControlBlockPtr myBTreeCBPtr;
91447636 229 daddr64_t myPhyBlockNum;
14353aa8
A
230 u_int32_t myBufferSize;
231 struct vnode * myDevPtr;
232 int myBlockRun;
233 u_int32_t myBlocksInBufferCount;
234
235 // release old buffer if we have one
236 if ( theScanStatePtr->bufferPtr != NULL )
237 {
91447636
A
238 buf_markinvalid(theScanStatePtr->bufferPtr);
239 buf_brelse( theScanStatePtr->bufferPtr );
14353aa8
A
240 theScanStatePtr->bufferPtr = NULL;
241 theScanStatePtr->currentNodePtr = NULL;
242 }
243
244 myBTreeCBPtr = theScanStatePtr->btcb;
245
246 // map logical block in catalog btree file to physical block on volume
91447636
A
247 myErr = hfs_bmap(myBTreeCBPtr->fileRefNum, theScanStatePtr->nodeNum,
248 &myDevPtr, &myPhyBlockNum, &myBlockRun);
14353aa8
A
249 if ( myErr != E_NONE )
250 {
251 goto ExitThisRoutine;
252 }
253
254 // bmap block run gives us the remaining number of valid blocks (number of blocks
255 // minus the first). so if there are 10 valid blocks our run number will be 9.
256 // blocks, in our case is the same as nodes (both are 4K)
257 myBlocksInBufferCount = (theScanStatePtr->bufferSize / myBTreeCBPtr->nodeSize );
258 myBufferSize = theScanStatePtr->bufferSize;
259 if ( (myBlockRun + 1) < myBlocksInBufferCount )
260 {
261 myBufferSize = (myBlockRun + 1) * myBTreeCBPtr->nodeSize;
262 }
263
264 // now read blocks from the device
91447636
A
265 myErr = (int)buf_bread(myDevPtr,
266 myPhyBlockNum,
267 myBufferSize,
268 NOCRED,
269 &theScanStatePtr->bufferPtr );
14353aa8
A
270 if ( myErr != E_NONE )
271 {
272 goto ExitThisRoutine;
273 }
274
91447636
A
275 theScanStatePtr->nodesLeftInBuffer = buf_count(theScanStatePtr->bufferPtr) / theScanStatePtr->btcb->nodeSize;
276 theScanStatePtr->currentNodePtr = (BTNodeDescriptor *) buf_dataptr(theScanStatePtr->bufferPtr);
14353aa8
A
277
278ExitThisRoutine:
279 return myErr;
280
281} /* ReadMultipleNodes */
282
283
284
285//_________________________________________________________________________________
286//
287// Routine: BTScanInitialize
288//
289// Purpose: Prepare to start a new BTree scan, or resume a previous one.
290//
291// Inputs:
292// btreeFile The B-Tree's file control block
293// startingNode Initial node number
294// startingRecord Initial record number within node
295// recordsFound Number of valid records found so far
296// bufferSize Size (in bytes) of buffer
297//
298// Outputs:
299// scanState Scanner's current state; pass to other scanner calls
300//
301// Notes:
302// To begin a new scan and see all records in the B-Tree, pass zeroes for
303// startingNode, startingRecord, and recordsFound.
304//
305// To resume a scan from the point of a previous BTScanTerminate, use the
306// values returned by BTScanTerminate as input for startingNode, startingRecord,
307// and recordsFound.
308//
309// When resuming a scan, the caller should check the B-tree's write count. If
310// it is different from the write count when the scan was terminated, then the
311// tree may have changed and the current state may be incorrect. In particular,
312// you may see some records more than once, or never see some records. Also,
313// the scanner may not be able to detect when all leaf records have been seen,
314// and will have to scan through many empty nodes.
315//
316