userlibandfileserver/fileserver/sfile/sf_prel.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
child 43 c1f20ce4abcf
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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\sfile\sf_prel.cpp
// 
//

#include "sf_std.h"
#include "u32std.h"
#include <e32hal.h>
#include "sf_cache_man.h"

_LIT(KLitInitCompleteThread,"InitCompleteThread");

#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
_LIT(KCorruptFileNamesList,"CorruptFileNames.lst");
_LIT(KSysData,"\\sys\\data\\");
_LIT(KSystemData,"\\system\\data\\");
/**
ASCII text file reader constructor
This code is more or less lifted directly from estart.cpp
*/
TText8FileReader::TText8FileReader()
	{

	iBufPos=-1;
	iFileDataBuf=NULL;
	iFileSize=0;	
	}

/**
ASCII text file reader destructor
*/	
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 
	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);
	}

/**
Parse a record and split it into filename, error code & use once flag
@param aLine, this a a record from read from the file
@param aName, this is the parsed filename component of the record
@param aReturnCode, the error code that will be returned when an attempt is made to open the file
@param aUseOnce, flag which states whether the error should persist over more than one open attempt
@return error code, if the record is malformed return KErrCorrupt (ironic, what?) else KErrNone
*/
TInt ParseCorruptNamesRecord(TPtr aLine, TPtr& aName, TInt& aReturnCode, TBool&  aUseOnce)
	{
	aName.Set(NULL,0,0);
	// Remove leading spaces
	aLine.TrimLeft();
	TPtr remainderPtr(aLine);

	// collect pathname
	TInt lenFileName=remainderPtr.Locate(',');
	if(lenFileName<1)
		return KErrCorrupt;
	TPtr pathNamePtr(remainderPtr.LeftTPtr(lenFileName));
	// Remove trailing spaces
	pathNamePtr.TrimRight();
	// Parse the pathname to see if it could be valid, do not allow wild cards
	TParse fileParse;
	TInt r=fileParse.SetNoWild(pathNamePtr,NULL,NULL);
	if(r!=KErrNone)
		return KErrCorrupt;

	// move over delimiter to collect the user supplied return code
	// see first if sufficient length in the record
	TInt lenRemainder=remainderPtr.Length();
	if(lenRemainder<lenFileName+2)
		return KErrCorrupt;

	remainderPtr.Set(remainderPtr.MidTPtr(lenFileName+1));
	remainderPtr.TrimLeft();
	TInt lenReturnCode=remainderPtr.Locate(',');
	if(lenReturnCode<1)
		return KErrCorrupt;

	TPtr returnCodePtr(remainderPtr.LeftTPtr(lenReturnCode));
	TLex lexLine(returnCodePtr);
	TInt returnCode;
	if(lexLine.Val(returnCode)!=KErrNone)
		return KErrCorrupt;

	lenRemainder=remainderPtr.Length();
	if(lenRemainder<lenReturnCode+2)
		return KErrCorrupt;

	// collect the useOnce flag value
	remainderPtr.Set(remainderPtr.MidTPtr(lenReturnCode+1));
	remainderPtr.Trim();
	TBool useOnce;
	// This must either be "EVERY" or "ONCE"
	if (remainderPtr.MatchF(_L("EVERY"))!=KErrNotFound)
		useOnce=EFalse;
	else if(remainderPtr.MatchF(_L("ONCE"))!=KErrNotFound)
		useOnce=ETrue;
	else
		return KErrCorrupt;

	// Everything has worked out, so set up output args

	aName.Set(pathNamePtr);
	aReturnCode=returnCode;
	aUseOnce=useOnce;
	return KErrNone;
	}

/**
Open c:\CorruptFileNames.lst
File contains a set of text records
Each record has comma delimited fields and has the form:
 <filename>, <errorCode>, <[ONCE,EVERY]>
e.g.
c:\system\bin\bt.lst, -6,EVERY
the filename should be fully qualified,
errorCode should be a literal not a symbol
EVERY means that every attempt to open the file will be failed
ONCE means that only the first access to the file will be failed
*/

TInt FindHitListFile(RFs aFs)
	{
	TFindFile finder(aFs);
	TInt r=finder.FindByDir(KCorruptFileNamesList,_L("\\"));
	if(r!=KErrNone)
		{
		r=finder.FindByDir(KCorruptFileNamesList,KSysData);
		}

	if(r!=KErrNone)
		{
		r=finder.FindByDir(KCorruptFileNamesList,KSystemData);
		}

	if(r==KErrNone)
		{  // This is stored as a global because the name can be retrieved by a user api
		gCorruptFileNamesListFile=finder.File().Alloc();
		if(gCorruptFileNamesListFile==NULL)
			{
			r=KErrNoMemory;
			}
		}
	return r;
	}

void CreateCorruptFileNamesList()
	{
	RFs fs;
	fs.Connect();
	TInt r=FindHitListFile(fs);
	if(r!=KErrNone)
		return;
	RFile f;
	r=f.Open(fs,*gCorruptFileNamesListFile,EFileShareExclusive|EFileStreamText|EFileRead);
	if(r!=KErrNone)
		{
		return;
		}
	// Create a corrupt filenames 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. Filename 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.
	__PRINT1(_L("@@@@ Using Corrupt names file %S"),gCorruptFileNamesListFile);

	TText8FileReader* namesFile=new TText8FileReader;	
	if (!namesFile)
		{
		f.Close();
		return;
		}

	r=namesFile->Set(f);
	f.Close();
	fs.Close();
	if(r==KErrNone)
		{
		// 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);
		while ((r=namesFile->Read(linePtr))==KErrNone)
			{		
			TInt returnCode;
			TBool useOnce;
			TPtr namePtr(NULL,0);
			if (ParseCorruptNamesRecord(linePtr,namePtr,returnCode,useOnce)==KErrNone)
				{
				// Valid corrupt filename record found
				TCorruptNameRec* newRec=new TCorruptNameRec;
				if(!newRec)
					{
					break;
					}
				if(newRec->Construct(&namePtr,returnCode,useOnce,gCorruptFileNameList)!=KErrNone)
					{
					delete newRec;
					newRec=NULL;
					break;
					}
	
				gCorruptFileNameList=newRec;
				}
			else
				{
				__PRINT1(_L("@@@@@ Bad Parse corrupt file name record %S\n"),&linePtr);
				}
			}
		}

	delete namesFile;
	}
#endif

TInt InitCompleteThread(TAny* aPtr)
	{
	__PRINT(KLitInitCompleteThread);
	RMessagePtr2 message=*(RMessagePtr2*)aPtr;
	RThread::Rendezvous(0);


	//
#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
	CreateCorruptFileNamesList();
#endif

	TInt r = KErrNone;
	message.Complete(r);
	return(KErrNone);
	}


TInt TFsStartupInitComplete::DoRequestL(CFsRequest *aRequest)
//
// do further initialisation once necessary startup init complete outside file server
//
	{
	if(StartupInitCompleted)
		return(KErrAlreadyExists);


	StartupInitCompleted=ETrue;
	RMessagePtr2 msg=aRequest->Message();
	RThread thread;
	TInt r=thread.Create(KLitInitCompleteThread,InitCompleteThread,KDefaultStackSize,NULL,&msg);
	if (KErrNone == r)
		{
		TRequestStatus s;
		thread.Rendezvous(s);
		if (s==KRequestPending)
			thread.Resume();
		else
			thread.Kill(0);
		thread.Close();
		User::WaitForRequest(s);
		r = s.Int();
		}
	return(KErrNone);
	}

TInt TFsStartupInitComplete::Initialise(CFsRequest* /*aRequest*/)
//
//
//
	{
	return KErrNone;
	}