#include "Scavenger.h"
OSErr FlushCatalogFile( SVCB *vcb )
{
OSErr err;
err = BTFlushPath(vcb->vcbCatalogFile);
if ( err == noErr )
{
if( ( vcb->vcbCatalogFile->fcbFlags & fcbModifiedMask ) != 0 )
{
(void) MarkVCBDirty( vcb );
err = FlushVolumeControlBlock( vcb );
}
}
return( err );
}
OSErr LocateCatalogNode(SFCB *fcb, BTreeIterator *iterator, FSBufferDescriptor *btRecord, UInt16 *reclen)
{
CatalogRecord * recp;
CatalogKey * keyp;
CatalogName * namep = NULL;
UInt32 threadpid = 0;
OSErr result;
Boolean isHFSPlus = false;
result = BTSearchRecord(fcb, iterator, kInvalidMRUCacheKey, btRecord, reclen, iterator);
if (result == btNotFound)
result = cmNotFound;
ReturnIfError(result);
recp = (CatalogRecord *)btRecord->bufferAddress;
keyp = (CatalogKey*)&iterator->key;
switch (recp->recordType) {
case kHFSFileThreadRecord:
case kHFSFolderThreadRecord:
threadpid = recp->hfsThread.parentID;
namep = (CatalogName *) &recp->hfsThread.nodeName;
isHFSPlus = false;
break;
case kHFSPlusFileThreadRecord:
case kHFSPlusFolderThreadRecord:
threadpid = recp->hfsPlusThread.parentID;
namep = (CatalogName *) &recp->hfsPlusThread.nodeName;
isHFSPlus = true;
break;
default:
threadpid = 0;
break;
}
if (threadpid) {
(void) BTInvalidateHint(iterator);
BuildCatalogKey(threadpid, namep, isHFSPlus, keyp);
result = BTSearchRecord(fcb, iterator, kInvalidMRUCacheKey, btRecord, reclen, iterator);
}
return result;
}
OSErr
UpdateFolderCount(SVCB *vcb, HFSCatalogNodeID pid, const CatalogName *name, SInt16 newType,
UInt32 hint, SInt16 valenceDelta)
{
CatalogRecord tempData; HFSCatalogNodeID folderID;
UInt16 reclen;
OSErr result;
BTreeIterator btIterator;
FSBufferDescriptor btRecord;
btRecord.bufferAddress = &tempData;
btRecord.itemCount = 1;
btRecord.itemSize = sizeof(tempData);
ClearMemory(&btIterator, sizeof(btIterator));
btIterator.hint.nodeNum = hint;
BuildCatalogKey(pid, name, vcb->vcbSignature == kHFSPlusSigWord, (CatalogKey*)&btIterator.key);
result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
ReturnIfError(result);
if (vcb->vcbSignature == kHFSPlusSigWord) {
UInt32 timeStamp;
timeStamp = GetTimeUTC();
tempData.hfsPlusFolder.valence += valenceDelta; tempData.hfsPlusFolder.contentModDate = timeStamp; folderID = tempData.hfsPlusFolder.folderID;
} else {
tempData.hfsFolder.valence += valenceDelta; tempData.hfsFolder.modifyDate = GetTimeLocal(true); folderID = tempData.hfsFolder.folderID;
}
result = BTReplaceRecord(vcb->vcbCatalogFile, &btIterator, &btRecord, reclen);
ReturnIfError(result);
if (folderID == kHFSRootFolderID) {
if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
vcb->vcbNmRtDirs += valenceDelta; else
vcb->vcbNmFls += valenceDelta; }
if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
vcb->vcbFolderCount += valenceDelta; else
vcb->vcbFileCount += valenceDelta;
vcb->vcbModifyDate = GetTimeUTC(); MarkVCBDirty( vcb );
return result;
}
OSErr
DeleteCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint)
{
CatalogKey * keyp;
CatalogRecord rec;
BTreeIterator btIterator;
FSBufferDescriptor btRecord;
HFSCatalogNodeID nodeID;
HFSCatalogNodeID nodeParentID;
UInt16 nodeType;
UInt16 reclen;
OSErr result;
Boolean isHFSPlus = (vcb->vcbSignature == kHFSPlusSigWord);
btRecord.bufferAddress = &rec;
btRecord.itemCount = 1;
btRecord.itemSize = sizeof(rec);
ClearMemory(&btIterator, sizeof(btIterator));
btIterator.hint.nodeNum = hint;
keyp = (CatalogKey*)&btIterator.key;
BuildCatalogKey(pid, name, isHFSPlus, keyp);
result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
ReturnIfError(result);
nodeParentID = isHFSPlus ? keyp->hfsPlus.parentID : keyp->hfs.parentID;
nodeType = rec.recordType;
nodeID = 0;
switch (nodeType) {
case kHFSFolderRecord:
if (rec.hfsFolder.valence != 0)
return cmNotEmpty;
nodeID = rec.hfsFolder.folderID;
break;
case kHFSPlusFolderRecord:
if (rec.hfsPlusFolder.valence != 0)
return cmNotEmpty;
nodeID = rec.hfsPlusFolder.folderID;
break;
case kHFSFileRecord:
if (rec.hfsFile.flags & kHFSThreadExistsMask)
nodeID = rec.hfsFile.fileID;
break;
case kHFSPlusFileRecord:
nodeID = rec.hfsPlusFile.fileID;
break;
default:
return cmNotFound;
}
if (nodeID == kHFSRootFolderID)
return cmRootCN;
result = BTDeleteRecord(vcb->vcbCatalogFile, &btIterator);
ReturnIfError(result);
(void) BTInvalidateHint(&btIterator);
if ( nodeID ) {
BuildCatalogKey(nodeID, NULL, isHFSPlus, keyp);
(void) BTDeleteRecord(vcb->vcbCatalogFile, &btIterator);
}
result = UpdateFolderCount(vcb, nodeParentID, NULL, nodeType, kNoHint, -1);
ReturnIfError(result);
(void) FlushCatalogFile(vcb);
if ((nodeType == kHFSPlusFileRecord) || (nodeType == kHFSFileRecord))
result = DeallocateFile(vcb, &rec);
return result;
}
OSErr
GetCatalogNode(SVCB *vcb, UInt32 pid, const CatalogName * name, UInt32 hint, CatalogRecord *data)
{
CatalogKey * keyp;
BTreeIterator btIterator;
FSBufferDescriptor btRecord;
UInt16 reclen;
OSErr result;
Boolean isHFSPlus = (vcb->vcbSignature == kHFSPlusSigWord);
btRecord.bufferAddress = data;
btRecord.itemCount = 1;
btRecord.itemSize = sizeof(CatalogRecord);
ClearMemory(&btIterator, sizeof(btIterator));
btIterator.hint.nodeNum = hint;
keyp = (CatalogKey*)&btIterator.key;
BuildCatalogKey(pid, name, isHFSPlus, keyp);
result = LocateCatalogNode(vcb->vcbCatalogFile, &btIterator, &btRecord, &reclen);
return result;
}