// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// f32\estart\estart.cpp
// Generic startup code run by the fileserver on boot
//
//
#include <e32std.h>
#include <e32std_private.h>
#include <e32def_private.h>
#include <hal.h>
#include <f32file.h>
#include <f32file_private.h>
#include <f32fsys.h>
#ifndef SYMBIAN_EXCLUDE_ESTART_DOMAIN_MANAGER
#include <domainmanager.h>
#endif
#include <e32uid.h>
#include <e32property.h>
//#ifndef _DEBUG
// #define _DEBUG
//#endif
//#define TRACING_ON
#include "estart.h"
#include <u32exec.h>
//-- define this macro in order to have system start time measurement (SYSSTATEMGR.EXE process life time)
//#define SYMBIAN_ESTART_OUTPUT_BOOT_TIME
TInt LoadCodePageDll();
/** Maximum Codepage Dll name length. */
const TInt KMaxCodepageDllName=16;
#ifdef _DEBUG
TBool DebugTraceEnabled()
{
#ifdef TRACING_ON
return ETrue;
#else
return UserSvr::DebugMask() & 2;
#endif
}
#endif
_LIT(KEStartPanicCatagory, "ESTART");
enum TEStartPanic
{
ELitNoDM = 1, // No Domain Manager
ELitDMInitFail, // Domain Manager init fail
ELitHALFail, // HAL init fail
ELitConnectFsFail1, // Connect fs 1 fail
ELitInitLocalPwStoreFail, // Init PwStore fail
ELitLocaleInitialisationFail, // Initialisation of locale properties failed
ELitFSInitDriveInfoFail, // FS Init DriveInfo fail
ELitCreateTrapHandlerFail, // Create trap handler fail
ELitLoadSysLddsFail, // Load sys ldds fail
ELitLocalDriveMappingFail, // Local drive mapping fail
ELitDriveMappingFileFail, // Drive mapping file not found
ELitSwapMappingFailArrayInconsistent, // Swap mappings fail - array inconsistent
ELitFsSwapMappingFail, // Swap mappings fail - Fs request failed
EPropertyError, // RProperty return error
ECompMountFsFail, // Failed comp fs mount
EFsNameFail, // File system name on Z: failed
ELitNoWS, // No WSERV
EStartupModeFail, // Get startup mode failed
ESysAgentFail, // Fail to launch system agent
ESetSystemDriveFail // Fail to set System Drive
};
inline void Panic(TEStartPanic aPanic, TInt aReason)
{
TBuf<10> panic(KEStartPanicCatagory);
panic.AppendFormat(_L("_%d"), aPanic);
User::Panic(panic, aReason);
}
_LIT(KRofs,"erofs.fsy");
_LIT(KCompfs,"ecomp.fsy");
_LIT(KEcomp,"ECOMP");
_LIT(KServerPathSysBin, "0:\\Sys\\Bin\\");
_LIT(KSystemAgentName, "z:\\sys\\bin\\SysAgt2Svr.exe");
_LIT(KLitLocaleData,"?:\\System\\Data\\LOCALE.D");
_LIT(KLocaleDllNameBase, "ELOCL");
_LIT(KLocalDriveMappingFile,"Z:\\SYS\\DATA\\ESTART.TXT");
_LIT(KWindowServerRootName1,"EWSRV.EXE");
_LIT(KSystemStarterName, "z:\\sys\\bin\\SYSSTART.EXE");
_LIT(KSystemStateManager, "z:\\sys\\bin\\SYSSTATEMGR.EXE");
//const TInt KPatchLddUidValue=0x100000cc; // patch ldds should specify this as their third uid
GLDEF_D TBool gMountRofsAlone=ETrue;
GLDEF_D TBool gMountComposite=EFalse;
enum TCompositeMountSate
{
ENoMounts,
EHasMounts,
ESwapped
};
LOCAL_D TCompositeMountSate gCompositeMountState=ENoMounts;
#if !defined(AUTODETECT_DISABLE)
LOCAL_D TInt gNCompositeMounts=0;
#endif
#if defined(__EPOC32__) && defined(__X86__)
LOCAL_D TInt gNFloppies=0;
#endif
/**
ASCII text file reader constructor
*/
TText8FileReader::TText8FileReader()
{
iBufPos=-1;
iFileDataBuf=NULL;
iFileSize=0;
}
/**
ASCII text file reader desctructor
*/
TText8FileReader::~TText8FileReader()
{
delete[] iFileDataBuf;
}
/**
Supply an ASCII text file for the file reader.
This function reads the entire contents of this file into a buffer, converting to
unicode / folding each character. Subsequent parsing of the file data is all done from this
buffer.
@param aFile The file to be read. Must already be opened for read access in EFileStreamText mode.
@return KErrNone if no error.
*/
TInt TText8FileReader::Set(RFile& aFile)
{
iFile=aFile;
iBuf.Zero();
iBufPos=0;
// Read the size of the file
TInt r=iFile.Size(iFileSize);
if (r!=KErrNone || !iFileSize)
return(KErrGeneral);
// Allocate a buffer to read in the file
iFileDataBuf=new TText[iFileSize+1]; // +1 in case need to NULL terminate the end of the last string
if (iFileDataBuf==NULL)
return(KErrNoMemory);
// Read the entire contents of the file into the buffer
TPtr fdata(NULL,0);
TInt pos=0;
r=iFile.Seek(ESeekStart,pos);
while (pos<iFileSize)
{
if ((r=iFile.Read(iBuf))!=KErrNone)
return(r);
fdata.Set((iFileDataBuf+pos),0,iBuf.Length());
fdata.Copy(iBuf);
fdata.Fold();
pos+=iBuf.Length();
}
return(KErrNone);
}
/**
Return the next record from the text file.
@param aPtr A TPtr which is setup with the address and length of the next record, referencing
the data in the reader's buffer.
@return KErrNone if a record is successfully loaded into the buffer, KErrEof if the end of the
file is encountered, KErrGeneral if a file hasn't been set.
*/
TInt TText8FileReader::Read(TPtr& aPtr)
{
// Check that Set() has been called.
if (iBufPos<0)
return(KErrGeneral);
// Check if we have run into the end of the file
TInt bufRemainder=(iFileSize-iBufPos);
if (!bufRemainder)
return(KErrEof);
// Setup the descriptor passed with the next record - don't include the record terminator
// The line terminators are CR + LF for DOS
// whereas only LF for Unix line endings
aPtr.Set((iFileDataBuf+iBufPos),bufRemainder,bufRemainder);
TInt len=aPtr.Locate('\n');
if (len != KErrNotFound)
{
iBufPos += len;
// Check for DOS line ending to support both DOS and Unix formats
if ((len != 0) && (iFileDataBuf[iBufPos-1] == '\r'))
{
len--;
}
aPtr.SetLength(len);
}
else
iBufPos=iFileSize;
// Point iBufPos to the next non-empty line
while (iBufPos<iFileSize && (iFileDataBuf[iBufPos]=='\n' || iFileDataBuf[iBufPos]=='\r'))
iBufPos++;
return(KErrNone);
}
const TInt DefaultLocalDrives[KMaxLocalDrives]=
{
EDriveC, //0
EDriveD, //1
EDriveE, //2
EDriveF, //3
EDriveG, //4
EDriveH, //5
EDriveI, //6
EDriveJ, //7
EDriveK, //8
EDriveL, //9
EDriveM, //10
EDriveN, //11
EDriveO, //12
EDriveP, //13
EDriveQ, //14
EDriveR //15
};
/**
Return the default drive letter for the specified local drive.
To alter the default mapping scheme on auto-configuration, override this function.
@param aLocalDrive The number of the local drive (0-15).
@return The default drive number associated with this local drive.
*/
TInt TFSStartup::DefaultLocalDrive(TInt aLocalDrive)
{
return(DefaultLocalDrives[aLocalDrive]);
}
//typedef TInt TLocalDriveList[KMaxLocalDrives];
/**
Write the local drive mapping data to the file server. If there is no potential of a drive swap then also commit it.
Once committed, the setting cannot be changed.
@panic ESTART_10 Error_Code; If unable to set local drive mapping in the file server.
Error_Code is the error code returned by RFs::SetLocalDriveMapping()
*/
void TFSStartup::SetFServLocalDriveMapping()
{
DEBUGPRINT("SetFServLocalDriveMapping");
TLocalDriveMappingInfoBuf mBuf;
TLocalDriveMappingInfo& ldmi=mBuf();
Mem::Copy(&ldmi.iDriveMapping[0],&iLocalDriveList[0],(KMaxLocalDrives*sizeof(TInt)));
// Can't set the mapping yet - if there is the potential of a drive swap .
ldmi.iOperation = (iDriveSwapCount) ? TLocalDriveMappingInfo::EWriteMappingsNoSet : TLocalDriveMappingInfo::EWriteMappingsAndSet;
TInt r=iFs.SetLocalDriveMapping(mBuf);
__ASSERT_ALWAYS(r==KErrNone,Panic(ELitLocalDriveMappingFail, r));
}
/**
Swap and commit the file server's local drive mapping data. Change the local drive mapping info already set with the file server.
@param aFirstDrive First Drive number to be swapped.
@param aSecondDrive Second Drive number to be swapped.
@panic ESTART_13 Error_Code; if unable to set the local drive mapping to file server.
Error_Code is the error code returned by RFs::SetLocalDriveMapping()
*/
void TFSStartup::SwapFServLocalDriveMapping(TInt aFirstDrive,TInt aSecondDrive)
{
DEBUGPRINT("SwapFServLocalDriveMapping");
TLocalDriveMappingInfoBuf mBuf;
TLocalDriveMappingInfo& ldmi=mBuf();
ldmi.iDriveMapping[0]=aFirstDrive;
ldmi.iDriveMapping[1]=aSecondDrive;
ldmi.iOperation=TLocalDriveMappingInfo::ESwapIntMappingAndSet;
TInt r=iFs.SetLocalDriveMapping(mBuf);
__ASSERT_ALWAYS(r==KErrNone,Panic(ELitFsSwapMappingFail,r));
}
// Warning - File format changes must be replicated in EikSrv.
struct TLocData
{
TLocale iLocale;
TCurrencySymbol iCurrency;
};
/**
Attempt to open the locale data file from system drive. If found, read the
locale and currency symbol data from this file and transfer it to 'the system'.
@return KErrNone if successful.
*/
TInt TFSStartup::LoadLocale()
{
// Append the language index to the standard locale filename.
TFileName filename(KLitLocaleData);
filename[0] = (TUint8) RFs::GetSystemDriveChar();
TInt lang;
if (HAL::Get(HAL::ELanguageIndex,lang) == KErrNone)
{
filename.AppendNumFixedWidth(lang,EDecimal,2);
HAL::Set(HAL::ELocaleLoaded, lang);
}
// Attempt to open the file, read/set the data.
RFile file;
if (file.Open(iFs,filename,EFileRead) == KErrNone)
{
TPckgBuf<TLocData> data;
if( file.Read(data) == KErrNone && data.Size()==sizeof(TLocData))
{
data().iLocale.Set();
TInt offset = data().iLocale.UniversalTimeOffset().Int();
if (data().iLocale.QueryHomeHasDaylightSavingOn())
offset += 3600;
User::SetUTCOffset(offset);
User::SetCurrencySymbol(data().iCurrency);
}
file.Close();
}
return(KErrNone);
}
/**
Load the Locale DLL
@return KErrNone if successful.
KErrNotFound if locale DLL not found.
Or other system wide error code.
*/
TInt LoadLocaleDll()
{
TBuf<16> localeDllName;
TInt languageIndex;
TInt error=HAL::Get(HALData::ELanguageIndex,languageIndex);
if (error!=KErrNone)
error = KErrNotFound;
else
{
TBuf<6> extension; // Dot plus five digit locale
_LIT(KExtension,".%u");
extension.Format(KExtension, languageIndex);
if (extension.Length()<3) // Padd ".1" to ".01" for compatibility.
{
_LIT(KPadding,"0");
extension.Insert(1,KPadding);
}
localeDllName=KLocaleDllNameBase;
localeDllName.Append(extension);
error = UserSvr::ChangeLocale(localeDllName);
}
if (error==KErrNotFound)
{
// Try default locale
_LIT(KLocaleDllNameExtension, ".LOC");
localeDllName=KLocaleDllNameBase;
localeDllName.Append(KLocaleDllNameExtension);
error = UserSvr::ChangeLocale(localeDllName);
}
if (error == KErrNone)
TLocale().Set();
return error;
}
/**
Initialise the HAL.
Search for a saved HAL file - containing a series of saved HAL attributes.
If found, initialise each attribute saved.
@return KErrNone if successful; KErrGeneral if the exe panicked.
*/
TInt TFSStartup::InitialiseHAL()
{
RProcess process;
TInt result = process.Create(_L("HALSettings.exe"), _L("INITIALISE"));
if(result != KErrNone)
return result;
TRequestStatus status;
process.Logon(status);
if (status != KRequestPending)
process.Kill(0); // abort
else
process.Resume(); // logon OK
User::WaitForRequest(status);
// Special case to ensure the nonsecure clock offset set function gets called
TInt nsc_offset = 0;
result = HAL::Get(HAL::ETimeNonSecureOffset,nsc_offset);
if (result == KErrNone)
{
HAL::Set(HAL::ETimeNonSecureOffset,nsc_offset); // this will only succeed when hal.dat is missing and the function wasnt called by halsettings.exe
}
// we can't use the 'exit reason' if the exe panicked as this
// is the panic 'reason' and may be '0' which cannot be distinguished
// from KErrNone
result = process.ExitType() == EExitPanic ? KErrGeneral : status.Int();
process.Close();
return result;
}
/**
Create and resume a server. Start without specifying a path.
If this fails, then systematically try to start it from
each valid drive in turn (Y: - A:, then Z:).
The second phase is to handle the sitation where a version
of the executable is found on a drive early in the search order
(e.g. C:) - that fails to load. Rather than failing the load
on the 1st error, this function keeps going through all the valid drives.
@param aDrives The drive list, to determine which are valid.
@param aRootName The root name of the executable.
@return ETrue if the server was eventually created successfully, EFalse if not.
*/
TBool TFSStartup::CreateServer(const TDriveList& aDrives, const TDesC& aRootName)
{
RProcess ws;
TInt r=ws.Create(aRootName, KNullDesC);
if (r!=KErrNone)
{
TFileName name;
name = KServerPathSysBin();
name+=aRootName;
TInt i=EDriveZ;
FOREVER
{
i= (i==0) ? EDriveZ : i-1;
if (aDrives[i]!=KDriveAbsent) // Got a valid drive
{
name[0]=(TText)('A'+i); // Set the drive letter
r=ws.Create(name,KNullDesC);
if (r==KErrNone)
break;
}
if (i==EDriveZ)
return EFalse;
}
}
ws.Resume();
ws.Close();
return ETrue;
}
#ifdef AUTO_PROFILE
_LIT(KProfilerName,"profiler.exe");
_LIT(KProfilerCmd,"start");
/**
Start the profiler
*/
void TFSStartup::StartProfiler()
{
RProcess p;
TInt r=p.Create(KProfilerName,KProfilerCmd);
if (r==KErrNone)
{
p.Resume();
p.Close();
}
}
#endif
#if !defined(AUTODETECT_DISABLE)
/**
FSY detection function for the local FSY (assumed to be FAT). This will return success for MMC,
ATA, Floppy and IRAM devices that are FAT formatted. Will also return success for any drive
(other than those designated for CD ROMs) which isn't ready - assuming these to be removable FAT
formatted devices. For floppy devices detected on the X86 build, we need to change the drive
mapping so that these are mounted on drives A: or B:.
*/
GLDEF_C TInt DetectELocal(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
TInt socknum;
if (cr==KErrNotReady && caps.iType != EMediaCdRom)
{
#if defined(__EPOC32__) && defined(__X86__)
// For FDD iEraseBlockSize top 16 bits is sectors per track
if (caps.iType==EMediaFloppy && (caps.iEraseBlockSize>>16))
{
pc_floppy:
if (gNFloppies < 2)
{
// Change the default mapping to A: or B:
TInt ret = gNFloppies ? EDriveB : EDriveA;
++gNFloppies;
return KFsDetectMappingChangeReturnOffset + ret;
}
return KErrNone;
}
#endif
return KErrNone; // Removable and not ready - assume fat
}
if(cr == KErrCorrupt && ld.IsRemovable(socknum)) // Removable and media corrupt - assume fat
{
return KErrNone;
}
if (caps.iType!=EMediaFloppy && caps.iType!=EMediaHardDisk)
return KErrGeneral;
if (cr==KErrNone && (PartitionIsFAT32(caps.iPartitionType) || PartitionIsFAT(caps.iPartitionType)) )
{
#if defined(__EPOC32__) && defined(__X86__)
if (cr!=KErrNotSupported && caps.iType==EMediaFloppy && (caps.iEraseBlockSize>>16))
goto pc_floppy;
#endif
return KErrNone;
}
return KErrGeneral;
}
/**
FSY detection function for the local FSY (assumed to be FAT) running over internal RAM. This will
return success for any drive containing RAM media which reports a FAT16 partition type.
*/
GLDEF_C TInt DetectIRam(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if (caps.iType==EMediaRam && caps.iPartitionType==KPartitionTypeFAT16)
return KErrNone;
return KErrGeneral;
}
/**
FSY detection function for the local FSY (assumed to be FAT) running over a NAND FTL. This will
return success for any drive containing NAND media which reports a FAT16 partition type.
*/
GLDEF_C TInt DetectFtl(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if (caps.iType==EMediaNANDFlash && caps.iPartitionType==KPartitionTypeFAT16)
return KErrNone;
return KErrGeneral;
}
/**
FSY detection function for the ROFS FSY. This will return success for any drive containing NAND
media which reports a ROFS partition type as long as the ROFS FSY is present - but not the Composite FSY
*/
GLDEF_C TInt DetectRofs(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if ((caps.iType==EMediaNANDFlash) && caps.iPartitionType==KPartitionTypeRofs && gMountRofsAlone)
return KErrNone;
return KErrGeneral;
}
/**
FSY detection function for the Composite FSY. This will return success for the 1st drive containing NAND
media which reports a ROFS partition type as long as both the ROFS and Composite FSYs are present. We
change the DRIVE mapping so that this is mounted on drive Z:. Any subsequent ROFS partitions detected
can be mounted as ROFS.
*/
GLDEF_C TInt DetectComposite(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if ((caps.iType==EMediaNANDFlash) && caps.iPartitionType==KPartitionTypeRofs && gMountComposite)
{
if (!gNCompositeMounts)
{
gNCompositeMounts++;
gMountRofsAlone=ETrue; // Any further ROFS drives found can be mounted as such
return(KFsDetectMappingChangeReturnOffset+EDriveZ);
}
}
return KErrGeneral;
}
/**
FSY detection function for the LFFS FSY. This will return success for any drive containing NOR
media which reports an LFFS partition type.
*/
GLDEF_C TInt DetectEneaLFFS(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if (caps.iType==EMediaFlash && caps.iPartitionType==KPartitionTypeEneaLFFS)
return KErrNone;
return KErrGeneral;
}
/**
FSY detection function for the ISO 9660 FSY (X86 only). This will return success for CD ROM
devices.
*/
GLDEF_C TInt DetectIso9660(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if (caps.iType == EMediaCdRom)
return KErrNone;
return KErrGeneral;
}
/**
FSY detection function for the NTFS FSY (X86 only). This will return success for any drive
containing a hard disk device which reports an NTFS partition type.
*/
GLDEF_C TInt DetectNtfs(RLocalDrive ld, TInt cr, TLocalDriveCapsV2& caps)
{
(void)ld;
(void)cr;
if (caps.iType==EMediaHardDisk && PartitionIsNTFS(caps.iPartitionType))
return KErrNone;
return KErrGeneral;
}
#endif
/**
Format a drive.
@param aDrive The number of the drive to be formatted (0-25).
@return KErrNone if no error otherwise one of the other system wide error codes.
*/
TInt TFSStartup::FormatDrive(TInt aDrive)
{
TBuf<2> driveName(_S("A:"));
driveName[0] = (TText)(aDrive+'A');
RFormat format;
TInt count;
TInt d = format.Open(iFs, driveName, EHighDensity, count);
DEBUGPRINT2("FormatOpen %S -> %d", &driveName, d);
if(d!=KErrNone)
return d;
ShowFormatProgress(count, aDrive);
#ifdef _DEBUG
TInt lastCount = -1;
#endif
while (d==KErrNone && count)
{
#ifdef _DEBUG
if (lastCount != count)
DEBUGPRINT1("Format count %d", count);
lastCount = count;
#endif
d=format.Next(count);
ShowFormatProgress(count, aDrive);
}
format.Close();
DEBUGPRINT1("Format complete %d", d);
return d;
}
/**
Set System Drive if defined either in ESTART.TXT or in HALData::ESystemDrive
*/
void TFSStartup::SetSystemDrive()
{
DEBUGPRINT("TFSStartup::SetSystemDrive");
for(TInt i=0; i<iMapCount; i++)
{
if(iDriveMappingInfo[i].iFsInfo.iFlags&FS_SYSTEM_DRIVE)
{
TInt err = iFs.SetSystemDrive((TDriveNumber)iDriveMappingInfo[i].iDriveNumber);
DEBUGPRINT3("SetSystemDrive from FILE [%d], %d, err:%d", i, iDriveMappingInfo[i].iDriveNumber, err);
__ASSERT_ALWAYS(err==KErrNone, Panic(ESetSystemDriveFail, err));
}
}
TInt drive = KErrNotFound;
TInt err = HAL::Get(HAL::ESystemDrive, drive);
if(err == KErrNone && drive >= EDriveA && drive <= EDriveZ)
{
err = iFs.SetSystemDrive((TDriveNumber)drive);
DEBUGPRINT2("SetSystemDrive from HAL %d, err:%d", drive, err);
__ASSERT_ALWAYS(err==KErrNone || err==KErrAlreadyExists, Panic(ESetSystemDriveFail, err));
}
}
/**
Parse the flags field of a drive mapping record that has been read from the drive mapping file.
The flags field text is expected to contain one or more flags, each delimited with a "," char.
Override this function to support custom drive configuation flags.
@param aFlagDesc Non-modifiable descriptor holding the flags record text to be parsed.
@param aFlagVar An integer to hold the returned flag settings.
@param aSpare An integer to hold any additional info returned.
@return Always returns KErrNone (but derived version may not).
*/
TInt TFSStartup::ParseMappingFileFlags(const TPtrC& aFlagDesc,TUint32& aFlagVar,TInt& aSpare)
{
TInt r=KErrNone;
TInt pos=0;
TInt len;
TPtrC ptr;
TBool endOfFlagDesc=EFalse;
aFlagVar=0;
while (!endOfFlagDesc && r==KErrNone)
{
ptr.Set(aFlagDesc.Mid(pos));
len=ptr.Locate(',');
if (len==KErrNotFound)
endOfFlagDesc=ETrue;
else
{
ptr.Set(ptr.Left(len));
pos+=(len+1);
}
if (ptr.MatchF(_L("FS_FORMAT_ALWAYS"))!=KErrNotFound)
aFlagVar|=FS_FORMAT_ALWAYS;
else if (ptr.MatchF(_L("FS_FORMAT_COLD"))!=KErrNotFound)
aFlagVar|=FS_FORMAT_COLD;
else if (ptr.MatchF(_L("FS_FORMAT_CORRUPT"))!=KErrNotFound)
aFlagVar|=FS_FORMAT_CORRUPT;
else if (ptr.MatchF(_L("FS_DISMNT_CORRUPT"))!=KErrNotFound)
aFlagVar|=FS_DISMNT_CORRUPT;
else if (ptr.MatchF(_L("FS_SWAP_CORRUPT*"))!=KErrNotFound)
{
len=ptr.Locate('-');
if (iFs.CharToDrive(ptr[len+1],aSpare)==KErrNone && iDriveSwapCount==0) // We only allow one swap
{
aFlagVar|=FS_SWAP_CORRUPT;
iDriveSwapCount++;
}
}
else if (ptr.MatchF(_L("FS_SYNC_DRIVE"))!=KErrNotFound)
aFlagVar|=FS_SYNC_DRIVE;
else if (ptr.MatchF(_L("FS_SCANDRIVE"))!=KErrNotFound)
aFlagVar|=FS_SCANDRIVE;
else if (ptr.MatchF(_L("FS_COMPOSITE"))!=KErrNotFound)
aFlagVar|=FS_COMPOSITE;
else if (ptr.MatchF(_L("FS_NO_MOUNT"))!=KErrNotFound)
aFlagVar|=FS_NO_MOUNT;
else if (ptr.MatchF(_L("FS_ALLOW_REM_ACC"))!=KErrNotFound)
aFlagVar|=FS_ALLOW_REM_ACC;
else if (ptr.MatchF(_L("FS_NOT_RUGGED")) != KErrNotFound)
aFlagVar |= FS_NOT_RUGGED;
else if (ptr.MatchF(_L("FS_SYSTEM_DRIVE")) != KErrNotFound)
aFlagVar |= FS_SYSTEM_DRIVE;
else
r=ParseCustomMountFlags(&ptr,aFlagVar,aSpare);
}
return(r);
}
/**
Parse for custom mount flags - default implementation.
In either the auto-configuration scheme or the drive mapping file scheme,
to add support for additional mount flags, this function needs to be override.
@param aFlagPtr The flag text.
@param aFlags An integer to hold the returned mount flag settings
@param aSpare An integer to hold any additional info returned.
@return KErrNone if no error.
*/
TInt TFSStartup::ParseCustomMountFlags(TPtrC* /*aFlagPtr*/,TUint32& /*aFlags*/,TInt& /*aSpare*/)
{
return(KErrNone);
}
/**
Process any custom mount flags - default implementation.
In either the auto-configuration scheme or the drive mapping file scheme,
to add support for additional mount flags, this function needs to be override.
@param aMountRet The value returned when attempting to mount the drive.
@param aFlags The mount flags.
@param aSpare An integer containing any additional info associated with the flags.
@param aDrive The drive number.
@return KErrNone if no error.
*/
TInt TFSStartup::HandleCustomMountFlags(TInt& /*aMountRet*/,TInt& /*aFlags*/,TInt& /*aSpare*/,TInt /*aDrive*/)
{
return(KErrNone);
}
/**
Process the local drive field of a drive mapping record
@param aDriveDesc The comma seperated local drives
@param aDrives An array of drive numbers (return reference)
@param aCount The number of local drives found.
@return KErrNone if no error, otherwise a System-wide error code.
*/
TInt TFSStartup::ParseMappingFileLocalDrive(const TPtrC& aDriveDesc,TUint32 (&aDrives)[KMaxLocalDrives],TInt& aCount)
{
TInt len;
TInt pos=0;
TPtrC ptr;
TBool endOfDriveDesc=EFalse;
TInt err = KErrNone;
aCount=0;
while (!endOfDriveDesc)
{
ptr.Set(aDriveDesc.Mid(pos));
len=ptr.Locate(',');
if (len==KErrNotFound)
endOfDriveDesc=ETrue;
else
{
ptr.Set(ptr.Left(len));
pos+=(len+1);
}
// Get numeric value
TLex lex;
lex.Assign(ptr);
lex.SkipSpace();
TUint32 locDrvNum;
if (lex.BoundedVal(locDrvNum,EDecimal,(KMaxLocalDrives-1))!=KErrNone)
return(KErrArgument);
// Store
if(aCount >= KMaxLocalDrives)
return KErrOverflow;
aDrives[aCount]=locDrvNum;
++aCount;
}
return err;
}
/**
Parse a drive mapping record that has been read from the drive mapping file.
@param aTextLine Modifiable ptr descriptor holding the mapping record text
to be parsed. Note that this function will null-terminate
any FSY or extension names it detects. This will generally
result in the over-writing of the field separator or end of
record delimitor but consideration is required where a
mapping file ends with such a string.
@param anInfo A stucture to hold the returned mapping settings,
FSY/ext name string pointers and mounting flags.
@return KErrNone if record is successfully parsed and 'anInfo' contains
mapping info to be applied.
KErrNotFound if the record is a comment line.
KErrArgument if the syntax of record is incorrect.
*/
TInt TFSStartup::ParseMappingRecord(TPtr& aTextLine,SLocalDriveMappingInfo& anInfo)
{
TPtrC token;
TLex lex(aTextLine);
TInt driveNumber = KDriveInvalid;
TUint32 localDriveNums[KMaxLocalDrives];
const TText* fsyName = NULL;
const TText* objName = NULL;
const TText* extName = NULL;
TUint32 flags = 0;
TInt spare = 0;
// Get all of the above Attributes.
token.Set(lex.NextToken());
if (token.Length() <= 1 || token[0]=='#') // Blank line or comment line
return(KErrNotFound);
// Drive number
if (token[1]!=':' || iFs.CharToDrive(token[0],driveNumber)!=KErrNone)
return(KErrArgument);
// Local drive number(s)
lex.SkipSpace();
token.Set(lex.NextToken());
TInt localDriveCount = 0;
TInt err = ParseMappingFileLocalDrive(token,localDriveNums,localDriveCount);
if(err != KErrNone)
{
return err;
}
if(localDriveCount==0)
{
return KErrArgument;
}
TInt tokLen;
TPtr fileName(NULL,0);
TBool endOfRecord = EFalse;
// .FSY file name
token.Set(lex.NextToken());
if (!endOfRecord && (token.Length()==0 || token[0]=='#'))
endOfRecord = ETrue;
else
{
if (token[0]!='0')
{
tokLen=token.Length();
fileName.Set((TUint16*)token.Ptr(),tokLen,tokLen+1);
token.Set(lex.NextToken());
fsyName=fileName.PtrZ();
}
else
{
token.Set(lex.NextToken());
}
}
// Object name of .FSY
if (!endOfRecord && (token.Length()==0 || token[0]=='#'))
{
endOfRecord = ETrue;
}
else // Get FSY
{
if (token[0]!='0')
{
tokLen=token.Length();
fileName.Set((TUint16*)token.Ptr(),tokLen,tokLen+1);
token.Set(lex.NextToken());
objName=fileName.PtrZ();
}
else
{
token.Set(lex.NextToken());
}
}
// Extension name
if (!endOfRecord && (token.Length()==0 || token[0]=='#'))
{
endOfRecord = ETrue;
}
else // Get extension
{
if (token[0]!='0')
{
tokLen=token.Length();
fileName.Set((TUint16*)token.Ptr(),tokLen,tokLen+1);
token.Set(lex.NextToken());
extName=fileName.PtrZ();
}
else
{
token.Set(lex.NextToken());
}
}
// Flags
if (!endOfRecord && (token.Length()==0 || token[0]=='#'))
{
endOfRecord = ETrue;
}
else // Get Flags
{
if (token[0]!='0')
{
TInt r=ParseMappingFileFlags(token,flags,spare);
if(r!=KErrNone)
return r;
}
}
//
// For every local drive
//
SLocalDriveMappingInfo* mappingInfo = &anInfo;
for(TInt i = 0; i<localDriveCount; i++)
{
if(iMapCount >= KMaxLocalDrives)
return KErrOverflow;
Mem::FillZ(mappingInfo,sizeof(SLocalDriveMappingInfo));
mappingInfo->iDriveNumber = driveNumber;
mappingInfo->iLocalDriveNumber = localDriveNums[i];
mappingInfo->iFsInfo.iExtName = extName;
mappingInfo->iFsInfo.iFsyName = fsyName;
mappingInfo->iFsInfo.iObjName = objName;
mappingInfo->iSpare = spare;
mappingInfo->iFsInfo.iFlags = flags;
// If there was more than 1 local drive number (multi-slot device)
// then increase iMapCount so that the mappingInfo doesn't get
// clobbered next time this function is called.
if(i>=1 && ((TInt)localDriveNums[i])!=KDriveInvalid)
{
iMapCount++;
DEBUGPRINT2("Alternative Entry found for registered ldrive:%d -> %c:",localDriveNums[i],(mappingInfo->iDriveNumber+'A'));
}
mappingInfo++;
}
return KErrNone;
}
/**
This is only called if a mapping configuration has specified "FS_SWAP_CORRUPT".
If it is necessary to implement the drive swap then it is required that
the entry for the second drive involved in the swap (ie the one specified
in "FS_SWAP_CORRUPT-<drv>") occurs later in the mapping array than the one
specifying the swap. This functions checks whether the ordering is OK and
swaps the entries for the two drives if necessary.
@param aTotalEntries The total number of valid entries in the mapping array.
*/
void TFSStartup::CheckAndReOrderArrayForSwapping(TInt aTotalEntries)
{
// Find the swapper - and determine its entry number
TInt i;
for (i=0;i<aTotalEntries;i++)
{
if (iDriveMappingInfo[i].iFsInfo.iFlags & FS_SWAP_CORRUPT)
break;
}
if (i==aTotalEntries)
return;
TInt swapperEntryNo=i;
TInt swappeeDrvNo=iDriveMappingInfo[i].iSpare;
// Now find the swappee and determine its entry number
for (i=0;i<aTotalEntries;i++)
{
if (iDriveMappingInfo[i].iDriveNumber == swappeeDrvNo)
break;
}
if (i==aTotalEntries)
return;
TInt swappeeEntryNo=i;
// If swappee comes before swapper then we need to switch then around
if (swapperEntryNo>swappeeEntryNo)
{
SLocalDriveMappingInfo tmp;
tmp=iDriveMappingInfo[swapperEntryNo];
iDriveMappingInfo[swapperEntryNo]=iDriveMappingInfo[swappeeEntryNo];
iDriveMappingInfo[swappeeEntryNo]=tmp;
}
}
/**
Swap the local drive mappings of two entries in the mapping array. Also, update the local drive mapping previously
written to the file server.
@param aCurrentEntry The position in the mapping array of the next mapping to be applied.
This coincides with the drive which has 'requested' the swap.
(The other mapping involved in the swap is guarenteed to be later
in the list and therefore not yet applied).
@param aTotalEntries The total number of valid entries in the mapping array.
@panic ESTART_12 0; If swap mapping file array is inconsistent.
*/
void TFSStartup::SwapDriveMappings(TInt aCurrentEntry,TInt aTotalEntries)
{
DEBUGPRINT1("TFSStartup::SwapDriveMappings - Index %d",aCurrentEntry);
TInt firstDrive=iDriveMappingInfo[aCurrentEntry].iDriveNumber;
TInt secondDrive=iDriveMappingInfo[aCurrentEntry].iSpare;
// Find the entry for the other mapping that we need to swap with
TInt secondEntry;
for (secondEntry=aCurrentEntry ; secondEntry<aTotalEntries ; secondEntry++)
{
if (iDriveMappingInfo[secondEntry].iDriveNumber==secondDrive)
break;
}
if (secondEntry==aTotalEntries)
Panic(ELitSwapMappingFailArrayInconsistent,0);
// Swap the entries over in the list of mappings still to be applied
iDriveMappingInfo[aCurrentEntry].iDriveNumber=secondDrive;
iDriveMappingInfo[secondEntry].iDriveNumber=firstDrive;
// If second drive is replacing one that is corrupt then we always want to mount it
iDriveMappingInfo[secondEntry].iFsInfo.iFlags&=~FS_NO_MOUNT;
// Change the local drive mapping info already set with the file server
SwapFServLocalDriveMapping(firstDrive,secondDrive);
iDriveSwapCount=0; // Swap now handled and the FS local drive mapping is set
}
/**
Return the filename of the drive mapping file. If it is required to vary
the local drive mapping for a given platform, depending on a particular platform
specific setting (e.g. state of a switch or jumper setting, detection of
a particular h/w feature etc) then it is still possible to use the map file scheme.
In this situation, the ROM can be built with more than one mapping file.
A custom version of ESTART should then override this virtual function to detect
the current setting and return the name of the appropriate map file.
@return A non-modifiable ptr descriptor containing the path and filename of the mapping file.
*/
TPtrC TFSStartup::LocalDriveMappingFileName()
{
return(KLocalDriveMappingFile());
}
/**
Open the drive mapping file, and process each mapping record it contains.
For each record, this involves updating the local drive list, adding the FSY and
any extension specified and then mounting these on the drive in question -
processing any mounting flags in the process. The local drive mapping is also
written to the File Server.
Calls InitCompositeFileSystem but carries on should this fail.
@return KErrNone if no error.
*/
TInt TFSStartup::ProcessLocalDriveMappingFile()
{
DEBUGPRINT("ProcessLocalDriveMappingFile");
TInt r = InitCompositeFileSystem();
__ASSERT_ALWAYS(r==KErrNone || r==KErrNotFound || r==KErrAlreadyExists,User::Panic(_L("EStart init composite fs failed"),r));
// Following block of code tries to initialise the reading facilities of
// estart.txt file.
// Note: RFs::InitialisePropertiesFile() MUST always be called even there
// is no estart.txt file. It is for the default construction of File
// Cache Manager and Global Cache Memory Manager.
RFile f;
TPtrC mappingFileName(LocalDriveMappingFileName());
r=f.Open(iFs,mappingFileName,EFileShareExclusive|EFileStreamText|EFileRead);
DEBUGPRINT2("Opening mapping file %S -> %d", &mappingFileName, r);
if (r == KErrNone)
{
// pass ROM address of estart.txt file to file server to allow it to support
// reading of ".ini file" - style parameters
TInt romAddress = 0;
r = f.Seek(ESeekAddress, romAddress);
if(r == KErrNone)
{
TInt size = 0;
r = f.Size(size);
if (r == KErrNone)
{
if(size > 0)
{
TPtrC8 ptr((TUint8*)romAddress, size);
iFs.InitialisePropertiesFile(ptr);
}
else
{
r = KErrGeneral;
}
}
}
}
// If any error detected found, the default version of RFs::InitialisePropertiesFile()
// will be called before exiting.
if (r!=KErrNone)
{
TPtrC8 ptr(0, 0);
iFs.InitialisePropertiesFile(ptr);
return(r);
}
// Create a mapping file reader and pass it the file object. This will also result in the copying of the contents of
// the file into reader's buffer. Mapping information read from the file will include pointers to text strings in
// this buffer and so the reader object must not be deleted until processing is complete.
iMapFile = new TText8FileReader;
if (!iMapFile)
{
f.Close();
return(KErrNoMemory);
}
r=iMapFile->Set(f);
DEBUGPRINT1("Reading map file returns %d",r);
f.Close(); // Can't leave file on Z: open too long because can't mount composite FSY on Z: in this sitaution
if (r!=KErrNone)
return(r);
// Parse each drive mapping record in turn, saving the information in an array of mapping structures - one for
// each valid record.
TPtr linePtr(NULL,0);
iMapCount=0;
SLocalDriveMappingInfo* infoPtr;
while ((r=iMapFile->Read(linePtr))==KErrNone && iMapCount<KMaxLocalDrives)
{
infoPtr=&iDriveMappingInfo[iMapCount];
if (ParseMappingRecord(linePtr,*infoPtr)==KErrNone)
{
// Valid mapping record found
TInt localDriveNumber=infoPtr->iLocalDriveNumber;
__ASSERT_DEBUG(localDriveNumber >=0 && localDriveNumber < KMaxLocalDrives, User::Invariant());
if (iLocalDriveList[localDriveNumber]!=KDriveInvalid)
{
DEBUGPRINT2("Entry found for registered ldrive:%d -> %c:",localDriveNumber,(infoPtr->iDriveNumber+'A'));
iMapCount++;
}
else
{
DEBUGPRINT1("Invalid LocalDriveNumber : %d",localDriveNumber);
}
}
else
{
infoPtr->iLocalDriveNumber = KDriveInvalid; // reset all local drives
}
}
if (r!=KErrEof)
{
return((r==KErrNone)?KErrGeneral:r); // Error reading the records, or too many records in mapping file
}
// If there is the potential of a drive swap then check that the order of the entries in the mapping array
// are consitent for this - re-order if necessary
if (iDriveSwapCount)
CheckAndReOrderArrayForSwapping(iMapCount);
// Scan through the array of valid mappings - updating the the local drive list. Once, complete, write the list
// to the File Server. (Apart from swapping internal drives, this can only be written once).
TInt firstComp=-1;
// first clear default mappings for all local drives not listed on mapping file
TInt i;
for(i=0;i<KMaxLocalDrives;i++)
iLocalDriveList[i]=KDriveInvalid;
// then map non composite local drives
for (i=0;i<iMapCount;i++)
{
if (iDriveMappingInfo[i].iFsInfo.iFlags & FS_COMPOSITE)
continue;
iLocalDriveList[iDriveMappingInfo[i].iLocalDriveNumber]=iDriveMappingInfo[i].iDriveNumber;
}
// finally map composite drives: the first is mapped to the drive letter specifed on the mapping file, the following
// are mapped to unused drive letters. Later when they are added to the compsite mount their mappings are invalidated
TInt drvNumber=EDriveA-1;
for(i=0;i<iMapCount;i++)
{
if (iDriveMappingInfo[i].iFsInfo.iFlags & FS_COMPOSITE)
{
if (firstComp==-1)
{
firstComp=iDriveMappingInfo[i].iDriveNumber;
iLocalDriveList[iDriveMappingInfo[i].iLocalDriveNumber]=iDriveMappingInfo[i].iDriveNumber;
}
else
{
r=SearchForUnusedDriveNumber(drvNumber);
__ASSERT_ALWAYS(r==KErrNone, Panic(ELitLocalDriveMappingFail,r));
iLocalDriveList[iDriveMappingInfo[i].iLocalDriveNumber]=drvNumber;
}
}
}
SetFServLocalDriveMapping();
// Scan through the array of valid mappings again - adding the FSY and any extension specified and then mounting
// these on the drive in question.
// Now that the mapping is written to the file server - we can't auto-detect file systems any more. Hence, don't
// return an error if a drive fails to mount, just keep going.
for (i=0;i<iMapCount;i++)
{
// Record removable drives for later mount
TLocalDriveCapsBuf caps;
TBusLocalDrive drive;
TBool changed;
SLocalDriveMappingInfo* infoPtr = &iDriveMappingInfo[i];
infoPtr->iRemovable = EFalse;
r = drive.Connect(iDriveMappingInfo[i].iLocalDriveNumber, changed);
if (r == KErrNone)
{
infoPtr->iCapsRetCode = r = drive.Caps(caps);
if (r==KErrNone && caps().iDriveAtt&KDriveAttRemovable)
{
infoPtr->iRemovable = ETrue;
drive.Disconnect();
continue;
}
drive.Disconnect();
}
r=MountFileSystem(iDriveMappingInfo[i]);
if (r==KErrDisMounted)
{
// We have encountered a corrupt internal drive which should be swapped with another internal drive
SwapDriveMappings(i,iMapCount);
i--; // Re-attempt to mount the same drive now that the mappings are swapped
}
// If the drive is pageable, search for a ROM image file name and if found clamp it
// so that nothing can overwrite it
DEBUGPRINT3("Testing if Drive %c is pageable, r %d att %08X", 'A' + iDriveMappingInfo[i].iDriveNumber, r, caps().iMediaAtt);
if (r == KErrNone && (caps().iMediaAtt & KMediaAttPageable))
{
RFile file;
RArray<TPtrC> sysFiles;
r = SysFileNames(sysFiles);
TInt sysFilesCount = sysFiles.Count();
for (TInt n=0; n< sysFilesCount; n++)
{
TFileName romFilePath;
romFilePath.Append( (TText) ('A'+iDriveMappingInfo[i].iDriveNumber) );
romFilePath.Append(':');
romFilePath.Append(sysFiles[n]);
DEBUGPRINT1("Drive %c is pageable", 'A' + iDriveMappingInfo[i].iDriveNumber);
r = file.Open(iFs, romFilePath, EFileRead);
DEBUGPRINT2("Opening %S returned %d", &romFilePath, r);
if (r == KErrNone)
{
RFileClamp handle;
r = handle.Clamp(file);
DEBUGPRINT2("Clamping %S returned %d", &romFilePath, r);
file.Close();
}
}
sysFiles.Close();
}
}
if (gCompositeMountState==1)
LoadCompositeFileSystem(firstComp);
return(KErrNone);
}
/**
Return the filenames of any "System" files on a writable drive (e.g internal MMC).
If the files are found, then they are clamped (and never unclamped) to prevent them from being overridden.
This function should be overriden by the variant if needed.
@return KErrNotSupported, by default if the function is not overridden.
*/
TInt TFSStartup::SysFileNames(RArray<TPtrC>& /*aFileNames*/)
{
return KErrNotSupported;
}
/**
Search for any unused drive number that has not been added to the list.
@param aDrvNum Drive number to be checked, if used or not.
@return KErrNone if found one unused drive; KErrOverflow if all drives are used.
*/
TInt TFSStartup::SearchForUnusedDriveNumber(TInt& aDrvNum)
{
TInt i;
while(++aDrvNum<=(TInt)EDriveZ)
{
for(i=0;i<KMaxLocalDrives;i++)
{
if(iLocalDriveList[i]==aDrvNum)
break;
}
if(i==KMaxLocalDrives) // found one
return KErrNone;
}
return KErrOverflow; // all used up??
}
/**
Mount a file system on a drive. Adds the FSY and any extension specified and
then mounts these on the specified drive. Also, processes any mount flags specified.
@param anInfo A stucture holding the drive number, the details of the FSY/ext to be mounted on it and the mount flags.
@return KErrNone if no error, KErrDisMounted if this needs to be mounted on an alternative drive.
*/
TInt TFSStartup::MountFileSystem(SLocalDriveMappingInfo& anInfo)
{
TInt r=KErrNone;
TInt flags=anInfo.iFsInfo.iFlags;
TInt drive=anInfo.iDriveNumber;
TPtrC fsyname;
TPtrC objname;
// If an FSY is specified, mount this on the drive in question.
if (anInfo.iFsInfo.iFsyName && !(flags & (FS_NO_MOUNT | FS_COMPOSITE)))
{
fsyname.Set(anInfo.iFsInfo.iFsyName);
r=iFs.AddFileSystem(fsyname);
DEBUGPRINT2("AddFileSystem(%S) -> %d",&fsyname,r);
if (r!=KErrNone && r!=KErrAlreadyExists)
return(r);
if (flags & FS_NOT_RUGGED)
{
r = iFs.SetStartupConfiguration(ESetRugged, (TAny*)drive, (TAny*)EFalse);
iRuggedFileSystem = 0;
}
objname.Set((anInfo.iFsInfo.iObjName) ? anInfo.iFsInfo.iObjName : anInfo.iFsInfo.iFsyName);
TBool isSync=(flags & FS_SYNC_DRIVE);
if (anInfo.iFsInfo.iExtName)
{
TPtrC extname(anInfo.iFsInfo.iExtName);
r=iFs.AddExtension(extname);
if (r==KErrNone || r==KErrAlreadyExists)
r=iFs.MountFileSystem(objname,extname,drive,isSync);
}
else
r=iFs.MountFileSystem(objname,drive,isSync);
DEBUGPRINT4("MountFileSystem(%S) on drive %c: -> %d (sync=%d)",&objname,(drive+'A'),r,isSync);
iUnmountedDriveBitmask&=~(0x01<<(anInfo.iLocalDriveNumber));
}
// Process the mount flags
DEBUGPRINT1("FSI flags %08x",flags);
TInt cf;
if ((cf=HandleCustomMountFlags(r,flags,anInfo.iSpare,drive))!=KErrNone)
return(cf);
if (flags & FS_COMPOSITE)
if (anInfo.iFsInfo.iFsyName && TPtrC(anInfo.iFsInfo.iFsyName).CompareF(KEcomp))
LoadCompositeFileSystem(anInfo);
else
LoadCompositeFileSystem(drive);
// Handle format related flags
if (flags & FS_FORMAT_ALWAYS)
r=FormatDrive(drive);
if ((flags & FS_FORMAT_COLD) && iColdStart)
r=FormatDrive(drive);
if (r==KErrCorrupt && (flags & FS_FORMAT_CORRUPT))
r=FormatDrive(drive);
//-- running ScanDrive on Rugged FAT volumes. "Rugged FAT" and "ScanDrive" are counterparts.
//-- 1. Having "Rugged FAT" volume and not running ScanDrive on it doesn't make any sense and dangerous because "Rugged FAT" mechanisms imply using ScanDrive
//-- 2. Vice versa, running ScanDrive on "non-rugged FAT" doesn't make any sense, it is jsut waste of time.
//-- Thus: if the volume is detected as "Rugged FAT", force running ScanDrive on it; otherwise ignore FS_SCANDRIVE flag
#if !defined(__X86__)
if(r==KErrNone)
{
TText driveLetter=(TText)(drive+'A');
TBuf<3> driveDes=_L("?:\\");
driveDes[0]=driveLetter;
if(iRuggedFileSystem)
{//-- the volume has rugged FAT, force ScanDrive
if(!(flags & FS_SCANDRIVE))
{//-- no FS_SCANDRIVE flag, this is obvious misconfiguration
if(objname.CompareF(_L("FAT")) == 0)
{
DEBUGPRINT1("### !!!! WARNING!!! Drive %S has RuggedFAT, but no FS_SCANDRIVE flag in estart.txt", &driveDes);
DEBUGPRINT( "### !!!! Forcing ScanDrive. Check that the drive is configured properly !!!");
}
}
iFs.ScanDrive(driveDes);
}
else
{//-- the volume doesn't have rugged FAT
if(flags & FS_SCANDRIVE)
{//-- FS_SCANDRIVE flag is set for non-rugged-FAT drive. don't run ScanDrive
DEBUGPRINT1("### !!!! WARNING!!! Drive %S has NON-Rugged FAT, but FS_SCANDRIVE flag is set in estart.txt", &driveDes);
DEBUGPRINT( "### !!!! SKipping ScanDrive. Check that the drive is configured properly !!!");
}
}
}
#endif
// Handle swap on corrupt or dismount on corrupt
if (r==KErrCorrupt && ((flags & FS_DISMNT_CORRUPT) || (flags & FS_SWAP_CORRUPT)))
// if (((flags & FS_DISMNT_CORRUPT) || (flags & FS_SWAP_CORRUPT))) // Testing swap mode - always swaps
{
if (objname.Ptr())
iFs.DismountFileSystem(objname,drive);
if (flags & FS_SWAP_CORRUPT)
{
anInfo.iFsInfo.iFlags&=~FS_SWAP_CORRUPT; // Mustn't try to swap again the next time
r=KErrDisMounted; // Signal that this needs to be re-mounted on another drive
}
}
return(r);
}
#if !defined(AUTODETECT_DISABLE)
const TInt KMaxFSInfoTableEntries=8;
/**
Standard file system info. array - used when auto-detecting an appropraite FSY for a local drive. In this scheme, the local
drive capabilities and partition type information is examined to determine an appropraite FSY for the drive. Each entry
contains an FSY detection function together with the corresponding information for that particular FSY configuration. This
information includes the FSY/ext name string pointers and mounting flags. Each detection function should uniquely identify
its associated FSY configuration.
*/
LOCAL_D const SFileSystemInfo FileSystems[KMaxFSInfoTableEntries] =
{
{DetectELocal, {_S("elocal"), _S("fat"), 0, FS_SCANDRIVE}},
{DetectIRam, {_S("elocal"), _S("fat"), 0, FS_FORMAT_COLD|FS_SYNC_DRIVE}},
{DetectFtl, {_S("elocal"), _S("fat"), 0, FS_FORMAT_CORRUPT|FS_SCANDRIVE}},
{DetectRofs, {_S("erofs"), _S("rofs"), 0, FS_DISMNT_CORRUPT}},
{DetectComposite, {0, 0, 0, FS_COMPOSITE}},
{DetectEneaLFFS, {_S("elffs"), _S("lffs"), 0, FS_FORMAT_CORRUPT}},
{DetectIso9660, {_S("iso9660"), 0, 0, 0}},
{DetectNtfs, {_S("ntfs"), 0, 0, 0}},
};
/**
Return the next entry from the standard file system info array - used when auto-detecting an FSY for a local drive.
Override this function when altering or extending the standard file system info. array.
@param anInfo Address of a pointer to a stucture to hold the returned mapping settings,
FSY/ext name string pointers and mounting flags.
@param aPos The current position within the array. The caller is responsible to
initializing and incrementing this.
@return KErrNone if no error, KErrNotFound if the end of the array is reached.
*/
TInt TFSStartup::GetNextStandardFSInfoEntry(const SFileSystemInfo** anEntry,TInt aPos)
{
if (aPos<KMaxFSInfoTableEntries)
{
*anEntry=&FileSystems[aPos];
return(KErrNone);
}
else
return(KErrNotFound);
}
/**
Detect the appropraite FSY configuration for a particular local drive. This is
achieved by reading the drives capabilities and partition information and using
this to determine an appropraite config.
@param aLocalDriveNumber The number of the local drive .
@param anInfo A stucture to hold the returned mapping settings,
FSY/ext name string pointers and mounting flags.
@return KErrNone if successful, KErrNotFound if an appropriate file system isn't found or any other error.
*/
TInt TFSStartup::DetectFileSystem(TInt aLocalDriveNumber,SLocalDriveMappingInfo& anInfo)
{
DEBUGPRINT1("DetectFileSystem ldrive:%d",aLocalDriveNumber);
TLocalDriveCapsV2 caps;
TPckg<TLocalDriveCapsV2> capsBuf(caps);
RLocalDrive ld;
TBool changed;
TInt r = ld.Connect(aLocalDriveNumber, changed);
DEBUGPRINT1("Connect -> %d", r);
if (r!=KErrNone)
return(r);
TInt cr=ld.Caps(capsBuf);
DEBUGPRINT1("Caps -> %d", cr);
const SFileSystemInfo* fsi=NULL;
for (TInt i=0 ; (r=GetNextStandardFSInfoEntry(&fsi,i))==KErrNone ; i++)
{
TInt d=(*fsi->iDetect)(ld,cr,caps);
DEBUGPRINT2("FS:%d Detect -> %d",i,d);
if (d<KErrNone)
continue;
if (d>KErrNone)
{
d-=KFsDetectMappingChangeReturnOffset;
if (d>=EDriveA && d<=EDriveZ)
iLocalDriveList[aLocalDriveNumber]=d;
}
TInt drive=iLocalDriveList[aLocalDriveNumber];
anInfo.iDriveNumber=drive;
anInfo.iLocalDriveNumber=aLocalDriveNumber;
anInfo.iFsInfo=fsi->iFsInfo;
anInfo.iSpare=0;
break;
}
ld.Close();
return(r);
}
/**
For each registered local drive on the system detect an appropriate FSY configuration
and attempt to mount this on the drive concerned.
@return Always returns KErrNone.
*/
TInt TFSStartup::DetectAndMountFileSystems()
{
InitCompositeFileSystem();
// Determine an appropriate FSY configuration for each registered local drive
TInt i;
DEBUGPRINT("DetectAndMountFileSystems");
iMapCount=0;
SLocalDriveMappingInfo* infoPtr;
for (i=0;i<KMaxLocalDrives;++i)
{
if(iLocalDriveList[i]!=KDriveInvalid)
{
infoPtr=&iDriveMappingInfo[iMapCount];
if (DetectFileSystem(i,*infoPtr)==KErrNone)
{
DEBUGPRINT3("Entry found for registered ldrive: %2d->%c: (%s)",i,(infoPtr->iDriveNumber+'A'),infoPtr->iFsInfo.iFsyName);
iMapCount++;
}
}
}
// Scan through the array of valid mappings - updating the the local drive list. Once, complete, write the list
// to the File Server (can only be written once).
for (i=0;i<iMapCount;i++)
iLocalDriveList[iDriveMappingInfo[i].iLocalDriveNumber]=iDriveMappingInfo[i].iDriveNumber;
SetFServLocalDriveMapping();
// Scan through the array of valid mappings again - adding the FSY and any extension specified and then mounting
// these on the drive in question
for (i=0;i<iMapCount;i++)
{
// Record removable drives for later mount
TLocalDriveCapsBuf caps;
TBusLocalDrive drive;
TBool changed;
SLocalDriveMappingInfo* infoPtr = &iDriveMappingInfo[i];
infoPtr->iRemovable = EFalse;
TInt r = drive.Connect(iDriveMappingInfo[i].iLocalDriveNumber, changed);
if (r == KErrNone)
{
infoPtr->iCapsRetCode = r = drive.Caps(caps);
TInt sockNum;
if (r==KErrNone && (caps().iDriveAtt&KDriveAttRemovable || drive.IsRemovable(sockNum)))
{
infoPtr->iRemovable = ETrue;
drive.Disconnect();
continue;
}
drive.Disconnect();
}
r=MountFileSystem(iDriveMappingInfo[i]);
if (r==KErrDisMounted)
{
// We have encountered a corrupt internal drive which should be swapped with another internal drive
SwapDriveMappings(i,iMapCount);
i--; // Re-attempt to mount the same drive now that the mappings are swapped
}
}
return(KErrNone);
}
#endif
#if defined(_LOCKABLE_MEDIA)
/**
Initialise the local media password store with contents of a file.
@param aFile The file used to initialize the store. Must already be opened for
read access in EFileStreamText mode.
@return KErrNone if successful, KErrNoMemory if heap is full, otherwise one of the other system-wide error codes.
*/
TInt TFSStartup::WriteLocalPwStore(RFile& aFile)
//
// Initialise local media password store with contents of aFile
//
{
DEBUGPRINT("WriteLocalPwStore");
TInt size;
TInt r=aFile.Size(size);
if(r!=KErrNone || size==0)
return(r);
HBufC8* hBuf=HBufC8::New(size);
if(hBuf==NULL)
return(KErrNoMemory);
TPtr8 pBuf=hBuf->Des();
r=aFile.Read(pBuf);
if(r==KErrNone)
{
TBusLocalDrive TBLD;
TBool TBLDChangedFlag;
for (TInt i=0; i<iMapCount; i++)
{
SLocalDriveMappingInfo* infoPtr = &iDriveMappingInfo[i];
DEBUGPRINT3("drive %d: removable %d capsret %d", i, infoPtr->iRemovable, infoPtr->iCapsRetCode);
if (infoPtr->iRemovable || infoPtr->iCapsRetCode == KErrNotReady)
{
r = TBLD.Connect(iDriveMappingInfo[i].iLocalDriveNumber, TBLDChangedFlag);
if(r==KErrNone)
{
r = TBLD.WritePasswordData(pBuf);
DEBUGPRINT2("WritePasswordData on drive %d returned %d", i, r);
TBLD.Disconnect();
// ignore error if media not ready (it MAY not be a removable drive)
if (r != KErrNone && infoPtr->iCapsRetCode == KErrNotReady)
r = KErrNone;
}
}
}
}
delete hBuf;
return(r);
}
/**
Attempt to initilise the local media password store. This allows locked media devices
(e.g. password protected MMC cards) to be accessed without notifier.
@return KErrNone if successful otherwise one of the other system-wide error codes.
*/
TInt TFSStartup::InitializeLocalPwStore()
{
// Attempt to initilise the local media password store
// Allows locked device to be accessed without notifier
DEBUGPRINT("InitializeLocalPwStore");
RFile f;
TBuf<sizeof(KMediaPWrdFile)> mediaPWrdFile(KMediaPWrdFile);
mediaPWrdFile[0] = (TUint8) RFs::GetSystemDriveChar();
TInt r=f.Open(iFs,mediaPWrdFile,EFileShareExclusive | EFileStream | EFileRead);
if (r==KErrNone)
{
r=WriteLocalPwStore(f);
__ASSERT_DEBUG(r == KErrNone || r == KErrCorrupt || r == KErrNotReady, Panic(ELitInitLocalPwStoreFail,r));
f.Close();
}
return(r);
}
#endif
#ifdef LOAD_PATCH_LDD
/**
Find any patch LDDs and load them.
@panic ESTART_8 0; if creation of trap handler failed.
@panic ESTART_9 Error_Code; if loading of LDD failed.
Error_Code is the error code returned by User::LoadLogicalDevice().
*/
void TFSStartup::LoadPatchLDDs()
{
#if defined(__EPOC32__)
// Load an LDD to patch any bugs in the ROM
// This will always return an error - ignore it
_LIT(KLitPatchBootLdd,"Z:\\Sys\\Bin\\BOOT.LDD");
TInt r;
User::LoadLogicalDevice(KLitPatchBootLdd);
// Install a trap handler - fs.GetDir calls functions which might leave
CTrapCleanup* trapHandler=CTrapCleanup::New();
__ASSERT_ALWAYS(trapHandler!=NULL,Panic(ELitCreateTrapHandlerFail,0));
// Find any patch ldds and load them - files with the .SYS extension and second uid KLogicalDeviceDriverUid
// and third uid KPatchLddUid (0x100000CC, BOOT.LDD should probably be checked for this too)
CDir* patchList=NULL;
_LIT(KLitPatchSysLdd,"?:\\Sys\\Bin\\*.SYS");
TBuf<sizeof(KLitPatchSysLdd)> litPatchSysLdd(KLitPatchSysLdd);
litPatchSysLdd[0] = (TUint8) RFs::GetSystemDriveChar();
if (iFs.GetDir(litPatchSysLdd,(KEntryAttSystem|KEntryAttAllowUid),ESortByName,patchList)==KErrNone)
{
patchList->Sort(ESortByName);
TInt i;
for (i=0;i<patchList->Count();i++)
{
TEntry& entry=(*patchList)[i];
if (entry[1]==KLogicalDeviceDriverUid && entry[2].iUid==KPatchLddUidValue)
{
r=User::LoadLogicalDevice(entry.iName);
__ASSERT_DEBUG(r==KErrNone,Panic(ELitLoadSysLddsFail,r));
}
}
}
delete trapHandler;
#endif
}
#endif
/**
Try to add both the ROFS and Composite file systems.
@return KErrNone if successful, KErrNotFound if either fail to be added.
*/
TInt TFSStartup::InitCompositeFileSystem()
{
DEBUGPRINT("InitCompositeFileSystem");
TInt r=iFs.AddFileSystem(KRofs);
if (r==KErrNone || r==KErrAlreadyExists)
{
DEBUGPRINT("ROFS is present");
r=iFs.AddFileSystem(KCompfs);
if (r==KErrNone || r==KErrAlreadyExists)
{
gMountComposite=ETrue;
gMountRofsAlone=EFalse;
DEBUGPRINT("Comp FS is present");
return(KErrNone);
}
}
else
gMountRofsAlone=EFalse;
return(KErrNotFound);
}
/**
Mount the composite file system on the specified drive.
@param The number of the drive on which the composite FSY is to be loaded on.
@panic ESTART_16 Error_Code; If unable to get file system name on the drive.
Error_Code is the error code returned by RFs::FileSystemName().
@panic ESTART_15 Error_Code; If unable to mount composite file system.
Error_Code is the error code returned by RFs::SwapFileSystem().
*/
_LIT(KCompositeName,"Composite");
void TFSStartup::LoadCompositeFileSystem(TInt aDrive)
{
if (gMountComposite)
{
DEBUGPRINT1("LoadCompositeFileSystem on %c:",(aDrive+'A'));
TBuf<16> buf;
TInt r=iFs.FileSystemName(buf,aDrive);
DEBUGPRINT1("Read current FSY returns %d",r);
__ASSERT_ALWAYS(r==KErrNone, Panic(EFsNameFail,r));
__ASSERT_ALWAYS(buf!=KCompositeName, Panic(EFsNameFail,r));
DEBUGPRINT1("Swap composite for %S",&buf);
r=iFs.SwapFileSystem(buf,_L("Composite"),aDrive);
DEBUGPRINT1("Swap file system returned %d", r);
__ASSERT_ALWAYS(r==KErrNone, Panic(ECompMountFsFail,r));
gCompositeMountState=ESwapped;
}
}
/**
Adds a local drive to the composite filesystem.
@param anInfo A stucture holding mounting flags, drive number info.
@panic ESTART_15 -11; If composite mount file already exist.
*/
void TFSStartup::LoadCompositeFileSystem(SLocalDriveMappingInfo& anInfo)
{
if (gMountComposite)
{
__ASSERT_ALWAYS(gCompositeMountState<2, Panic(ECompMountFsFail,KErrAlreadyExists));
TPtrC fsyname;
TBool sync = (anInfo.iFsInfo.iFlags & FS_SYNC_DRIVE)!=0;
fsyname.Set(anInfo.iFsInfo.iFsyName);
TInt r=iFs.AddFileSystem(fsyname);
DEBUGPRINT2("AddFileSystem(%S) -> %d",&fsyname,r);
__ASSERT_ALWAYS(r==KErrNone || r==KErrAlreadyExists, Panic(ECompMountFsFail,r));
TPtrC objname;
objname.Set((anInfo.iFsInfo.iObjName) ? anInfo.iFsInfo.iObjName : anInfo.iFsInfo.iFsyName);
DEBUGPRINT4("LoadCompositeFileSystem on %c: with drive %i (%S) included. Sync=%d",(anInfo.iDriveNumber+'A'),anInfo.iLocalDriveNumber,&objname, anInfo.iFsInfo.iFlags);
r=iFs.AddCompositeMount(objname,anInfo.iLocalDriveNumber,anInfo.iDriveNumber, sync);
DEBUGPRINT1("AddCompositeMount returned %d", r);
if (r==KErrNone)
gCompositeMountState=EHasMounts;
}
}
/**
Initialize the local drives.It loads the relevant File Systems (FSYs),
File Server extensions (FXTs) and mounts these on the appropriate drives.
This involves mapping local drives to particular drive letters.
First it attempts to open the local drive mapping file ESTART.TXT.If this file is
found then ESTART loads this and attempts to apply the mapping contained within it.
If a mapping file is not found then it attempts to automatically detect the most
appropriate configuration for each local drive registered.
Hence, if it has been necessary to customize ESTART solely to provide a custom set
of local drive mappings then the generic ESTART can now be used - in conjunction
with a platform specific version of the local drive mapping file: ESTART.TXT.
However The entire local drive initialisation sequence provided by the generic version
of ESTART can be overridden (while possibly re-using some of the services provided by
the generic version).
@return KErrNone if successful.
@panic ESTART_11 Error_Code; If drive mapping file was not found and autodetect was not enabled.
Error_Code is the error code returned by ProcessLocalDriveMappingFile().
*/
TInt TFSStartup::LocalDriveInit()
{
TInt i;
for(i=0;i<KMaxLocalDrives;i++)
iDriveMappingInfo[i].iLocalDriveNumber=KDriveInvalid; // reset all local drives
TInt r=ProcessLocalDriveMappingFile();
if (r!=KErrNone)
#if !defined(AUTODETECT_DISABLE)
DetectAndMountFileSystems();
#else
Panic(ELitDriveMappingFileFail,r);
#endif
SetSystemDrive();
#if defined(_LOCKABLE_MEDIA)
InitializeLocalPwStore();
#endif
#ifdef LOAD_PATCH_LDD
LoadPatchLDDs();
#endif
// Notify file server that local fs initialisation complete
TRequestStatus status;
iFs.StartupInitComplete(status);
User::WaitForRequest(status);
DEBUGPRINT1("StatusInitComplete r=%d",status.Int());
return(KErrNone);
}
/**
Get system startup mode. Licensees should override one of these two GetStartupMode
functions to provide mechanism of getting startup mode. Startup mode then is put in iStartupMode.
@return KErrNone if successful.
@see TFSStartup::GetStartupModeFromFile()
*/
TInt TFSStartup::GetStartupMode()
{
return KErrNone;
}
/**
Get system startup mode from file after file server startup.
@return KErrNone if successful.
@see TFSStartup::GetStartupMode()
*/
TInt TFSStartup::GetStartupModeFromFile()
{
return KErrNotSupported;
}
/**
Start the rest of the system. Try to find sysstart.exe and launch it.
If failed to find it launch window server instead. This path is deprecated.
@return KErrNone if successful.
@panic ESTART_18 Error_Code; If getting startup mode fails.
Error_Code is the error returned by GetStartupModeFromFile().
@panic ESTART_14 Error_Code; If set for startup Mode fails.
Error_Code is the error returned by RProperty::Set()
@panic ESTART_19 Error_Code; If fails to lunch system agent.
Error_Code is the error returned by StartSysAgt2()
@panic ESTART_17 -1; If unable to start windows server.
*/
TInt TFSStartup::StartSystem()
{
// Get startup mode when need to access file server
TInt r = GetStartupModeFromFile();
if (r != KErrNotSupported)
{
__ASSERT_ALWAYS(r==KErrNone, Panic(EStartupModeFail,r));
// Update startup mode property value
r = RProperty::Set(KUidSystemCategory, KSystemStartupModeKey, iStartupMode);
__ASSERT_ALWAYS(r==KErrNone, Panic(EPropertyError,r));
}
// Launch system starter in system path
RProcess ws;
r=ws.Create(KSystemStateManager, KNullDesC);
if (r!=KErrNone)
{
r=ws.Create(KSystemStarterName, KNullDesC);
if (r!=KErrNone)
{
r = StartSysAgt2();
if (r != KErrNone && r != KErrNotFound)
Panic(ESysAgentFail,r);
// Start the window server if failed starting up system starter
TDriveList list;
iFs.DriveList(list);
if (!CreateServer(list,KWindowServerRootName1))
Panic(ELitNoWS,KErrNotFound);
}
else
{
#ifdef SYMBIAN_ESTART_OUTPUT_BOOT_TIME
TRequestStatus status;
ws.Logon(status);
ws.Resume();
//-- wait for SystemStarter to finish and then output the number of ticks since boot
//-- !! N.B on some systems SystemStarter process never finish, so the "status" never gets completed.
//-- !! In this case it is worth trying Rendezvous(); because it usually call it.
User::WaitForRequest(status);
TUint tickCount = User::TickCount();
RDebug::Printf("Boot time ticks %d (%d ms)\n", tickCount, tickCount*1000/64);
#else
ws.Resume();
#endif // SYMBIAN_ESTART_OUTPUT_BOOT_TIME
ws.Close();
}
}
else
{
TRequestStatus status;
ws.Rendezvous(status);
ws.Resume();
User::WaitForRequest(status);
#ifdef SYMBIAN_ESTART_OUTPUT_BOOT_TIME
// wait for SystemStateManager to finish and then output the number of ticks since boot
TUint tickCount = User::TickCount();
RDebug::Printf("Boot time ticks %d (%d ms)\n", tickCount, tickCount*1000/64);
#else
// System state manager may not exit on completion.
if (ws.ExitType() != EExitKill && ws.ExitType() != EExitPending)
User::Panic(_L("SysState died"),status.Int());
#endif // SYMBIAN_ESTART_OUTPUT_BOOT_TIME
ws.Close();
}
return(KErrNone);
}
/**
File system startup class constructor
*/
TFSStartup::TFSStartup()
{
iStartupMode=0;
iMuid=0;
iTotalSupportedDrives=0;
iRuggedFileSystem=0;
iRegisteredDriveBitmask=0;
iDriveSwapCount=0;
iColdStart=EFalse;
iUnmountedDriveBitmask=0;
iMapFile = NULL;
}
/**
Initilize the file system startup class. Checks for the Capability of the process.
Sets the termination effect of current and subsequently created thread on the
owning process. Publishes startup mode property. Ensures HAL memory allocation is
done and connects to the file server.
@panic ESTART_14 Error_Code; If either the capability is not present or unable to define or set the property.
Error_Code is the error code returned by RProcess().HasCapability() or
RProperty::Define() or RProperty::Set().
@panic ESTART_18 Error_Code; If unable to get startup mode.
Error_Code is the error code returned by GetStartupMode().
@panic ESTART_3 Error_Code; If HAL initialization fails.
Error_Code is the error code returned by HAL::Get().
@panic ESTART_4 Error_Code; If unable to connect to file server.
Error_Code is the error code returned by RFs::Connect().
@panic ESTART_7 Error_Code; If unable to fetch drive information.
Error_Code is the error code returned by UserHal::DriveInfo().
*/
void TFSStartup::Init()
{
#ifndef SYMBIAN_EXCLUDE_ESTART_DOMAIN_MANAGER
#ifndef __REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
const char myDiagMsg[] = __PLATSEC_DIAGNOSTIC_STRING("Capability Check Failure");
#endif //!__REMOVE_PLATSEC_DIAGNOSTIC_STRINGS__
TBool cap=RProcess().HasCapability(ECapabilityPowerMgmt, __PLATSEC_DIAGNOSTIC_STRING(myDiagMsg));
__ASSERT_ALWAYS(cap, Panic(EPropertyError, cap));
#endif
User::SetProcessCritical(User::ESystemCritical);
User::SetCritical(User::ESystemCritical);
// Get boot mode without need to access file server
TInt r = GetStartupMode();
__ASSERT_ALWAYS(r==KErrNone, Panic(EStartupModeFail,r));
// Publish startup mode property
_LIT_SECURITY_POLICY_PASS(readPolicy);
_LIT_SECURITY_POLICY_C1(writePolicy, ECapabilityWriteDeviceData);
r = RProperty::Define(KUidSystemCategory, KSystemStartupModeKey, RProperty::EInt, readPolicy, writePolicy);
__ASSERT_ALWAYS(r==KErrNone, Panic(EPropertyError, r));
r = RProperty::Set(KUidSystemCategory, KSystemStartupModeKey, iStartupMode);
__ASSERT_ALWAYS(r==KErrNone, Panic(EPropertyError, r));
r=HAL::Get(HAL::EMachineUid,iMuid); // make sure HAL memory allocation is done
__ASSERT_ALWAYS(r==KErrNone, Panic(ELitHALFail, r));
r=iFs.Connect();
__ASSERT_ALWAYS(r==KErrNone, Panic(ELitConnectFsFail1, r));
TDriveInfoV1Buf driveInfo;
r=UserHal::DriveInfo(driveInfo);
__ASSERT_ALWAYS(r==KErrNone,Panic(ELitFSInitDriveInfoFail,r));
iTotalSupportedDrives=driveInfo().iTotalSupportedDrives;
iRuggedFileSystem=driveInfo().iRuggedFileSystem;
iRegisteredDriveBitmask=driveInfo().iRegisteredDriveBitmask;
TUint registeredDriveBitmask=iRegisteredDriveBitmask;
for (TInt i=0;i<KMaxLocalDrives;i++)
{
if (registeredDriveBitmask & 0x01)
iLocalDriveList[i]=DefaultLocalDrive(i);
else
iLocalDriveList[i]=KDriveInvalid;
registeredDriveBitmask >>= 1;
}
iUnmountedDriveBitmask=iRegisteredDriveBitmask;
TMachineStartupType reason;
UserHal::StartupReason(reason);
if (reason==EStartupCold || reason==EStartupColdReset)
iColdStart=ETrue;
}
/**
Mount all removable drives.
@return KErrNone if successful.
*/
TInt TFSStartup::MountRemovableDrives()
{
DEBUGPRINT("TFSStartup::MountRemovableDrives");
for (TInt i=0;i<iMapCount;i++)
{
SLocalDriveMappingInfo* infoPtr = &iDriveMappingInfo[i];
if (!infoPtr->iRemovable)
continue;
TInt r = MountFileSystem(iDriveMappingInfo[i]);
DEBUGPRINT2("Mount drive (%c) -> %d",'A'+iDriveMappingInfo[i].iDriveNumber,r);
if (r==KErrDisMounted)
{
// We have encountered a corrupt internal drive which should be swapped with another internal drive
SwapDriveMappings(i,iMapCount);
i--; // Re-attempt to mount the same drive now that the mappings are swapped
}
}
return KErrNone;
}
/**
This is the main execution function which is responsible to start the File system.
It sets the default Locale properties. Initializes all the local drives, HAL and
creates the domain manager process. It also loads the locale and mounts all the
removable drives.
@return KErrNone if successful.
@panic ESTART_6 Error_Code; If initialization of local properties to default fails.
Error_Code is the error code returned by UserSvr::LocalePropertiesSetDefaults().
@panic ESTART_1 -1; If unable to create domain manager.
@panic ESTART_2 Error_Code; If initialization of domain manager fails.
Error_Code is the error code returned by RDmDomainManager::WaitForInitialization().
*/
TInt TFSStartup::Run()
{
TInt r = UserSvr::LocalePropertiesSetDefaults();
__ASSERT_ALWAYS(r==KErrNone,Panic(ELitLocaleInitialisationFail,r));
LocalDriveInit();
#ifdef AUTO_PROFILE
StartProfiler();
#endif
InitialiseHAL();
r=LoadCodePageDll();
if(r != KErrNone)
{
DEBUGPRINT1("\nLoadCodePageDll() FAILED !!! : returned : %d", r);
}
// Seperate ScanDrive from MountDrive; this allows drives to be mounted
// followed by locale loading. Scanning drives after locale is set thus can
// recognise non-english filename.
MountRemovableDrives();
#ifdef _DEBUG
// display the setting for all drives
DEBUGPRINT(" L FSY OBJ EXT Flags FileCacheFlags");
for(TInt i=0;i<KMaxLocalDrives;i++)
{
if (iDriveMappingInfo[i].iLocalDriveNumber != KDriveInvalid)
{
TPtrC fsyName;
fsyName.Set(iDriveMappingInfo[i].iFsInfo.iFsyName?iDriveMappingInfo[i].iFsInfo.iFsyName:_L(""));
TPtrC objName;
objName.Set(iDriveMappingInfo[i].iFsInfo.iObjName?iDriveMappingInfo[i].iFsInfo.iObjName:_L(""));
TPtrC extName;
extName.Set(iDriveMappingInfo[i].iFsInfo.iExtName?iDriveMappingInfo[i].iFsInfo.iExtName:_L(""));
// Get the TFileCacheFlags for this drive
TVolumeInfo volInfo;
volInfo.iFileCacheFlags = TFileCacheFlags(0xFFFFFFFF);
r = iFs.Volume(volInfo, iDriveMappingInfo[i].iDriveNumber);
DEBUGPRINT7("%c: %-2d %-8S %-8S %-8S %08X %08X",
(TInt) TChar(iDriveMappingInfo[i].iDriveNumber) + TChar('A'),
iDriveMappingInfo[i].iLocalDriveNumber,
&fsyName,
&objName,
&extName,
iDriveMappingInfo[i].iFsInfo.iFlags,
volInfo.iFileCacheFlags);
}
}
#endif
#ifndef SYMBIAN_EXCLUDE_ESTART_DOMAIN_MANAGER
TDriveList list;
r=iFs.DriveList(list);
// Create Domain Manager Process
if (!CreateServer(list,KDmManagerFileNameLit))
Panic(ELitNoDM, KErrNotFound);
// Wait until Domain Manager completes its intialization
r=RDmDomainManager::WaitForInitialization();
__ASSERT_ALWAYS(r==KErrNone,Panic(ELitDMInitFail,r));
// Now File Server can connect to Domain Manager
#endif
return(KErrNone);
}
/**
Close the file system startup class.
*/
void TFSStartup::Close()
{
// Ensure that the file servers local drive mapping is set.
if (iDriveSwapCount)
SwapFServLocalDriveMapping(KDriveInvalid,KDriveInvalid);
delete iMapFile;
iFs.Close();
}
TInt StartSysAgt2()
{
// SysAgt2Svr uid
const TUid KSystemAgentExeUid = {0x10204FC5};
const TUidType serverUid(KNullUid, KNullUid, KSystemAgentExeUid);
RProcess server;
TInt err = server.Create(KSystemAgentName, KNullDesC, serverUid);
if(err != KErrNone)
return err;
TRequestStatus stat;
server.Rendezvous(stat);
if(stat != KRequestPending)
server.Kill(0); // abort startup
else
server.Resume(); // logon OK - start the server
User::WaitForRequest(stat); // wait for start or death
// we can't use the 'exit reason' if the server panicked as this
// is the panic 'reason' and may be '0' which cannot be distinguished
// from KErrNone
err = server.ExitType() == EExitPanic ? KErrGeneral : stat.Int();
server.Close();
return err;
}
/**
This function is intended to be derived by licensee to show format progress
in their way.
@param aPercent Percentage of format process
@param aDrive Drive number
*/
void TFSStartup::ShowFormatProgress(TInt /*aPercent*/, TInt /*aDrive*/)
{
}
/**
This function loads the codepage dll based on the language index.
@return KErrNotFound if No codepage dll is found to be loaded
KErrNone if codepage dll is successfully loaded
*/
_LIT(KNonStandardCodePageName, "X-FAT%u");
_LIT(KMicrosoftStandardCodePageName, "CP%u");
TInt LoadCodePageDll()
{
// Always MS codepage type. Currently only supports the Microsoft Standard codepage names
// cp932.dll, cp 950.dll etc
const TFatFilenameConversionType fatConvType = EFatConversionMicrosoftCodePage;
TInt fatConvNumber = 0;
TInt err = KErrNone;
TBuf<KMaxCodepageDllName> codepageDllName;
TBool CodepageFound = EFalse;
/* Default LanguageID --> LocaleDll --> CodepageDll Mapping. Must be maintained.
|---------------|---------------------------|-------------------------|---------------------------|
| Language ID | Language Name | Locale dll (eloc.xxx) | FATCharsetConv (cpnnn.dll)|
|---------------|---------------------------|-------------------------|---------------------------|
| 29 | TaiwanChinese | elocl.29 | cp950.dll |
| 30 | HongKongChinese | elocl.30 | cp950.dll |
| 31 | PrcChinese | elocl.31 | cp936.dll |
| 32 | Japanese | elocl.32 | cp932.dll |
| 157 | English taiwan | elocl.157 | cp950.dll |
| 158 | English HK | elocl.158 | cp950.dll |
| 159 | English prc | elocl.159 | cp936.dll |
| 160 | English japan | elocl.160 | cp932.dll |
| 326 | Bahas Malay | elocl.326 | cp936.dll |
| 327 | Indonesian(APAC)(Bahasa)| elocl.327 | cp936.dll |
|---------------|---------------------------|-------------------------|---------------------------|
Language ID is read from the HAL data file as Language Index. Based on the read Language Index,
corresponding Codepage Dll name is created.
*/
TInt languageIndex;
TInt error=HAL::Get(HALData::ELanguageIndex,languageIndex);
if (error==KErrNone)
{
switch(languageIndex)
{
case 29:
{
fatConvNumber = 950;
CodepageFound=ETrue;
break;
}
case 30:
{
fatConvNumber = 950;
CodepageFound=ETrue;
break;
}
case 31:
{
fatConvNumber = 936;
CodepageFound=ETrue;
break;
}
case 32:
{
fatConvNumber = 936;
CodepageFound=ETrue;
break;
}
case 157:
{
fatConvNumber = 950;
CodepageFound=ETrue;
break;
}
case 158:
{
fatConvNumber = 950;
CodepageFound=ETrue;
break;
}
case 159:
{
fatConvNumber = 936;
CodepageFound=ETrue;
break;
}
case 160:
{
fatConvNumber = 932;
CodepageFound=ETrue;
break;
}
case 326:
{
fatConvNumber = 936;
CodepageFound=ETrue;
break;
}
case 327:
{
fatConvNumber = 936;
CodepageFound=ETrue;
break;
}
default:
{
CodepageFound=EFalse;
break;
}
}
}
// Do not use any codepage dll if the language index uses default FATCharsetconv conversions.
if(!CodepageFound)
return KErrNotFound;
// Create the codepage dll name to be loaded.
switch(fatConvType)
{
// coverity[dead_error_condition]
// Always MS codepage type. Currently only supports the Microsoft Standard codepage names.
case EFatConversionDefault:
// Undefined conversion scheme; conversion obtained is whatever the
// default policy is for this version of the OS.
DEBUGPRINT("...EFatConversionDefault");
break;
case EFatConversionNonStandard:
// x-fat<nnn>.dll is loaded, where <nnn> is the FAT filename conversion number.
DEBUGPRINT("...EFatConversionNonStandard");
codepageDllName.Format(KNonStandardCodePageName, fatConvNumber);
break;
case EFatConversionMicrosoftCodePage:
// cp<nnn>.dll is loaded, where <nnn> is the FAT filename conversion number.
DEBUGPRINT("...EFatConversionMicrosoftCodePage");
codepageDllName.Format(KMicrosoftStandardCodePageName, fatConvNumber);
break;
default:
DEBUGPRINT("...FAT Conversion Type Unknown");
break;
}
// Load the codepage dll.
if(codepageDllName.Length())
{
// No need for an F32 API to do this - ESTART is then only intended client for now.
// - Note that we load the code page via the loader, as doing so in the file server
// will cause deadlock (as RLibrary::Load depends on the file server).
RLoader loader;
err = loader.Connect();
if (err==KErrNone)
{
err = loader.SendReceive(ELoadCodePage, TIpcArgs(0, &codepageDllName, 0));
loader.Close();
}
DEBUGPRINT2("...Loaded codepage DLL : %S [err: %d]", &codepageDllName, err);
}
return(err);
}