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