-//_________________________________________________________________________________
-// 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;
-}
-
-