]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/BTreeWrapper.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / BTreeWrapper.c
1 /*
2 * Copyright (c) 2000, 2002, 2005 Apple Computer, 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
31
32 // local routines
33 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
34 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize);
35
36
37
38
39 OSErr SearchBTreeRecord(__unused FileReference refNum, __unused const void* key, __unused u_int32_t hint, __unused void* foundKey, __unused void* data, __unused u_int16_t *dataSize, __unused u_int32_t *newHint)
40 {
41 panic("SearchBTreeRecord is dead code!");
42 return (-1);
43 #if 0
44 FSBufferDescriptor btRecord;
45 BTreeIterator searchIterator;
46 FCB *fcb;
47 BTreeControlBlock *btcb;
48 OSStatus result;
49
50
51 fcb = GetFileControlBlock(refNum);
52 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
53
54 btRecord.bufferAddress = data;
55 btRecord.itemCount = 1;
56 if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
57 btRecord.itemSize = sizeof(HFSExtentRecord);
58 else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
59 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
60 else
61 btRecord.itemSize = sizeof(CatalogRecord);
62
63 searchIterator.hint.writeCount = 0; // clear these out for debugging...
64 searchIterator.hint.reserved1 = 0;
65 searchIterator.hint.reserved2 = 0;
66
67 searchIterator.hint.nodeNum = hint;
68 searchIterator.hint.index = 0;
69
70 result = CheckBTreeKey((BTreeKey *) key, btcb);
71 ExitOnError(result);
72
73 BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
74
75 result = BTSearchRecord( fcb, &searchIterator, &btRecord, dataSize, &searchIterator );
76
77 if (result == noErr)
78 {
79 *newHint = searchIterator.hint.nodeNum;
80
81 result = CheckBTreeKey(&searchIterator.key, btcb);
82 ExitOnError(result);
83
84 BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //\80\80 warning, this could overflow user's buffer!!!
85
86 if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
87 DebugStr("\pSearchBTreeRecord: bad record?");
88 }
89
90 ErrorExit:
91
92 return result;
93 #endif
94 }
95
96
97 OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, u_int32_t hint, void *newData, u_int16_t dataSize, u_int32_t *newHint)
98 {
99 FSBufferDescriptor btRecord;
100 BTreeIterator iterator;
101 FCB *fcb;
102 BTreeControlBlock *btcb;
103 OSStatus result;
104
105
106 fcb = GetFileControlBlock(refNum);
107 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
108
109 btRecord.bufferAddress = newData;
110 btRecord.itemSize = dataSize;
111 btRecord.itemCount = 1;
112
113 iterator.hint.nodeNum = hint;
114
115 result = CheckBTreeKey((const BTreeKey *) key, btcb);
116 ExitOnError(result);
117
118 BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (const BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
119
120 if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
121 DebugStr("\pReplaceBTreeRecord: bad record?");
122
123 result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize );
124
125 *newHint = iterator.hint.nodeNum;
126
127 //\80\80 do we need to invalidate the iterator?
128
129 ErrorExit:
130
131 return result;
132 }
133
134
135
136 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
137 {
138 u_int16_t keyLen;
139
140 if ( btcb->attributes & kBTBigKeysMask )
141 keyLen = key->length16;
142 else
143 keyLen = key->length8;
144
145 if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
146 {
147 if ( DEBUG_BUILD )
148 DebugStr("\pCheckBTreeKey: bad key length!");
149 return fsBTInvalidKeyLengthErr;
150 }
151
152 return noErr;
153 }
154
155
156 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize)
157 {
158 u_int32_t cNodeID;
159
160 if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
161 {
162 return ( recordSize == sizeof(HFSExtentRecord) );
163 }
164 else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
165 {
166 return ( recordSize == sizeof(HFSPlusExtentRecord) );
167 }
168 else // Catalog record
169 {
170 const CatalogRecord *catalogRecord = (const CatalogRecord*) record;
171
172 switch(catalogRecord->recordType)
173 {
174 case kHFSFolderRecord:
175 {
176 if ( recordSize != sizeof(HFSCatalogFolder) )
177 return false;
178 if ( catalogRecord->hfsFolder.flags != 0 )
179 return false;
180 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
181 return false;
182
183 cNodeID = catalogRecord->hfsFolder.folderID;
184
185 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
186 return false;
187 }
188 break;
189
190 case kHFSPlusFolderRecord:
191 {
192 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
193 return false;
194 if ( catalogRecord->hfsPlusFolder.flags != 0 )
195 return false;
196 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
197 return false;
198
199 cNodeID = catalogRecord->hfsPlusFolder.folderID;
200
201 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
202 return false;
203 }
204 break;
205
206 case kHFSFileRecord:
207 {
208 // u_int16_t i;
209 HFSExtentDescriptor *dataExtent;
210 HFSExtentDescriptor *rsrcExtent;
211
212 if ( recordSize != sizeof(HFSCatalogFile) )
213 return false;
214 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
215 return false;
216
217 cNodeID = catalogRecord->hfsFile.fileID;
218
219 if ( cNodeID < 16 )
220 return false;
221
222 // make sure 0 ¾ LEOF ¾ PEOF for both forks
223
224 if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
225 return false;
226 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
227 return false;
228 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
229 return false;
230 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
231 return false;
232
233 dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
234 rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
235
236 #if 0
237 for (i = 0; i < kHFSExtentDensity; ++i)
238 {
239 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
240 return false;
241 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
242 return false;
243 }
244 #endif
245 }
246 break;
247
248 case kHFSPlusFileRecord:
249 {
250 // u_int16_t i;
251 HFSPlusExtentDescriptor *dataExtent;
252 HFSPlusExtentDescriptor *rsrcExtent;
253
254 if ( recordSize != sizeof(HFSPlusCatalogFile) )
255 return false;
256 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
257 return false;
258
259 cNodeID = catalogRecord->hfsPlusFile.fileID;
260
261 if ( cNodeID < 16 )
262 return false;
263
264 // make sure 0 ¾ LEOF ¾ PEOF for both forks
265
266 dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
267 rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
268
269 #if 0
270 for (i = 0; i < kHFSPlusExtentDensity; ++i)
271 {
272 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
273 return false;
274 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
275 return false;
276 }
277 #endif
278 }
279 break;
280
281 case kHFSFolderThreadRecord:
282 case kHFSFileThreadRecord:
283 {
284 if ( recordSize != sizeof(HFSCatalogThread) )
285 return false;
286
287 cNodeID = catalogRecord->hfsThread.parentID;
288 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
289 return false;
290
291 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
292 (catalogRecord->hfsThread.nodeName[0] > 31) )
293 return false;
294 }
295 break;
296
297 case kHFSPlusFolderThreadRecord:
298 case kHFSPlusFileThreadRecord:
299 {
300 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
301 return false;
302
303 cNodeID = catalogRecord->hfsPlusThread.parentID;
304 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
305 return false;
306
307 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
308 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
309 return false;
310 }
311 break;
312
313 default:
314 return false;
315 }
316 }
317
318 return true; // record appears to be OK
319 }