]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/BTreeWrapper.c
590fd9397fe00d69b3cbac48f00051a9610f82e4
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / BTreeWrapper.c
1 /*
2 * Copyright (c) 2000, 2002, 2005-2008 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 == kHFSExtentKeyMaximumLength )
110 {
111 return ( recordSize == sizeof(HFSExtentRecord) );
112 }
113 else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
114 {
115 return ( recordSize == sizeof(HFSPlusExtentRecord) );
116 }
117 else // Catalog record
118 {
119 const CatalogRecord *catalogRecord = (const CatalogRecord*) record;
120
121 switch(catalogRecord->recordType)
122 {
123 case kHFSFolderRecord:
124 {
125 if ( recordSize != sizeof(HFSCatalogFolder) )
126 return false;
127 if ( catalogRecord->hfsFolder.flags != 0 )
128 return false;
129 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
130 return false;
131
132 cNodeID = catalogRecord->hfsFolder.folderID;
133
134 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
135 return false;
136 }
137 break;
138
139 case kHFSPlusFolderRecord:
140 {
141 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
142 return false;
143 if ( catalogRecord->hfsPlusFolder.flags != 0 )
144 return false;
145 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
146 return false;
147
148 cNodeID = catalogRecord->hfsPlusFolder.folderID;
149
150 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
151 return false;
152 }
153 break;
154
155 case kHFSFileRecord:
156 {
157 // u_int16_t i;
158 HFSExtentDescriptor *dataExtent;
159 HFSExtentDescriptor *rsrcExtent;
160
161 if ( recordSize != sizeof(HFSCatalogFile) )
162 return false;
163 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
164 return false;
165
166 cNodeID = catalogRecord->hfsFile.fileID;
167
168 if ( cNodeID < 16 )
169 return false;
170
171 // make sure 0 ¾ LEOF ¾ PEOF for both forks
172
173 if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
174 return false;
175 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
176 return false;
177 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
178 return false;
179 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
180 return false;
181
182 dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
183 rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
184
185 #if 0
186 for (i = 0; i < kHFSExtentDensity; ++i)
187 {
188 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
189 return false;
190 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
191 return false;
192 }
193 #endif
194 }
195 break;
196
197 case kHFSPlusFileRecord:
198 {
199 // u_int16_t i;
200 HFSPlusExtentDescriptor *dataExtent;
201 HFSPlusExtentDescriptor *rsrcExtent;
202
203 if ( recordSize != sizeof(HFSPlusCatalogFile) )
204 return false;
205 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
206 return false;
207
208 cNodeID = catalogRecord->hfsPlusFile.fileID;
209
210 if ( cNodeID < 16 )
211 return false;
212
213 // make sure 0 ¾ LEOF ¾ PEOF for both forks
214
215 dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
216 rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
217
218 #if 0
219 for (i = 0; i < kHFSPlusExtentDensity; ++i)
220 {
221 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
222 return false;
223 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
224 return false;
225 }
226 #endif
227 }
228 break;
229
230 case kHFSFolderThreadRecord:
231 case kHFSFileThreadRecord:
232 {
233 if ( recordSize != sizeof(HFSCatalogThread) )
234 return false;
235
236 cNodeID = catalogRecord->hfsThread.parentID;
237 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
238 return false;
239
240 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
241 (catalogRecord->hfsThread.nodeName[0] > 31) )
242 return false;
243 }
244 break;
245
246 case kHFSPlusFolderThreadRecord:
247 case kHFSPlusFileThreadRecord:
248 {
249 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
250 return false;
251
252 cNodeID = catalogRecord->hfsPlusThread.parentID;
253 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
254 return false;
255
256 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
257 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
258 return false;
259 }
260 break;
261
262 default:
263 return false;
264 }
265 }
266
267 return true; // record appears to be OK
268 }