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