2 * Copyright (c) 2000, 2002, 2005-2013 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
== kHFSPlusExtentKeyMaximumLength
)
111 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
114 else if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
116 return ( recordSize
== sizeof(HFSExtentRecord
) );
120 else // Catalog record
122 const CatalogRecord
*catalogRecord
= (const CatalogRecord
*) record
;
124 switch(catalogRecord
->recordType
)
129 * HFS standard File/folder records and File/Folder Thread records
130 * are only valid on configs that support HFS standard.
132 case kHFSFolderRecord
:
134 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
136 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
138 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
141 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
143 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
150 const HFSExtentDescriptor
*dataExtent
;
151 const HFSExtentDescriptor
*rsrcExtent
;
153 if ( recordSize
!= sizeof(HFSCatalogFile
) )
155 if ( (catalogRecord
->hfsFile
.flags
& ~(0x83)) != 0 )
158 cNodeID
= catalogRecord
->hfsFile
.fileID
;
163 // make sure 0 ¾ LEOF ¾ PEOF for both forks
165 if ( catalogRecord
->hfsFile
.dataLogicalSize
< 0 )
167 if ( catalogRecord
->hfsFile
.dataPhysicalSize
< catalogRecord
->hfsFile
.dataLogicalSize
)
169 if ( catalogRecord
->hfsFile
.rsrcLogicalSize
< 0 )
171 if ( catalogRecord
->hfsFile
.rsrcPhysicalSize
< catalogRecord
->hfsFile
.rsrcLogicalSize
)
174 dataExtent
= (const HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
175 rsrcExtent
= (const HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.rsrcExtents
;
178 for (i
= 0; i
< kHFSExtentDensity
; ++i
)
180 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
182 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
189 case kHFSFileThreadRecord
:
190 case kHFSFolderThreadRecord
:
192 if ( recordSize
!= sizeof(HFSCatalogThread
) )
195 cNodeID
= catalogRecord
->hfsThread
.parentID
;
196 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
199 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
200 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
206 case kHFSPlusFolderRecord
:
208 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
210 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
212 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
215 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
217 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
222 case kHFSPlusFileRecord
:
225 const HFSPlusExtentDescriptor
*dataExtent
;
226 const HFSPlusExtentDescriptor
*rsrcExtent
;
228 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
230 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
233 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
238 // make sure 0 ¾ LEOF ¾ PEOF for both forks
240 dataExtent
= (const HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
241 rsrcExtent
= (const HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
244 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
246 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
248 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
255 case kHFSPlusFileThreadRecord
:
256 case kHFSPlusFolderThreadRecord
:
258 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
261 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
262 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
265 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
266 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
276 return true; // record appears to be OK