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
33static OSErr	CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
34static Boolean	ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize);
35
36
37
38
39OSErr 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));		//�� 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));	//�� warning, this could overflow user's buffer!!!
85
86		if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
87			DebugStr("\pSearchBTreeRecord: bad record?");
88	}
89
90ErrorExit:
91
92	return result;
93#endif
94}
95
96
97OSErr 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));		//�� 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	//���do we need to invalidate the iterator?
128
129ErrorExit:
130
131	return result;
132}
133
134
135
136static 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
156static 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}
320