TInt TFsFormatNext::DoRequestL(CFsRequest* aRequest) // // Format the next part of the media. // { __PRINT1(_L("TFsFormatNext::DoRequestL() drv:%d"), aRequest->DriveNumber()); CFormatCB* format=(CFormatCB*)aRequest->ScratchValue(); TInt r=format->CheckMount(); if (r!=KErrNone && r!=KErrInUse) { __PRINT1(_L("TFsFormatNext::DoRequestL() err:%d"), r); return r; } TPtr8 pStep((TUint8*)&format->CurrentStep(),sizeof(TInt)); aRequest->ReadL(KMsgPtr0,pStep); OstTrace1(TRACE_FILESYSTEM, FSYS_ECFORMATCBDOFORMATSTEPL, "this %x", format); TRAP(r,format->DoFormatStepL()); OstTraceExt2(TRACE_FILESYSTEM, FSYS_ECFORMATCBDOFORMATSTEPLRET, "r %d iCurrentStep %d", r, (TUint) format->CurrentStep()); if (r==KErrNone) aRequest->WriteL(KMsgPtr0,pStep); if (r==KErrNone && format->CurrentStep()==0) { FsNotify::DiskChange(aRequest->DriveNumber()); } return(r); }
static void DumpOpenedObjects(TDrive& aDrive) { {//-- 1. files const TInt nFiles = Files->Count(); for(TInt i=0; i<nFiles; ++i) { CFileCB* pFile=(CFileCB*)(*Files)[i]; if(pFile->Drive().DriveNumber() == aDrive.DriveNumber()) { __PRINT1(_L("FsFormatOpen() opened file:'%S'"), &pFile->FileName()); } } } {//-- 2. directories; CDirCB doesn't have associated name. const TInt nDirs = Dirs->Count(); TInt cntDirs = 0; for(TInt i=0; i<nDirs; ++i) { CDirCB* pDir = (CDirCB*)(*Dirs)[i]; if(pDir->Drive().DriveNumber() == aDrive.DriveNumber()) { ++cntDirs; } } if(cntDirs) { __PRINT1(_L("FsFormatOpen() opened directories:%d"), cntDirs); } } }
/** Publishing method Sends a property event on behalf of CMassStorageDrive, with the mountstate and drivestate values encoded into one 32-bit word. */ void RDriveStateChangedPublisher::DriveStateChanged() { __MSFNLOG TUsbMsDrivesStatus allDrivesStatus; for(TUint8 i = 0; i < iDrives.Count(); i++) { allDrivesStatus.Append(iDriveMap[i]); CMassStorageDrive::TMountState ms = iDrives[i]->MountState(); TLocalDriveRef::TDriveState ds = iDrives[i]->DriveState(); TInt driveStatus = EUsbMsDriveState_Error; if((TUint8)ds < sizeof(table[0]) && (TUint8)ms < sizeof(table)/sizeof(table[0])) { driveStatus = table[ms][ds]; __PRINT3(_L("ms=%d ds=%d %d"), ms, ds, driveStatus); } allDrivesStatus.Append(driveStatus); } __PRINT1(_L("Publishing EUsbMsDriveState_DriveStatus for %d drives\n"), allDrivesStatus.Length()/2); if(KErrNone != RProperty::Set(KUsbMsDriveState_Category, EUsbMsDriveState_DriveStatus, allDrivesStatus)) { __ASSERT_DEBUG(EFalse,User::Invariant()); } }
CFsObjectIx::~CFsObjectIx() // // Destructor // Assumes that no need to lock // { __PRINT1(_L("CFsObjectIx::~CFsObjectIx() 0x%x"),this); // We have to be very careful here. Calling Close() on the objects in the array // may result in other entries being removed from the array before we delete // them here, and may result in the array being ReAlloc()ed, corrupting the removed // entries, hence we must check the iHighWaterMark value each time round the loop. TInt i=-1; while(++i<iHighWaterMark) { SFsObjectIxRec* pS=iObjects+i; CFsObject *pO=pS->obj; if (pO) { // invalidate entry before closing it pS->obj=NULL; pO->Close(); } } delete iObjects; iLock.Close(); }
TInt CMediaWTCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* /*aParam2*/) { TInt nRes = KErrNotSupported; #ifdef _DEBUG switch(aFunction) { //-- disable / enable cache, for debug //-- if aParam1 !=0 cache will be disabled, enabled otherwise case EDisableCache: iCacheDisabled = aParam1 ? 1 : 0; nRes = KErrNone; break; case EDumpCache: break; case ECacheInfo: break; default: __PRINT1(_L("CMediaWTCache::Control() invalid function: %d"), aFunction); ASSERT(0); break; } #else (void)aFunction; //-- supress warnings (void)aParam1; User::Invariant(); //-- don't call this method in release build #endif //_DEBUG return nRes; }
/** Destructor. Deallocates memory associated with this objects name, if a name has been set. @panic FSERV 104 if the reference count is not zero when the destructor is called. */ EXPORT_C CFsObject::~CFsObject() { __PRINT1(_L("CFsObject::~CFsObject() 0x%x"),this); __ASSERT_ALWAYS(Dec()==0,Fault(EObjDestructorAccessCount)); __ASSERT_ALWAYS(!iContainer,Fault(EObjDestructorContainer)); if(iName) User::Free(iName); #if defined(_DEBUG) || defined(_DEBUG_RELEASE) __e32_atomic_add_ord32(&ObjectCount, (TUint32) -1); #endif }
/** Unlock a locked page. @return TInt KErrNone if unlocking was successful, otherwise system-wide error code. @param aPage the pointer of the page to be unlocked. */ TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage) { ASSERT(aPage != NULL); __PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos()); TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs()); if (r == KErrNone) { aPage->SetLocked(EFalse); } return r; }
/** Destructor of CLeafDirTree */ CLeafDirTree::~CLeafDirTree() { __PRINT1(_L("~CLeafDirTree[0x%x]"), this); Reset(); delete iRoot; iLruList.Close(); #ifdef _DEBUG iContainer.Close(); #endif //_DEBUG }
/** Implementation of pure virtual function. @see MWTCacheInterface::Control() */ TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2) { TInt r = KErrNotSupported; #ifdef _DEBUG (void)aParam2; switch(aFunction) { // disable / enable cache, for debug // if aParam1 != 0 cache will be disabled, enabled otherwise case EDisableCache: iCacheDisabled = aParam1 ? 1 : 0; r = KErrNone; break; // dump cache, for debug case EDumpCache: { RFs fs; fs.Connect(); const TUint32 debugRegister = DebugRegister(); fs.SetDebugRegister(debugRegister|KFSYS); Dump(); fs.SetDebugRegister(debugRegister); fs.Close(); break; } case ECacheInfo: { RFs fs; fs.Connect(); const TUint32 debugRegister = DebugRegister(); fs.SetDebugRegister(debugRegister|KFSYS); Info(); fs.SetDebugRegister(debugRegister); fs.Close(); break; } default: __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction); ASSERT(0); break; } #else (void)aFunction; //-- supress warnings (void)aParam1; (void)aParam2; User::Invariant(); //-- don't call this method in release build #endif //_DEBUG return r; }
/** Set the Drive State to Active or Idle. Ref: 3.6.3.2 - PREVENT_MEDIUM_REMOVAL @return KErrNone on success, otherwise system wide error code @param aLun The Logical Drive Unit identifier (0..numDrives-1) @param aCritical ETrue for Active, EFalse for Idle */ TInt CDriveManager::SetCritical(TUint aLun, TBool aCritical) { __PRINT1(_L("CDriveManager::SetCritical lun=%d\n"), aLun); TInt err = KErrUnknown; // never return this CMassStorageDrive* drive = Drive(aLun, err); if(drive) { err = drive->SetCritical(aCritical); } return err; }
/** Publishing method Publishes the Media Error property event @param aError ETrue if drive media has an error else EFalse for no error */ void RDriveMediaErrorPublisher::PublishErrorL(TBool aError) { __MSFNLOG __PRINT1(_L("<< RDriveMediaErrorPublisher::PublishError %x"), aError); TInt oldValue; iMediaErrorProperty.Get(oldValue); if (oldValue != aError) { User::LeaveIfError(iMediaErrorProperty.Set(aError)); } }
/** @return KErrNone on success, KErrArgument if arguments are illegal @param aNewState @param aLocalDrive Only provide this if aNewState is EConnected, in which case it is required. Only sets/clears iLocalDrive if new state is Connected or Disconnected. */ TInt CMassStorageDrive::SetMountState(TMountState aNewState, CLocalDriveRef* aLocalDrive/*=NULL*/) { __FNLOG("CMassStorageDrive::SetMountState"); TInt err = KErrUnknown; //Never return this if(iMountState != aNewState) { if (iMountState == EConnected && aNewState==EConnecting || iMountState == EDisconnected && aNewState==EDisconnecting) { return KErrNone; } iMountState = aNewState; if(aNewState==EDisconnected || aNewState==EConnecting) { // Reset the drive state on disconnection. // Note: This should be called before ProxyDrive is NULLed. SetDriveState(EErrDisMounted); } // Only mounting and unmounting transitions affect iProxyDrive if(aNewState==EConnected || aNewState==EDisconnected) { delete iLocalDrive; iLocalDrive = aLocalDrive; // possibly NULL } #ifndef USB_TRANSFER_PUBLISHER // The data transferred counts are "since the host connected to the drive" // so reset them when going to the connected state. if(aNewState==EConnected) { iBytesWritten = iBytesRead = 0; } #endif __PRINT1(_L("SetMountState: state=%d\n"), iMountState); err = KErrNone; } else if(aLocalDrive != iLocalDrive) { // Caller is not allowed to change the proxy drive err = KErrArgument; } return err; }
/** Internal query function, to check if aPos is cached or not. iActive page is included in searching. */ TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos) { __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos); // align the page position TInt64 pageStartMedPos = CalcPageStartPos(aPos); if ((iActivePage->StartPos() == pageStartMedPos)) { ASSERT(iActivePage->IsValid()); return iActivePage; } // search in lookup table return LookupTblFind(pageStartMedPos); }
/** Try to create a new page and lock the page content when it is created. This function should only be called when creating iActive page or making a page MRU (which might result in page evictions). @return the pointer of the newly created page, or NULL if allocation failed. @param aStartMedPos the starting media address of the page to be created. @pre aStartMedPos should not already be existing in the cache. */ TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos) { __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos); TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); if (startRamAddr) { // create new page and return TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr); pPage->SetLocked(ETrue); pPage->SetValid(EFalse); return pPage; } return NULL; }
CFatFileCB::~CFatFileCB() { __PRINT1(_L("CFatFileCB deleted 0x%x"),this); //-- a nasty trick to find out if the CFatFileCB is in consistent state on the moment of destruction. //-- Because of OOM conditions CFatFileCB might not be fully constructed and to be deleted, while FlushAll() //-- implies valid iMount. const CMountCB* pMount = &Mount(); if(pMount) { //-- do some finalisation work if CMountCB is valid if (iAtt&KEntryAttModified) TRAP_IGNORE(FlushAllL()); } delete[] iSeekIndex; }
/** Decommit a locked or unlocked page. @return TInt KErrNone if decommition was successful, otherwise system-wide error code. @param aPage the pointer of the page to be decommitted. */ TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage) { ASSERT(aPage != NULL); __PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos()); if (aPage) { TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs()); if (r == KErrNone) { aPage->SetLocked(EFalse); aPage->SetValid(EFalse); } return r; } return KErrArgument; }
/** Initialize the FAT cache and disk access @param aLocDrvCaps local drive capabilities @param aIgnoreFSInfo if ETrue, FSInfo sector shall be ignored. Used on volume remount to force FAT free clusters counting. @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown. */ void CFatMountCB::InitializeL(const TLocalDriveCaps& aLocDrvCaps, TBool aIgnoreFSInfo/*=EFalse*/) { __PRINT1(_L("CFatMountCB::InitializeL() drv:%d"), DriveNumber()); ASSERT(State() == EMounting); //-- we must get here only from MountL() //========== Find out number of clusters on the volume if(iRamDrive && SectorsPerCluster()!=1) {// Align iFirstFreeByte to cluster boundary if internal ram drive const TInt sectorsPerClusterLog2=ClusterSizeLog2()-SectorSizeLog2(); const TInt rootDirEndSector=RootDirEnd()>>SectorSizeLog2(); const TInt alignedSector=((rootDirEndSector+SectorsPerCluster()-1)>>sectorsPerClusterLog2)<<sectorsPerClusterLog2; iFirstFreeByte=alignedSector<<SectorSizeLog2(); } else { if(Is32BitFat())
void CDevice::MountLogicalUnitsL() { __MSFNLOG iExt.OpenL(); for (TInt lun = 0; lun < iNumLuns; lun++) { TDriveNumber driveNumber = iExt.GetDriveL(); __PRINT2(_L("Mounting drive=%d lun=%d..."), driveNumber, lun); RDebug::Print(_L("Mounting drive=%d lun=%d..."), driveNumber, lun); TRAPD(err, iExt.MountL(iUsbHostMsDevice, driveNumber, iDeviceToken, lun)); if (err == KErrNone || err == KErrNotReady || err == KErrCorrupt) { iLuList.Append(driveNumber); } __PRINT1(_L("%d"), err); RDebug::Print(_L("err=%d"), err); } }
CFatFileCB::~CFatFileCB() { __PRINT1(_L("~CFatFileCB deleted 0x%x"),this); //-- a nasty trick to find out if the CFatFileCB is in consistent state on the moment of destruction. //-- Because of OOM conditions CFatFileCB might not be fully constructed and to be deleted, while FlushAll() //-- implies valid iMount. const CMountCB* pMount = &Mount(); if(pMount) {//-- do some finalisation work if CMountCB is valid if(FileAttModified()) { IndicateFileTimeModified(ETrue); //-- this will force writing file modification time to the media on Flush TRAP_IGNORE(FlushAllL()); } } delete[] iSeekIndex; }
//------------------------------------------------------------------------------------------------------------------- void Dump_TLDFormatInfo(const TLDFormatInfo& aInfo) { (void)aInfo; #ifdef _DEBUG __PRINT(_L("----- TLDFormatInfo dump:")); __PRINT1(_L("iCapacity:%d"), aInfo.iCapacity); __PRINT1(_L("iSectorsPerCluster:%d"), aInfo.iSectorsPerCluster); __PRINT1(_L("iSectorsPerTrack:%d"), aInfo.iSectorsPerTrack); __PRINT1(_L("iFATBits:%d"), aInfo.iFATBits); __PRINT1(_L("iReservedSectors:%d"), aInfo.iReservedSectors); __PRINT1(_L("iFlags:%d"), aInfo.iFlags); __PRINT(_L("-----")); #endif }
/** Implementation of pure virtual function. @see MWTCacheInterface::PosCached() */ TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart) { const TInt64 pageStartMedPos = CalcPageStartPos(aPos); // only search the page in lookup table // NOTE: we don't count the active page into acount here, // this is to avoid pulling next pages recursively TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos); // then check if page is still valid if page is on Unlocked Page Queue if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked) { if (LockPage(pPage) != NULL) { // __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos); // have to unlock it before returning, otherwise there will be memory leak UnlockPage(pPage); aCachedPosStart = pPage->StartPos(); return pPage->PageSizeInBytes(); } else // if the unlocked page is not valid anymore, remove it { DeQueue(pPage); LookupTblRemove(pPage->StartPos()); DecommitPage(pPage); delete pPage; pPage = NULL; } } // otherwise if page is already locked or valid active page else if (pPage) { __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos); aCachedPosStart = pPage->StartPos(); return pPage->PageSizeInBytes(); } // page is not found or not valid anymore return 0; }
/** Set or reset "VolumeClean" (ClnShutBitmask) flag. @param aClean if ETrue, marks the volume as clean, otherwise as dirty. @leave if write error occured. */ void CFatMountCB::SetVolumeCleanL(TBool aClean) { //-- The volume can't be set clean if there are disk access objects opened on it. This precondition must be checked before calling this function if(aClean && Locked()) { __PRINT1(_L("#- CFatMountCB::SetVolumeCleanL drive:%d isn't free!"),DriveNumber()); ASSERT(0); User::Leave(KErrInUse); return; } if(FatType() == EFat12) {//-- Fat12 doesn't support this feature; do nothing other than notify the underlying drive (ignoring any error for now as there's nothing we can do with it) (void)LocalDrive()->Finalise(aClean); return; } //-- further read and write will be directly from the CProxyDrive, bypassing FAT cache. //-- this is because CFatTable doesn't allow access to FAT[0] & FAT[1] //-- We also need to write data through CProxyDrive, because TDriveInterface has a call back that can call this method if(Is32BitFat()) {//-- Fat32 __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT32"),DriveNumber(), aClean); TFat32Entry fatEntry; const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes TPtr8 ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize); User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT32[1] entry const TFat32Entry tmp = fatEntry; if(aClean) fatEntry |= KFat32CleanShutDownMask; //-- set ClnShutBit flag else fatEntry &= ~KFat32CleanShutDownMask; //-- reset ClnShutBit flag if(tmp != fatEntry) {//-- write FAT[1] entry to all available FATs for(TUint32 i=0; i<NumberOfFats(); ++i) { const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i); User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT32[1] entry } } __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry: %x->%x"), tmp, fatEntry); } else if(Is16BitFat()) {//-- Fat16. __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL, drive:%d, param:%d, FAT16"),DriveNumber(), aClean); if(FatConfig().FAT16_UseCleanShutDownBit()) { TFat16Entry fatEntry; const TInt KFatEntrySize=sizeof(fatEntry); //-- FAT entry size in bytes TPtr8 ptrFatEntry((TUint8*)&fatEntry,KFatEntrySize); User::LeaveIfError(LocalDrive()->Read(StartOfFatInBytes()+KFatEntrySize, KFatEntrySize, ptrFatEntry)); //read FAT16[1] entry const TFat16Entry tmp = fatEntry; if(aClean) fatEntry |= KFat16CleanShutDownMask; //-- set ClnShutBit flag else fatEntry &= ~KFat16CleanShutDownMask; //-- reset ClnShutBit flag if(tmp != fatEntry) {//-- write FAT[1] entry to all available FATs for(TUint32 i=0; i<NumberOfFats(); ++i) { const TInt64 pos = StartOfFatInBytes()+KFatEntrySize+(FatSizeInBytes()*i); User::LeaveIfError(LocalDrive()->Write(pos, ptrFatEntry)); //write FAT16[1] entry } } __PRINT2(_L("#- CFatMountCB::SetVolumeCleanL() entry: %x->%x"), tmp, fatEntry); } else { __PRINT(_L("#- changing FAT16[1] is disabled in config!")); } } else {//-- must never get here ASSERT(0); } //-- Notify the underlying media that the mount is consistent (ignoring any error for now as there's nothing we can do with it) (void)LocalDrive()->Finalise(aClean); }
/** Open the device and do some initalisation work. @param aParams device parameters @return Epoc error code, KErrNone if everything is OK */ TInt CWinVolumeDevice::Connect(const TMediaDeviceParams& aParams) { __PRINT(_L("#-- CWinVolumeDevice::Connect()")); if(!aParams.ipDevName) { __LOG(_L("#-- CWinVolumeDevice::Connect() device name is not set!")); return KErrBadName; } __PRINTF(aParams.ipDevName); ASSERT(!HandleValid() && ipScratchBuf); //-- open the device DWORD dwAccess = GENERIC_READ; if(!aParams.iReadOnly) dwAccess |= GENERIC_WRITE; iDevHandle = CreateFileA(aParams.ipDevName, dwAccess, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(!HandleValid()) { __LOG1(_L("#-- CWinVolumeDevice::Connect() Error creating device handle! WinErr:%d"), GetLastError()); return KErrGeneral; } //-- find out device geometry iMediaType = Unknown; iDrvGeometry.iBytesPerSector = KDefaultSectorSz; DWORD junk; //-- 1. try to query disk geometry, but it can produce wrong results for partitioned media BOOL bResult = DeviceIoControl(Handle(), IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, ipScratchBuf, KScratchBufSz, &junk, (LPOVERLAPPED)NULL); if(bResult) { const DISK_GEOMETRY& dg = (const DISK_GEOMETRY&)*ipScratchBuf; iDrvGeometry.iBytesPerSector = dg.BytesPerSector; iMediaType = dg.MediaType; __PRINT3(_L("#-- dev geometry: Cyl:%d Heads:%d Sectors:%d"), dg.Cylinders.LowPart, dg.TracksPerCylinder, dg.SectorsPerTrack); __PRINT2(_L("#-- dev geometry: MediaType:%d, bps:%d"), dg.MediaType, dg.BytesPerSector); } else { iMediaType = Unknown; iDrvGeometry.iBytesPerSector = KDefaultSectorSz; __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_DRIVE_GEOMETRY WinError:%d !"), GetLastError()); } //-- 1.1 check "bytes per sector" value and how it corresponds to the request from parameters if(aParams.iDrvGeometry.iBytesPerSector == 0) {//-- do nothing, this parameter is not set in config file, use media's } else if(aParams.iDrvGeometry.iBytesPerSector != iDrvGeometry.iBytesPerSector) {//-- we can't set "SectorSize" value for the physical media __LOG1(_L("#-- CWinVolumeDevice::Connect() can not use 'Sec. Size' value from config:%d !"), aParams.iDrvGeometry.iBytesPerSector); Disconnect(); return KErrArgument; } ASSERT(IsPowerOf2(BytesPerSector()) && BytesPerSector() >= KDefaultSectorSz && BytesPerSector() < 4096); //-- find out partition information in order to determine volume size. bResult = DeviceIoControl(Handle(), IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, ipScratchBuf, KScratchBufSz, &junk, (LPOVERLAPPED)NULL); if(!bResult) {//-- this is a fatal error __LOG1(_L("#-- CWinVolumeDevice::Connect() IOCTL_DISK_GET_PARTITION_INFO WinError:%d !"), GetLastError()); Disconnect(); return KErrBadHandle; } //-- get partition informaton const PARTITION_INFORMATION& pi = (const PARTITION_INFORMATION&)*ipScratchBuf; TInt64 volSz = MAKE_TINT64(pi.PartitionLength.HighPart, pi.PartitionLength.LowPart); iDrvGeometry.iSizeInSectors = (TUint32)(volSz / iDrvGeometry.iBytesPerSector); __LOG3(_L("#-- partition size, bytes:%LU (%uMB), sectors:%u"), volSz, (TUint32)(volSz>>20), iDrvGeometry.iSizeInSectors); //-- check if the media size is set in coonfig and if we can use this setting. if(aParams.iDrvGeometry.iSizeInSectors == 0) {//-- do nothing, the media size is not set in the ini file, use existing media parameters } else if(aParams.iDrvGeometry.iSizeInSectors > iDrvGeometry.iSizeInSectors) {//-- requested media size in ini file is bigger than physical media, error. //-- we can't increase physical media size __LOG2(_L("#-- CWinVolumeDevice::Connect() 'MediaSizeSectors' value from config:%d > than physical:%d !"), aParams.iDrvGeometry.iSizeInSectors, iDrvGeometry.iSizeInSectors); Disconnect(); return KErrArgument; } else if(aParams.iDrvGeometry.iSizeInSectors < iDrvGeometry.iSizeInSectors) {//-- settings specify smaller media than physical one, adjust the size __PRINT1(_L("#-- reducing media size to %d sectors"), aParams.iDrvGeometry.iSizeInSectors); iDrvGeometry.iSizeInSectors = aParams.iDrvGeometry.iSizeInSectors; } ASSERT(iDrvGeometry.iSizeInSectors > KMinMediaSizeInSectors); return KErrNone; }
/** Format a disk section, called iteratively to erase whole of media, on last iteration creates an empty volume. If called with quick formatonly erases the Fat leaving the rest of the volume intact. @leave System wide error code */ void CFatFormatCB::DoFormatStepL() { if (iFormatInfo.iFormatIsCurrent==EFalse) { // Only done first time through if (iMode & EForceErase) { TInt r = FatMount().ErasePassword(); User::LeaveIfError(r); // CFatMountCB::ErasePassword() calls TBusLocalDrive::ForceRemount(), // so need to stop a remount from occurring in next call to : // TFsFormatNext::DoRequestL((), TDrive::CheckMount(). FatMount().Drive().SetChanged(EFalse); } RecordOldInfoL(); InitializeFormatDataL(); FatMount().DoDismount(); if (iVariableSize) FatMount().ReduceSizeL(0,I64LOW(FatMount().iSize)); } // // Blank disk if not EQuickFormat // if (!iVariableSize && !(iMode & EQuickFormat) && iCurrentStep) { if (iFormatInfo.iFormatIsCurrent == EFalse) {//-- firstly invalidate sectors 0-6 inclusive, they may contain main boot sector, backup boot sector and FSInfo sector. DoZeroFillMediaL(0, (KBkBootSectorNum+1)*iBytesPerSector); } TInt ret=FatMount().LocalDrive()->Format(iFormatInfo); if (ret!=KErrNone && ret!=KErrEof) // Handle format error ret = HandleCorrupt(ret); if (ret!=KErrNone && ret!=KErrEof) // KErrEof could be set by LocalDrive()->Format() User::Leave(ret); if (ret==KErrNone) { iCurrentStep = I64LOW( 100 - (100 * TInt64(iFormatInfo.i512ByteSectorsFormatted)) / iMaxDiskSectors ); if (iCurrentStep<=0) iCurrentStep=1; return; } } // ReMount since MBR may have been rewritten and partition may have moved / changed size TInt ret = LocalDrive()->ForceRemount(0); if (ret != KErrNone && ret != KErrNotSupported) User::Leave(ret); // MBR may have changed, so need to re-read iHiddenSectors etc.before BPB is written InitializeFormatDataL(); // Translate bad sector number to cluster number which contains that sector // This only happens in full format, in quick format they are already cluster numbers if (!iVariableSize && !(iMode & EQuickFormat)) User::LeaveIfError(BadSectorToCluster()); //Check if root cluster is bad and update as required if(Is32BitFat() && !iVariableSize && (iMode & EQuickFormat)) { if(iBadClusters.Find(iRootClusterNum) != KErrNotFound) { iRootClusterNum++; while(iBadClusters.Find(iRootClusterNum) != KErrNotFound) { iRootClusterNum++; } } } // // Do the rest of the disk in one lump // iCurrentStep=0; //-- zero-fill media from position 0 to the FAT end, i.e main & backup boot sector, FSInfo and its copy and all FATs const TUint32 posFatEnd = ((iSectorsPerFat*iNumberOfFats) + iReservedSectors) * iBytesPerSector; //-- last FAT end position if (iVariableSize) FatMount().EnlargeL(posFatEnd); DoZeroFillMediaL(0, posFatEnd); if(Is32BitFat()) {//create an empty root directory entry here const TUint KFat32EntrySz = 4; //-- FAT32 entry size, bytes const TInt startFAT1 = iReservedSectors; //-- FAT1 start sector const TInt entryOffset = iRootClusterNum*KFat32EntrySz; //-- Root dir entry offset in the FAT, bytes TBuf8<KFat32EntrySz> EOF(KFat32EntrySz); EOF[0]=0xFF; EOF[1]=0xFF; EOF[2]=0xFF; EOF[3]=0x0F; //-- write EOF mark to the every FAT copy for(TInt i=0; i<iNumberOfFats; i++) { const TInt rootDirEntryPos = iBytesPerSector*(startFAT1 + i*iSectorsPerFat) + entryOffset; User::LeaveIfError(LocalDrive()->Write(rootDirEntryPos, EOF)); } //-- zero-fill FAT32 root directory (just 1 cluster) const TInt firstDataSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); //+RootDirSectors (not required for fat32) const TInt firstSectorOfCluster = ((iRootClusterNum - KFatFirstSearchCluster) * iSectorsPerCluster) + firstDataSector; const TUint32 posRootDirStart = firstSectorOfCluster * iBytesPerSector; const TUint32 posRootDirEnd = posRootDirStart + iSectorsPerCluster*iBytesPerSector; DoZeroFillMediaL(posRootDirStart, posRootDirEnd); } else {//-- FAT12/16 //-- Zero fill root directory const TInt rootDirSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); const TInt rootDirSize = iRootDirEntries * KSizeOfFatDirEntry; //-- size in bytes const TUint32 posRootDirStart = rootDirSector * iBytesPerSector; const TUint32 posRootDirEnd = posRootDirStart + rootDirSize; const TInt numOfRootSectors=(rootDirSize%iBytesPerSector) ? (rootDirSize/iBytesPerSector+1) : (rootDirSize/iBytesPerSector); if (iVariableSize) FatMount().EnlargeL(iBytesPerSector*numOfRootSectors); DoZeroFillMediaL(posRootDirStart, posRootDirEnd); // Enlarge ram drive to take into account rounding of // data start to cluster boundary if(iVariableSize && iSectorsPerCluster!=1) { const TInt firstFreeSector=rootDirSector+numOfRootSectors; const TInt firstFreeCluster=firstFreeSector%iSectorsPerCluster ? firstFreeSector/iSectorsPerCluster+1 : firstFreeSector/iSectorsPerCluster; const TInt alignedSector=firstFreeCluster*iSectorsPerCluster; if(alignedSector!=firstFreeSector) FatMount().EnlargeL((alignedSector-firstFreeSector)*iBytesPerSector); } } //-- FAT[0] must contain media descriptor in the low byte, FAT[1] for fat16/32 may contain some flags TBuf8<8> startFat(8); startFat.Fill(0xFF); if(Is32BitFat()) //-- FAT32 {//-- FAT32 uses only low 28 bits in FAT entry. startFat[3] = 0x0F; startFat[7] = 0x0F; } else if(iVariableSize||Is16BitFat()) //-- FAT16 or RAM drive which is always FAT16 { startFat.SetLength(4); } else //-- FAT12 { startFat.SetLength(3); } startFat[0]=KBootSectorMediaDescriptor; //-- write FAT[0] and FAT[1] entries to all copies of FAT for(TInt i=0;i<iNumberOfFats;i++) { User::LeaveIfError(LocalDrive()->Write(iBytesPerSector*(iReservedSectors+(iSectorsPerFat*i)),startFat)); } //-- create boot sectors CreateBootSectorL(); //-- create FSInfo sectors if (Is32BitFat()) { CreateReservedBootSectorL(); CreateFSInfoSectorL(); } //-- here we have bad clusters numbers saved by the quick format //-- Interpret old bad cluster number to new cluster number and mark new bad clusters if (!iVariableSize && iBadClusters.Count()>0) { //-- Here we need fully mounted volume, so mount it normally. FatMount().MountL(EFalse); iBadClusters.Sort(); TranslateL(); const TInt mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit); for (TInt i=0; i<iBadClusters.Count(); ++i) FatMount().FAT().WriteL(iBadClusters[i], mark); FatMount().FAT().FlushL(); //-- indicate that the volume is "dirty" in order to the next Mount evend not to use FSInfo, which //-- contains incorrect value of free clusters because we already have bad ones saved. //-- This is a very rare condition. FatMount().SetVolumeCleanL(EFalse); #if defined(_DEBUG) TInt r=FatMount().CheckDisk(); __PRINT1(_L("CFatFormatCB::DoFormatStepL() CheckDisk res: %d"),r); #endif } else { //-- We do not need to perform full mount in this case, the TDrive object will be marked as changed in ~CFormatCB and the //-- mount will be closed. Therefore on the first access to it it will be mounted normally. FatMount().MountL(ETrue); //-- force mount } __PRINT1(_L("CFatFormatCB::DoFormatStepL() Format complete drv:%d"), DriveNumber()); }
/** Create the boot sector on media for the volume. For FAT32 also creates a backup copy of the boot sector. @leave System wide error codes */ void CFatFormatCB::CreateBootSectorL() { __PRINT1(_L("CFatFormatCB::CreateBootSector() drive:%d"),DriveNumber()); _LIT8(KName_Fat12,"FAT12 "); ///< Name in BPB given to a Fat12 volume _LIT8(KName_Fat16,"FAT16 "); ///< Name in BPB given to a Fat16 volume _LIT8(KName_Fat32,"FAT32 "); ///< Name in BPB given to a Fat32 volume _LIT8(KDefaultVendorID, "EPOC"); ///< Vendor Name for BPB for any volume formated using a Symbian OS device const TBool bFat32 = Is32BitFat(); TFatBootSector bootSector; bootSector.SetVendorID(KDefaultVendorID); bootSector.SetBytesPerSector(iBytesPerSector); bootSector.SetSectorsPerCluster(iSectorsPerCluster); bootSector.SetReservedSectors(iReservedSectors); bootSector.SetNumberOfFats(iNumberOfFats); iCountOfClusters=iMaxDiskSectors/iSectorsPerCluster; if (!bFat32) { if (iCountOfClusters>(TInt)KMaxTUint16) User::Leave(KErrTooBig); } bootSector.SetReservedByte(0); TTime timeID; timeID.HomeTime(); bootSector.SetUniqueID(I64LOW(timeID.Int64())); // Generate Volume UniqueID from time bootSector.SetVolumeLabel(_L8("")); //-- set a text string in BPB that corresponds to the FS type switch(FatType()) { case EFat12: bootSector.SetFileSysType(KName_Fat12); break; case EFat16: bootSector.SetFileSysType(KName_Fat16); break; case EFat32: bootSector.SetFileSysType(KName_Fat32); break; default: ASSERT(0); User::Leave(KErrArgument); }; bootSector.SetJumpInstruction(); bootSector.SetMediaDescriptor(KBootSectorMediaDescriptor); bootSector.SetNumberOfHeads(iNumberOfHeads); bootSector.SetHiddenSectors(iHiddenSectors); bootSector.SetSectorsPerTrack(iSectorsPerTrack); bootSector.SetPhysicalDriveNumber(128); bootSector.SetExtendedBootSignature(0x29); if(bFat32) { bootSector.SetFatSectors(0); bootSector.SetFatSectors32(iSectorsPerFat); bootSector.SetRootDirEntries(0); bootSector.SetTotalSectors(0); bootSector.SetHugeSectors(iMaxDiskSectors); bootSector.SetFATFlags(0); bootSector.SetVersionNumber(0x00); bootSector.SetRootClusterNum(iRootClusterNum); bootSector.SetFSInfoSectorNum(KFSInfoSectorNum); bootSector.SetBkBootRecSector(KBkBootSectorNum); } else//fat12 and 16 { bootSector.SetFatSectors32(0); bootSector.SetFatSectors(iSectorsPerFat); bootSector.SetRootDirEntries(iRootDirEntries); if (iMaxDiskSectors<=KMaxTUint16) { bootSector.SetTotalSectors(iMaxDiskSectors); bootSector.SetHugeSectors(0); } else { bootSector.SetTotalSectors(0); bootSector.SetHugeSectors(iMaxDiskSectors); } } //-- write main boot sector to the first sector on media User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*bootSector.BytesPerSector(), bootSector)); //-- for FAT32 write backup copy of the boot sector if(bFat32) { User::LeaveIfError(FatMount().DoWriteBootSector(KBkBootSectorNum*bootSector.BytesPerSector(), bootSector)); } }
CFatFileCB::CFatFileCB() { __PRINT1(_L("CFatFileCB created 0x%x"),this); }
/** Dump cache information, only enabled in debug mode. @see CDynamicDirCache::Control() */ void CDynamicDirCache::Info() const { __PRINT(_L("======== CDynamicDirCache::Info =========")); const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2(); // page size __PRINT1(_L("=== Pages size: [%d Bytes]"), iPageSizeInBytes); __PRINT1(_L("=== Segment size: [%d Bytes]"), 1 << SegmentSizeInBytesLog2); // data size: __PRINT1(_L("=== Min data size: [%d Bytes]"), iMinSizeInPages << iPageSizeLog2); __PRINT1(_L("=== Max data size: [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2); // memory size: const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2; __PRINT1(_L("=== Min memory size: [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2); __PRINT1(_L("=== Max memory size: [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2); // reserved pages __PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages); __PRINT1(_L("=== Reserved memory: [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2); // locked page num __PRINT1(_L("=== Number of pages locked: [%d]"), iLockedQCount); __PRINT1(_L("=== Locked memory: [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2); // unlocked page num __PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount); __PRINT1(_L("=== Unlocked memory: [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2); }
/** Open a drive for formatting. */ TInt FsFormatOpen(CFsRequest* aRequest) { TDrive& drive = *aRequest->Drive(); __PRINT1(_L("FsFormatOpen() drv:%d"), drive.DriveNumber()); TInt nMountRes = drive.CheckMount(); //-- KErrNotReady means that there is no file system mounted on this drive //-- KErrInUse means that there are some "disk access" objects, like RFormat or RRawDisk opened on the mount. if(nMountRes == KErrNotReady || nMountRes == KErrInUse) { __PRINT1(_L("FsFormatOpen() ChkMount:%d"), nMountRes); return nMountRes; } const TFormatMode fmtMode = (TFormatMode)aRequest->Message().Int1(); TName buf; TUint32 currFsNameHash = 0; //-- current file system name hash, 0 means "not set"; used during forced FS dismounting if((nMountRes == KErrNone) && drive.CurrentMount().LockStatus() < 0) {//-- the mount is locked, it has normal objects (files, directories) opened on it. //-- if someone is interested in the list of opened files and number of opened directories, compile this code in. #ifdef DUMP_OPENED_OBJECTS DumpOpenedObjects(drive); #endif //DUMP_OPENED_OBJECTS if(!(fmtMode & EForceFormat)) { __PRINT(_L("FsFormatOpen() The mount is in use")); return KErrInUse; } //-- there is a special flag that tells to force media dismounting even if it has files or dirs opened. __PRINT(_L("FsFormatOpen() The mount is in use, forcing dismounting!")); //-- record currently mounted FS name hash, it may be used after forced dismounting drive.CurrentMount().FileSystemName(buf); //-- the iCurrentMount is alive currFsNameHash = TVolFormatParam::CalcFSNameHash(buf); //-- kill the current mount FsThreadManager::LockDrive(drive.DriveNumber()); TInt nRes = drive.ForceUnmountFileSystemForFormatting(); FsThreadManager::UnlockDrive(drive.DriveNumber()); switch(nRes) { case KErrInUse: __PRINT(_L("FsFormatOpen() The mount has clamps! Can't force dismount")); return KErrInUse; //-- there are clamps on this drive - can't dismount case KErrNone: break; default: ASSERT(0); //-- unexpected error code return nRes; }; if(fmtMode & EQuickFormat) {//-- quick format may require the normally mounted FS, make the best effrot to mount it nMountRes = drive.CheckMount(); } else {//-- this will make the FS mounted by force; for full format it will be quicker nMountRes = KErrCorrupt; } } //-- if True, we will need mount (probably specific) file system by force because normal mounting has failed TBool bNeedForceMount = (nMountRes != KErrNone); //-- find out if we have optional data structure that describes format parameter TUint32 newFsNameHash = 0; //-- file system name hash, may be used for selecting which file system to put onto the volume. 0 means "not specified" const TLDFormatInfo* pLDFormatInfo = NULL; const TVolFormatParam* pVolFormatParam = NULL; __ASSERT_COMPILE(sizeof(TVolFormatParam) >= sizeof(TLDFormatInfo)); TBuf8<sizeof(TVolFormatParam)> paramBuf; if(fmtMode & ESpecialFormat) { //-- the user has provided format parameters structure. //-- IPC argument #2 contains a structure: <TUint32>[optional package descriptor] //-- where 1st mandatory TUint32 is a pointer to format counter and the optional additional package is a data structure passed to the filesystem by the client of RFormat const TInt desLen = aRequest->GetDesLength(KMsgPtr2); ASSERT((TUint32)desLen >= sizeof(TUint32)); const TInt dataPckgLen = desLen - sizeof(TUint32); if((TUint32)dataPckgLen > sizeof(TUint32)) { aRequest->ReadL(KMsgPtr2, paramBuf); } if(dataPckgLen == sizeof(TLDFormatInfo)) {//-- the user has provided formatting parameters via TLDFormatInfo structure. pLDFormatInfo = (const TLDFormatInfo*)(paramBuf.Ptr() + sizeof(TUint32)); } else if(dataPckgLen == sizeof(TVolFormatParam)) {//-- it's likely to be TVolFormatParam, need to check UId to be sure. pVolFormatParam = (const TVolFormatParam*)(const TVolFormatParam*)(paramBuf.Ptr() + sizeof(TUint32)); if(pVolFormatParam->iUId == TVolFormatParam::KUId) //-- check the class UID {//-- this is the real TVolFormatParam object passed newFsNameHash = pVolFormatParam->FSNameHash(); } } else if(dataPckgLen >0) {//-- parameters data structure has strange length return KErrArgument; } } //------------------- if(!newFsNameHash && currFsNameHash) {//-- new file system name isn't specified (default formatting), but the volume had been forcedly dismounted. //-- restore the original file system newFsNameHash = currFsNameHash; } if(newFsNameHash) {//-- check if the specified FS is already mounted on the volume if(!bNeedForceMount) { drive.CurrentMount().FileSystemName(buf); //-- the iCurrentMount is alive } else { //-- the iCurrentMount can be NULL, use the iFsys - the real file system associated with this drive buf = drive.GetFSys()->Name(); } const TUint32 currFSNameHash = TVolFormatParam::CalcFSNameHash(buf); if(currFSNameHash == newFsNameHash) {//-- no need to do anything, the required FS is already mounted newFsNameHash = 0; } } if(newFsNameHash) { //-- the user has specified some filesystem to be mounted on the volume. Check if this FS is supported at all. //-- if it is supported, but some other FS is currently mounted, it will be dismounted and the new one will be forced. TInt nRes; for(TInt cntFS=0; ;++cntFS) { nRes = drive.FSys().GetSupportedFileSystemName(cntFS, buf); //-- enumerate possible child file systems if(nRes != KErrNone) return KErrNotSupported; //-- the filesystem with the given name (fsNameHash) is not supported. if(newFsNameHash == TVolFormatParam::CalcFSNameHash(buf)) {//-- the filesystem with the given name (fsNameHash) is supported, but some other filesystem can be already mounted drive.Dismount(); bNeedForceMount = ETrue; //-- this will force the desired FS to be mounted break; } } }//if(fsNameHash) //-- try force mounting the desired file system if it is required if(bNeedForceMount) { const TInt KMaxRetries = 3; for(TInt cnt=0; ; ++cnt) { drive.MountFileSystem(ETrue, newFsNameHash); nMountRes = drive.GetReason(); if(nMountRes == KErrNone || nMountRes == KErrLocked) break; drive.Dismount(); //-- will reset mount retries counter if(cnt >= KMaxRetries) { __PRINT1(_L("FsFormatOpen() can't mount FS! res:%d"), nMountRes); return nMountRes; } } } ASSERT(nMountRes == KErrNone || nMountRes == KErrLocked); __ASSERT_DEBUG(drive.CurrentMount().LockStatus()==0, Fault(ESvrFormatOpenFailed)); TDriveInfo dInfo; drive.DriveInfo(dInfo); const TInt mediaAtt = dInfo.iMediaAtt; #if defined(_LOCKABLE_MEDIA) if (!(fmtMode & EForceErase) && (mediaAtt & KMediaAttLocked)) { // if attempting to format a locked drive, dismount otherwise subsequent // requests will operate on a mount that has been forcibly mounted (a few lines above) CMountCB* pM = &drive.CurrentMount(); if(pM) pM->Close(); drive.MountFileSystem(EFalse); // clear iCurrentMount return KErrLocked; } #endif if (!(mediaAtt & KMediaAttFormattable) || (mediaAtt & KMediaAttWriteProtected)) { CMountCB* pM = &drive.CurrentMount(); if(pM) pM->Close(); drive.MountFileSystem(EFalse); return KErrAccessDenied; } //-- instantinate and open CFormatCB object for this drive CFormatCB* formatCB=NULL; TInt fmtHandle; TRAPD(ret, formatCB = drive.FormatOpenL(aRequest, fmtHandle, fmtMode, pLDFormatInfo, pVolFormatParam )); if (ret!=KErrNone) { if(formatCB) formatCB->Close(); return ret; } TPtrC8 pH((TUint8*)&fmtHandle,sizeof(TInt)); aRequest->WriteL(KMsgPtr3,pH); TInt count=100; TPtrC8 pCount((TUint8*)&count,sizeof(TInt)); aRequest->WriteL(KMsgPtr2,pCount); aRequest->Session()->IncResourceCount(); return KErrNone; }
/** Implementation of pure virtual function. @see MWTCacheInterface::MakePageMRU() */ void CDynamicDirCache::MakePageMRU(TInt64 aPos) { __PRINT1(_L("MakePageMRU (%lx)"), aPos); // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages); // check the MRU page first, if it is already the MRU page, we can return immediately TInt64 pageStartMedPos = CalcPageStartPos(aPos); if (!iLockedQ.IsEmpty()) { if (iLockedQ.First()->StartPos() == pageStartMedPos) { return; } } TDynamicDirCachePage* pPage = FindPageByPos(aPos); if (pPage) { ASSERT(pPage->IsValid()); // lock page before make it MRU if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) { ASSERT(!pPage->IsLocked()); if (LockPage(pPage) == NULL) { DeQueue(pPage); LookupTblRemove(pPage->StartPos()); DecommitPage(pPage); delete pPage; pPage = NULL; } } else { // error checking: page should either be locked or active ASSERT(LockPage(pPage) != NULL); } } // if page not found or page data not valid anymore, use active page to read data if (!pPage) { TRAPD(err, pPage = UpdateActivePageL(aPos)); if (err != KErrNone) { // problem occurred reading active page, return immediately. return; } } // by now, the page is either locked or active page ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); switch (pPage->PageType()) { // if the page is the active page, we will need to find a new active page for replacement case TDynamicDirCachePage::EActivePage: { TDynamicDirCachePage* newAP = NULL; // if there is more cache room available, try to create a new page first if (!CacheIsFull()) { // allocate and lock a new page TRAPD(err, newAP = AllocateAndLockNewPageL(0)); // if any error ocurrs, return immediately if (err != KErrNone) { // unlock the page that was originally unlocked before leave if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) { UnlockPage(pPage); } return; } if (newAP) { // replace the active page with the new page newAP->SetPageType(TDynamicDirCachePage::EActivePage); iActivePage = newAP; } } // if cache has grown to its max size, or new page allocation failed if (!newAP) { // try to lock the LRU page on the unlocked page queque first if (!iUnlockedQ.IsEmpty()) { newAP = iUnlockedQ.Last(); ASSERT(newAP->IsValid()); if (LockPage(newAP) != NULL) { // deque, reset pos, set new type DeQueue(newAP); LookupTblRemove(newAP->StartPos()); ResetPagePos(newAP); newAP->SetPageType(TDynamicDirCachePage::EActivePage); // replace active page iActivePage = newAP; } // if falied locking the LRU page from unclocked queque, // delete it else { DeQueue(newAP); LookupTblRemove(newAP->StartPos()); DecommitPage(newAP); delete newAP; newAP = NULL; } } } // if still have not found new active page // grab the LRU page from Locked Page Queue for active page if (!newAP) { ASSERT(!iLockedQ.IsEmpty()); newAP = iLockedQ.Last(); // deque, reset pos, set new type DeQueue(newAP); LookupTblRemove(newAP->StartPos()); ResetPagePos(newAP); newAP->SetPageType(TDynamicDirCachePage::EActivePage); // replace active page iActivePage = newAP; } // we should always be able to find a locked page for active page ASSERT(newAP != NULL); // make original page (i.e. former active page) MRU // add onto locked queue AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); // add onto lookuptbl, as active page is not on lookup tbl originally LookupTblAdd(pPage); // check cache limit CheckThresholds(); return; } case TDynamicDirCachePage::EUnlocked: { // if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it // to the Locked Page Queue and make it MRU DeQueue(pPage); AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); // check cache limit CheckThresholds(); return; } case TDynamicDirCachePage::ELocked: { // otherwise the page was on Locked Page Queue, make it MRU // no need to check cache limit if (pPage != iLockedQ.First()) { DeQueue(pPage); AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); return; } break; } default: ASSERT(0); } }