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