]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Misc/BTreeWrapper.c
5ce31fd3c572e6ba303be27b2386d81de6e90528
[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
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 OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, u_int32_t hint, void *newData, u_int16_t dataSize, u_int32_t *newHint)
38 {
39 FSBufferDescriptor btRecord;
40 BTreeIterator iterator;
41 FCB *fcb;
42 BTreeControlBlock *btcb;
43 OSStatus result;
44
45
46 fcb = GetFileControlBlock(refNum);
47 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
48
49 btRecord.bufferAddress = newData;
50 btRecord.itemSize = dataSize;
51 btRecord.itemCount = 1;
52
53 iterator.hint.nodeNum = hint;
54
55 result = CheckBTreeKey((const BTreeKey *) key, btcb);
56 ExitOnError(result);
57
58 BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (const BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
59
60 if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
61 DebugStr("ReplaceBTreeRecord: bad record?");
62
63 result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize );
64
65 *newHint = iterator.hint.nodeNum;
66
67 //\80\80 do we need to invalidate the iterator?
68
69 ErrorExit:
70
71 return result;
72 }
73
74
75
76 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
77 {
78 u_int16_t keyLen;
79
80 if ( btcb->attributes & kBTBigKeysMask )
81 keyLen = key->length16;
82 else
83 keyLen = key->length8;
84
85 if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
86 {
87 if ( DEBUG_BUILD )
88 DebugStr("CheckBTreeKey: bad key length!");
89 return fsBTInvalidKeyLengthErr;
90 }
91
92 return noErr;
93 }
94
95
96 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize)
97 {
98 u_int32_t cNodeID;
99
100 if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
101 {
102 return ( recordSize == sizeof(HFSExtentRecord) );
103 }
104 else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
105 {
106 return ( recordSize == sizeof(HFSPlusExtentRecord) );
107 }
108 else // Catalog record
109 {
110 const CatalogRecord *catalogRecord = (const CatalogRecord*) record;
111
112 switch(catalogRecord->recordType)
113 {
114 case kHFSFolderRecord:
115 {
116 if ( recordSize != sizeof(HFSCatalogFolder) )
117 return false;
118 if ( catalogRecord->hfsFolder.flags != 0 )
119 return false;
120 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
121 return false;
122
123 cNodeID = catalogRecord->hfsFolder.folderID;
124
125 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
126 return false;
127 }
128 break;
129
130 case kHFSPlusFolderRecord:
131 {
132 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
133 return false;
134 if ( catalogRecord->hfsPlusFolder.flags != 0 )
135 return false;
136 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
137 return false;
138
139 cNodeID = catalogRecord->hfsPlusFolder.folderID;
140
141 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
142 return false;
143 }
144 break;
145
146 case kHFSFileRecord:
147 {
148 // u_int16_t i;
149 HFSExtentDescriptor *dataExtent;
150 HFSExtentDescriptor *rsrcExtent;
151
152 if ( recordSize != sizeof(HFSCatalogFile) )
153 return false;
154 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
155 return false;
156
157 cNodeID = catalogRecord->hfsFile.fileID;
158
159 if ( cNodeID < 16 )
160 return false;
161
162 // make sure 0 ¾ LEOF ¾ PEOF for both forks
163
164 if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
165 return false;
166 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
167 return false;
168 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
169 return false;
170 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
171 return false;
172
173 dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
174 rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
175
176 #if 0
177 for (i = 0; i < kHFSExtentDensity; ++i)
178 {
179 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
180 return false;
181 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
182 return false;
183 }
184 #endif
185 }
186 break;
187
188 case kHFSPlusFileRecord:
189 {
190 // u_int16_t i;
191 HFSPlusExtentDescriptor *dataExtent;
192 HFSPlusExtentDescriptor *rsrcExtent;
193
194 if ( recordSize != sizeof(HFSPlusCatalogFile) )
195 return false;
196 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
197 return false;
198
199 cNodeID = catalogRecord->hfsPlusFile.fileID;
200
201 if ( cNodeID < 16 )
202 return false;
203
204 // make sure 0 ¾ LEOF ¾ PEOF for both forks
205
206 dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
207 rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
208
209 #if 0
210 for (i = 0; i < kHFSPlusExtentDensity; ++i)
211 {
212 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
213 return false;
214 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
215 return false;
216 }
217 #endif
218 }
219 break;
220
221 case kHFSFolderThreadRecord:
222 case kHFSFileThreadRecord:
223 {
224 if ( recordSize != sizeof(HFSCatalogThread) )
225 return false;
226
227 cNodeID = catalogRecord->hfsThread.parentID;
228 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
229 return false;
230
231 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
232 (catalogRecord->hfsThread.nodeName[0] > 31) )
233 return false;
234 }
235 break;
236
237 case kHFSPlusFolderThreadRecord:
238 case kHFSPlusFileThreadRecord:
239 {
240 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
241 return false;
242
243 cNodeID = catalogRecord->hfsPlusThread.parentID;
244 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
245 return false;
246
247 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
248 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
249 return false;
250 }
251 break;
252
253 default:
254 return false;
255 }
256 }
257
258 return true; // record appears to be OK
259 }