]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/BTreeWrapper.c
xnu-3247.10.11.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / BTreeWrapper.c
1 /*
2 * Copyright (c) 2000, 2002, 2005-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include "../headers/BTreesPrivate.h"
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
32 #include <libkern/libkern.h>
33
34
35 // local routines
36 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
37 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize);
38
39
40 OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, u_int32_t hint, void *newData, u_int16_t dataSize, u_int32_t *newHint)
41 {
42 FSBufferDescriptor btRecord;
43 struct BTreeIterator *iterator = NULL;
44 FCB *fcb;
45 BTreeControlBlock *btcb;
46 OSStatus result;
47
48 MALLOC (iterator, struct BTreeIterator *, sizeof (struct BTreeIterator), M_TEMP, M_WAITOK);
49 if (iterator == NULL) {
50 return memFullErr; //translates to ENOMEM
51 }
52 bzero (iterator, sizeof (*iterator));
53
54 fcb = GetFileControlBlock(refNum);
55 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
56
57 btRecord.bufferAddress = newData;
58 btRecord.itemSize = dataSize;
59 btRecord.itemCount = 1;
60
61 iterator->hint.nodeNum = hint;
62
63 result = CheckBTreeKey((const BTreeKey *) key, btcb);
64 if (result) {
65 goto ErrorExit;
66 }
67
68 BlockMoveData(key, &iterator->key, CalcKeySize(btcb, (const BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
69
70 if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
71 DebugStr("ReplaceBTreeRecord: bad record?");
72
73 result = BTReplaceRecord( fcb, iterator, &btRecord, dataSize );
74
75 *newHint = iterator->hint.nodeNum;
76
77 ErrorExit:
78
79 FREE (iterator, M_TEMP);
80 return result;
81 }
82
83
84
85 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
86 {
87 u_int16_t keyLen;
88
89 if ( btcb->attributes & kBTBigKeysMask )
90 keyLen = key->length16;
91 else
92 keyLen = key->length8;
93
94 if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
95 {
96 if ( DEBUG_BUILD )
97 DebugStr("CheckBTreeKey: bad key length!");
98 return fsBTInvalidKeyLengthErr;
99 }
100
101 return noErr;
102 }
103
104
105 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize)
106 {
107 u_int32_t cNodeID;
108
109 if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
110 {
111 return ( recordSize == sizeof(HFSPlusExtentRecord) );
112 }
113 #if CONFIG_HFS_STD
114 else if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
115 {
116 return ( recordSize == sizeof(HFSExtentRecord) );
117 }
118 #endif
119
120 else // Catalog record
121 {
122 const CatalogRecord *catalogRecord = (const CatalogRecord*) record;
123
124 switch(catalogRecord->recordType)
125 {
126
127 #if CONFIG_HFS_STD
128 /*
129 * HFS standard File/folder records and File/Folder Thread records
130 * are only valid on configs that support HFS standard.
131 */
132 case kHFSFolderRecord:
133 {
134 if ( recordSize != sizeof(HFSCatalogFolder) )
135 return false;
136 if ( catalogRecord->hfsFolder.flags != 0 )
137 return false;
138 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
139 return false;
140
141 cNodeID = catalogRecord->hfsFolder.folderID;
142
143 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
144 return false;
145 }
146 break;
147
148 case kHFSFileRecord:
149 {
150 const HFSExtentDescriptor *dataExtent;
151 const HFSExtentDescriptor *rsrcExtent;
152
153 if ( recordSize != sizeof(HFSCatalogFile) )
154 return false;
155 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
156 return false;
157
158 cNodeID = catalogRecord->hfsFile.fileID;
159
160 if ( cNodeID < 16 )
161 return false;
162
163 // make sure 0 ¾ LEOF ¾ PEOF for both forks
164
165 if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
166 return false;
167 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
168 return false;
169 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
170 return false;
171 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
172 return false;
173
174 dataExtent = (const HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
175 rsrcExtent = (const HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
176
177 #if 0
178 for (i = 0; i < kHFSExtentDensity; ++i)
179 {
180 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
181 return false;
182 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
183 return false;
184 }
185 #endif
186 }
187 break;
188
189 case kHFSFileThreadRecord:
190 case kHFSFolderThreadRecord:
191 {
192 if ( recordSize != sizeof(HFSCatalogThread) )
193 return false;
194
195 cNodeID = catalogRecord->hfsThread.parentID;
196 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
197 return false;
198
199 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
200 (catalogRecord->hfsThread.nodeName[0] > 31) )
201 return false;
202 }
203 break;
204 #endif
205
206 case kHFSPlusFolderRecord:
207 {
208 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
209 return false;
210 if ( catalogRecord->hfsPlusFolder.flags != 0 )
211 return false;
212 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
213 return false;
214
215 cNodeID = catalogRecord->hfsPlusFolder.folderID;
216
217 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
218 return false;
219 }
220 break;
221
222 case kHFSPlusFileRecord:
223 {
224 // u_int16_t i;
225 const HFSPlusExtentDescriptor *dataExtent;
226 const HFSPlusExtentDescriptor *rsrcExtent;
227
228 if ( recordSize != sizeof(HFSPlusCatalogFile) )
229 return false;
230 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
231 return false;
232
233 cNodeID = catalogRecord->hfsPlusFile.fileID;
234
235 if ( cNodeID < 16 )
236 return false;
237
238 // make sure 0 ¾ LEOF ¾ PEOF for both forks
239
240 dataExtent = (const HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
241 rsrcExtent = (const HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
242
243 #if 0
244 for (i = 0; i < kHFSPlusExtentDensity; ++i)
245 {
246 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
247 return false;
248 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
249 return false;
250 }
251 #endif
252 }
253 break;
254
255 case kHFSPlusFileThreadRecord:
256 case kHFSPlusFolderThreadRecord:
257 {
258 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
259 return false;
260
261 cNodeID = catalogRecord->hfsPlusThread.parentID;
262 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
263 return false;
264
265 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
266 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
267 return false;
268 }
269 break;
270
271 default:
272 return false;
273 }
274 }
275
276 return true; // record appears to be OK
277 }