1/* 2 * Copyright (c) 2000, 2002, 2005-2013 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 == kHFSPlusExtentKeyMaximumLength ) 110 { 111 return ( recordSize == sizeof(HFSPlusExtentRecord) ); 112 } 113#if CONFIG_HFS_STD 114 else if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength ) 115 { 116 return ( recordSize == sizeof(HFSExtentRecord) ); 117 } 118#endif 119 120 else // Catalog record 121 { 122 const CatalogRecord *catalogRecord = (const CatalogRecord*) record; 123 124 switch(catalogRecord->recordType) 125 { 126 127#if CONFIG_HFS_STD 128 /* 129 * HFS standard File/folder records and File/Folder Thread records 130 * are only valid on configs that support HFS standard. 131 */ 132 case kHFSFolderRecord: 133 { 134 if ( recordSize != sizeof(HFSCatalogFolder) ) 135 return false; 136 if ( catalogRecord->hfsFolder.flags != 0 ) 137 return false; 138 if ( catalogRecord->hfsFolder.valence > 0x7FFF ) 139 return false; 140 141 cNodeID = catalogRecord->hfsFolder.folderID; 142 143 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) 144 return false; 145 } 146 break; 147 148 case kHFSFileRecord: 149 { 150 HFSExtentDescriptor *dataExtent; 151 HFSExtentDescriptor *rsrcExtent; 152 153 if ( recordSize != sizeof(HFSCatalogFile) ) 154 return false; 155 if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 ) 156 return false; 157 158 cNodeID = catalogRecord->hfsFile.fileID; 159 160 if ( cNodeID < 16 ) 161 return false; 162 163 // make sure 0 � LEOF � PEOF for both forks 164 165 if ( catalogRecord->hfsFile.dataLogicalSize < 0 ) 166 return false; 167 if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize ) 168 return false; 169 if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 ) 170 return false; 171 if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize ) 172 return false; 173 174 dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents; 175 rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents; 176 177#if 0 178 for (i = 0; i < kHFSExtentDensity; ++i) 179 { 180 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) 181 return false; 182 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) 183 return false; 184 } 185#endif 186 } 187 break; 188 189 case kHFSFileThreadRecord: 190 case kHFSFolderThreadRecord: 191 { 192 if ( recordSize != sizeof(HFSCatalogThread) ) 193 return false; 194 195 cNodeID = catalogRecord->hfsThread.parentID; 196 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) 197 return false; 198 199 if ( (catalogRecord->hfsThread.nodeName[0] == 0) || 200 (catalogRecord->hfsThread.nodeName[0] > 31) ) 201 return false; 202 } 203 break; 204#endif 205 206 case kHFSPlusFolderRecord: 207 { 208 if ( recordSize != sizeof(HFSPlusCatalogFolder) ) 209 return false; 210 if ( catalogRecord->hfsPlusFolder.flags != 0 ) 211 return false; 212 if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF ) 213 return false; 214 215 cNodeID = catalogRecord->hfsPlusFolder.folderID; 216 217 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) 218 return false; 219 } 220 break; 221 222 case kHFSPlusFileRecord: 223 { 224// u_int16_t i; 225 HFSPlusExtentDescriptor *dataExtent; 226 HFSPlusExtentDescriptor *rsrcExtent; 227 228 if ( recordSize != sizeof(HFSPlusCatalogFile) ) 229 return false; 230 if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 ) 231 return false; 232 233 cNodeID = catalogRecord->hfsPlusFile.fileID; 234 235 if ( cNodeID < 16 ) 236 return false; 237 238 // make sure 0 � LEOF � PEOF for both forks 239 240 dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents; 241 rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents; 242 243#if 0 244 for (i = 0; i < kHFSPlusExtentDensity; ++i) 245 { 246 if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) ) 247 return false; 248 if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) ) 249 return false; 250 } 251#endif 252 } 253 break; 254 255 case kHFSPlusFileThreadRecord: 256 case kHFSPlusFolderThreadRecord: 257 { 258 if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255))) 259 return false; 260 261 cNodeID = catalogRecord->hfsPlusThread.parentID; 262 if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) ) 263 return false; 264 265 if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) || 266 (catalogRecord->hfsPlusThread.nodeName.length > 255) ) 267 return false; 268 } 269 break; 270 271 default: 272 return false; 273 } 274 } 275 276 return true; // record appears to be OK 277} 278