]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/BTreeWrapper.c
f0f21ea9dc8587f4cd5f643c5dfa57b5b60a078e
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / BTreeWrapper.c
1 /*
2 * Copyright (c) 2000,2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30
31 #include "../headers/BTreesPrivate.h"
32
33
34 // local routines
35 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
36 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize);
37
38
39
40
41 OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint)
42 {
43 panic("SearchBTreeRecord is dead code!");
44 return (-1);
45 #if 0
46 FSBufferDescriptor btRecord;
47 BTreeIterator searchIterator;
48 FCB *fcb;
49 BTreeControlBlock *btcb;
50 OSStatus result;
51
52
53 fcb = GetFileControlBlock(refNum);
54 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
55
56 btRecord.bufferAddress = data;
57 btRecord.itemCount = 1;
58 if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
59 btRecord.itemSize = sizeof(HFSExtentRecord);
60 else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
61 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
62 else
63 btRecord.itemSize = sizeof(CatalogRecord);
64
65 searchIterator.hint.writeCount = 0; // clear these out for debugging...
66 searchIterator.hint.reserved1 = 0;
67 searchIterator.hint.reserved2 = 0;
68
69 searchIterator.hint.nodeNum = hint;
70 searchIterator.hint.index = 0;
71
72 result = CheckBTreeKey((BTreeKey *) key, btcb);
73 ExitOnError(result);
74
75 BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
76
77 result = BTSearchRecord( fcb, &searchIterator, &btRecord, dataSize, &searchIterator );
78
79 if (result == noErr)
80 {
81 *newHint = searchIterator.hint.nodeNum;
82
83 result = CheckBTreeKey(&searchIterator.key, btcb);
84 ExitOnError(result);
85
86 BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //\80\80 warning, this could overflow user's buffer!!!
87
88 if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
89 DebugStr("\pSearchBTreeRecord: bad record?");
90 }
91
92 ErrorExit:
93
94 return result;
95 #endif
96 }
97
98
99 OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void *newData, UInt16 dataSize, UInt32 *newHint)
100 {
101 FSBufferDescriptor btRecord;
102 BTreeIterator iterator;
103 FCB *fcb;
104 BTreeControlBlock *btcb;
105 OSStatus result;
106
107
108 fcb = GetFileControlBlock(refNum);
109 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
110
111 btRecord.bufferAddress = newData;
112 btRecord.itemSize = dataSize;
113 btRecord.itemCount = 1;
114
115 iterator.hint.nodeNum = hint;
116
117 result = CheckBTreeKey((BTreeKey *) key, btcb);
118 ExitOnError(result);
119
120 BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
121
122 if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
123 DebugStr("\pReplaceBTreeRecord: bad record?");
124
125 result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize );
126
127 *newHint = iterator.hint.nodeNum;
128
129 //\80\80 do we need to invalidate the iterator?
130
131 ErrorExit:
132
133 return result;
134 }
135
136
137
138 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
139 {
140 UInt16 keyLen;
141
142 if ( btcb->attributes & kBTBigKeysMask )
143 keyLen = key->length16;
144 else
145 keyLen = key->length8;
146
147 if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
148 {
149 if ( DEBUG_BUILD )
150 DebugStr("\pCheckBTreeKey: bad key length!");
151 return fsBTInvalidKeyLengthErr;
152 }
153
154 return noErr;
155 }
156
157
158 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize)
159 {
160 UInt32 cNodeID;
161
162 if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
163 {
164 return ( recordSize == sizeof(HFSExtentRecord) );
165 }
166 else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
167 {
168 return ( recordSize == sizeof(HFSPlusExtentRecord) );
169 }
170 else // Catalog record
171 {
172 CatalogRecord *catalogRecord = (CatalogRecord*) record;
173
174 switch(catalogRecord->recordType)
175 {
176 case kHFSFolderRecord:
177 {
178 if ( recordSize != sizeof(HFSCatalogFolder) )
179 return false;
180 if ( catalogRecord->hfsFolder.flags != 0 )
181 return false;
182 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
183 return false;
184
185 cNodeID = catalogRecord->hfsFolder.folderID;
186
187 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
188 return false;
189 }
190 break;
191
192 case kHFSPlusFolderRecord:
193 {
194 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
195 return false;
196 if ( catalogRecord->hfsPlusFolder.flags != 0 )
197 return false;
198 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
199 return false;
200
201 cNodeID = catalogRecord->hfsPlusFolder.folderID;
202
203 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
204 return false;
205 }
206 break;
207
208 case kHFSFileRecord:
209 {
210 // UInt16 i;
211 HFSExtentDescriptor *dataExtent;
212 HFSExtentDescriptor *rsrcExtent;
213
214 if ( recordSize != sizeof(HFSCatalogFile) )
215 return false;
216 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
217 return false;
218
219 cNodeID = catalogRecord->hfsFile.fileID;
220
221 if ( cNodeID < 16 )
222 return false;
223
224 // make sure 0 ¾ LEOF ¾ PEOF for both forks
225
226 if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
227 return false;
228 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
229 return false;
230 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
231 return false;
232 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
233 return false;
234
235 dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
236 rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
237
238 #if 0
239 for (i = 0; i < kHFSExtentDensity; ++i)
240 {
241 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
242 return false;
243 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
244 return false;
245 }
246 #endif
247 }
248 break;
249
250 case kHFSPlusFileRecord:
251 {
252 // UInt16 i;
253 HFSPlusExtentDescriptor *dataExtent;
254 HFSPlusExtentDescriptor *rsrcExtent;
255
256 if ( recordSize != sizeof(HFSPlusCatalogFile) )
257 return false;
258 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
259 return false;
260
261 cNodeID = catalogRecord->hfsPlusFile.fileID;
262
263 if ( cNodeID < 16 )
264 return false;
265
266 // make sure 0 ¾ LEOF ¾ PEOF for both forks
267
268 dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
269 rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
270
271 #if 0
272 for (i = 0; i < kHFSPlusExtentDensity; ++i)
273 {
274 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
275 return false;
276 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
277 return false;
278 }
279 #endif
280 }
281 break;
282
283 case kHFSFolderThreadRecord:
284 case kHFSFileThreadRecord:
285 {
286 if ( recordSize != sizeof(HFSCatalogThread) )
287 return false;
288
289 cNodeID = catalogRecord->hfsThread.parentID;
290 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
291 return false;
292
293 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
294 (catalogRecord->hfsThread.nodeName[0] > 31) )
295 return false;
296 }
297 break;
298
299 case kHFSPlusFolderThreadRecord:
300 case kHFSPlusFileThreadRecord:
301 {
302 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
303 return false;
304
305 cNodeID = catalogRecord->hfsPlusThread.parentID;
306 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
307 return false;
308
309 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
310 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
311 return false;
312 }
313 break;
314
315 default:
316 return false;
317 }
318 }
319
320 return true; // record appears to be OK
321 }