1/* 2 * Copyright (c) 2000-2002, 2004-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#include <sys/param.h> 29#include <sys/utfconv.h> 30#include <sys/stat.h> 31#include <sys/kernel.h> 32#include <sys/malloc.h> 33#include <libkern/libkern.h> 34 35#include "../headers/FileMgrInternal.h" 36#include "../headers/BTreesInternal.h" 37#include "../headers/CatalogPrivate.h" 38#include "../headers/HFSUnicodeWrappers.h" 39#include "../headers/BTreesPrivate.h" 40#include <string.h> 41 42// 43// Routine: LocateCatalogNodeByKey 44// 45// Function: Locates the catalog record for an existing folder or file 46// CNode and returns the key and data records. 47// 48 49OSErr 50LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr, 51 CatalogRecord *dataPtr, u_int32_t *newHint) 52{ 53 OSErr result; 54 CatalogName *nodeName = NULL; 55 HFSCatalogNodeID threadParentID; 56 u_int16_t tempSize; 57 FSBufferDescriptor btRecord; 58 struct BTreeIterator *searchIterator; 59 FCB *fcb; 60 61 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); 62 if (searchIterator == NULL) { 63 return memFullErr; // translates to ENOMEM 64 } 65 66 bzero(searchIterator, sizeof(*searchIterator)); 67 68 fcb = GetFileControlBlock(volume->catalogRefNum); 69 70 btRecord.bufferAddress = dataPtr; 71 btRecord.itemCount = 1; 72 btRecord.itemSize = sizeof(CatalogRecord); 73 74 searchIterator->hint.nodeNum = hint; 75 76 bcopy(keyPtr, &searchIterator->key, sizeof(CatalogKey)); 77 78 result = BTSearchRecord( fcb, searchIterator, &btRecord, &tempSize, searchIterator ); 79 80 if (result == noErr) 81 { 82 *newHint = searchIterator->hint.nodeNum; 83 84 BlockMoveData(&searchIterator->key, keyPtr, sizeof(CatalogKey)); 85 } 86 87 if (result == btNotFound) { 88 result = cmNotFound; 89 } 90 91 if (result) { 92 FREE(searchIterator, M_TEMP); 93 return result; 94 } 95 96 // if we got a thread record, then go look up real record 97 switch ( dataPtr->recordType ) 98 { 99 100#if CONFIG_HFS_STD 101 case kHFSFileThreadRecord: 102 case kHFSFolderThreadRecord: 103 threadParentID = dataPtr->hfsThread.parentID; 104 nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName; 105 break; 106#endif 107 108 case kHFSPlusFileThreadRecord: 109 case kHFSPlusFolderThreadRecord: 110 threadParentID = dataPtr->hfsPlusThread.parentID; 111 nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName; 112 break; 113 114 default: 115 threadParentID = 0; 116 break; 117 } 118 119 if ( threadParentID ) // found a thread 120 result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint); 121 122 FREE (searchIterator, M_TEMP); 123 return result; 124} 125 126 127 128//******************************************************************************* 129// Routine: LocateCatalogRecord 130// 131// Function: Locates the catalog record associated with folderID and name 132// 133//******************************************************************************* 134 135OSErr 136LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name, 137 __unused u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint) 138{ 139 OSErr result; 140 uint16_t tempSize; 141 FSBufferDescriptor btRecord; 142 struct BTreeIterator *searchIterator = NULL; 143 FCB *fcb; 144 BTreeControlBlock *btcb; 145 146 MALLOC (searchIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); 147 if (searchIterator == NULL) { 148 return memFullErr; // translates to ENOMEM 149 } 150 151 bzero(searchIterator, sizeof(*searchIterator)); 152 153 154 fcb = GetFileControlBlock(volume->catalogRefNum); 155 btcb = (BTreeControlBlock *)fcb->fcbBTCBPtr; 156 157 btRecord.bufferAddress = dataPtr; 158 btRecord.itemCount = 1; 159 btRecord.itemSize = sizeof(CatalogRecord); 160 161 BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), (CatalogKey *)&searchIterator->key); 162 163 result = BTSearchRecord(fcb, searchIterator, &btRecord, &tempSize, searchIterator); 164 if (result == noErr) { 165 *newHint = searchIterator->hint.nodeNum; 166 BlockMoveData(&searchIterator->key, keyPtr, CalcKeySize(btcb, &searchIterator->key)); 167 } 168 169 FREE (searchIterator, M_TEMP); 170 return (result == btNotFound ? cmNotFound : result); 171} 172 173 174 175/* 176 * Routine: BuildCatalogKey 177 * 178 * Function: Constructs a catalog key record (ckr) given the parent 179 * folder ID and CName. Works for both classic and extended 180 * HFS volumes. 181 * 182 */ 183 184void 185BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key) 186{ 187 if ( isHFSPlus ) 188 { 189 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2) 190 key->hfsPlus.parentID = parentID; // set parent ID 191 key->hfsPlus.nodeName.length = 0; // null CName length 192 if ( cName != NULL ) 193 { 194 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus); 195 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length 196 } 197 } 198#if CONFIG_HFS_STD 199 else 200 { 201 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1) 202 key->hfs.reserved = 0; // clear unused byte 203 key->hfs.parentID = parentID; // set parent ID 204 key->hfs.nodeName[0] = 0; // null CName length 205 if ( cName != NULL ) 206 { 207 UpdateCatalogName(cName->pstr, key->hfs.nodeName); 208 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length 209 } 210 } 211#endif 212 213} 214 215OSErr 216BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength, 217 CatalogKey *key, u_int32_t *textEncoding) 218{ 219 OSErr err = 0; 220 221 if ( name == NULL) 222 nameLength = 0; 223 else if (nameLength == kUndefinedStrLen) 224 nameLength = strlen((const char *)name); 225 226 if ( volume->vcbSigWord == kHFSPlusSigWord ) { 227 size_t unicodeBytes = 0; 228 229 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2) 230 key->hfsPlus.parentID = parentID; // set parent ID 231 key->hfsPlus.nodeName.length = 0; // null CName length 232 if ( nameLength > 0 ) { 233 err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode, 234 &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED); 235 key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar); 236 key->hfsPlus.keyLength += unicodeBytes; 237 } 238 239 if (textEncoding && (*textEncoding != kTextEncodingMacUnicode)) 240 *textEncoding = hfs_pickencoding(key->hfsPlus.nodeName.unicode, 241 key->hfsPlus.nodeName.length); 242 } 243#if CONFIG_HFS_STD 244 else { 245 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1) 246 key->hfs.reserved = 0; // clear unused byte 247 key->hfs.parentID = parentID; // set parent ID 248 key->hfs.nodeName[0] = 0; // null CName length 249 if ( nameLength > 0 ) { 250 err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]); 251 /* 252 * Retry with MacRoman in case that's how it was exported. 253 * When textEncoding != NULL we know that this is a create 254 * or rename call and can skip the retry (ugly but it works). 255 */ 256 if (err && (textEncoding == NULL)) 257 err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]); 258 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length 259 } 260 if (textEncoding) 261 *textEncoding = 0; 262 } 263#endif 264 265 if (err) { 266 if (err == ENAMETOOLONG) 267 err = bdNamErr; /* name is too long */ 268 else 269 err = paramErr; /* name has invalid characters */ 270 } 271 272 return err; 273} 274 275 276//******************************************************************************* 277// Routine: FlushCatalog 278// 279// Function: Flushes the catalog for a specified volume. 280// 281//******************************************************************************* 282 283OSErr 284FlushCatalog(ExtendedVCB *volume) 285{ 286 FCB * fcb; 287 OSErr result; 288 struct hfsmount *hfsmp = VCBTOHFS (volume); 289 290 fcb = GetFileControlBlock(volume->catalogRefNum); 291 result = BTFlushPath(fcb); 292 293 if (result == noErr) 294 { 295 //--- check if catalog's fcb is dirty... 296 297 if ( 0 /*fcb->fcbFlags & fcbModifiedMask*/ ) 298 { 299 hfs_lock_mount (hfsmp); 300 MarkVCBDirty(volume); // Mark the VCB dirty 301 volume->vcbLsMod = GetTimeUTC(); // update last modified date 302 hfs_unlock_mount (hfsmp); 303 304 // result = FlushVolumeControlBlock(volume); 305 } 306 } 307 308 return result; 309} 310 311 312//������������������������������������������������������������������������������� 313// Routine: UpdateCatalogName 314// 315// Function: Updates a CName. 316// 317//������������������������������������������������������������������������������� 318 319void 320UpdateCatalogName(ConstStr31Param srcName, Str31 destName) 321{ 322 Size length = srcName[0]; 323 324 if (length > CMMaxCName) 325 length = CMMaxCName; // truncate to max 326 327 destName[0] = length; // set length byte 328 329 BlockMoveData(&srcName[1], &destName[1], length); 330} 331 332//_______________________________________________________________________ 333 334void 335CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPlus) 336{ 337 u_int32_t length = 0; 338 339 if ( srcName == NULL ) 340 { 341 if ( dstName != NULL ) 342 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) 343 return; 344 } 345 346 if (isHFSPlus) { 347 length = sizeof(UniChar) * (srcName->ustr.length + 1); 348 } 349#if CONFIG_HFS_STD 350 else { 351 length = sizeof(u_int8_t) + srcName->pstr[0]; 352 } 353#endif 354 355 if ( length > 1 ) 356 BlockMoveData(srcName, dstName, length); 357 else 358 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) 359} 360 361