X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..b4c24cb9d3df001f2892dc4ed451bc769ff28a9f:/bsd/hfs/hfscommon/Catalog/Catalog.c diff --git a/bsd/hfs/hfscommon/Catalog/Catalog.c b/bsd/hfs/hfscommon/Catalog/Catalog.c index c71d5c7f9..e7134028f 100644 --- a/bsd/hfs/hfscommon/Catalog/Catalog.c +++ b/bsd/hfs/hfscommon/Catalog/Catalog.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -19,141 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - File: Catalog.c - - Contains: Catalog Manager Implementation - - Version: HFS Plus 1.0 - - Copyright: © 1996-2000 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Don Brady - - Other Contact: Mark Day - - Technology: xxx put technology here xxx - - Writers: - - (msd) Mark Day - (DSH) Deric Horn - (djb) Don Brady - - Change History (most recent first): - 2/2/99 djb Fix CreateFileIDRef to copy entire name when creating thread record. - 1/7/99 djb Use a max bytes of 256 in calls to ConvertUnicodeToUTF8. - 12/9/98 djb UpdateCatalogNode only updates vcbLsMod if contentModDate changes. - 11/5/98 djb Add support for UTF-8 names. - 8/31/98 djb GetTimeLocal now takes an input. - 7/8/98 ser Added accessDate and AttributeModDate init. to create routine. - 6/5/98 djb Added CreateFileIDRef routine. - 6/3/98 djb Merge MoveCatalogRecord and RenameCatalogRecord into one routine. - 4/17/98 djb Add VCB locking. - 4/6/98 djb Catalog iterators now need to be released. - 4/6/98 djb Removed CreateVolumeCatalogCache and DisposeVolumeCatalogCache (obsolete). - 3/31/98 djb Make UpdateCatalogNode interface thread-safe. - 3/31/98 djb Sync up with final HFSVolumes.h header file. - 3/17/98 djb Fixed CreateCatalogNode interface to take kCatalogFolderNode and - kCatalogFileNode as type input. - - 12/10/97 DSH 2201501, UpdateCatalogNode to only update CatalogRecords which - are under 2 Gig by checking the overloaded valence field. - 11/20/97 djb Radar #2002357. Fixing retry mechanism. - 11/17/97 djb PrepareInputName routine now returns an error. - 11/13/97 djb Radar #1683572. Add new GetCatalogOffspringFile routine for - PBGetFileInfo calls (support used to be in HFSPathnameCalls.a). - 11/7/97 msd Change calls to the wrapper routine CompareUnicodeNames() to use - the underlying routine FastUnicodeCompare() instead. - 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. - 10/17/97 djb Change Catalog Create/Rename to use ConvertInputNameToUnicode. - 10/13/97 djb Update volumeNameEncodingHint when changing volume name. Change - name of GetSystemTextEncoding to GetDefaultTextEncoding. - 10/1/97 djb Add new catalog iterators and node cache to improve performance. - 9/12/97 msd In CreateCatalogNode, make sure parent is a folder, not a file. - 9/10/97 msd In RenameCatalogNodeUnicode, remove HFS-only code and make sure - the conversion context is set up and marked in the volume's - bitmap. - 9/9/97 DSH Added RelString_Glue to avoid having to link DFAEngine with - Interface.o - 9/8/97 msd Make sure a folder's modifyDate is set whenever its - contentModDate is set. In UpdateCatalogNode, make sure the - modifyDate is greater or equal to contentModDate; do a DebugStr - only for debug builds. - 9/7/97 djb Make some DebuStrs HFS_DIAGNOSTIC only. - 9/4/97 djb Add more Catalog Iterators, Instrument RelString. - 9/4/97 msd Remove call to PropertyDeleteObject. - 8/18/97 DSH Use RelString instead of FastRelString in DFA to avoid loading - branch island instead of table. - 8/14/97 djb Remove hard link support. Switch over to FastRelString. - 8/8/97 djb Fixed bugs in LinkCatalogNode. - 8/5/97 djb Don't restore vcbNxtCNID if thread exists (radar #1670614). - 7/25/97 DSH Pass heuristicHint to BTSearchRecord from GetCatalogOffspring. - 7/18/97 msd Include LowMemPriv.h. In LinkCatalogNode, now sets the - kInsertedFileThread2 flag correctly; should only affect error - recovery code. - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 6/27/97 msd Add PBLongRename SPI. Added RenameCatalogNodeUnicode call, which - takes Unicode names for HFS Plus volumes. Removed calls to - Attributes module when creating, renaming or moving nodes. - 6/24/97 djb Validate the mangled name matches in - LocateCatalogNodeByMangledName. - 6/24/97 djb Add hard link support. - 6/20/97 msd Use contentModDate and attributeModDate fields instead of - modifyDate. Made CopyCatalogNodeData public. - 6/18/97 djb Add routines LocateCatalogNodeWithRetry & UpdateVolumeEncodings. - Add mangled name retry to DeleteCatalogNode, MoveCatalogNode and - RenameCatalogNode. - 6/13/97 djb Major changes for longname support and multiple scripts. - 6/9/97 msd Instead of calling GetDateTime, call GetTimeUTC or GetTimeLocal. - Dates on an HFS Plus volume need to be converted to/from UTC. - 6/4/97 djb Set textEncoding hint in Rename and Create. TrashCatalogIterator - was not always called with the correct folder ID. - 5/21/97 djb Turn off recursive iterators. - 5/19/97 djb Add support for B-tree iterators to GetCatalogOffspring. - 5/9/97 djb Get in sync with FilesInternal.i. - 4/24/97 djb First checked into Common System Project. - 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum. - 4/4/97 djb Get in sync with volume format changes. - 3/31/97 djb Additional HFS Plus optimization added to GetCatalogNode. - 3/28/97 djb Add Optimization to GetCatalogNode. - 3/27/97 djb Unicode conversion routines now use byte counts. - 3/17/97 DSH Casting to compile with SC, GetRecordSize -> - GetCatalogRecordSize, moved some prototypes to extern. - 3/5/97 msd Add calls to Property Manager when catalog entries are created, - deleted, moved, renamed. - 2/19/97 djb HFS Plus catalog keys no longer have a pad word. - 1/24/97 DSH (djb) GetCatalogOffSpring() fix volume->vcbDirIDM = 0 - 1/23/97 DSH Truncate name to CMMaxCName characters in PrepareInputName(). - 1/14/97 djb Fixed RenameCatalogNode for case when just a cnid is passed. - 1/13/97 djb Added support for varaible sized thread records in HFS+. - 1/11/97 DSH Moving PrepareInputName() declaration fo FilesInternal.h - 1/10/97 djb CopyCatalogNodeData was trashing the resource extents on HFS+. - 1/10/97 djb CopyCatalogNodeData was trashing dataLogicalSize on HFS+ disks. - 1/9/97 djb Get in sync with new HFSVolumesPriv.i. - 1/6/97 djb Added name length checking to CompareExtendedCatalogKeys. Fixed - GetCatalogOffspring - it was not correctly passing the HFS+ flag - to PrepareOutputName. Fixed BuildKey for HFS+ keys. - 1/3/97 djb Fixed termination bug in GetCatalogOffspring. Added support for - large keys. Integrated latest HFSVolumesPriv.h changes. - 12/19/96 DSH Changed call from C_FlushMDB to HFS+ savy - FlushVolumeControlBlock() - 12/19/96 djb Add new B-tree manager... - 12/13/96 djb Fixing bugs for HFS+. Switch to HFSUnicodeWrappers routines. - 12/12/96 djb Changed the SPI for GetCatalogNode, GetCatalogOffspring, and - UpdateCatalogNode. - 12/12/96 DSH Removed static function declarations for functions used by - FileIDServices.c. - 11/11/96 djb Added support for HFS+ Unicode names. Major changes throughout. - 11/4/96 djb Added FSSpec output to GetCatalogNode and GetCatalogOffspring - routines. - 10/29/96 djb first checked in - -*/ #pragma segment Catalog @@ -166,618 +31,20 @@ #include "../headers/BTreesInternal.h" #include "../headers/CatalogPrivate.h" #include "../headers/HFSUnicodeWrappers.h" -#include "../headers/HFSInstrumentation.h" // External routines extern SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 ); -extern SInt16 RelString_Glue(StringPtr pStr1, StringPtr pStr2); - - -// Internal routines - -static OSErr IterateCatalogNode(ExtendedVCB *volume, CatalogIterator *catalogIterator, - UInt16 index, CatalogNodeData *nodeData, - HFSCatalogNodeID *nodeID, SInt16 *nodeType); - -void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey, - CatalogRecord *record, UInt32 *threadSize); - -void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding, - CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID catalogNodeID); - -#if HFS_DIAGNOSTIC - #include - #define PRINTIT(A) kprintf A; -#else - #define PRINTIT(A) -#endif /* HFS_DIAGNOSTIC */ //_________________________________________________________________________________ // Exported Routines // -// CreateCatalogNode - Creates a new folder or file CNode. -// DeleteCatalogNode - Deletes an existing folder or file CNode. -// GetCatalogNode - Locates an existing folder or file CNode. -// GetCatalogOffspringFile - Gets an offspring file record from a folder. -// GetCatalogOffspring - Gets an offspring record from a folder. -// MoveRenameCatalogNode - Moves/Renames an existing folder or file CNode. -// UpdateCatalogNode - Marks a Catalog BTree node as 'dirty'. -// CreateFileIDRef - Creates a file thread record for hfs file node -// CompareCatalogKeys - Compares two catalog keys. -// -//_________________________________________________________________________________ - - -//_________________________________________________________________________________ -// -// About date/time values: -// -// Date/time values stored in control blocks and generic structures (such as -// CatalogNodeData) are always stored in local time. Values stored in HFS volume -// format structures (such as B-tree records) are also stored in local time. -// Values stored in HFS Plus format structures are stored in UTC. -//_________________________________________________________________________________ - - -// Implementation - - -//_________________________________________________________________________________ -// Routine: CreateCatalogNode -// -// Function: Creates a new folder or file CNode. A new folder or file -// record is added to the catalog BTree. If a folder CNode is -// being created, a new thread record is also added. -// -//_________________________________________________________________________________ - -OSErr -CreateCatalogNode ( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, - UInt32 nodeType, HFSCatalogNodeID *catalogNodeID, UInt32 *catalogHint) -{ - CatalogKey *nodeKey; - CatalogRecord nodeData; // 520 bytes - UInt32 nodeDataSize; - CatalogRecord parentThreadData; // 520 bytes - HFSCatalogNodeID parentsParentID; - CatalogName *parentNamePtr; - UInt32 tempHint; - UInt32 textEncoding; - UInt16 tempSize; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - FCB *fcb; - FSBufferDescriptor btRecord; - BTreeIterator iterator; - BTreeIterator threadIter; - HFSCatalogNodeID nextCNID; - - if (nodeType != kCatalogFolderNode && nodeType != kCatalogFileNode) - return paramErr; - - fcb = GetFileControlBlock(volume->catalogRefNum); - nodeKey = (CatalogKey *) &iterator.key; - - //--- make sure parent exists (by locating the parent's thread record) - - result = LocateCatalogThread(volume, parentID, &parentThreadData, &tempSize, &tempHint); - ReturnIfError(result); - - TrashCatalogIterator(volume, parentID); // invalidate any iterators for this parentID - - // save copy of parent's parentID and name. - - if (isHFSPlus) - { - if (parentThreadData.recordType != kHFSPlusFolderThreadRecord) - return dirNFErr; - - parentsParentID = parentThreadData.hfsPlusThread.parentID; - parentNamePtr = (CatalogName*) &parentThreadData.hfsPlusThread.nodeName; - } - else - { - if (parentThreadData.recordType != kHFSFolderThreadRecord) - return dirNFErr; - - parentsParentID = parentThreadData.hfsThread.parentID; - parentNamePtr = (CatalogName*) &parentThreadData.hfsThread.nodeName; - } - - // invalidate cache for parent since its about to change - InvalidateCatalogNodeCache(volume, parentsParentID); - - //--- build key for new catalog node - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, nodeKey, &textEncoding); - ReturnIfError(result); - - /* make sure it doesn't exist */ - result = BTSearchRecord(fcb, &iterator, kInvalidMRUCacheKey, NULL, NULL, &iterator); - if (result != btNotFound) - return (cmExists); - - nextCNID = volume->vcbNxtCNID; - if (!isHFSPlus && nextCNID == 0xFFFFFFFF) - return (dskFulErr); - - //--- build thread record for new CNode - if (isHFSPlus || nodeType == kCatalogFolderNode) - { - CatalogRecord threadData; // 520 bytes - UInt32 threadSize; - - btRecord.bufferAddress = &threadData; - btRecord.itemSize = threadSize; - btRecord.itemCount = 1; - InitCatalogThreadRecord(volume, nodeType, nodeKey, &threadData, &threadSize); -TryNextID: - BuildCatalogKey(nextCNID, NULL, isHFSPlus, (CatalogKey*) &threadIter.key); - result = BTInsertRecord(fcb, &threadIter, &btRecord, threadSize); - if (result == btExists && isHFSPlus) - { - /* - * Allow CNIDs on HFS Plus volumes to wrap around - */ - ++nextCNID; - if (nextCNID < kHFSFirstUserCatalogNodeID) - { - volume->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; - volume->vcbFlags |= 0xFF00; - nextCNID = kHFSFirstUserCatalogNodeID; - } - goto TryNextID; - } - ReturnIfError(result); - } - - //--- initialize catalog data record (for folder or file) - btRecord.bufferAddress = &nodeData; - btRecord.itemSize = nodeDataSize; - btRecord.itemCount = 1; - InitCatalogRecord(volume, nodeType, textEncoding, &nodeData, &nodeDataSize, nextCNID); - - //--- add new folder/file record to catalog BTree - result = BTInsertRecord(fcb, &iterator, &btRecord, nodeDataSize ); - if (result) - { - if (result == btExists) - result = cmExists; - - if (isHFSPlus || nodeType == kCatalogFolderNode) - (void) BTDeleteRecord(fcb, &threadIter); - - return result; - } - - /* - * Return the CNID actually used. Update the volume's next ID. - */ - *catalogNodeID = nextCNID; - if (++nextCNID < kHFSFirstUserCatalogNodeID) - { - volume->vcbAtrb |= kHFSCatalogNodeIDsReusedMask; - volume->vcbFlags |= 0xFF00; - nextCNID = kHFSFirstUserCatalogNodeID; - } - volume->vcbNxtCNID = nextCNID; - - //--- update counters... - - result = UpdateFolderCount( volume, parentsParentID, parentNamePtr, nodeData.recordType, kNoHint, +1); - ReturnIfError(result); /* XXX what about cleanup ??? */ - - AdjustVolumeCounts(volume, nodeData.recordType, +1); - - result = FlushCatalog(volume); - - return result; - -} // end CreateCatalogNode - - -/* - * initialize catalog data record (for folder or file) - */ -void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding, CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID nodeID) -{ - UInt32 timeStamp; - - ClearMemory(record, sizeof(CatalogRecord)); // first clear the record - - if (volume->vcbSigWord == kHFSPlusSigWord) - { - timeStamp = GetTimeUTC(); // get current date/time (universal) - - UpdateVolumeEncodings(volume, textEncoding); - - if (nodeType == kCatalogFolderNode ) - { - record->recordType = kHFSPlusFolderRecord; - record->hfsPlusFolder.folderID = nodeID; - record->hfsPlusFolder.createDate = timeStamp; - record->hfsPlusFolder.contentModDate = timeStamp; - record->hfsPlusFolder.accessDate = timeStamp; - record->hfsPlusFolder.attributeModDate = timeStamp; - record->hfsPlusFolder.textEncoding = textEncoding; - *recordSize = sizeof(HFSPlusCatalogFolder); - // threadType = kHFSPlusFolderThreadRecord; - } - else if (nodeType == kCatalogFileNode ) - { - record->recordType = kHFSPlusFileRecord; - record->hfsPlusFile.fileID = nodeID; - record->hfsPlusFile.createDate = timeStamp; - record->hfsPlusFile.contentModDate = timeStamp; - record->hfsPlusFile.accessDate = timeStamp; - record->hfsPlusFile.attributeModDate = timeStamp; - record->hfsPlusFile.flags |= kHFSThreadExistsMask; - record->hfsPlusFile.textEncoding = textEncoding; - *recordSize = sizeof(HFSPlusCatalogFile); - // threadType = kHFSPlusFileThreadRecord; - } - } - else /* standard hfs */ - { - timeStamp = GetTimeLocal(true); // get current local date/time - - if (nodeType == kCatalogFolderNode ) - { - record->recordType = kHFSFolderRecord; - record->hfsFolder.folderID = nodeID; - record->hfsFolder.createDate = timeStamp; - record->hfsFolder.modifyDate = timeStamp; - *recordSize = sizeof(HFSCatalogFolder); - // threadType = kHFSFolderThreadRecord; - } - else if (nodeType == kCatalogFileNode ) - { - record->recordType = kHFSFileRecord; - record->hfsFile.fileID = nodeID; - record->hfsFile.createDate = timeStamp; - record->hfsFile.modifyDate = timeStamp; - *recordSize = sizeof(HFSCatalogFile); - } - } -} - - -void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey, - CatalogRecord *record, UInt32 *threadSize) -{ - ClearMemory(record, sizeof(CatalogRecord) ); // first clear the record - - if (volume->vcbSigWord == kHFSPlusSigWord) - { - if (nodeType == kCatalogFolderNode) - record->recordType = kHFSPlusFolderThreadRecord; - else - record->recordType = kHFSPlusFileThreadRecord; - record->hfsPlusThread.parentID = nodeKey->hfsPlus.parentID; - *threadSize = sizeof(record->hfsPlusThread); - - // HFS Plus has varaible sized threads so adjust to actual length - *threadSize -= ( sizeof(record->hfsPlusThread.nodeName.unicode) - - (nodeKey->hfsPlus.nodeName.length * sizeof(UniChar)) ); - BlockMoveData(&nodeKey->hfsPlus.nodeName, &record->hfsPlusThread.nodeName, - sizeof(UniChar) * (nodeKey->hfsPlus.nodeName.length + 1)); - } - else // classic HFS - { - if (nodeType == kCatalogFolderNode) - record->recordType = kHFSFolderThreadRecord; - else - record->recordType = kHFSFileThreadRecord; - record->hfsThread.parentID = nodeKey->hfs.parentID; - *threadSize = sizeof(record->hfsThread); - BlockMoveData(&nodeKey->hfs.nodeName, &record->hfsThread.nodeName, - nodeKey->hfs.nodeName[0] + 1); - } -} - - -//_________________________________________________________________________________ -// Routine: DeleteCatalogNode -// -// Function: Deletes an existing folder or file CNode. The thread record -// is also deleted for directories and files that have thread -// records. -// -// The valence for a folder must be zero before it can be deleted. -// The rootfolder cannot be deleted. -// -//_________________________________________________________________________________ - -OSErr -DeleteCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint) -{ - CatalogKey key; // 518 bytes - CatalogRecord data; // 520 bytes - UInt32 nodeHint; - HFSCatalogNodeID nodeID; - HFSCatalogNodeID nodeParentID; - UInt16 nodeType; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - //--- locate subject catalog node - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, &key, NULL); - ReturnIfError(result); - - result = LocateCatalogNodeByKey(volume, hint, &key, &data, &nodeHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, &key, &data, &nodeHint); - ReturnIfError(result); - - nodeParentID = isHFSPlus ? key.hfsPlus.parentID : key.hfs.parentID; // establish real parent cnid - nodeType = data.recordType; // establish cnode type - nodeID = 0; - - switch (nodeType) - { - case kHFSFolderRecord: - if (data.hfsFolder.valence != 0) // is it empty? - return cmNotEmpty; - - nodeID = data.hfsFolder.folderID; - break; - - case kHFSPlusFolderRecord: - if (data.hfsPlusFolder.valence != 0) // is it empty? - return cmNotEmpty; - - nodeID = data.hfsPlusFolder.folderID; - break; - - case kHFSFileRecord: - if (data.hfsFile.flags & kHFSThreadExistsMask) - nodeID = data.hfsFile.fileID; - break; - - case kHFSPlusFileRecord: - nodeID = data.hfsPlusFile.fileID; // note: HFS Plus files always have a thread - break; - - default: - return cmNotFound; - } - - - if (nodeID == fsRtDirID) // is this the root folder? - return cmRootCN; // sorry, you can't delete the root! - - TrashCatalogIterator(volume, nodeParentID); // invalidate any iterators for this parentID - InvalidateCatalogNodeCache(volume, nodeParentID); // and invalidate node cache - - //--- delete catalog records for CNode and file threads if they exist - - result = DeleteBTreeRecord(volume->catalogRefNum, &key); - ReturnIfError(result); - - if ( nodeID ) - { - CatalogKey threadKey; // 518 bytes - - BuildCatalogKey(nodeID, NULL, isHFSPlus, &threadKey); - - (void) DeleteBTreeRecord(volume->catalogRefNum, &threadKey); // ignore errors for thread deletes - } - - //--- update counters... - - result = UpdateFolderCount(volume, nodeParentID, NULL, nodeType, kNoHint, -1); - ReturnIfError(result); - - AdjustVolumeCounts(volume, nodeType, -1); // all done with this file or folder - - result = FlushCatalog(volume); - - return result; - -} // end DeleteCatalogNode - - -//_________________________________________________________________________________ -// Routine: GetCatalogNode -// -// Function: Locates an existing folder or file CNode and pointer to the CNode data record. +// CompareCatalogKeys - Compares two catalog keys. // //_________________________________________________________________________________ -OSErr -GetCatalogNode( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 nameLen, UInt32 hint, - CatalogNodeData *nodeData, UInt32 *newHint) -{ - CatalogKey *key; - CatalogRecord *record; - BTreeIterator searchIterator; - FSBufferDescriptor btRecord; - ByteCount utf8len; - UInt32 heuristicHint; - UInt32 *cachedHint; - FCB *fcb; - OSErr result = noErr; - UInt16 dataSize; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - if (isHFSPlus) { - btRecord.bufferAddress = nodeData; - btRecord.itemSize = sizeof(CatalogNodeData); - } else { - btRecord.bufferAddress = &nodeData->cnd_extra; - btRecord.itemSize = sizeof(HFSCatalogFile); - } - - btRecord.itemCount = 1; - record = (CatalogRecord *) btRecord.bufferAddress; - key = (CatalogKey *) &searchIterator.key; - - if (name && nameLen == kUndefinedStrLen) - nameLen = strlen(name); - - result = BuildCatalogKeyUTF8(volume, parentID, name, nameLen, key, NULL); - ReturnIfError(result); - - fcb = GetFileControlBlock(volume->catalogRefNum); - searchIterator.hint.nodeNum = *newHint; - searchIterator.hint.index = 0; - - /* - * We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint - * is a mapping of dirID and nodeNumber, in hopes that the current - * search will be in the same node as the last search with the same - * parentID. - */ - if (name != NULL && GetMRUCacheBlock(parentID, volume->hintCachePtr, (Ptr *)&cachedHint) == 0) - heuristicHint = *cachedHint; - else - heuristicHint = kInvalidMRUCacheKey; - - result = BTSearchRecord(fcb, &searchIterator, heuristicHint, &btRecord, &dataSize, &searchIterator); - if (result == btNotFound) - result = cmNotFound; - - if (name != NULL && result == noErr) - InsertMRUCacheBlock(volume->hintCachePtr, parentID, (Ptr) &(searchIterator.hint.nodeNum)); - - if (result == noErr) { - CatalogName *nodeName = NULL; - HFSCatalogNodeID threadParentID; - - /* if we got a thread record, then go look up real record */ - switch (record->recordType) { - - case kHFSFileThreadRecord: - case kHFSFolderThreadRecord: - threadParentID = record->hfsThread.parentID; - nodeName = (CatalogName *) &record->hfsThread.nodeName; - break; - - case kHFSPlusFileThreadRecord: - case kHFSPlusFolderThreadRecord: - threadParentID = record->hfsPlusThread.parentID; - nodeName = (CatalogName *) &record->hfsPlusThread.nodeName; - break; - - default: - threadParentID = 0; - *newHint = searchIterator.hint.nodeNum; - break; - } - if (threadParentID) { - BuildCatalogKey(threadParentID, nodeName, isHFSPlus, key); - searchIterator.hint.nodeNum = kNoHint; - searchIterator.hint.index = 0; - - result = BTSearchRecord(fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, &dataSize, &searchIterator); - if (result == btNotFound) - result = cmNotFound; - if (result == noErr) - *newHint = searchIterator.hint.nodeNum; - } - } - - /* - * If we did not find it by name, then look for an embedded - * file ID in a mangled name. - */ - if ( result == cmNotFound && isHFSPlus) - result = LocateCatalogNodeByMangledName(volume, parentID, name, nameLen, - key, record, newHint); - - /* - * In Mac OS X there can also be HFS filenames that - * could not be encoded using the default encoding. - * In which case they were encoded as MacRoman. - */ - if (result == cmNotFound && !isHFSPlus) { - Str31 hfsName; - - utf8_to_mac_roman(nameLen, name, hfsName); - result = LocateCatalogNode(volume, parentID, (CatalogName*)hfsName, - 0, key, record, newHint); - } - ReturnIfError(result); - - nodeData->cnm_parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID; - - if (nodeData->cnm_flags & kCatNameNoCopyName) { - if (! isHFSPlus) { - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) - CopyCatalogNodeData(volume, record, nodeData); - else - result = cmNotFound; - } - } - else { - nodeData->cnm_nameptr = nodeData->cnm_namespace; - if ( isHFSPlus ) { - result = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - nodeData->cnm_namespace, (size_t *)&utf8len, - MAXHFSVNODELEN + 1, ':', 0); - - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - utf8len = utf8_encodelen(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - ':', 0); - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = utf8_encodestr(key->hfsPlus.nodeName.unicode, - key->hfsPlus.nodeName.length * sizeof(UniChar), - nodeData->cnm_nameptr, (size_t *)&utf8len, - utf8len + 1, ':', 0); - } - } - else { // classic HFS - - /* convert data to HFS Plus format */ - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) { - CopyCatalogNodeData(volume, record, nodeData); - result = hfs_to_utf8(volume, key->hfs.nodeName, MAXHFSVNODELEN + 1, - &utf8len, nodeData->cnm_namespace); - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = hfs_to_utf8(volume, key->hfs.nodeName, utf8len + 1, - &utf8len, nodeData->cnm_nameptr); - } else if (result) { - /* - * When an HFS name cannot be encoded with the current - * volume encoding we use MacRoman as a fallback. - */ - result = mac_roman_to_utf8(key->hfs.nodeName, MAXHFSVNODELEN + 1, - &utf8len, nodeData->cnm_namespace); - } - } else - result = cmNotFound; - } - - nodeData->cnm_length = utf8len; - if (result && (nodeData->cnm_flags & kCatNameIsAllocated)) - { - DisposePtr(nodeData->cnm_nameptr); - nodeData->cnm_flags &= ~kCatNameIsAllocated; - nodeData->cnm_nameptr = 0; /* Just to be clean */ - } - } - - - #if DEBUG_BUILD - if ( nodeData->cnd_nodeID > volume->vcbNxtCNID || nodeData->cnd_nodeID == 0) - DebugStr("\pGetCatalogNode bad file ID found!"); - #endif - - return result; - -} // end GetCatalogNode UInt32 @@ -797,12 +64,18 @@ GetDirEntrySize(BTreeIterator *bip, ExtendedVCB * vol) cnp->ustr.length * sizeof(UniChar), ':', 0); if (utf8chars > kdirentMaxNameBytes) utf8chars = kdirentMaxNameBytes; - utf8chars++; /* account for NULL termination */ } else { /* hfs */ cnp = (CatalogName*) ckp->hfs.nodeName; result = hfs_to_utf8(vol, cnp->pstr, kdirentMaxNameBytes + 1, &utf8chars, name); - /*XXX ignoring error */ + if (result) { + /* + * When an HFS name cannot be encoded with the current + * volume encoding we use MacRoman as a fallback. + */ + result = mac_roman_to_utf8(cnp->pstr, MAXHFSVNODELEN + 1, + &utf8chars, name); + } } return DIRENTRY_SIZE(utf8chars); @@ -839,26 +112,12 @@ PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op = kBTreeNextRecord; } else { /* start from beginning */ - UInt32 heuristicHint; - UInt32 *cachedHint; - *op = kBTreeNextRecord; - /* - * We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint - * is a mapping of dirID and nodeNumber, in hopes that the current - * search will be in the same node as the last search with the same - * parentID. - */ - result = GetMRUCacheBlock( cip->folderID, vol->hintCachePtr, (Ptr *)&cachedHint ); - heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; - /* Position iterator at the folder's thread record */ - result = BTSearchRecord(fcb, bip, heuristicHint, NULL, NULL, bip); + result = BTSearchRecord(fcb, bip, NULL, NULL, bip); if (result) goto exit; - - InsertMRUCacheBlock( vol->hintCachePtr, cip->folderID, (Ptr) &bip->hint.nodeNum ); /* find offset (note: n^2 / 2) */ if (offset > CAT_START_OFFSET) { @@ -878,7 +137,7 @@ PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 pid = *idp; curOffset = CAT_START_OFFSET; - nextOffset = GetDirEntrySize(bip, vol); + nextOffset = CAT_START_OFFSET + GetDirEntrySize(bip, vol); while (nextOffset < offset) { result = BTIterateRecord( fcb, kBTreeNextRecord, bip, NULL, NULL ); @@ -915,866 +174,6 @@ exit: } /* end PositionIterator */ -//_________________________________________________________________________________ -// Routine: GetCatalogOffspring -// -// Function: Gets an offspring record from a specified folder. The folder -// is identified by it's folderID. The desired offspring CNode is -// indicated by the value of the offspring index (1 = 1st offspring -// CNode, 2 = 2nd offspring CNode, etc.). -// -//_________________________________________________________________________________ - -OSErr -GetCatalogOffspring(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index, - CatalogNodeData *nodeData, - HFSCatalogNodeID *nodeID, SInt16 *nodeType) -{ - CatalogIterator * catalogIterator; - OSErr result; - - - if ( folderID == 0 ) - return cmNotFound; - - /* - * return cmNotFound for index 32767, to prevent overflowing - * the index into negative numbers. - */ - if ( index == 32767 ) - return cmNotFound; - - // get best catalog iterator... - catalogIterator = oGetCatalogIterator(volume, folderID, index); - - result = IterateCatalogNode(volume, catalogIterator, index, - nodeData, nodeID, nodeType); - - (void) ReleaseCatalogIterator(catalogIterator); - - return result; - -} // end GetCatalogOffspring - - -//_________________________________________________________________________________ -// Routine: IterateCatalogNode -// -// Function: Gets an offspring record from a specified folder. The folder -// is identified by it's folderID. The desired offspring CNode is -// indicated by the value of the offspring index (1 = 1st offspring -// CNode, 2 = 2nd offspring CNode, etc.). -// -//_________________________________________________________________________________ - -static OSErr -IterateCatalogNode( ExtendedVCB *volume, CatalogIterator *catalogIterator, UInt16 index, - CatalogNodeData *nodeData, HFSCatalogNodeID *nodeID, - SInt16 *nodeType ) -{ - HFSCatalogNodeID offspringParentID; - CatalogKey * offspringKey; - CatalogName * offspringName; - BTreeIterator btreeIterator; - FSBufferDescriptor btRecord; - CatalogRecord * record; - UInt8 databuf[32]; /* space for partial record */ - FCB * fcb; - SInt16 selectionIndex; - UInt16 tempSize; - UInt16 operation; - OSErr result; - Boolean isHFSPlus; - ByteCount utf8len; - - - isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - fcb = GetFileControlBlock(volume->catalogRefNum); - - // make a btree iterator from catalog iterator - UpdateBtreeIterator(catalogIterator, &btreeIterator); - - /* if client doesn't want data (ie readdir), just get type and id */ - if (nodeData == NULL) { - /* data buf has space to cover all type/id offsets */ - btRecord.bufferAddress = databuf; - btRecord.itemSize = sizeof(databuf); - } else if (isHFSPlus) { - btRecord.bufferAddress = nodeData; - btRecord.itemSize = sizeof(CatalogNodeData); - } else { - btRecord.bufferAddress = &nodeData->cnd_extra; - btRecord.itemSize = sizeof(HFSCatalogFile); - } - btRecord.itemCount = 1; - - //--- if neccessary position the iterator at the thread record for the specified folder - - if ( catalogIterator->currentIndex == 0 ) // is this a new iterator? - { - UInt32 heuristicHint; - UInt32 *cachedHint; - - // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of - // dirID and nodeNumber, in hopes that the current search will be in the same node - // as the last search with the same parentID. - result = GetMRUCacheBlock( catalogIterator->folderID, volume->hintCachePtr, (Ptr *)&cachedHint ); - heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey; - - result = BTSearchRecord( fcb, &btreeIterator, heuristicHint, &btRecord, &tempSize, &btreeIterator ); - ExitOnError(result); - - UpdateCatalogIterator(&btreeIterator, catalogIterator); // update btree hint and key - - InsertMRUCacheBlock( volume->hintCachePtr, catalogIterator->folderID, (Ptr) &btreeIterator.hint.nodeNum ); - } - - //--- get offspring record (relative to catalogIterator's position) - - selectionIndex = index - catalogIterator->currentIndex; - - // now we have to map index into next/prev operations... - if (selectionIndex == 1) - { - operation = kBTreeNextRecord; - } - else if (selectionIndex == -1) - { - operation = kBTreePrevRecord; - } - else if (selectionIndex == 0) - { - operation = kBTreeCurrentRecord; - } - else if (selectionIndex > 1) - { - UInt32 i; - - for (i = 1; i < selectionIndex; ++i) - { - result = BTIterateRecord( fcb, kBTreeNextRecord, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - } - operation = kBTreeNextRecord; - } - else // (selectionIndex < -1) - { - SInt32 i; - - for (i = -1; i > selectionIndex; --i) - { - result = BTIterateRecord( fcb, kBTreePrevRecord, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - } - operation = kBTreePrevRecord; - } - - result = BTIterateRecord( fcb, operation, &btreeIterator, &btRecord, &tempSize ); - ExitOnError(result); - - offspringKey = (CatalogKey*) &btreeIterator.key; - - if (isHFSPlus) - { - offspringParentID = offspringKey->hfsPlus.parentID; - offspringName = (CatalogName*) &offspringKey->hfsPlus.nodeName; - } - else - { - offspringParentID = offspringKey->hfs.parentID; - offspringName = (CatalogName*) offspringKey->hfs.nodeName; - } - - if (offspringParentID != catalogIterator->folderID) // different parent? - { - AgeCatalogIterator(catalogIterator); // we reached the end, so don't hog the cache! - - result = cmNotFound; // must be done with this folder - goto ErrorExit; - } - - UpdateCatalogIterator(&btreeIterator, catalogIterator); // update btree hint and key - catalogIterator->currentIndex = index; // update the offspring index marker - - record = (CatalogRecord *) btRecord.bufferAddress; - - if (nodeData == NULL) { /* Just copy the id and type...not name */ - if (isHFSPlus) - { - *nodeType = record->recordType; - *nodeID = record->hfsPlusFolder.folderID; - } - else /* hfs name */ - { - - if (record->recordType == kHFSFileRecord) { - *nodeType = kCatalogFileNode; - *nodeID = record->hfsFile.fileID; - } else if (record->recordType == kHFSFolderRecord) { - *nodeType = kCatalogFolderNode; - *nodeID = record->hfsFolder.folderID; - } else - result = cmNotFound; - } - } else { - nodeData->cnm_parID = isHFSPlus ? offspringKey->hfsPlus.parentID : offspringKey->hfs.parentID; - nodeData->cnm_nameptr = nodeData->cnm_namespace; - if (isHFSPlus) - { - result = utf8_encodestr(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - nodeData->cnm_namespace, (size_t *)&utf8len, - MAXHFSVNODELEN + 1, ':', 0); - - /* Need to allocate buffer large enough */ - if (result == ENAMETOOLONG) { - utf8len = utf8_encodelen(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - ':', 0); - nodeData->cnm_nameptr = NewPtr(utf8len + 1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = utf8_encodestr(offspringName->ustr.unicode, - offspringName->ustr.length * sizeof(UniChar), - nodeData->cnm_nameptr, (size_t *)&utf8len, - utf8len + 1, ':', 0); - } - } - else /* hfs name */ - { - if (record->recordType == kHFSFolderRecord || record->recordType == kHFSFileRecord) { - - CopyCatalogNodeData(volume, record, nodeData); - result = hfs_to_utf8(volume, offspringName->pstr, MAXHFSVNODELEN + 1, &utf8len, nodeData->cnm_namespace); - if (result == ENAMETOOLONG) { /* Need to allocate buffer large enough */ - nodeData->cnm_nameptr = NewPtr(utf8len+1); - nodeData->cnm_flags |= kCatNameIsAllocated; - result = hfs_to_utf8(volume, offspringName->pstr, utf8len + 1, &utf8len, nodeData->cnm_nameptr); - } - - } else { - result = cmNotFound; - } - } - } - - return result; - -ErrorExit: - - if ( result == btNotFound ) - result = cmNotFound; - - return result; - -} // end IterateCatalogNode - - -//_________________________________________________________________________________ -// Routine: MoveRenameCatalogNode -// -// Function: Moves and/or rename an existing folder or file CNode. -// Note that when moving a folder, all decendants (its offspring, -// their offspring, etc.) are also moved. -// -// Assumes srcHint contains a text encoding that was set by a GetCatalogNode call -//_________________________________________________________________________________ - -OSErr -MoveRenameCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID srcParentID, ConstUTF8Param srcName, - UInt32 srcHint, HFSCatalogNodeID dstParentID, ConstUTF8Param dstName, UInt32 *newHint) -{ - CatalogKey srcKey; // 518 bytes - CatalogRecord srcRecord; // 520 bytes - CatalogKey dstKey; // 518 bytes - CatalogKey dstFolderKey; // 518 bytes - HFSCatalogNodeID dstFolderParentID = 0; - UInt32 dstFolderHint; - CatalogName *dstFolderNamePtr = NULL; - CatalogRecord tmpRecord; // 520 bytes - HFSCatalogNodeID threadID; - UInt32 textEncoding; - OSErr result; - Boolean isNewName; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - Boolean isOrigDeleted = false; - short srcNameLen; - short dstNameLen; - - - result = BuildCatalogKeyUTF8(volume, srcParentID, srcName, kUndefinedStrLen, &srcKey, &textEncoding); - ReturnIfError(result); - - /* XXX can strlen and bcmp handle NULL pointers? */ - - srcNameLen = strlen(srcName); - dstNameLen = strlen(dstName); - - //--- check if names match - - if ((srcNameLen == dstNameLen) && (bcmp(srcName, dstName, srcNameLen) == 0)) - { - isNewName = false; - dstKey = srcKey; - if ( isHFSPlus ) { - dstKey.hfsPlus.parentID = dstParentID; // set parent ID - } - else { - dstKey.hfs.parentID = dstParentID; // set parent ID - } - } - else /* names are different */ - { - isNewName = true; - result = BuildCatalogKeyUTF8(volume, dstParentID, dstName, kUndefinedStrLen, &dstKey, &textEncoding); - ReturnIfError(result); - } - - //--- make sure source record exists - - result = LocateCatalogNodeByKey(volume, srcHint, &srcKey, &srcRecord, &srcHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, srcParentID, srcName, kUndefinedStrLen, &srcKey, &srcRecord, &srcHint); - ReturnIfError(result); - - srcParentID = (isHFSPlus ? srcKey.hfsPlus.parentID : srcKey.hfs.parentID); - - // if we're moving then do some additional preflighting... - - if (srcParentID != dstParentID) - { - //--- make sure destination folder exists - - result = LocateCatalogNode(volume, dstParentID, NULL, kNoHint, &dstFolderKey, &tmpRecord, &dstFolderHint); - ReturnIfError(result); - - if (tmpRecord.recordType == kHFSPlusFolderRecord) - { - dstParentID = tmpRecord.hfsPlusFolder.folderID; - dstFolderParentID = dstFolderKey.hfsPlus.parentID; - dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfsPlus.nodeName; - } - else if (tmpRecord.recordType == kHFSFolderRecord) - { - dstParentID = tmpRecord.hfsFolder.folderID; - dstFolderParentID = dstFolderKey.hfs.parentID; - dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfs.nodeName; - } - else - { - return badMovErr; - } - - //--- if source is a folder, make sure its a proper move - - if (srcRecord.recordType == kHFSPlusFolderRecord || srcRecord.recordType == kHFSFolderRecord) - { - HFSCatalogNodeID srcFolderID; - HFSCatalogNodeID ancestorParentID; - CatalogKey tempKey; // 518 bytes - UInt32 tempHint; - - if (isHFSPlus) - { - srcFolderID = srcRecord.hfsPlusFolder.folderID; - ancestorParentID = dstFolderKey.hfsPlus.parentID; - } - else - { - srcFolderID = srcRecord.hfsFolder.folderID; - ancestorParentID = dstFolderKey.hfs.parentID; - } - - if ( srcFolderID == fsRtDirID || // source == root? - srcFolderID == dstParentID || // source == destination? - srcFolderID == ancestorParentID ) // source == destination's parent? - { - return badMovErr; - } - - while (ancestorParentID > fsRtDirID) // loop until we reach the root folder - { - // locate next folder up the tree... - result = LocateCatalogNode(volume, ancestorParentID, NULL, kNoHint, &tempKey, &tmpRecord, &tempHint); - ReturnIfError(result); - - ancestorParentID = isHFSPlus ? tempKey.hfsPlus.parentID : tempKey.hfs.parentID; - - if (srcFolderID == ancestorParentID) // source = destination ancestor? - return badMovErr; - } - } - - TrashCatalogIterator(volume, dstParentID); // invalidate any iterators for destination parentID - } - else /* (srcParentID == dstParentID) */ - { - if ( !isNewName ) - { - *newHint = srcHint; // they match, so we're all done! - return noErr; - } - } - - TrashCatalogIterator(volume, srcParentID); // invalidate any iterators for source's parentID - InvalidateCatalogNodeCache(volume, srcParentID); // invalidate node cache since parent changed - - if (isNewName && isHFSPlus) - { - // update textEncoding hint (works for folders and files) - srcRecord.hfsPlusFolder.textEncoding = textEncoding; - - UpdateVolumeEncodings(volume, textEncoding); - } - - //--- insert source CNode record in BTree with new key (a new parent id and/or new name) - - result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, GetCatalogRecordSize(&srcRecord), newHint); - - if (result == btExists) - { - UInt16 dataSize; - - /* XXX what about the case: move id1,foo to id2,FOO ?? */ - if (srcParentID != dstParentID || isNewName == false) - return cmExists; - - //--- new CNode name already exists in the same folder, locate the existing one - result = SearchBTreeRecord(volume->catalogRefNum, &dstKey, srcHint, - &dstFolderKey, &tmpRecord, &dataSize, newHint); - - if (result == btNotFound) - result = cmNotFound; - ReturnIfError(result); - - //--- check if its the same CNode (same name but different upper/lower case) - - if (srcRecord.recordType != tmpRecord.recordType) - return cmExists; - - switch (srcRecord.recordType) - { - case kHFSPlusFileRecord: /* HFS Plus records share same cnid location */ - case kHFSPlusFolderRecord: - if (srcRecord.hfsPlusFolder.folderID != tmpRecord.hfsPlusFolder.folderID) - return cmExists; - break; - - case kHFSFolderRecord: - if (srcRecord.hfsFolder.folderID != tmpRecord.hfsFolder.folderID) - return cmExists; - break; - - case kHFSFileRecord: - if (srcRecord.hfsFile.fileID != tmpRecord.hfsFile.fileID) - return cmExists; - break; - - default: - return cmExists; - } - - //--- same name but different case, so delete old and insert with new name... - - result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey); - ReturnIfError(result); - isOrigDeleted = true; // So we dont delete it again down below - - result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, dataSize, newHint); - } - ReturnIfError(result); - - // - // from this point on we need to cleanup (ie delete the new record) if we encounter errors! - // - - //--- update thread record for node (if it exists) - - switch (srcRecord.recordType) - { - case kHFSPlusFileRecord: - case kHFSPlusFolderRecord: - threadID = srcRecord.hfsPlusFolder.folderID; - break; - - case kHFSFolderRecord: - threadID = srcRecord.hfsFolder.folderID; - break; - - case kHFSFileRecord: - if (srcRecord.hfsFile.flags & kHFSThreadExistsMask) - { - threadID = srcRecord.hfsFile.fileID; - break; - } - /* fall through if no thread... */ - - default: - threadID = 0; - } - - if (threadID) - { - UInt32 threadHint; - CatalogKey threadKey; // 518 bytes - CatalogRecord threadRecord; // 520 bytes - UInt16 threadSize; - - result = LocateCatalogRecord(volume, threadID, NULL, kNoHint, &threadKey, &threadRecord, &threadHint); - if (result != noErr) goto Exit_Delete; - - if (isHFSPlus) - { - if (srcParentID != dstParentID) - threadRecord.hfsPlusThread.parentID = dstParentID; - if (isNewName) - CopyCatalogName((CatalogName *)&dstKey.hfsPlus.nodeName, (CatalogName *) &threadRecord.hfsPlusThread.nodeName, isHFSPlus); - - threadSize = sizeof(threadRecord.hfsPlusThread); - // HFS Plus has varaible sized threads so adjust to actual length - threadSize -= ( sizeof(threadRecord.hfsPlusThread.nodeName.unicode) - (threadRecord.hfsPlusThread.nodeName.length * sizeof(UniChar)) ); - } - else - { - if (srcParentID != dstParentID) - threadRecord.hfsThread.parentID = dstParentID; - if (isNewName) - CopyCatalogName((CatalogName *)&dstKey.hfs.nodeName,(CatalogName *) threadRecord.hfsThread.nodeName, isHFSPlus); - - threadSize = sizeof(threadRecord.hfsThread); - } - - result = DeleteBTreeRecord(volume->catalogRefNum, &threadKey); - if (result != noErr) goto Exit_Delete; - - result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadRecord, threadSize, &threadHint); - if (result != noErr) goto Exit_Delete; //XXX exiting with a missing thread! - } - - //--- we successfully added the new node so delete the old source CNode record - - if (! isOrigDeleted) { - result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey); - if (result) - { - // uh oh, we could not delete the original - // so we better get rid of the new node... - - (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey); - - //XXX also need to fix up the thread... - - return result; - } - } - - if (srcParentID != dstParentID) - { - result = UpdateFolderCount(volume, srcParentID, NULL, srcRecord.recordType, kNoHint, -1); - result = UpdateFolderCount(volume, dstFolderParentID, dstFolderNamePtr, srcRecord.recordType, dstFolderHint, +1); - } - - //--- make sure changes get flushed out - VCB_LOCK(volume); - volume->vcbFlags |= 0xFF00; // Mark the VCB dirty - volume->vcbLsMod = GetTimeUTC(); // update last modified date - VCB_UNLOCK(volume); - - (void) FlushCatalog(volume); - - return result; - - -Exit_Delete: - (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey); - - return result; - -} // end MoveRenameCatalogNode - - -//_________________________________________________________________________________ -// Routine: UpdateCatalogNode -// -// Function: Marks the Catalog BTree node identified by the given catalog hint -// as 'dirty'. -// -//_________________________________________________________________________________ - - -OSErr -UpdateCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, - UInt32 catalogHint, const CatalogNodeData *nodeData) -{ - CatalogKey *key; - CatalogRecord *record; - UInt32 hint; - UInt16 recordSize; - OSErr result; - CatalogKey catalogKey; // 518 bytes - CatalogRecord catalogRecord; // 520 bytes - Boolean isHFSPlus = volume->vcbSigWord == kHFSPlusSigWord; - - /* XXX no reason to have ptrs to local variables... */ - key = &catalogKey; - record = &catalogRecord; - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, key, NULL); - ReturnIfError(result); - - //--- locate subject catalog node - - result = LocateCatalogNodeByKey(volume, catalogHint, key, record, &hint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, key, record, &hint); - - if (result == btNotFound) - result = cmNotFound; - - if (catalogHint != hint) - PRINTIT(("UpdateCatalogNode: catalogHint does not match (in: %ld, out: %ld)\n", catalogHint, hint)); - ReturnIfError(result); - - // update user modifiable fields in the catalog node record... - - switch (record->recordType) - { - case kHFSFolderRecord: - { - #if DEBUG_BUILD - if (nodeData->cnd_type != kCatalogFolderNode) - DebugStr("\p UpdateCatalogNode: folder/file mismatch!"); - #endif - - record->hfsFolder.createDate = UTCToLocal(nodeData->cnd_createDate); - record->hfsFolder.modifyDate = UTCToLocal(nodeData->cnd_contentModDate); - record->hfsFolder.backupDate = UTCToLocal(nodeData->cnd_backupDate); - - *(DInfo*) &record->hfsFolder.userInfo = *(DInfo*) &nodeData->cnd_finderInfo; - *(DXInfo*) &record->hfsFolder.finderInfo = *(DXInfo*) ((UInt32)&nodeData->cnd_finderInfo + 16); - - recordSize = sizeof(HFSCatalogFolder); - break; - } - - case kHFSFileRecord: - { - UInt32 i; - - #if DEBUG_BUILD - if (nodeData->cnd_type != kCatalogFileNode) - DebugStr("UpdateCatalogNode: folder/file mismatch!"); - if ((nodeData->cnd_datafork.totalBlocks > (0x7FFFFFFF/volume->blockSize)) || - (nodeData->cnd_rsrcfork.totalBlocks > (0x7FFFFFFF/volume->blockSize))) - DebugStr("HFS file size is larger than 2Gig"); - #endif - - record->hfsFile.flags = (UInt8) nodeData->cnd_flags; - record->hfsFile.createDate = UTCToLocal(nodeData->cnd_createDate); - record->hfsFile.modifyDate = UTCToLocal(nodeData->cnd_contentModDate); - record->hfsFile.backupDate = UTCToLocal(nodeData->cnd_backupDate); - - record->hfsFile.dataLogicalSize = nodeData->cnd_datafork.logicalSize; - record->hfsFile.dataPhysicalSize = nodeData->cnd_datafork.totalBlocks * volume->blockSize; - record->hfsFile.rsrcLogicalSize = nodeData->cnd_rsrcfork.logicalSize; - record->hfsFile.rsrcPhysicalSize = nodeData->cnd_rsrcfork.totalBlocks * volume->blockSize; - - *(FInfo*) &record->hfsFile.userInfo = *(FInfo*) &nodeData->cnd_finderInfo; - *(FXInfo*) &record->hfsFile.finderInfo = *(FXInfo*) ((UInt32)&nodeData->cnd_finderInfo + 16); - - // copy extent info - for (i = 0; i < kHFSExtentDensity; ++i) - { - record->hfsFile.dataExtents[i].startBlock = - (UInt16) nodeData->cnd_datafork.extents[i].startBlock; - record->hfsFile.dataExtents[i].blockCount = - (UInt16) nodeData->cnd_datafork.extents[i].blockCount; - record->hfsFile.rsrcExtents[i].startBlock = - (UInt16) nodeData->cnd_rsrcfork.extents[i].startBlock; - record->hfsFile.rsrcExtents[i].blockCount = - (UInt16) nodeData->cnd_rsrcfork.extents[i].blockCount; - } - - recordSize = sizeof(HFSCatalogFile); - break; - } - - case kHFSPlusFolderRecord: - { - record->hfsPlusFolder.createDate = nodeData->cnd_createDate; - record->hfsPlusFolder.contentModDate = nodeData->cnd_contentModDate; - record->hfsPlusFolder.backupDate = nodeData->cnd_backupDate; - record->hfsPlusFolder.accessDate = nodeData->cnd_accessDate; - record->hfsPlusFolder.attributeModDate = nodeData->cnd_attributeModDate; - record->hfsPlusFolder.bsdInfo.ownerID = nodeData->cnd_ownerID; - record->hfsPlusFolder.bsdInfo.groupID = nodeData->cnd_groupID; - record->hfsPlusFolder.bsdInfo.ownerFlags = nodeData->cnd_ownerFlags; - record->hfsPlusFolder.bsdInfo.adminFlags = nodeData->cnd_adminFlags; - record->hfsPlusFolder.bsdInfo.fileMode = nodeData->cnd_mode; - record->hfsPlusFolder.textEncoding = nodeData->cnd_textEncoding; - - BlockMoveData(&nodeData->cnd_finderInfo, &record->hfsPlusFolder.userInfo, 32); - - recordSize = sizeof(HFSPlusCatalogFolder); - break; - } - - case kHFSPlusFileRecord: - { - record->hfsPlusFile.flags = nodeData->cnd_flags; - record->hfsPlusFile.createDate = nodeData->cnd_createDate; - record->hfsPlusFile.contentModDate = nodeData->cnd_contentModDate; - record->hfsPlusFile.backupDate = nodeData->cnd_backupDate; - record->hfsPlusFile.accessDate = nodeData->cnd_accessDate; - record->hfsPlusFile.attributeModDate = nodeData->cnd_attributeModDate; - record->hfsPlusFile.bsdInfo.ownerID = nodeData->cnd_ownerID; - record->hfsPlusFile.bsdInfo.groupID = nodeData->cnd_groupID; - record->hfsPlusFile.bsdInfo.ownerFlags = nodeData->cnd_ownerFlags; - record->hfsPlusFile.bsdInfo.adminFlags = nodeData->cnd_adminFlags; - record->hfsPlusFile.bsdInfo.fileMode = nodeData->cnd_mode; - /* get special value (iNodeNum, linkCount or rawDevice) */ - record->hfsPlusFile.bsdInfo.special.rawDevice = nodeData->cnd_rawDevice; - record->hfsPlusFile.textEncoding = nodeData->cnd_textEncoding; - - record->hfsPlusFile.dataFork.logicalSize = nodeData->cnd_datafork.logicalSize; - record->hfsPlusFile.dataFork.totalBlocks = nodeData->cnd_datafork.totalBlocks; - BlockMoveData(&nodeData->cnd_datafork.extents, - &record->hfsPlusFile.dataFork.extents, sizeof(HFSPlusExtentRecord)); - - record->hfsPlusFile.resourceFork.logicalSize = nodeData->cnd_rsrcfork.logicalSize; - record->hfsPlusFile.resourceFork.totalBlocks = nodeData->cnd_rsrcfork.totalBlocks; - BlockMoveData(&nodeData->cnd_rsrcfork.extents, - &record->hfsPlusFile.resourceFork.extents, sizeof(HFSPlusExtentRecord)); - - BlockMoveData(&nodeData->cnd_finderInfo, &record->hfsPlusFile.userInfo, 32); - -#if HFS_HARDLINKS && DEBUG_BUILD - /* Must swap opaque finder data */ - if (SWAP_BE32 (record->hfsPlusFile.userInfo.fdType) == kHardLinkFileType && - SWAP_BE32 (record->hfsPlusFile.userInfo.fdCreator) == kHardLinkCreator) { - if (record->hfsPlusFile.dataFork.logicalSize != 0) - DebugStr("UpdateCatalogNode: link has data fork!"); - } -#endif - recordSize = sizeof(HFSPlusCatalogFile); - break; - } - - default: - return cmNotFound; - } - - result = ReplaceBTreeRecord(volume->catalogRefNum, key, catalogHint, record, recordSize, &hint); - - if ( result == btNotFound ) - { - result = cmNotFound; - } - else if ( result == noErr ) - { - /* if we're just updating the accessDate then no need to change volume mod date */ - if (nodeData->cnd_contentModDate > volume->vcbLsMod || - (isHFSPlus && nodeData->cnd_attributeModDate > volume->vcbLsMod)) - { - VCB_LOCK(volume); - volume->vcbFlags |= 0xFF00; // Mark the VCB dirty - volume->vcbLsMod = GetTimeUTC(); // update last modified date - VCB_UNLOCK(volume); - } - - result = FlushCatalog(volume); // flush the catalog - } - - return result; -} - - -//_________________________________________________________________________________ -// Routine: CreateFileIDRef -// -// Function: Creates a file thread record for hfs file node -// -//_________________________________________________________________________________ - -OSErr -CreateFileIDRef(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint, HFSCatalogNodeID *threadID) -{ - CatalogKey nodeKey; // 518 bytes - CatalogRecord nodeData; // 520 bytes - HFSCatalogKey threadKey; - HFSCatalogThread threadData; - UInt32 nodeHint; - UInt32 tempHint; - OSErr result; - Boolean isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord); - - *threadID = 0; - - result = BuildCatalogKeyUTF8(volume, parentID, name, kUndefinedStrLen, &nodeKey, NULL); - ReturnIfError(result); - - //--- locate subject catalog node - - result = LocateCatalogNodeByKey(volume, hint, &nodeKey, &nodeData, &nodeHint); - - // if we did not find it by name, then look for an embedded file ID in a mangled name - if ( (result == cmNotFound) && isHFSPlus ) - result = LocateCatalogNodeByMangledName(volume, parentID, name, kUndefinedStrLen, &nodeKey, &nodeData, &nodeHint); - ReturnIfError(result); - - if (nodeData.recordType == kHFSPlusFileRecord) - { - *threadID = nodeData.hfsPlusFile.fileID; - return noErr; // already have one - } - - if (nodeData.recordType != kHFSFileRecord) - { - return notAFileErr; - } - - - if (nodeData.hfsFile.flags & kHFSThreadExistsMask) - { - *threadID = nodeData.hfsFile.fileID; - return noErr; // already have one - } - - result = VolumeWritable( volume ); - if ( result != noErr ) return result; - - // - // need to insert a thread record - // - BuildCatalogKey(nodeData.hfsFile.fileID, NULL, false, (CatalogKey *)&threadKey); - - ClearMemory(&threadData, sizeof(HFSCatalogThread)); - threadData.recordType = kHFSFileThreadRecord; - threadData.parentID = nodeKey.hfs.parentID; - BlockMoveData(&nodeKey.hfs.nodeName, &threadData.nodeName, nodeKey.hfs.nodeName[0] + 1); - - result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadData, sizeof(HFSCatalogThread), &tempHint); - if (result == btExists) result = noErr; //XXX could return cmExists or fidExists - ReturnIfError(result); - - // - // Finally, set the flag in the file record to say this file has a thread record. - // - nodeData.hfsFile.flags |= kHFSThreadExistsMask; - result = ReplaceBTreeRecord(volume->catalogRefNum, &nodeKey, nodeHint, &nodeData, sizeof(HFSCatalogFile), &nodeHint ); - - if (result == noErr) { - (void) FlushCatalog(volume); - *threadID = nodeData.hfsFile.fileID; - } - - return result; -} - - //_________________________________________________________________________________ // Routine: CompareCatalogKeys // @@ -1799,18 +198,8 @@ CompareCatalogKeys(HFSCatalogKey *searchKey, HFSCatalogKey *trialKey) else if ( searchParentID < trialParentID ) result = -1; else // parent dirID's are equal, compare names - { - #if ( ! FORDISKFIRSTAID ) - LogStartTime(kTraceRelString); - result = FastRelString(searchKey->nodeName, trialKey->nodeName); - LogEndTime(kTraceRelString, noErr); - #else - result = (SInt32) RelString_Glue(searchKey->nodeName, trialKey->nodeName); - #endif - } - return result; }