--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/estart/estart.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2478 @@
+// 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);
+ }
+