fixed permissions check for executable files exported on systems where 'ls' reports alternative access characters
/*
* Copyright (c) 2005-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:
* @internalComponent
* @released
*
*/
#include "common.h"
#include "r_obey.h"
#include "rofs_image_reader.h"
#include "e32_image_reader.h"
RofsImage::RofsImage(RCoreImageReader *aReader) : CCoreImage(aReader) ,
iRofsHeader(0), iRofsExtnHeader(0),iAdjustment(0), iImageType(RCoreImageReader::E_UNKNOWN)
{
}
RofsImageReader::RofsImageReader(char* aFile) : ImageReader(aFile), iInputFile(0)
{
iImageReader = new RCoreImageReader(aFile);
iImage = new RofsImage(iImageReader);
}
RofsImageReader::~RofsImageReader()
{
if(iInputFile)
iInputFile->close();
delete iInputFile;
delete iImage;
delete iImageReader;
}
void RofsImageReader::SetSeek(streampos aOff, ios::seek_dir aStartPos)
{
if(!iInputFile)
return;
iInputFile->seekg(aOff, aStartPos);
}
void RofsImageReader::ReadImage()
{
if(!iImageReader->Open())
{
throw ImageReaderException((char*)(iImageReader->Filename()), "Failed to open Image File");
}
}
void RofsImageReader::Validate()
{
}
TInt RofsImage::ProcessImage()
{
int result = CreateRootDir();
if (result == KErrNone)
{
if (iReader->Open())
{
iImageType = iReader->ReadImageType();
if (iImageType == RCoreImageReader::E_ROFS)
{
iRofsHeader = new TRofsHeader;
result = iReader->ReadCoreHeader(*iRofsHeader);
if (result != KErrNone)
return result;
SaveDirInfo(*iRofsHeader);
result = ProcessDirectory(0);
}
#if defined(__TOOLS2__) || defined(__MSVCDOTNET__)
else if (iImageType == RCoreImageReader::E_ROFX)
#else
else if (iImageType == RCoreImageReader::TImageType::E_ROFX)
#endif
{
iRofsExtnHeader = new TExtensionRofsHeader ;
result = iReader->ReadExtensionHeader(*iRofsExtnHeader);
if(result != KErrNone)
return result;
long filePos = iReader->FilePosition();
iAdjustment = iRofsExtnHeader->iDirTreeOffset - filePos;
SaveDirInfo(*iRofsExtnHeader);
result = ProcessDirectory(iAdjustment);
}
else
{
result = KErrNotSupported;
}
}
else
{
result = KErrGeneral;
}
}
return result;
}
void RofsImageReader::ProcessImage()
{
iImage->ProcessImage();
iRootDirEntry = iImage->RootDirectory();
}
void RofsImageReader::Dump()
{
if( !((iDisplayOptions & EXTRACT_FILES_FLAG) || (iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG) ||
(iDisplayOptions & EXTRACT_FILE_SET_FLAG)) )
{
MarkNodes();
if(iDisplayOptions & DUMP_HDR_FLAG)
{
DumpHeader();
}
if( (iDisplayOptions & DUMP_DIR_ENTRIES_FLAG) ||
(iDisplayOptions & DUMP_VERBOSE_FLAG) )
{
DumpDirStructure();
DumpFileAttributes();
}
}
}
void RofsImageReader::DumpHeader()
{
*out << "Image Name................." << iImgFileName.c_str() << endl;
int aPos = 0;
if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFS)
{
*out << "ROFS Image" << endl;
*out << "Image Signature..........." ;
while(aPos < K_ID_SIZE)
{
*out << ((RofsImage*)iImage)->iRofsHeader->iIdentifier[aPos++];
}
*out << endl << endl;
TUint aTotalDirSz = ((RofsImage*)iImage)->iRofsHeader->iDirTreeSize +
((RofsImage*)iImage)->iRofsHeader->iDirFileEntriesSize;
(*out).width(8);
*out << "Directory block size: 0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iDirTreeSize << endl;
*out << "File block size: 0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iDirFileEntriesSize << endl;
*out << "Total directory size: 0x" << hex << ( aTotalDirSz ) << endl;
*out << "Total image size: 0x" << hex << ((RofsImage*)iImage)->iRofsHeader->iImageSize << endl;
}
else if(((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
{
*out << "Extension ROFS Image" << endl;
*out << "Image Signature..........." ;
while(aPos < K_ID_SIZE)
{
*out << ((RofsImage*)iImage)->iRofsExtnHeader->iIdentifier[aPos++];
}
*out << endl << endl;
TUint aTotalDirSz = ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeSize +
((RofsImage*)iImage)->iRofsExtnHeader->iDirFileEntriesSize;
out->width(8);
*out << "Directory block size: 0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeSize << endl;
*out << "File block size: 0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iDirFileEntriesSize << endl;
*out << "Total directory size: 0x" << hex << ( aTotalDirSz ) << endl;
*out << "Total image size: 0x" << hex << ((RofsImage*)iImage)->iRofsExtnHeader->iImageSize << endl;
}
}
void RofsImageReader::DumpDirStructure()
{
*out << "Directory Listing" << endl;
*out << "=================" << endl;
iImage->Display(out);
}
void RofsImageReader::MarkNodes()
{
TRomNode *aNode = iRootDirEntry->NextNode();
while( aNode )
{
if(aNode->iEntry)
{
if( ReaderUtil::IsExecutable(aNode->iEntry->iUids) )
{
aNode->iEntry->iExecutable = true;
}
else
{
aNode->iEntry->iExecutable = false;
}
}
aNode = aNode->NextNode();
}
}
void RofsImageReader::DumpFileAttributes()
{
TRomNode *aNode = iRootDirEntry->NextNode();
E32ImageFile aE32Img;
streampos aFileOffset;
string iPath;
while( aNode )
{
if( aNode->IsFile() )
{
if( !iInputFile )
{
// Open the image file once and to access the E32 images within,#
// seek to the file offsets...
iInputFile = new ifstream( (char*)(iImageReader->Filename()), ios::binary|ios::in);
if(!iInputFile->is_open())
{
throw ImageReaderException((char*)iImageReader->Filename(), "Failed to open file");
}
}
try
{
if( aNode->iEntry->iExecutable)
{
aFileOffset = 0;
if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
{
if((TUint)aNode->iEntry->iFileOffset > ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeOffset)
{
//This is set only for files within this extended ROFS
aFileOffset = aNode->iEntry->iFileOffset - ((RofsImage*)iImage)->iAdjustment;
}
}
else
{
//This is set only for files within ROFS
aFileOffset = aNode->iEntry->iFileOffset;
}
if( aFileOffset )
{
SetSeek(aFileOffset , ios::beg);
memset(&aE32Img, 0, sizeof(aE32Img));
aE32Img.Adjust(aNode->iSize);
aE32Img.iFileSize = aNode->iSize;
if( iInputFile->fail())
{
// Check why is the fail bit set causing all subsequent
// istream operations to fail.
// For now, clear the fail bit...
iInputFile->clear();
}
*iInputFile >> aE32Img;
if(aE32Img.iError != KErrNone)
{
throw int (0);
}
}
}
}
catch(...)
{
// Just in case this was't a valid E32 image and the E32 reader didn't
// catch it...
string aStr("Failed to read contents of ");
aStr.append((char*)aNode->iName);
throw ImageReaderException((char*)iImageReader->Filename(), (char*)aStr.c_str());
}
*out << "********************************************************************" << endl;
iPath.assign((char*)aNode->iName);
GetCompleteNodePath(aNode,iPath,"/");
*out << "File........................" << iPath.c_str() << endl;
if( aNode->iEntry->iExecutable )
{
if(aFileOffset)
{
// When its an E32 Image...
E32ImageReader::DumpE32Attributes(aE32Img);
if( iDisplayOptions & DUMP_E32_IMG_FLAG){
if(stricmp(iE32ImgFileName.c_str(), (const char*)aNode->iName) == 0){
TUint aSectionOffset = aE32Img.iOrigHdr->iCodeOffset;
TUint* aCodeSection = (TUint*)(aE32Img.iData + aSectionOffset);
*out << "\nCode (Size=0x" << hex << aE32Img.iOrigHdr->iCodeSize << ")" << endl;
DumpData(aCodeSection, aE32Img.iOrigHdr->iCodeSize);
aSectionOffset = aE32Img.iOrigHdr->iDataOffset;
TUint* aDataSection = (TUint*)(aE32Img.iData + aSectionOffset);
if( aE32Img.iOrigHdr->iDataSize){
*out << "\nData (Size=0x" << hex << aE32Img.iOrigHdr->iDataSize << ")" << endl;
DumpData(aDataSection, aE32Img.iOrigHdr->iDataSize);
}
}
}
}
else
{
*out << "Image "<< aNode->iName << " not in the extended ROFS " << iImgFileName.c_str() << endl;
}
}
}
aNode = aNode->NextNode();
}
}
/**
Function iterates through all the entries in the image.If the entry is a file,
then it makes a call to GetFileExtension to check for the extension.
@internalComponent
@released
*/
void RofsImageReader::ExtractImageContents()
{
if( (iDisplayOptions & EXTRACT_FILE_SET_FLAG) )
{
ImageReader::ExtractFileSet(NULL);
}
if( iDisplayOptions & EXTRACT_FILES_FLAG || iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG )
{
// get the next Node
TRomNode *nextNode = iRootDirEntry->NextNode();
// current Node.
TRomNode *currNode = iRootDirEntry;
// name of the log file.
string logFile;
// output stream for the log file.
ofstream oFile;
if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG ){
if( ImageReader::iZdrivePath.compare("")){
// create a string to hold path information.
string filePath;
string delimiter;
delimiter.assign("\\");
filePath.assign( ImageReader::iZdrivePath );
// replace backslash with double backslash.
FindAndInsertString(filePath,delimiter,delimiter);
logFile.assign(filePath);
// create specified directory.
CreateSpecifiedDir(&filePath[0],"\\\\");
logFile.append("\\\\");
logFile.append(ImageReader::iLogFileName);
}
else {
logFile.assign(ImageReader::iLogFileName);
}
// open the specified file in append mode.
oFile.open(logFile.c_str(),ios::out|ios::app);
if(!oFile.is_open()) {
throw ImageReaderException((char*)ImageReader::iLogFileName.c_str(), "Failed to open the log file");
}
}
while( nextNode ){
if(nextNode->IsDirectory()) {
// if next node is a directory set current node as next node.
currNode = nextNode;
}
else {
// get file extension
CheckFileExtension((char*) nextNode->iName,nextNode->iEntry,currNode,oFile);
}
nextNode = nextNode->NextNode();
}
if(oFile.is_open()) oFile.close();
}
}
/**
Function to get check extension of the given file.If the extension of the file is "sis"
then call ExtractFile function to extract the file from the image.
@internalComponent
@released
@param aFile - file name.
@param aEntry - entry of the file in image.
@param aNode - current node.
@param aLogFile - output stream.
*/
void RofsImageReader::CheckFileExtension(char* aFileName,TRomBuilderEntry* aEntry,TRomNode* aNode,ofstream& aLogFile)
{
//create a string to hold path information.
string path;
// check whether the node has parent
if(aNode->GetParent())
{
// get the complete path
path.assign( (char*)aNode->iName );
GetCompleteNodePath( aNode, path, "\\\\" );
}
else
{
// else path is the current path
path.assign("");
}
if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG && iDisplayOptions & EXTRACT_FILES_FLAG )
{
size_t pos = string(aFileName).find_last_of(".");
const char* extName = "";
if(pos != string::npos)
extName = aFileName + pos + 1;
if ( 0 == stricmp(extName,"SIS") || 0 == stricmp(extName,"DAT")) {
// if the two strings are same then extract the corresponding file.
ImageReader::ExtractFile(aEntry->iFileOffset,aEntry->RealFileSize(),aFileName,path.c_str(),&ImageReader::iZdrivePath[0]);
}
else {
// log the entry path information on to the specified file.
WriteEntryToFile(aFileName,aNode,aLogFile);
}
}
else if( iDisplayOptions & LOG_IMAGE_CONTENTS_FLAG ) {
// log the entry path information on to the specified file.
WriteEntryToFile(aFileName,aNode,aLogFile);
}
else {
// if the two strings are same then extract the corresponding file.
ImageReader::ExtractFile(aEntry->iFileOffset,aEntry->RealFileSize(),aFileName,path.c_str(),&ImageReader::iZdrivePath[0]);
}
}
/**
Function to get the complete path information of a file from an image.
@internalComponent
@released
@param aNode - starting offset of the file in the image.
@param aName - name of the current entry in the image.
@param aAppStr - string to append.
@return - returns full path of the given file.
*/
void RofsImageReader::GetCompleteNodePath(TRomNode* aNode,string& aName,char* aAppStr)
{
// check if the entry has a parent.
TRomNode* NodeParent = aNode->GetParent();
if(NodeParent)
{
string str( (char*)NodeParent->iName );
str.append( aAppStr );
str.append( aName );
aName = str;
GetCompleteNodePath(NodeParent,aName,aAppStr);
}
}
/**
Function to write the rom entry to an output stream.
@internalComponent
@released
@param aNode - starting offset of the file in the image.
@param aFileName - name of the current entry in the image.
@param aLogFile - output stream.
*/
void RofsImageReader::WriteEntryToFile(char* aFileName,TRomNode* aNode,ofstream& aLogFile)
{
//create a string to hold path information.
string path;
if(aNode->GetParent())
{
// get the complete path
path.assign( (char*)aNode->iName );
GetCompleteNodePath( aNode, path, "\\" );
}
else
{
// else path is the current path
path.assign("");
}
if(aLogFile.is_open())
{
aLogFile.seekp(0,ios::end);
aLogFile<<path.c_str()<<"\\"<<aFileName<<"\n";
}
}
/**
Function to get the directory structure information.
@internalComponent
@released
@param aFileMap - map of filename with its size and offset values.
*/
void RofsImageReader::GetFileInfo(FILEINFOMAP &aFileMap)
{
// get the next Node
TRomNode *nextNode = iRootDirEntry->NextNode();
// current Node.
TRomNode *currNode = iRootDirEntry;
// image size
TUint32 imgSize = GetImageSize();
while(nextNode)
{
if(nextNode->IsDirectory())
{
// if next node is a directory set current node as next node.
currNode = nextNode;
}
else
{
PFILEINFO fileInfo = new FILEINFO;
//create a string to hold path information.
string fileName;
TUint32 aFileOffset = 0;
// check whether the node has parent
if(currNode->GetParent())
{
if( !((currNode->GetParent() == currNode->FirstNode()) && !(currNode->IsDirectory())) )
{
// get the complete path
fileName.assign( (char*)currNode->iName );
GetCompleteNodePath( currNode, fileName, (char*)DIR_SEPARATOR );
}
}
else
{
// else path is the current path
fileName.assign("");
}
fileName.append(DIR_SEPARATOR);
fileName.append((char*)nextNode->iName);
// get the size of the entity.
fileInfo->iSize = nextNode->iEntry->RealFileSize();
// get the offset of the entity.
if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
{
if((TUint)nextNode->iEntry->iFileOffset > ((RofsImage*)iImage)->iRofsExtnHeader->iDirTreeOffset)
{
//This is set only for files within this extended ROFS
aFileOffset = nextNode->iEntry->iFileOffset - ((RofsImage*)iImage)->iAdjustment;
}
}
else
{
//This is set only for files within ROFS
aFileOffset = nextNode->iEntry->iFileOffset;
}
fileInfo->iOffset = aFileOffset;
if((!fileInfo->iOffset) || ((fileInfo->iOffset + fileInfo->iSize) > imgSize))
{
fileInfo->iOffset = 0;
fileInfo->iSize = 0;
}
aFileMap[fileName] = fileInfo;
}
nextNode = nextNode->NextNode();
}
}
/**
Function to get the ROFS image size.
@internalComponent
@released
*/
TUint32 RofsImageReader::GetImageSize()
{
TUint32 result = 0;
if( ((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFS)
{
result = ((RofsImage*)iImage)->iRofsHeader->iImageSize;
}
else if(((RofsImage*)iImage)->iImageType == RCoreImageReader::E_ROFX)
{
result = ((RofsImage*)iImage)->iRofsExtnHeader->iImageSize;
}
return result;
}