|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: File: BTreeWrapper.c
24:
25: Contains: Interface glue for new B-tree manager.
26:
27: Version: HFS Plus 1.0
28:
29: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved.
30:
31: File Ownership:
32:
33: DRI: Don Brady
34:
35: Other Contact: Mark Day
36:
37: Technology: xxx put technology here xxx
38:
39: Writers:
40:
41: (msd) Mark Day
42: (DSH) Deric Horn
43: (djb) Don Brady
44:
45: Change History (most recent first):
46: <MacOSX> 8/10/98 djb Removed all references to btcb global iterator (lastIterator).
47: <MacOSX> 04/02/98 djb GetBTreeRecord is only used for MacOS builds.
48: <MacOSX> 03/31/98 djb Sync up with final HFSVolumes.h header file.
49: <CS18> 9/4/97 msd Fix ValidHFSRecord to determine the type of B-tree by FileID,
50: not record size. Add better checking for attribute b-tree keys.
51: <CS17> 8/22/97 djb Get blockReadFromDisk flag from GetCacheBlock call.
52: <CS16> 8/14/97 djb Remove reserved field checks in ValidHFSRecord (radar #1649593).
53: Only call if ValidHFSRecord HFS_DIAGNOSTIC is true.
54: <CS15> 8/11/97 djb Bug 1670441. In SetEndOfForkProc, don't DebugStr if the disk is
55: full.
56: <CS14> 7/25/97 DSH Pass heuristicHint to BTSearchRecord from SearchBTreeRecord.
57: <CS13> 7/24/97 djb CallBackProcs now take a file refNum instead of an FCB.
58: GetBlockProc now reports if block came from disk.
59: <CS12> 7/22/97 djb Move all trace points to BTree.c file.
60: <CS11> 7/21/97 djb LogEndTime now takes an error code.
61: <CS10> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision
62: <CS9> 7/15/97 msd Bug #1664103. OpenBTree is not propagating errors from
63: BTOpenPath.
64: <CS8> 7/9/97 djb Remove maxCNID check from ValidHFSRecord (radar #1649593).
65: <CS7> 6/13/97 djb In ValidHFSRecord HFSPlus threads names can be > 31 chars.
66: <CS6> 6/2/97 DSH Also flush AlternateVolumeHeader whenever Attributes or Startup
67: files change size.
68: <CS5> 5/28/97 msd In ValidHFSRecord, check for attribute keys.
69: <CS4> 5/19/97 djb Move summary traces from GetBTreeRecord to BTIterateRecord.
70: <CS3> 5/9/97 djb Get in sync with new FilesInternal.i.
71: <CS2> 5/7/97 djb Add summary traces to B-tree SPI.
72: <CS1> 4/24/97 djb first checked in
73: <HFS18> 4/16/97 djb Always use new B-tree code.
74: <HFS17> 4/4/97 djb Remove clumpSize test from ValidHFSRecord.
75: <HFS16> 4/4/97 djb Get in sync with volume format changes.
76: <HFS15> 3/17/97 DSH Casting for SC, BlockProcs are now not static.
77: <HFS14> 3/3/97 djb Call trash block after closing btree!
78: <HFS13> 2/19/97 djb Add support for accessing bigger B-tree nodes.
79: <HFS12> 2/6/97 msd In CheckBTreeKey, remove test and DebugStr for parent ID being
80: too big.
81: <HFS11> 1/23/97 DSH SetEndOfForkProc now calls through to update the Alternate MDB
82: or VolumeHeader.
83: <HFS10> 1/16/97 djb Switched to dynamic lengths for BufferDescriptor length field in
84: SearchBTreeRecord and GetBTreeRecord. Round up to clump size in
85: SetEndOfForkProc.
86: <HFS9> 1/15/97 djb Don't return errors for bad file ids in key.
87: <HFS8> 1/13/97 djb Adding support for getting current record. ValidHFSRecord now
88: supports variable sized thread records.
89: <HFS7> 1/9/97 djb Call CheckBTreeKey before using key length in a BlockMoveData
90: call.
91: <HFS6> 1/6/97 djb Implement SetEndOfForkProc.
92: <HFS5> 1/6/97 djb Added HFS Plus support to CheckBTreeKey and ValidHFSRecord.
93: <HFS4> 1/3/97 djb Added support for large keys. Integrated latest HFSVolumesPriv.h
94: changes.
95: <HFS3> 12/23/96 djb Fixed problem in SearchBTreeRecord (dataSize is an output so it
96: was undefined). Added some debugging code.
97: <HFS2> 12/20/96 msd Fix OpenBTree to use the real data type for the key compare proc
98: pointer (not void *). Fixed problem in SearchBTreeRecord that
99: assigns a pointer to a buffer size field (forgot to dereference
100: the pointer).
101: <HFS1> 12/19/96 djb first checked in
102:
103: */
104:
105: #include "../headers/BTreesPrivate.h"
106:
107:
108:
109:
110: // B-tree callbacks...
111: #if TARGET_API_MAC_OS8
112: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block );
113: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options );
114: OSStatus SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount );
115: #endif
116:
117:
118: // local routines
119: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
120: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize);
121:
122:
123:
124:
125: OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint)
126: {
127: FSBufferDescriptor btRecord;
128: BTreeIterator searchIterator;
129: FCB *fcb;
130: BTreeControlBlock *btcb;
131: OSStatus result;
132:
133:
134: fcb = GetFileControlBlock(refNum);
135: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
136:
137: btRecord.bufferAddress = data;
138: btRecord.itemCount = 1;
139: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
140: btRecord.itemSize = sizeof(HFSExtentRecord);
141: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
142: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
143: else
144: btRecord.itemSize = sizeof(CatalogRecord);
145:
146: searchIterator.hint.writeCount = 0; // clear these out for debugging...
147: searchIterator.hint.reserved1 = 0;
148: searchIterator.hint.reserved2 = 0;
149:
150: searchIterator.hint.nodeNum = hint;
151: searchIterator.hint.index = 0;
152:
153: result = CheckBTreeKey((BTreeKey *) key, btcb);
154: ExitOnError(result);
155:
156: BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
157:
158: // We only optimize for catalog records
159: if( btRecord.itemSize == sizeof(CatalogRecord) )
160: {
161: UInt32 heuristicHint;
162: UInt32 *cachedHint;
163: Ptr hintCachePtr = FCBTOVCB(fcb)->hintCachePtr;
164:
165: // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of
166: // dirID and nodeNumber, in hopes that the current search will be in the same node
167: // as the last search with the same parentID.
168: result = GetMRUCacheBlock( ((HFSCatalogKey *)key)->parentID, hintCachePtr, (Ptr *)&cachedHint );
169: heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey;
170:
171: result = BTSearchRecord( fcb, &searchIterator, heuristicHint, &btRecord, dataSize, &searchIterator );
172:
173: InsertMRUCacheBlock( hintCachePtr, ((HFSCatalogKey *)key)->parentID, (Ptr) &(searchIterator.hint.nodeNum) );
174: }
175: else
176: {
177: result = BTSearchRecord( fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, dataSize, &searchIterator );
178: }
179:
180: if (result == noErr)
181: {
182: *newHint = searchIterator.hint.nodeNum;
183:
184: result = CheckBTreeKey(&searchIterator.key, btcb);
185: ExitOnError(result);
186:
187: BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //�� warning, this could overflow user's buffer!!!
188:
189: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
190: DebugStr("\pSearchBTreeRecord: bad record?");
191: }
192:
193: ErrorExit:
194:
195: return result;
196: }
197:
198:
199:
200: OSErr InsertBTreeRecord(FileReference refNum, void* key, void* data, UInt16 dataSize, UInt32 *newHint)
201: {
202: FSBufferDescriptor btRecord;
203: BTreeIterator iterator;
204: FCB *fcb;
205: BTreeControlBlock *btcb;
206: OSStatus result;
207:
208:
209: fcb = GetFileControlBlock(refNum);
210: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
211:
212: btRecord.bufferAddress = data;
213: btRecord.itemSize = dataSize;
214: btRecord.itemCount = 1;
215:
216: iterator.hint.nodeNum = 0; // no hint
217:
218: result = CheckBTreeKey((BTreeKey *) key, btcb);
219: ExitOnError(result);
220:
221: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
222:
223: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) )
224: DebugStr("\pInsertBTreeRecord: bad record?");
225:
226: result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize );
227:
228: *newHint = iterator.hint.nodeNum;
229:
230: ErrorExit:
231:
232: return result;
233: }
234:
235:
236: OSErr DeleteBTreeRecord(FileReference refNum, void* key)
237: {
238: BTreeIterator iterator;
239: FCB *fcb;
240: BTreeControlBlock *btcb;
241: OSStatus result;
242:
243:
244: fcb = GetFileControlBlock(refNum);
245: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
246:
247: iterator.hint.nodeNum = 0; // no hint
248:
249: result = CheckBTreeKey((BTreeKey *) key, btcb);
250: ExitOnError(result);
251:
252: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
253:
254: result = BTDeleteRecord( fcb, &iterator );
255:
256: ErrorExit:
257:
258: return result;
259: }
260:
261:
262: OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void *newData, UInt16 dataSize, UInt32 *newHint)
263: {
264: FSBufferDescriptor btRecord;
265: BTreeIterator iterator;
266: FCB *fcb;
267: BTreeControlBlock *btcb;
268: OSStatus result;
269:
270:
271: fcb = GetFileControlBlock(refNum);
272: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
273:
274: btRecord.bufferAddress = newData;
275: btRecord.itemSize = dataSize;
276: btRecord.itemCount = 1;
277:
278: iterator.hint.nodeNum = hint;
279:
280: result = CheckBTreeKey((BTreeKey *) key, btcb);
281: ExitOnError(result);
282:
283: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
284:
285: if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
286: DebugStr("\pReplaceBTreeRecord: bad record?");
287:
288: result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize );
289:
290: *newHint = iterator.hint.nodeNum;
291:
292: //���do we need to invalidate the iterator?
293:
294: ErrorExit:
295:
296: return result;
297: }
298:
299:
300:
301: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
302: {
303: UInt16 keyLen;
304:
305: if ( btcb->attributes & kBTBigKeysMask )
306: keyLen = key->length16;
307: else
308: keyLen = key->length8;
309:
310: if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
311: {
312: if ( DEBUG_BUILD )
313: DebugStr("\pCheckBTreeKey: bad key length!");
314: return fsBTInvalidKeyLengthErr;
315: }
316:
317: return noErr;
318: }
319:
320:
321: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize)
322: {
323: UInt32 cNodeID;
324:
325: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
326: {
327: return ( recordSize == sizeof(HFSExtentRecord) );
328: }
329: else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
330: {
331: return ( recordSize == sizeof(HFSPlusExtentRecord) );
332: }
333: else // Catalog record
334: {
335: CatalogRecord *catalogRecord = (CatalogRecord*) record;
336:
337: switch(catalogRecord->recordType)
338: {
339: case kHFSFolderRecord:
340: {
341: if ( recordSize != sizeof(HFSCatalogFolder) )
342: return false;
343: if ( catalogRecord->hfsFolder.flags != 0 )
344: return false;
345: if ( catalogRecord->hfsFolder.valence > 0x7FFF )
346: return false;
347:
348: cNodeID = catalogRecord->hfsFolder.folderID;
349:
350: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
351: return false;
352: }
353: break;
354:
355: case kHFSPlusFolderRecord:
356: {
357: if ( recordSize != sizeof(HFSPlusCatalogFolder) )
358: return false;
359: if ( catalogRecord->hfsPlusFolder.flags != 0 )
360: return false;
361: if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
362: return false;
363:
364: cNodeID = catalogRecord->hfsPlusFolder.folderID;
365:
366: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
367: return false;
368: }
369: break;
370:
371: case kHFSFileRecord:
372: {
373: // UInt16 i;
374: HFSExtentDescriptor *dataExtent;
375: HFSExtentDescriptor *rsrcExtent;
376:
377: if ( recordSize != sizeof(HFSCatalogFile) )
378: return false;
379: if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
380: return false;
381:
382: cNodeID = catalogRecord->hfsFile.fileID;
383:
384: if ( cNodeID < 16 )
385: return false;
386:
387: // make sure 0 � LEOF � PEOF for both forks
388:
389: if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
390: return false;
391: if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
392: return false;
393: if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
394: return false;
395: if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
396: return false;
397:
398: dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
399: rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
400:
401: #if 0
402: for (i = 0; i < kHFSExtentDensity; ++i)
403: {
404: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
405: return false;
406: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
407: return false;
408: }
409: #endif
410: }
411: break;
412:
413: case kHFSPlusFileRecord:
414: {
415: // UInt16 i;
416: HFSPlusExtentDescriptor *dataExtent;
417: HFSPlusExtentDescriptor *rsrcExtent;
418:
419: if ( recordSize != sizeof(HFSPlusCatalogFile) )
420: return false;
421: if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
422: return false;
423:
424: cNodeID = catalogRecord->hfsPlusFile.fileID;
425:
426: if ( cNodeID < 16 )
427: return false;
428:
429: // make sure 0 � LEOF � PEOF for both forks
430:
431: dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
432: rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
433:
434: #if 0
435: for (i = 0; i < kHFSPlusExtentDensity; ++i)
436: {
437: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
438: return false;
439: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
440: return false;
441: }
442: #endif
443: }
444: break;
445:
446: case kHFSFolderThreadRecord:
447: case kHFSFileThreadRecord:
448: {
449: if ( recordSize != sizeof(HFSCatalogThread) )
450: return false;
451:
452: cNodeID = catalogRecord->hfsThread.parentID;
453: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
454: return false;
455:
456: if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
457: (catalogRecord->hfsThread.nodeName[0] > 31) )
458: return false;
459: }
460: break;
461:
462: case kHFSPlusFolderThreadRecord:
463: case kHFSPlusFileThreadRecord:
464: {
465: if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
466: return false;
467:
468: cNodeID = catalogRecord->hfsPlusThread.parentID;
469: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
470: return false;
471:
472: if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
473: (catalogRecord->hfsPlusThread.nodeName.length > 255) )
474: return false;
475: }
476: break;
477:
478: default:
479: return false;
480: }
481: }
482:
483: return true; // record appears to be OK
484: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.