2 * Copyright (c) 2000, 2002, 2005-2015 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 "BTreesPrivate.h"
30 #include <sys/kernel.h>
31 #include <libkern/libkern.h>
35 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
);
38 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
);
41 OSErr
ReplaceBTreeRecord(FileReference refNum
, const void* key
, u_int32_t hint
, void *newData
, u_int16_t dataSize
, u_int32_t
*newHint
)
43 FSBufferDescriptor btRecord
;
44 struct BTreeIterator
*iterator
= NULL
;
46 BTreeControlBlock
*btcb
;
49 iterator
= hfs_mallocz(sizeof(struct BTreeIterator
));
51 fcb
= GetFileControlBlock(refNum
);
52 btcb
= (BTreeControlBlock
*) fcb
->fcbBTCBPtr
;
54 btRecord
.bufferAddress
= newData
;
55 btRecord
.itemSize
= dataSize
;
56 btRecord
.itemCount
= 1;
58 iterator
->hint
.nodeNum
= hint
;
60 result
= CheckBTreeKey((const BTreeKey
*) key
, btcb
);
65 BlockMoveData(key
, &iterator
->key
, CalcKeySize(btcb
, (const BTreeKey
*) key
)); //\80\80 should we range check against maxkeylen?
68 if ( !ValidHFSRecord(newData
, btcb
, dataSize
) )
69 DebugStr("ReplaceBTreeRecord: bad record?");
72 result
= BTReplaceRecord( fcb
, iterator
, &btRecord
, dataSize
);
74 *newHint
= iterator
->hint
.nodeNum
;
78 hfs_free(iterator
, sizeof(*iterator
));
84 static OSErr
CheckBTreeKey(const BTreeKey
*key
, const BTreeControlBlock
*btcb
)
88 if ( btcb
->attributes
& kBTBigKeysMask
)
89 keyLen
= key
->length16
;
91 keyLen
= key
->length8
;
93 if ( (keyLen
< 6) || (keyLen
> btcb
->maxKeyLength
) )
95 hfs_debug("CheckBTreeKey: bad key length!");
96 return fsBTInvalidKeyLengthErr
;
104 static Boolean
ValidHFSRecord(const void *record
, const BTreeControlBlock
*btcb
, u_int16_t recordSize
)
108 if (btcb
->maxKeyLength
== kHFSPlusExtentKeyMaximumLength
)
110 return ( recordSize
== sizeof(HFSPlusExtentRecord
) );
113 else if ( btcb
->maxKeyLength
== kHFSExtentKeyMaximumLength
)
115 return ( recordSize
== sizeof(HFSExtentRecord
) );
119 else // Catalog record
121 const CatalogRecord
*catalogRecord
= (const CatalogRecord
*) record
;
123 switch(catalogRecord
->recordType
)
128 * HFS standard File/folder records and File/Folder Thread records
129 * are only valid on configs that support HFS standard.
131 case kHFSFolderRecord
:
133 if ( recordSize
!= sizeof(HFSCatalogFolder
) )
135 if ( catalogRecord
->hfsFolder
.flags
!= 0 )
137 if ( catalogRecord
->hfsFolder
.valence
> 0x7FFF )
140 cNodeID
= catalogRecord
->hfsFolder
.folderID
;
142 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
149 const HFSExtentDescriptor
*dataExtent
;
150 const 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
= (const HFSExtentDescriptor
*) &catalogRecord
->hfsFile
.dataExtents
;
174 rsrcExtent
= (const 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 kHFSFileThreadRecord
:
189 case kHFSFolderThreadRecord
:
191 if ( recordSize
!= sizeof(HFSCatalogThread
) )
194 cNodeID
= catalogRecord
->hfsThread
.parentID
;
195 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
198 if ( (catalogRecord
->hfsThread
.nodeName
[0] == 0) ||
199 (catalogRecord
->hfsThread
.nodeName
[0] > 31) )
205 case kHFSPlusFolderRecord
:
207 if ( recordSize
!= sizeof(HFSPlusCatalogFolder
) )
209 if ( catalogRecord
->hfsPlusFolder
.flags
!= 0 )
211 if ( catalogRecord
->hfsPlusFolder
.valence
> 0x7FFF )
214 cNodeID
= catalogRecord
->hfsPlusFolder
.folderID
;
216 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
221 case kHFSPlusFileRecord
:
224 const HFSPlusExtentDescriptor
*dataExtent
;
225 const HFSPlusExtentDescriptor
*rsrcExtent
;
227 if ( recordSize
!= sizeof(HFSPlusCatalogFile
) )
229 if ( (catalogRecord
->hfsPlusFile
.flags
& ~(0x83)) != 0 )
232 cNodeID
= catalogRecord
->hfsPlusFile
.fileID
;
237 // make sure 0 ¾ LEOF ¾ PEOF for both forks
239 dataExtent
= (const HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.dataFork
.extents
;
240 rsrcExtent
= (const HFSPlusExtentDescriptor
*) &catalogRecord
->hfsPlusFile
.resourceFork
.extents
;
243 for (i
= 0; i
< kHFSPlusExtentDensity
; ++i
)
245 if ( (dataExtent
[i
].blockCount
> 0) && (dataExtent
[i
].startBlock
== 0) )
247 if ( (rsrcExtent
[i
].blockCount
> 0) && (rsrcExtent
[i
].startBlock
== 0) )
254 case kHFSPlusFileThreadRecord
:
255 case kHFSPlusFolderThreadRecord
:
257 if ( recordSize
> sizeof(HFSPlusCatalogThread
) || recordSize
< (sizeof(HFSPlusCatalogThread
) - sizeof(HFSUniStr255
)))
260 cNodeID
= catalogRecord
->hfsPlusThread
.parentID
;
261 if ( (cNodeID
== 0) || (cNodeID
< 16 && cNodeID
> 2) )
264 if ( (catalogRecord
->hfsPlusThread
.nodeName
.length
== 0) ||
265 (catalogRecord
->hfsPlusThread
.nodeName
.length
> 255) )
275 return true; // record appears to be OK