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"
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
32 #include <libkern/libkern.h>
36 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
37 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
);
40 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, u_int32_t hint
, void *newData
, u_int16_t dataSize
, u_int32_t
*newHint
)
42 FSBufferDescriptor btRecord
;
43 struct BTreeIterator
*iterator
= NULL
;
45 BTreeControlBlock
*btcb
;
48 MALLOC (iterator
, struct BTreeIterator
*, sizeof (struct BTreeIterator
), M_TEMP
, M_WAITOK
);
49 if (iterator
== NULL
) {
50 return memFullErr
; //translates to ENOMEM
52 bzero (iterator
, sizeof (*iterator
));
54 fcb
= GetFileControlBlock(refNum
);
55 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
57 btRecord
.bufferAddress
= newData
;
58 btRecord
.itemSize
= dataSize
;
59 btRecord
.itemCount
= 1;
61 iterator
->hint
.nodeNum
= hint
;
63 result
= CheckBTreeKey((const BTreeKey
*) key
, btcb
);
68 BlockMoveData(key
, &iterator
->key
, CalcKeySize(btcb
, (const BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
70 if ( DEBUG_BUILD
&& !ValidHFSRecord(newData
, btcb
, dataSize
) )
71 DebugStr("ReplaceBTreeRecord: bad record?");
73 result
= BTReplaceRecord( fcb
, iterator
, &btRecord
, dataSize
);
75 *newHint
= iterator
->hint
.nodeNum
;
79 FREE (iterator
, M_TEMP
);
85 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
89 if ( btcb
->attributes
& kBTBigKeysMask
)
90 keyLen
= key
->length16
;
92 keyLen
= key
->length8
;
94 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
97 DebugStr("CheckBTreeKey: bad key length!");
98 return fsBTInvalidKeyLengthErr
;
105 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
)
109 if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
111 return ( recordSize
== sizeof(HFSExtentRecord
) );
113 else if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
115 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
117 else // Catalog record
119 const CatalogRecord
*catalogRecord
= (const CatalogRecord
*) record
;
121 switch(catalogRecord
->recordType
)
123 case kHFSFolderRecord
:
125 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
127 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
129 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
132 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
134 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
139 case kHFSPlusFolderRecord
:
141 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
143 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
145 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
148 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
150 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
158 HFSExtentDescriptor
*dataExtent
;
159 HFSExtentDescriptor
*rsrcExtent
;
161 if ( recordSize
!= sizeof(HFSCatalogFile
) )
163 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
166 cNodeID
= catalogRecord
->hfsFile
.fileID
;
171 // make sure 0 ¾ LEOF ¾ PEOF for both forks
173 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
175 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
177 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
179 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
182 dataExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
183 rsrcExtent
= (HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
186 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
188 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
190 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
197 case kHFSPlusFileRecord
:
200 HFSPlusExtentDescriptor
*dataExtent
;
201 HFSPlusExtentDescriptor
*rsrcExtent
;
203 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
205 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
208 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
213 // make sure 0 ¾ LEOF ¾ PEOF for both forks
215 dataExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
216 rsrcExtent
= (HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
219 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
221 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
223 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
230 case kHFSFolderThreadRecord
:
231 case kHFSFileThreadRecord
:
233 if ( recordSize
!= sizeof(HFSCatalogThread
) )
236 cNodeID
= catalogRecord
->hfsThread
.parentID
;
237 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
240 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
241 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
246 case kHFSPlusFolderThreadRecord
:
247 case kHFSPlusFileThreadRecord
:
249 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
252 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
253 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
256 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
257 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
267 return true; // record appears to be OK