2 * Copyright (c) 2000,2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
23 * @APPLE_LICENSE_HEADER_END@
26 #include "../headers/BTreesPrivate.h"
30 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
31 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
);
36 OSErr
SearchBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void* foundKey
, void* data
, UInt16
*dataSize
, UInt32
*newHint
)
38 panic("SearchBTreeRecord is dead code!");
41 FSBufferDescriptor btRecord
;
42 BTreeIterator searchIterator
;
44 BTreeControlBlock
*btcb
;
48 fcb
= GetFileControlBlock(refNum
);
49 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
51 btRecord
.bufferAddress
= data
;
52 btRecord
.itemCount
= 1;
53 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
54 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
55 else if ( btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
56 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
58 btRecord
.itemSize
= sizeof(CatalogRecord
);
60 searchIterator
.hint
.writeCount
= 0; // clear these out for debugging...
61 searchIterator
.hint
.reserved1
= 0;
62 searchIterator
.hint
.reserved2
= 0;
64 searchIterator
.hint
.nodeNum
= hint
;
65 searchIterator
.hint
.index
= 0;
67 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
70 BlockMoveData(key
, &searchIterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
72 result
= BTSearchRecord( fcb
, &searchIterator
, &btRecord
, dataSize
, &searchIterator
);
76 *newHint
= searchIterator
.hint
.nodeNum
;
78 result
= CheckBTreeKey(&searchIterator
.key
, btcb
);
81 BlockMoveData(&searchIterator
.key
, foundKey
, CalcKeySize(btcb
, &searchIterator
.key
)); //\80\80 warning, this could overflow user's buffer!!!
83 if ( DEBUG_BUILD
&& !ValidHFSRecord(data
, btcb
, *dataSize
) )
84 DebugStr("\pSearchBTreeRecord: bad record?");
94 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void *newData
, UInt16 dataSize
, UInt32
*newHint
)
96 FSBufferDescriptor btRecord
;
97 BTreeIterator iterator
;
99 BTreeControlBlock
*btcb
;
103 fcb
= GetFileControlBlock(refNum
);
104 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
106 btRecord
.bufferAddress
= newData
;
107 btRecord
.itemSize
= dataSize
;
108 btRecord
.itemCount
= 1;
110 iterator
.hint
.nodeNum
= hint
;
112 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
115 BlockMoveData(key
, &iterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
117 if ( DEBUG_BUILD
&& !ValidHFSRecord(newData
, btcb
, dataSize
) )
118 DebugStr("\pReplaceBTreeRecord: bad record?");
120 result
= BTReplaceRecord( fcb
, &iterator
, &btRecord
, dataSize
);
122 *newHint
= iterator
.hint
.nodeNum
;
124 //\80\80 do we need to invalidate the iterator?
133 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
137 if ( btcb
->attributes
& kBTBigKeysMask
)
138 keyLen
= key
->length16
;
140 keyLen
= key
->length8
;
142 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
145 DebugStr("\pCheckBTreeKey: bad key length!");
146 return fsBTInvalidKeyLengthErr
;
153 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
)
157 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
159 return ( recordSize
== sizeof(HFSExtentRecord
) );
161 else if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
163 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
165 else // Catalog record
167 CatalogRecord
*catalogRecord
= (CatalogRecord
*) record
;
169 switch(catalogRecord
->recordType
)
171 case kHFSFolderRecord
:
173 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
175 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
177 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
180 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
182 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
187 case kHFSPlusFolderRecord
:
189 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
191 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
193 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
196 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
198 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
206 HFSExtentDescriptor
*dataExtent
;
207 HFSExtentDescriptor
*rsrcExtent
;
209 if ( recordSize
!= sizeof(HFSCatalogFile
) )
211 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
214 cNodeID
= catalogRecord
->hfsFile
.fileID
;
219 // make sure 0 ¾ LEOF ¾ PEOF for both forks
221 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
223 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
225 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
227 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
230 dataExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
231 rsrcExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
234 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
236 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
238 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
245 case kHFSPlusFileRecord
:
248 HFSPlusExtentDescriptor
*dataExtent
;
249 HFSPlusExtentDescriptor
*rsrcExtent
;
251 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
253 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
256 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
261 // make sure 0 ¾ LEOF ¾ PEOF for both forks
263 dataExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
264 rsrcExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
267 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
269 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
271 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
278 case kHFSFolderThreadRecord
:
279 case kHFSFileThreadRecord
:
281 if ( recordSize
!= sizeof(HFSCatalogThread
) )
284 cNodeID
= catalogRecord
->hfsThread
.parentID
;
285 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
288 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
289 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
294 case kHFSPlusFolderThreadRecord
:
295 case kHFSPlusFileThreadRecord
:
297 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
300 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
301 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
304 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
305 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
315 return true; // record appears to be OK