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