2 * Copyright (c) 2000,2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include "../headers/BTreesPrivate.h"
35 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
36 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
);
41 OSErr
SearchBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void* foundKey
, void* data
, UInt16
*dataSize
, UInt32
*newHint
)
43 panic("SearchBTreeRecord is dead code!");
46 FSBufferDescriptor btRecord
;
47 BTreeIterator searchIterator
;
49 BTreeControlBlock
*btcb
;
53 fcb
= GetFileControlBlock(refNum
);
54 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
56 btRecord
.bufferAddress
= data
;
57 btRecord
.itemCount
= 1;
58 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
59 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
60 else if ( btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
61 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
63 btRecord
.itemSize
= sizeof(CatalogRecord
);
65 searchIterator
.hint
.writeCount
= 0; // clear these out for debugging...
66 searchIterator
.hint
.reserved1
= 0;
67 searchIterator
.hint
.reserved2
= 0;
69 searchIterator
.hint
.nodeNum
= hint
;
70 searchIterator
.hint
.index
= 0;
72 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
75 BlockMoveData(key
, &searchIterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
77 result
= BTSearchRecord( fcb
, &searchIterator
, &btRecord
, dataSize
, &searchIterator
);
81 *newHint
= searchIterator
.hint
.nodeNum
;
83 result
= CheckBTreeKey(&searchIterator
.key
, btcb
);
86 BlockMoveData(&searchIterator
.key
, foundKey
, CalcKeySize(btcb
, &searchIterator
.key
)); //\80\80 warning, this could overflow user's buffer!!!
88 if ( DEBUG_BUILD
&& !ValidHFSRecord(data
, btcb
, *dataSize
) )
89 DebugStr("\pSearchBTreeRecord: bad record?");
99 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void *newData
, UInt16 dataSize
, UInt32
*newHint
)
101 FSBufferDescriptor btRecord
;
102 BTreeIterator iterator
;
104 BTreeControlBlock
*btcb
;
108 fcb
= GetFileControlBlock(refNum
);
109 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
111 btRecord
.bufferAddress
= newData
;
112 btRecord
.itemSize
= dataSize
;
113 btRecord
.itemCount
= 1;
115 iterator
.hint
.nodeNum
= hint
;
117 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
120 BlockMoveData(key
, &iterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
122 if ( DEBUG_BUILD
&& !ValidHFSRecord(newData
, btcb
, dataSize
) )
123 DebugStr("\pReplaceBTreeRecord: bad record?");
125 result
= BTReplaceRecord( fcb
, &iterator
, &btRecord
, dataSize
);
127 *newHint
= iterator
.hint
.nodeNum
;
129 //\80\80 do we need to invalidate the iterator?
138 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
142 if ( btcb
->attributes
& kBTBigKeysMask
)
143 keyLen
= key
->length16
;
145 keyLen
= key
->length8
;
147 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
150 DebugStr("\pCheckBTreeKey: bad key length!");
151 return fsBTInvalidKeyLengthErr
;
158 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
)
162 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
164 return ( recordSize
== sizeof(HFSExtentRecord
) );
166 else if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
168 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
170 else // Catalog record
172 CatalogRecord
*catalogRecord
= (CatalogRecord
*) record
;
174 switch(catalogRecord
->recordType
)
176 case kHFSFolderRecord
:
178 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
180 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
182 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
185 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
187 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
192 case kHFSPlusFolderRecord
:
194 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
196 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
198 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
201 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
203 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
211 HFSExtentDescriptor
*dataExtent
;
212 HFSExtentDescriptor
*rsrcExtent
;
214 if ( recordSize
!= sizeof(HFSCatalogFile
) )
216 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
219 cNodeID
= catalogRecord
->hfsFile
.fileID
;
224 // make sure 0 ¾ LEOF ¾ PEOF for both forks
226 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
228 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
230 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
232 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
235 dataExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
236 rsrcExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
239 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
241 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
243 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
250 case kHFSPlusFileRecord
:
253 HFSPlusExtentDescriptor
*dataExtent
;
254 HFSPlusExtentDescriptor
*rsrcExtent
;
256 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
258 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
261 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
266 // make sure 0 ¾ LEOF ¾ PEOF for both forks
268 dataExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
269 rsrcExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
272 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
274 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
276 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
283 case kHFSFolderThreadRecord
:
284 case kHFSFileThreadRecord
:
286 if ( recordSize
!= sizeof(HFSCatalogThread
) )
289 cNodeID
= catalogRecord
->hfsThread
.parentID
;
290 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
293 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
294 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
299 case kHFSPlusFolderThreadRecord
:
300 case kHFSPlusFileThreadRecord
:
302 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
305 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
306 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
309 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
310 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
320 return true; // record appears to be OK