/** Write aligned members of TFatBootSector to media @param aMediaPos media position the data will be written to @param aBootSector data to write @return Media write error code */ TInt CFatMountCB::DoWriteBootSector(TInt64 aMediaPos, const TFatBootSector& aBootSector) const { __PRINT2(_L("#- CFatMountCB::DoWriteBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos); ASSERT(aMediaPos>=0); TBuf8<KDefaultSectorSize> bootSecBuf(KDefaultSectorSize); bootSecBuf.FillZ(); //-- externalize boot sector to the data buffer aBootSector.Externalize(bootSecBuf); //-- put a boot sector signature to the last 2 bytes bootSecBuf[KDefaultSectorSize-2] = 0x55; bootSecBuf[KDefaultSectorSize-1] = 0xaa; //-- write boot sector to the media TInt r=LocalDrive()->Write(aMediaPos, bootSecBuf); if (r!=KErrNone) {//-- write failure __PRINT2(_L("CFatMountCB::DoWriteBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r); } return r; }
/** Read non aligned boot data from media into TFatBootSector structure @param aMediaPos media position the data will be read from @param aBootSector refrence to TFatBootSector populate @return Media read error code */ TInt CFatMountCB::DoReadBootSector(TInt64 aMediaPos, TFatBootSector& aBootSector) const { __PRINT2(_L("#- CFatMountCB::DoReadBootSector() drv:%d, pos:0x%x"),Drive().DriveNumber(), (TUint32)aMediaPos); ASSERT(aMediaPos>=0); TBuf8<KSizeOfFatBootSector> bootSecBuf(KSizeOfFatBootSector); //-- read boot sector from the media TInt r=LocalDrive()->Read(aMediaPos, KSizeOfFatBootSector, bootSecBuf); if (r != KErrNone) { __PRINT2(_L("CFatMountCB::DoReadBootSector() failed! drv:%d, code:%d"),Drive().DriveNumber(),r); //-- fiddling with the error code; taken from MountL() if (r==KErrNotSupported) return KErrNotReady; #if defined(_LOCKABLE_MEDIA) else if(r==KErrLocked) return KErrLocked; #endif else if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown) return KErrCorrupt; return r; } ASSERT(r==KErrNone); //-- initialise TFatBootSector object aBootSector.Internalize(bootSecBuf); //-- Validate the partition size, and fix up if the out of bounds TLocalDriveCapsV2Buf localDriveCaps; r = LocalDrive()->Caps(localDriveCaps); if (r != KErrNone) { //-- fiddling with the error code; taken from MountL() if (r!=KErrNoMemory && r!=KErrNotReady && r!=KErrCorrupt && r!=KErrUnknown) return KErrCorrupt; else return r; } if(!(localDriveCaps().iMediaAtt & KMediaAttVariableSize)) {//-- this is not a RAM drive. const TUint32 maxSectors = I64LOW(localDriveCaps().iSize >> KDefSectorSzLog2); if(aBootSector.TotalSectors()) aBootSector.SetTotalSectors(Min(aBootSector.TotalSectors(), maxSectors)); else aBootSector.SetHugeSectors(Min(aBootSector.HugeSectors(), maxSectors)); } return KErrNone; }
/** Handle recoverable error @param aResult result from the media driver (error code) @return ERetry - retry write @return KErrCorrupt - media is corrupt @return KErrBadPower - low power failure @return KErrNotReady - non-critical error */ TInt TDriveInterface::HandleRecoverableError(TInt aResult) const { __PRINT2(_L("TDriveInterface::HandleRecoverableError drv:%d, code:%d"), iMount->DriveNumber(),aResult); if (aResult==KErrAccessDenied) return(KErrAccessDenied); if (aResult == KErrLocked) return KErrLocked; if (aResult==KErrArgument || aResult==KErrBadDescriptor) return(KErrCorrupt); if (aResult==KErrBadPower) return(KErrBadPower); if (aResult==KErrDied) // client thread died return(KErrDied); if (iMount->Drive().IsChanged()) { if(! iMount->CheckVolumeTheSame()) {//-- the media is different now. return KErrNotReady; } else if(!IsRecoverableRemount()) { return KErrAccessDenied; } } return(ERetry); }
/** read a page length data into iActive page and return iActive page if read is successful. */ TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos) { // align the page position TInt64 pageStartMedPos = CalcPageStartPos(aPos); if (iActivePage->StartPos() == pageStartMedPos && iActivePage->IsValid()) { return iActivePage; } __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, iActivePage->StartPos()); // set start med pos value, no other effects, only available to active page iActivePage->SetPos(pageStartMedPos); // read data, make active page valid TUint8* data = iActivePage->PtrInPage(iActivePage->iStartMedPos); TPtr8 dataPtr(data, iPageSizeInBytes); const TInt nErr = iDrive.ReadNonCritical(iActivePage->iStartMedPos, iPageSizeInBytes, dataPtr); if(nErr !=KErrNone) { // some serious problem occured during reading, invalidate cache. InvalidateCache(); User::Leave(nErr); } iActivePage->SetValid(ETrue); return iActivePage; }
/** @param aNewState */ void CMassStorageDrive::SetDriveState(TDriveState aNewState) { if(iLocalDrive) { __PRINT2(_L("SetDriveState: %d->%d\n"), iLocalDrive->iDriveState, aNewState); iLocalDrive->iDriveState = aNewState; } }
/* Print out current tree content */ void CLeafDirTree::DumpTreeContentL() const { RPointerArray<CLeafDirTreeNode>* nodeStack = new(ELeave) RPointerArray<CLeafDirTreeNode>(4); RFs fs; TInt nRes = fs.Connect(); User::LeaveIfError(nRes); const TUint32 debugRegister = DebugRegister(); fs.SetDebugRegister(debugRegister|KFSYS); if (iRoot != NULL) { nodeStack->Insert(iRoot, 0); while(nodeStack->Count() > 0) { CLeafDirTreeNode* current = (*nodeStack)[0]; if (current->Parent() != NULL) { __PRINT3(_L("(\"%S\") -> \"%S\" : (%d)\n"), ¤t->Parent()->Path(), ¤t->Path(), current->StartClusterNum()); } else { __PRINT2(_L("\"%S\" : (%d)\n"), ¤t->Path(), current->StartClusterNum()); } nodeStack->Remove(0); TInt currentCount = current->Children().Count(); if (currentCount > 0) { RPointerArray<CLeafDirTreeNode> children = current->Children(); for (TInt i = 0; i < currentCount; i++) { nodeStack->Insert(children[i], 0); } } } } fs.SetDebugRegister(debugRegister); fs.Close(); nodeStack->Close(); delete nodeStack; }
/** Implementation of pure virtual function. @see MWTCacheInterface::InvalidateCache() */ void CDynamicDirCache::InvalidateCache(void) { __PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount); // we should never decommit locked pages as they needs to be reserved anyway // the overhead of unnecessary page committing operations while(!iLockedQ.IsEmpty()) { TDynamicDirCachePage* page = iLockedQ.Last(); DeQueue(page); // remove from queue LookupTblRemove(page->StartPos()); // remove from lookuptable delete page; } ASSERT(iLockedQCount == 0); // however we should decommit unlocked pages here while (!iUnlockedQ.IsEmpty()) { TDynamicDirCachePage* page = iUnlockedQ.Last(); DeQueue(page); // remove from queue LookupTblRemove(page->StartPos()); // remove from lookuptable DecommitPage(page); // inform cache client to decommit page memory delete page; } ASSERT(iUnlockedQCount == 0); ASSERT(iLookupTable.Count() == 0); iLookupTable.Close(); ASSERT(iCacheMemoryClient); // initialize cache state. // Note that once the client is reset, all pages lose connection with the client // including the active page. So we will need to reset and re-allocate active page // properly. if (iCacheMemoryClient) iCacheMemoryClient->Reset(); // reset and re-allocate active page ResetPagePos(iActivePage); // reset start media position (0), invalidate page content TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); // this should always succeed as the client has just been reset and there are always reserved pages ASSERT(startRamAddr); iActivePage->SetStartPtr(startRamAddr); // set RAM address }
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); } }
/** Dump cache content, only enabled in debug mode. @see CDynamicDirCache::Control() */ void CDynamicDirCache::Dump() { __PRINT(_L("======== CDynamicDirCache::Dump =========")); if (!iLockedQ.IsEmpty()) { TDblQueIter<TDynamicDirCachePage> q(iLockedQ); q.SetToFirst(); TInt i = 0; while((TDynamicDirCachePage*)q) { TDynamicDirCachePage* pP = q++; __PRINT3(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, size=%d)"), i++, pP->StartPos(), pP->PageSizeInBytes()); } } if (!iUnlockedQ.IsEmpty()) { TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ); q.SetToFirst(); TInt i = 0; while((TDynamicDirCachePage*)q) { TDynamicDirCachePage* pP = q++; __PRINT3(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes()); } } __PRINT2(_L("=== CDynamicDirCache::iActivePage\t[*](pos=%lx, size=%u)"), iActivePage->StartPos(), iActivePage->PageSizeInBytes()); if (iLookupTable.Count()) { TInt i = 0; THashSetIter<TLookupEntry> iter(iLookupTable); TLookupEntry* pEntry; pEntry = (TLookupEntry*) iter.Next(); while(pEntry) { TDynamicDirCachePage* pP = pEntry->iPage; __PRINT3(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes()); pEntry = (TLookupEntry*) iter.Next(); }; } __PRINT(_L("===========================================\n")); }
/** Write some data to the device. @param aPos media position in bytes @param aLength how many bytes to read @param aDataDes data descriptor @return KErrNone on success, standard Epoc error code otherwise */ TInt CWinVolumeDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes) { //__PRINT2(_L("#-- CWinVolumeDevice::Write, pos:%LU, len:%u"), aPos, aLength); ASSERT(HandleValid()); if(aLength == 0 || aDataDes.Length() == 0) return KErrNone; if(aLength > aDataDes.Length()) { ASSERT(0); return KErrArgument; } //-- check position on the volume const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes(); if(aPos < 0 || aPos > maxPos) return KErrArgument; const TInt64 lastPos = aPos+aLength; if(lastPos > maxPos) return KErrArgument; TUint32 dataLen = aLength; DWORD dwRes; DWORD dwBytes = 0; const TUint32 KSectorSize = BytesPerSector(); const TUint8 *pData = aDataDes.Ptr(); try { LONG mediaPosHi = I64HIGH(aPos); const TUint32 mediaPosLo = I64LOW(aPos); const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1); const TUint32 sectorPos = mediaPosLo-startPosOffset; //-- 1. position to the media with sector size granularity dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN); if(dwRes == INVALID_SET_FILE_POINTER) { throw KDiskOpError; } if(startPosOffset || dataLen <= KSectorSize) {//-- need a read-modify-write here. //-- 1.1 read first sector if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL)) throw KDiskOpError; dwRes = SetFilePointer(iDevHandle, sectorPos, &mediaPosHi, FILE_BEGIN); if(dwRes == INVALID_SET_FILE_POINTER) { throw KDiskOpError; } if(dwRes == INVALID_SET_FILE_POINTER) throw KDiskOpError; //-- 1.2 copy chunk of data there const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset); Mem::Copy(ipScratchBuf+startPosOffset, pData, firstChunkLen); //-- 1.3 write sector if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL)) throw KDiskOpError; dataLen-=firstChunkLen; pData+=firstChunkLen; if(dataLen == 0) return KErrNone; //-- no more data to write } //-- 2. write whole number of sectors to the media const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector TUint32 KMainChunkBytes = dataLen - KBytesTail; ASSERT((KMainChunkBytes % KSectorSize) == 0); //-- the pointer to the data shall be 2-bytes aligned, otherwise WriteFile will fail if(!((DWORD)pData & 0x01)) {//-- data pointer aligned, ok if(!WriteFile(iDevHandle, pData, KMainChunkBytes, &dwBytes, NULL)) throw KDiskOpError; pData+=KMainChunkBytes; dataLen-=KMainChunkBytes; } else {//-- data pointer is odd, we need to copy data to the aligned buffer TUint32 rem = KMainChunkBytes; while(rem) { const TUint32 nBytesToWrite = Min(KScratchBufSz, rem); Mem::Copy(ipScratchBuf, pData, nBytesToWrite); if(!WriteFile(iDevHandle, ipScratchBuf, nBytesToWrite, &dwBytes, NULL)) throw KDiskOpError; rem-=nBytesToWrite; pData+=nBytesToWrite; dataLen-=nBytesToWrite; } } //-- 3. write the rest of the bytes into the incomplete last sector if(KBytesTail) { //-- 3.1 read last sector if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL)) throw KDiskOpError; LARGE_INTEGER liRelOffset; liRelOffset.QuadPart = -(LONG)KSectorSize; //dwRes = SetFilePointer(iDevHandle, -(LONG)KSectorSize, NULL, FILE_CURRENT); dwRes = SetFilePointer(iDevHandle, liRelOffset.LowPart, &liRelOffset.HighPart, FILE_CURRENT); if(dwRes == INVALID_SET_FILE_POINTER) throw KDiskOpError; //-- 1.2 copy chunk of data there Mem::Copy(ipScratchBuf, pData, KBytesTail); //-- 1.3 write sector if(!WriteFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytes, NULL)) throw KDiskOpError; } }//try catch(TInt nErrId) {//-- some disk operation finished with the error (void)nErrId; ASSERT(nErrId == KDiskOpError); const DWORD dwWinErr = GetLastError(); const TInt epocErr = MapWinError(dwWinErr); __PRINT2(_L("#-- CWinVolumeDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr); ASSERT(epocErr != KErrNone); return epocErr; } return KErrNone; }
/** Read a portion of data from the device. Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length @param aPos media position in bytes @param aLength how many bytes to read @param aDataDes data descriptor @return KErrNone on success, standard Epoc error code otherwise */ TInt CWinVolumeDevice::Read(TInt64 aPos, TInt aLength, TDes8& aDataDes) { //__PRINT2(_L("#-- CWinVolumeDevice::Read, pos:%LU, len:%u"), aPos, aLength); ASSERT(HandleValid()); ASSERT(aLength <= aDataDes.MaxLength()); //-- check position on the volume const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes(); if(aPos < 0 || aPos > maxPos) return KErrArgument; const TInt64 lastPos = aPos+aLength; if(lastPos > maxPos) return KErrArgument; //-- TUint32 dataLen = aLength; if(dataLen == 0) return KErrNone; DWORD dwRes; DWORD dwBytesRead = 0; //aDataDes.SetLength(0); const TUint32 KSectorSize = BytesPerSector(); try { LONG mediaPosHi = I64HIGH(aPos); const TUint32 mediaPosLo = I64LOW(aPos); const TUint32 startPosOffset = mediaPosLo & (KSectorSize-1); //-- 1. position to the media with sector size granularity and read 1st sector dwRes = SetFilePointer(iDevHandle, mediaPosLo-startPosOffset, &mediaPosHi, FILE_BEGIN); if(dwRes == INVALID_SET_FILE_POINTER) throw KDiskOpError; //-- 1.1 read 1st sector if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL)) throw KDiskOpError; const TUint32 firstChunkLen = Min(dataLen, KSectorSize - startPosOffset); aDataDes.Append(ipScratchBuf+startPosOffset, firstChunkLen); dataLen-=firstChunkLen; if(dataLen == 0) return KErrNone; //-- no more data to read //-- 2. read whole number of sectors from the meida const TUint32 KBytesTail = dataLen & (KSectorSize-1); //-- number of bytes in the incomplete last sector ASSERT((KScratchBufSz % KSectorSize) == 0); TUint32 rem = dataLen - KBytesTail; while(rem) { const TUint32 bytesToRead = Min(KScratchBufSz, rem); if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL)) throw KDiskOpError; aDataDes.Append(ipScratchBuf, bytesToRead); rem-=bytesToRead; } //-- 3. read the rest of the bytes in the incomplete last sector if(KBytesTail) { if(!ReadFile(iDevHandle, ipScratchBuf, KSectorSize, &dwBytesRead, NULL)) throw KDiskOpError; aDataDes.Append(ipScratchBuf, KBytesTail); } }//try catch(TInt nErrId) {//-- some disk operation finished with the error (void)nErrId; ASSERT(nErrId == KDiskOpError); const DWORD dwWinErr = GetLastError(); const TInt epocErr = MapWinError(dwWinErr); __PRINT2(_L("#-- CWinVolumeDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr); ASSERT(epocErr != KErrNone); return epocErr; } return KErrNone; }
/** 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; }
/** Constructor of CLeafDirTree @param aLimit the maximum number of 'leaf' nodes allowed of the tree */ CLeafDirTree::CLeafDirTree(TUint32 aSize) :iSize(aSize) { __PRINT2(_L("CLeafDirTree created[0x%x] sz:%d"), this, aSize); }
/** Handle critical error @param aResult result from the media driver (error code) @return ERetry - Attempt operation again @return KErrAbort - User aborted notifier @return KErrAccessDenied - media is read only @return KErrCorrupt - cf-card is corrupt */ TInt TDriveInterface::HandleCriticalError(TInt aResult) const { __PRINT2(_L("TDriveInterface::HandleCriticalError drv:%d, code:%d"), iMount->DriveNumber(),aResult); TLocaleMessage line1; TLocaleMessage line2; TInt r=KErrAbort; if (aResult==KErrLocked) { r=KErrLocked; goto End; } if (aResult==KErrAccessDenied) { r=KErrAccessDenied; goto End; } if (aResult==KErrArgument || aResult==KErrBadDescriptor) { r=KErrCorrupt; goto End; } if (iMount->Drive().IsChanged()) {//-- check if the media we accessing is the same as it used to be if(iMount->CheckVolumeTheSame()) {//-- the media is the same if(!IsDriveWriteProtected()) { iMount->Drive().SetChanged(EFalse); r=ERetry; goto End; } } } if (aResult==KErrAbort && !iMount->Drive().IsChanged()) { r=ERetry; goto End; } if (aResult==KErrBadPower) { line1=EFileServer_LowPowerLine1; line2=EFileServer_LowPowerLine2; } else if (iMount->Drive().IsChanged()) { line1=EFileServer_PutTheCardBackLine1; line2=EFileServer_PutTheCardBackLine2; } else { line1=EFileServer_DiskErrorLine1; line2=EFileServer_DiskErrorLine2; } if (NotifyUser()) { FOREVER { TInt buttonVal; TInt ret=iMount->Notifier()->Notify(TLocaleMessageText(line1), TLocaleMessageText(line2), TLocaleMessageText(EFileServer_Button1), TLocaleMessageText(EFileServer_Button2), buttonVal); if (ret!=KErrNone) break; if (buttonVal!=1) break; // Abort if (iMount->Drive().IsChanged()) { // // Without this code, retry will indiscriminately write over whatever disk happens to be present. // However if the write error is to the bootsector remounting will always fail because the boot // sector will have changed and hence the disk is useless. // if(!iMount->CheckVolumeTheSame()) continue; //-- the media isn't the same as originally mounted; continue asking if(IsDriveWriteProtected()) continue; //-- still can not write to the drive iMount->Drive().SetChanged(EFalse); } r=ERetry; // Retry break; } } End: return(r); }
/** Mount a Fat volume. @param aForceMount Flag to indicate whether mount should be forced to succeed if an error occurs @leave KErrNoMemory,KErrNotReady,KErrCorrupt,KErrUnknown. */ void CFatMountCB::MountL(TBool aForceMount) { const TInt driveNo = Drive().DriveNumber(); __PRINT3(_L("CFatMountCB::MountL() drv:%d, forceMount=%d, RuggedFAT:%d\n"), driveNo, aForceMount, IsRuggedFSys()); ASSERT(State() == ENotMounted || State() == EDismounted); SetState(EMounting); SetReadOnly(EFalse); User::LeaveIfError(CreateDrive(driveNo)); //-- read FAT configuration parameters from estart.txt iFatConfig.ReadConfig(driveNo); //-- initialise interface to the low-level drive access if(!iDriverInterface.Init(this)) User::LeaveIfError(KErrNoMemory); //-- get drive capabilities TLocalDriveCapsV2Buf capsBuf; User::LeaveIfError(LocalDrive()->Caps(capsBuf)); iSize=capsBuf().iSize; iRamDrive = EFalse; if(capsBuf().iMediaAtt & KMediaAttVariableSize) {//-- this is a RAM drive UserSvr::UnlockRamDrive(); iRamDrive = ETrue; } if(aForceMount) {//-- the state is "forcedly mounted", special case. This is an inconsistent state. SetState(EInit_Forced); return; } //-- read boot sector. If main is damaged, try to use backup one instead if this is not a RAM drive. TFatBootSector bootSector; User::LeaveIfError(ReadBootSector(bootSector, iRamDrive)); //-- print out boot sector debug information bootSector.PrintDebugInfo(); //-- determine FAT type by data from boot sector. This is done by counting number of clusters, not by BPB_RootEntCnt SetFatType(bootSector.FatType()); ASSERT(iFatType != EInvalid); //-- this shall be checked in ReadBootSector() if(bootSector.RootDirEntries() == 0 && !Is32BitFat()) {//-- FAT types mismatch. BPB_RootEntCnt is 0, which can be only for FAT32, but the number of clusters is less //-- than required for FAT32. Probably this is incorrectly FAT32 formatted media. Put the drive into ReadOnly mode, assuming //-- that is FAT32. __PRINT(_L("FAT type mismatch! Setting drive to ReadOnly mode for FAT32. \n")); SetFatType(EFat32); //-- force FAT type to be FAT32 SetReadOnly(ETrue); } //-- store volume UID, it can be checked on Remount iUniqueID = bootSector.UniqueID(); //-- populate volume parameters with the values from boot sector. They had been validated in TFatBootSector::IsValid() iVolParam.Populate(bootSector); //-- initialize the volume InitializeL(capsBuf()); ASSERT(State()==EInit_R); GetVolumeLabelFromDiskL(bootSector); __PRINT2(_L("CFatMountCB::MountL() Completed, drv: %d, state:%d"), DriveNumber(), State()); }
/** Read a portion of data from the device. Note: at present it _APPENDS_ data to the aDataDes, so the caller must take care of setting its length @param aPos media position in bytes @param aLength how many bytes to read @param aDataDes data descriptor @return KErrNone on success, standard Epoc error code otherwise */ TInt CWinImgFileDevice::Read(TInt64 aPos,TInt aLength, TDes8& aDataDes) { //__PRINT3(_L("#-- CWinImgFileDevice::Read, pos:%LU, len:%u, desMaxLen:%u"), aPos, aLength, aDataDes.MaxLength()); ASSERT(HandleValid()); ASSERT(aLength <= aDataDes.MaxLength()); //-- check position on the volume const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes(); if(aPos < 0 || aPos > maxPos) return KErrArgument; const TInt64 lastPos = aPos+aLength; if(lastPos > maxPos) return KErrArgument; TUint32 dataLen = aLength; if(dataLen == 0) return KErrNone; DWORD dwRes; DWORD dwBytesRead = 0; //aDataDes.SetLength(0); try { //-- 1. position to the media LONG mediaPosHi = I64HIGH(aPos); const TUint32 mediaPosLo = I64LOW(aPos); dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN); if(dwRes == INVALID_SET_FILE_POINTER) throw KDiskOpError; //-- 2. read data to the scratch buffer and copy it to the descriptor. ASSERT(ipScratchBuf); TUint32 rem = dataLen; while(rem) { const TUint32 bytesToRead = Min(KScratchBufSz, rem); if(!ReadFile(iDevHandle, ipScratchBuf, bytesToRead, &dwBytesRead, NULL)) throw KDiskOpError; aDataDes.Append(ipScratchBuf, bytesToRead); rem-=bytesToRead; } } catch(TInt nErrId) {//-- some disk operation finished with the error (void)nErrId; ASSERT(nErrId == KDiskOpError); const DWORD dwWinErr = GetLastError(); const TInt epocErr = MapWinError(dwWinErr); __PRINT2(_L("#-- CWinImgFileDevice::Read() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr); ASSERT(epocErr != KErrNone); return epocErr; } return KErrNone; }
/** Write some data to the device. @param aPos media position in bytes @param aLength how many bytes to read @param aDataDes data descriptor @return KErrNone on success, standard Epoc error code otherwise */ TInt CWinImgFileDevice::Write(TInt64 aPos, TInt aLength, const TDesC8& aDataDes) { //__PRINT3(_L("#-- CWinImgFileDevice::Write, pos:%LU, len:%u, desLen:%u" ), aPos, aLength, aDataDes.Length()); ASSERT(HandleValid()); if(aLength == 0 || aDataDes.Length() == 0) return KErrNone; if(aLength > aDataDes.Length()) { ASSERT(0); return KErrArgument; } //-- check position on the volume const TInt64 maxPos = iDrvGeometry.TotalSizeInBytes(); if(aPos < 0 || aPos > maxPos) return KErrArgument; const TInt64 lastPos = aPos+aLength; if(lastPos > maxPos) return KErrArgument; TUint32 dataLen = aLength; DWORD dwRes; DWORD dwBytes = 0; const TUint8 *pData = aDataDes.Ptr(); try { //-- 1. position to the media LONG mediaPosHi = I64HIGH(aPos); const TUint32 mediaPosLo = I64LOW(aPos); dwRes = SetFilePointer(iDevHandle, mediaPosLo, &mediaPosHi, FILE_BEGIN); if(dwRes == INVALID_SET_FILE_POINTER) { throw KDiskOpError; } //-- 2. write data to the media //-- check if the pointer is word-aligned const DWORD dwPtrMask = 0x01; if( (DWORD)pData & dwPtrMask) {//-- data pointer isn't aligned, write non-aligned bytes through buffer ASSERT(dataLen); const int oddCnt = 1; ipScratchBuf[0] = *pData; ++pData; --dataLen; if(!WriteFile(iDevHandle, ipScratchBuf, oddCnt, &dwBytes, NULL)) throw KDiskOpError; } ASSERT(!((DWORD)pData & dwPtrMask)); if(dataLen > 0) { if(!WriteFile(iDevHandle, pData, dataLen, &dwBytes, NULL)) throw KDiskOpError; } } catch(TInt nErrId) {//-- some disk operation finished with the error (void)nErrId; ASSERT(nErrId == KDiskOpError); const DWORD dwWinErr = GetLastError(); const TInt epocErr = MapWinError(dwWinErr); __PRINT2(_L("#-- CWinImgFileDevice::Write() error! WinErr:%d, EpocErr:%d"), dwWinErr, epocErr); ASSERT(epocErr != KErrNone); return epocErr; } return KErrNone; }
/** 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); }