2 * Copyright (c) 2000, 2002, 2005-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include "../headers/BTreesPrivate.h"
33 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
34 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
);
37 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, u_int32_t hint
, void *newData
, u_int16_t dataSize
, u_int32_t
*newHint
)
39 FSBufferDescriptor btRecord
;
40 BTreeIterator iterator
;
42 BTreeControlBlock
*btcb
;
46 fcb
= GetFileControlBlock(refNum
);
47 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
49 btRecord
.bufferAddress
= newData
;
50 btRecord
.itemSize
= dataSize
;
51 btRecord
.itemCount
= 1;
53 iterator
.hint
.nodeNum
= hint
;
55 result
= CheckBTreeKey((const BTreeKey
*) key
, btcb
);
58 BlockMoveData(key
, &iterator
.key
, CalcKeySize(btcb
, (const BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
60 if ( DEBUG_BUILD
&& !ValidHFSRecord(newData
, btcb
, dataSize
) )
61 DebugStr("ReplaceBTreeRecord: bad record?");
63 result
= BTReplaceRecord( fcb
, &iterator
, &btRecord
, dataSize
);
65 *newHint
= iterator
.hint
.nodeNum
;
67 //\80\80 do we need to invalidate the iterator?
76 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
80 if ( btcb
->attributes
& kBTBigKeysMask
)
81 keyLen
= key
->length16
;
83 keyLen
= key
->length8
;
85 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
88 DebugStr("CheckBTreeKey: bad key length!");
89 return fsBTInvalidKeyLengthErr
;
96 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
)
100 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
102 return ( recordSize
== sizeof(HFSExtentRecord
) );
104 else if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
106 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
108 else // Catalog record
110 const CatalogRecord
*catalogRecord
= (const CatalogRecord
*) record
;
112 switch(catalogRecord
->recordType
)
114 case kHFSFolderRecord
:
116 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
118 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
120 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
123 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
125 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
130 case kHFSPlusFolderRecord
:
132 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
134 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
136 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
139 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
141 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
149 HFSExtentDescriptor
*dataExtent
;
150 HFSExtentDescriptor
*rsrcExtent
;
152 if ( recordSize
!= sizeof(HFSCatalogFile
) )
154 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
157 cNodeID
= catalogRecord
->hfsFile
.fileID
;
162 // make sure 0 ¾ LEOF ¾ PEOF for both forks
164 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
166 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
168 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
170 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
173 dataExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
174 rsrcExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
177 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
179 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
181 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
188 case kHFSPlusFileRecord
:
191 HFSPlusExtentDescriptor
*dataExtent
;
192 HFSPlusExtentDescriptor
*rsrcExtent
;
194 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
196 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
199 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
204 // make sure 0 ¾ LEOF ¾ PEOF for both forks
206 dataExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
207 rsrcExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
210 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
212 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
214 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
221 case kHFSFolderThreadRecord
:
222 case kHFSFileThreadRecord
:
224 if ( recordSize
!= sizeof(HFSCatalogThread
) )
227 cNodeID
= catalogRecord
->hfsThread
.parentID
;
228 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
231 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
232 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
237 case kHFSPlusFolderThreadRecord
:
238 case kHFSPlusFileThreadRecord
:
240 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
243 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
244 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
247 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
248 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
258 return true; // record appears to be OK