2 * Copyright (c) 2000,2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 #include "../headers/BTreesPrivate.h"
27 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
28 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
);
33 OSErr
SearchBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void* foundKey
, void* data
, UInt16
*dataSize
, UInt32
*newHint
)
35 panic("SearchBTreeRecord is dead code!");
38 FSBufferDescriptor btRecord
;
39 BTreeIterator searchIterator
;
41 BTreeControlBlock
*btcb
;
45 fcb
= GetFileControlBlock(refNum
);
46 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
48 btRecord
.bufferAddress
= data
;
49 btRecord
.itemCount
= 1;
50 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
51 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
52 else if ( btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
53 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
55 btRecord
.itemSize
= sizeof(CatalogRecord
);
57 searchIterator
.hint
.writeCount
= 0; // clear these out for debugging...
58 searchIterator
.hint
.reserved1
= 0;
59 searchIterator
.hint
.reserved2
= 0;
61 searchIterator
.hint
.nodeNum
= hint
;
62 searchIterator
.hint
.index
= 0;
64 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
67 BlockMoveData(key
, &searchIterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
69 result
= BTSearchRecord( fcb
, &searchIterator
, &btRecord
, dataSize
, &searchIterator
);
73 *newHint
= searchIterator
.hint
.nodeNum
;
75 result
= CheckBTreeKey(&searchIterator
.key
, btcb
);
78 BlockMoveData(&searchIterator
.key
, foundKey
, CalcKeySize(btcb
, &searchIterator
.key
)); //\80\80 warning, this could overflow user's buffer!!!
80 if ( DEBUG_BUILD
&& !ValidHFSRecord(data
, btcb
, *dataSize
) )
81 DebugStr("\pSearchBTreeRecord: bad record?");
91 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, UInt32 hint
, void *newData
, UInt16 dataSize
, UInt32
*newHint
)
93 FSBufferDescriptor btRecord
;
94 BTreeIterator iterator
;
96 BTreeControlBlock
*btcb
;
100 fcb
= GetFileControlBlock(refNum
);
101 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
103 btRecord
.bufferAddress
= newData
;
104 btRecord
.itemSize
= dataSize
;
105 btRecord
.itemCount
= 1;
107 iterator
.hint
.nodeNum
= hint
;
109 result
= CheckBTreeKey((BTreeKey
*) key
, btcb
);
112 BlockMoveData(key
, &iterator
.key
, CalcKeySize(btcb
, (BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
114 if ( DEBUG_BUILD
&& !ValidHFSRecord(newData
, btcb
, dataSize
) )
115 DebugStr("\pReplaceBTreeRecord: bad record?");
117 result
= BTReplaceRecord( fcb
, &iterator
, &btRecord
, dataSize
);
119 *newHint
= iterator
.hint
.nodeNum
;
121 //\80\80 do we need to invalidate the iterator?
130 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
134 if ( btcb
->attributes
& kBTBigKeysMask
)
135 keyLen
= key
->length16
;
137 keyLen
= key
->length8
;
139 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
142 DebugStr("\pCheckBTreeKey: bad key length!");
143 return fsBTInvalidKeyLengthErr
;
150 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, UInt16 recordSize
)
154 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
156 return ( recordSize
== sizeof(HFSExtentRecord
) );
158 else if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
160 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
162 else // Catalog record
164 CatalogRecord
*catalogRecord
= (CatalogRecord
*) record
;
166 switch(catalogRecord
->recordType
)
168 case kHFSFolderRecord
:
170 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
172 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
174 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
177 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
179 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
184 case kHFSPlusFolderRecord
:
186 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
188 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
190 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
193 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
195 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
203 HFSExtentDescriptor
*dataExtent
;
204 HFSExtentDescriptor
*rsrcExtent
;
206 if ( recordSize
!= sizeof(HFSCatalogFile
) )
208 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
211 cNodeID
= catalogRecord
->hfsFile
.fileID
;
216 // make sure 0 ¾ LEOF ¾ PEOF for both forks
218 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
220 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
222 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
224 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
227 dataExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
228 rsrcExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
231 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
233 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
235 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
242 case kHFSPlusFileRecord
:
245 HFSPlusExtentDescriptor
*dataExtent
;
246 HFSPlusExtentDescriptor
*rsrcExtent
;
248 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
250 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
253 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
258 // make sure 0 ¾ LEOF ¾ PEOF for both forks
260 dataExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
261 rsrcExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
264 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
266 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
268 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
275 case kHFSFolderThreadRecord
:
276 case kHFSFileThreadRecord
:
278 if ( recordSize
!= sizeof(HFSCatalogThread
) )
281 cNodeID
= catalogRecord
->hfsThread
.parentID
;
282 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
285 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
286 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
291 case kHFSPlusFolderThreadRecord
:
292 case kHFSPlusFileThreadRecord
:
294 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
297 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
298 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
301 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
302 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
312 return true; // record appears to be OK