]> git.saurik.com Git - apple/hfs.git/blob - core/BTreeWrapper.c
12ce54dca7079b018816375c6e0d061fb5d2dd65
[apple/hfs.git] / core / BTreeWrapper.c
1 /*
2 * Copyright (c) 2000, 2002, 2005-2015 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 "BTreesPrivate.h"
30 #include <sys/kernel.h>
31 #include <libkern/libkern.h>
32
33
34 // local routines
35 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
36
37 #if DEBUG
38 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize);
39 #endif
40
41 OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, u_int32_t hint, void *newData, u_int16_t dataSize, u_int32_t *newHint)
42 {
43 FSBufferDescriptor btRecord;
44 struct BTreeIterator *iterator = NULL;
45 FCB *fcb;
46 BTreeControlBlock *btcb;
47 OSStatus result;
48
49 iterator = hfs_mallocz(sizeof(struct BTreeIterator));
50
51 fcb = GetFileControlBlock(refNum);
52 btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
53
54 btRecord.bufferAddress = newData;
55 btRecord.itemSize = dataSize;
56 btRecord.itemCount = 1;
57
58 iterator->hint.nodeNum = hint;
59
60 result = CheckBTreeKey((const BTreeKey *) key, btcb);
61 if (result) {
62 goto ErrorExit;
63 }
64
65 BlockMoveData(key, &iterator->key, CalcKeySize(btcb, (const BTreeKey *) key)); //\80\80 should we range check against maxkeylen?
66
67 #if DEBUG
68 if ( !ValidHFSRecord(newData, btcb, dataSize) )
69 DebugStr("ReplaceBTreeRecord: bad record?");
70 #endif
71
72 result = BTReplaceRecord( fcb, iterator, &btRecord, dataSize );
73
74 *newHint = iterator->hint.nodeNum;
75
76 ErrorExit:
77
78 hfs_free(iterator, sizeof(*iterator));
79 return result;
80 }
81
82
83
84 static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
85 {
86 u_int16_t keyLen;
87
88 if ( btcb->attributes & kBTBigKeysMask )
89 keyLen = key->length16;
90 else
91 keyLen = key->length8;
92
93 if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
94 {
95 hfs_debug("CheckBTreeKey: bad key length!");
96 return fsBTInvalidKeyLengthErr;
97 }
98
99 return noErr;
100 }
101
102 #if DEBUG
103
104 static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, u_int16_t recordSize)
105 {
106 u_int32_t cNodeID;
107
108 if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
109 {
110 return ( recordSize == sizeof(HFSPlusExtentRecord) );
111 }
112 #if CONFIG_HFS_STD
113 else if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
114 {
115 return ( recordSize == sizeof(HFSExtentRecord) );
116 }
117 #endif
118
119 else // Catalog record
120 {
121 const CatalogRecord *catalogRecord = (const CatalogRecord*) record;
122
123 switch(catalogRecord->recordType)
124 {
125
126 #if CONFIG_HFS_STD
127 /*
128 * HFS standard File/folder records and File/Folder Thread records
129 * are only valid on configs that support HFS standard.
130 */
131 case kHFSFolderRecord:
132 {
133 if ( recordSize != sizeof(HFSCatalogFolder) )
134 return false;
135 if ( catalogRecord->hfsFolder.flags != 0 )
136 return false;
137 if ( catalogRecord->hfsFolder.valence > 0x7FFF )
138 return false;
139
140 cNodeID = catalogRecord->hfsFolder.folderID;
141
142 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
143 return false;
144 }
145 break;
146
147 case kHFSFileRecord:
148 {
149 const HFSExtentDescriptor *dataExtent;
150 const 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 = (const HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
174 rsrcExtent = (const 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 kHFSFileThreadRecord:
189 case kHFSFolderThreadRecord:
190 {
191 if ( recordSize != sizeof(HFSCatalogThread) )
192 return false;
193
194 cNodeID = catalogRecord->hfsThread.parentID;
195 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
196 return false;
197
198 if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
199 (catalogRecord->hfsThread.nodeName[0] > 31) )
200 return false;
201 }
202 break;
203 #endif
204
205 case kHFSPlusFolderRecord:
206 {
207 if ( recordSize != sizeof(HFSPlusCatalogFolder) )
208 return false;
209 if ( catalogRecord->hfsPlusFolder.flags != 0 )
210 return false;
211 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
212 return false;
213
214 cNodeID = catalogRecord->hfsPlusFolder.folderID;
215
216 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
217 return false;
218 }
219 break;
220
221 case kHFSPlusFileRecord:
222 {
223 // u_int16_t i;
224 const HFSPlusExtentDescriptor *dataExtent;
225 const HFSPlusExtentDescriptor *rsrcExtent;
226
227 if ( recordSize != sizeof(HFSPlusCatalogFile) )
228 return false;
229 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
230 return false;
231
232 cNodeID = catalogRecord->hfsPlusFile.fileID;
233
234 if ( cNodeID < 16 )
235 return false;
236
237 // make sure 0 ¾ LEOF ¾ PEOF for both forks
238
239 dataExtent = (const HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
240 rsrcExtent = (const HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
241
242 #if 0
243 for (i = 0; i < kHFSPlusExtentDensity; ++i)
244 {
245 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
246 return false;
247 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
248 return false;
249 }
250 #endif
251 }
252 break;
253
254 case kHFSPlusFileThreadRecord:
255 case kHFSPlusFolderThreadRecord:
256 {
257 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
258 return false;
259
260 cNodeID = catalogRecord->hfsPlusThread.parentID;
261 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
262 return false;
263
264 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
265 (catalogRecord->hfsPlusThread.nodeName.length > 255) )
266 return false;
267 }
268 break;
269
270 default:
271 return false;
272 }
273 }
274
275 return true; // record appears to be OK
276 }
277
278 #endif // DEBUG