/**
    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;
    }
Exemple #3
0
/**
    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"), &current->Parent()->Path(), &current->Path(), current->StartClusterNum());
				}
			else
				{
				__PRINT2(_L("\"%S\" : (%d)\n"), &current->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);
	}
Exemple #14
0
/**
    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);
	}
Exemple #15
0
/**
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;
}
Exemple #18
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);


    }