CatalogIterators.c [plain text]
#include "../../hfs_macos_defs.h"
#include "../../hfs.h"
#include "../../hfs_dbg.h"
#include "../../hfs_format.h"
#include "../headers/FileMgrInternal.h"
#include "../headers/BTreesInternal.h"
#include "../headers/CatalogPrivate.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <libkern/libkern.h>
#include <sys/lock.h>
static void InsertCatalogIteratorAsMRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
static void InsertCatalogIteratorAsLRU( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator );
static void PrepareForLongName( CatalogIterator *iterator );
#if TARGET_API_MACOS_X
CatalogCacheGlobals *gCatalogCacheGlobals;
#define GetCatalogCacheGlobals() (gCatalogCacheGlobals)
#define CATALOG_ITER_LIST_LOCK(g) simple_lock(&(g)->simplelock)
#define CATALOG_ITER_LIST_UNLOCK(g) simple_unlock(&(g)->simplelock)
#define CI_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE, (simple_lock_t) 0, current_proc())
#define CI_UNLOCK(i) lockmgr(&(i)->iterator_lock, LK_RELEASE, (simple_lock_t) 0, current_proc())
#define CI_SLEEPLESS_LOCK(i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_NOWAIT, (simple_lock_t) 0, current_proc())
#define CI_LOCK_FROM_LIST(g,i) lockmgr(&(i)->iterator_lock, LK_EXCLUSIVE | LK_INTERLOCK, &(g)->simplelock, current_proc())
#else
#define GetCatalogCacheGlobals() ((CatalogCacheGlobals*) ((FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals))
#define CATALOG_ITER_LIST_LOCK(g)
#define CATALOG_ITER_LIST_UNLOCK(g)
#define CI_LOCK(i) 0
#define CI_UNLOCK(i) 0
#define CI_SLEEPLESS_LOCK(i) 0
#define CI_LOCK_FROM_LIST(g,i) 0
#endif
OSErr
InitCatalogCache(void)
{
CatalogCacheGlobals * cacheGlobals;
CatalogIterator * iterator;
UInt32 cacheSize;
UInt16 i;
UInt16 lastIterator;
OSErr err;
cacheSize = sizeof(CatalogCacheGlobals) + ( kCatalogIteratorCount * sizeof(CatalogIterator) );
cacheGlobals = (CatalogCacheGlobals *) NewPtrSysClear( cacheSize );
cacheGlobals->iteratorCount = kCatalogIteratorCount;
lastIterator = kCatalogIteratorCount - 1;
cacheGlobals->mru = (CatalogIterator *) ( (Ptr)cacheGlobals + sizeof(CatalogCacheGlobals) );
cacheGlobals->lru = (CatalogIterator *) ( (Ptr)(cacheGlobals->mru) + (lastIterator * sizeof(CatalogIterator)) );
for ( i = 0, iterator = cacheGlobals->mru; i < kCatalogIteratorCount ; i++, iterator = iterator->nextMRU )
{
if ( i == lastIterator )
iterator->nextMRU = nil; else
iterator->nextMRU = (CatalogIterator *) ( (Ptr)iterator + sizeof(CatalogIterator) );
if ( i == 0 )
iterator->nextLRU = nil; else
iterator->nextLRU = (CatalogIterator *) ( (Ptr)iterator - sizeof(CatalogIterator) );
#if TARGET_API_MACOS_X
lockinit(&iterator->iterator_lock, PINOD, "hfs_catalog_iterator", 0, 0);
#endif
}
#if TARGET_API_MAC_OS8
(FSVarsRec*) LMGetFSMVars()->gCatalogCacheGlobals = (Ptr) cacheGlobals;
#endif
#if TARGET_API_MACOS_X
gCatalogCacheGlobals = cacheGlobals;
simple_lock_init(&cacheGlobals->simplelock);
#endif
return noErr;
}
void PrintCatalogIterator( void );
void
InvalidateCatalogCache( ExtendedVCB *volume )
{
TrashCatalogIterator( volume, 0 );
}
#if HFS_DIAGNOSTIC
void
PrintCatalogIterator( void )
{
CatalogIterator *iterator;
CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
int i;
PRINTIT("CatalogCacheGlobals @ 0x%08lX are:\n", (unsigned long)cacheGlobals);
PRINTIT("\titeratorCount: %ld \n", cacheGlobals->iteratorCount);
PRINTIT("\tmru: 0x%08lX \n", (unsigned long)cacheGlobals->mru);
PRINTIT("\tlru: 0x%08lX \n", (unsigned long)cacheGlobals->lru);
for ( iterator = cacheGlobals->mru, i=0 ; iterator != nil && i<32 ; iterator = iterator->nextMRU, i++)
{
PRINTIT("%d: ", i);
PRINTIT(" i: 0x%08lX", (unsigned long)iterator);
PRINTIT(" M: 0x%08lX", (unsigned long)iterator->nextMRU);
PRINTIT(" L: 0x%08lX", (unsigned long)iterator->nextLRU);
PRINTIT("\n");
}
}
#endif
void
TrashCatalogIterator( const ExtendedVCB *volume, HFSCatalogNodeID folderID )
{
CatalogIterator *iterator;
CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
CATALOG_ITER_LIST_LOCK(cacheGlobals);
for ( iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU )
{
top:
if ( iterator->volume != volume )
continue;
if ( (folderID == 0) || (folderID == iterator->folderID) )
{
CatalogIterator *next;
iterator->volume = 0; iterator->folderID = 0;
next = iterator->nextMRU;
if ( next != nil )
{
InsertCatalogIteratorAsLRU( cacheGlobals, iterator );
iterator = next;
goto top; }
}
}
CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
}
void
AgeCatalogIterator ( CatalogIterator *catalogIterator )
{
CatalogCacheGlobals * cacheGlobals = GetCatalogCacheGlobals();
CATALOG_ITER_LIST_LOCK(cacheGlobals);
InsertCatalogIteratorAsLRU( cacheGlobals, catalogIterator );
CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
}
OSErr
ReleaseCatalogIterator( CatalogIterator* catalogIterator)
{
#if TARGET_API_MACOS_X
return CI_UNLOCK(catalogIterator);
#else
return noErr;
#endif
}
CatalogIterator*
GetCatalogIterator(ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt32 offset)
{
CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
CatalogIterator *iterator;
CatalogIterator *bestIterator;
bestIterator = NULL;
CATALOG_ITER_LIST_LOCK(cacheGlobals);
for (iterator = cacheGlobals->mru ; iterator != nil ; iterator = iterator->nextMRU) {
if ((iterator->volume != volume) || (iterator->folderID != folderID)) {
continue;
}
if ( CI_SLEEPLESS_LOCK(iterator) == EBUSY ) {
continue;
}
if ( iterator->currentOffset == offset || iterator->nextOffset == offset) {
bestIterator = iterator; break; }
(void) CI_UNLOCK(iterator); }
if (bestIterator == NULL)
{
bestIterator = cacheGlobals->lru;
(void) CI_LOCK_FROM_LIST(cacheGlobals, bestIterator);
CATALOG_ITER_LIST_LOCK(cacheGlobals);
bestIterator->volume = volume; bestIterator->folderID = folderID; bestIterator->currentIndex = 0xFFFFFFFF; bestIterator->currentOffset = 0xFFFFFFFF;
bestIterator->nextOffset = 0xFFFFFFFF;
bestIterator->btreeNodeHint = 0;
bestIterator->btreeIndexHint = 0;
bestIterator->parentID = folderID; bestIterator->folderName.unicodeName.length = 0;
if ( volume->vcbSigWord == kHFSPlusSigWord )
bestIterator->nameType = kShortUnicodeName;
else
bestIterator->nameType = kShortPascalName;
}
else {
}
InsertCatalogIteratorAsMRU( cacheGlobals, bestIterator );
CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
return bestIterator;
}
void
UpdateBtreeIterator(const CatalogIterator *catalogIterator, BTreeIterator *btreeIterator)
{
CatalogName * nodeName;
Boolean isHFSPlus;
btreeIterator->hint.writeCount = 0;
btreeIterator->hint.nodeNum = catalogIterator->btreeNodeHint;
btreeIterator->hint.index = catalogIterator->btreeIndexHint;
switch (catalogIterator->nameType)
{
case kShortPascalName:
if ( catalogIterator->folderName.pascalName[0] > 0 )
nodeName = (CatalogName *) catalogIterator->folderName.pascalName;
else
nodeName = NULL;
isHFSPlus = false;
break;
case kShortUnicodeName:
if ( catalogIterator->folderName.unicodeName.length > 0 )
nodeName = (CatalogName *) &catalogIterator->folderName.unicodeName;
else
nodeName = NULL;
isHFSPlus = true;
break;
case kLongUnicodeName:
if ( catalogIterator->folderName.longNamePtr->length > 0 )
nodeName = (CatalogName *) catalogIterator->folderName.longNamePtr;
else
nodeName = NULL;
isHFSPlus = true;
break;
default:
return;
}
BuildCatalogKey(catalogIterator->parentID, nodeName, isHFSPlus, (CatalogKey*) &btreeIterator->key);
}
void
UpdateCatalogIterator (const BTreeIterator *btreeIterator, CatalogIterator *catalogIterator)
{
void * srcName;
void * dstName;
UInt16 nameSize;
CatalogKey * catalogKey;
catalogIterator->btreeNodeHint = btreeIterator->hint.nodeNum;
catalogIterator->btreeIndexHint = btreeIterator->hint.index;
catalogKey = (CatalogKey*) &btreeIterator->key;
switch (catalogIterator->nameType)
{
case kShortPascalName:
catalogIterator->parentID = catalogKey->hfs.parentID;
dstName = catalogIterator->folderName.pascalName;
srcName = catalogKey->hfs.nodeName;
nameSize = catalogKey->hfs.nodeName[0] + sizeof(UInt8);
break;
case kShortUnicodeName:
catalogIterator->parentID = catalogKey->hfsPlus.parentID;
dstName = &catalogIterator->folderName.unicodeName;
srcName = &catalogKey->hfsPlus.nodeName;
nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
if ( nameSize > sizeof(catalogIterator->folderName.unicodeName) )
{
PrepareForLongName(catalogIterator); dstName = catalogIterator->folderName.longNamePtr;
}
break;
case kLongUnicodeName:
catalogIterator->parentID = catalogKey->hfsPlus.parentID;
dstName = catalogIterator->folderName.longNamePtr;
srcName = &catalogKey->hfsPlus.nodeName;
nameSize = (catalogKey->hfsPlus.nodeName.length + 1) * sizeof(UInt16);
break;
default:
return;
}
if (catalogIterator->parentID != catalogIterator->folderID)
catalogIterator->nextOffset = 0xFFFFFFFF;
BlockMoveData(srcName, dstName, nameSize);
}
static void
InsertCatalogIteratorAsMRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
{
CatalogIterator *swapIterator;
if ( cacheGlobals->mru != iterator ) {
swapIterator = cacheGlobals->mru; cacheGlobals->mru = iterator;
iterator->nextLRU->nextMRU = iterator->nextMRU;
if ( iterator->nextMRU != nil )
iterator->nextMRU->nextLRU = iterator->nextLRU;
else
cacheGlobals->lru= iterator->nextLRU;
iterator->nextMRU = swapIterator;
iterator->nextLRU = nil;
swapIterator->nextLRU = iterator;
}
}
static void
InsertCatalogIteratorAsLRU ( CatalogCacheGlobals *cacheGlobals, CatalogIterator *iterator )
{
CatalogIterator *swapIterator;
if ( cacheGlobals->lru != iterator )
{
swapIterator = cacheGlobals->lru;
cacheGlobals->lru = iterator;
iterator->nextMRU->nextLRU = iterator->nextLRU;
if ( iterator->nextLRU != nil )
iterator->nextLRU->nextMRU = iterator->nextMRU;
else
cacheGlobals->mru= iterator->nextMRU;
iterator->nextLRU = swapIterator;
iterator->nextMRU = nil;
swapIterator->nextMRU = iterator;
}
}
static void
PrepareForLongName ( CatalogIterator *iterator )
{
CatalogCacheGlobals *cacheGlobals = GetCatalogCacheGlobals();
CatalogIterator *iter;
if (DEBUG_BUILD && iterator->nameType != kShortUnicodeName)
DebugStr("\p PrepareForLongName: nameType is wrong!");
CATALOG_ITER_LIST_LOCK(cacheGlobals);
for ( iter = cacheGlobals->mru ; iter != nil ; iter = iter->nextMRU )
{
if (iter->nameType == kLongUnicodeName)
{
if ( iter->nextMRU != nil )
InsertCatalogIteratorAsLRU( cacheGlobals, iter );
(void) CI_LOCK_FROM_LIST(cacheGlobals,iter);
iter->volume = 0; iter->folderID = 0;
(void) CI_UNLOCK(iter);
#if TARGET_API_MACOS_X
break;
#endif
}
}
if (iter == nil)
CATALOG_ITER_LIST_UNLOCK(cacheGlobals);
iterator->nameType = kLongUnicodeName;
iterator->folderName.longNamePtr = &cacheGlobals->longName;
}