diff -r b33dd54aaa52 -r 122d2b873fd1 imgtools/romtools/rofsbuild/fatimagegenerator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imgtools/romtools/rofsbuild/fatimagegenerator.cpp Fri Jun 25 20:58:33 2010 +0800 @@ -0,0 +1,541 @@ +/* +* Copyright (c) 2010 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: +* +*/ +#include "fatimagegenerator.h" +#include "fatcluster.h" +#include "fsnode.h" +#include "h_utl.h" + +#include +#include +#include +#include +#include +using namespace std; + +const TInt KCharsOfCmdWndLine = 80 ; +const TInt KRootEntryCount = 0x200; +const TInt KRootClusterIndex = 0; + +TFatImgGenerator::TFatImgGenerator(TSupportedFatType aType ,ConfigurableFatAttributes& aAttr ) : +iType(aType), +iFatTable(0), +iFatTableBytes(0), +iTotalClusters(0), +iBytsPerClus(0) +{ + memset(&iBootSector,0,sizeof(iBootSector)); + memset(&iFat32Ext,0,sizeof(iFat32Ext)); + memset(&iFatHeader,0,sizeof(iFatHeader)); + if(aAttr.iDriveSectorSize != 512 && aAttr.iDriveSectorSize != 1024 && aAttr.iDriveSectorSize != 2048 && aAttr.iDriveSectorSize != 4096) { + iType = EFatUnknown ; + return ; + } + *((TUint32*)iBootSector.BS_jmpBoot) = 0x00905AEB ; + memcpy(iBootSector.BS_OEMName,"SYMBIAN ",8); + *((TUint16 *)iBootSector.BPB_BytsPerSec) = aAttr.iDriveSectorSize; + + iBootSector.BPB_NumFATs = aAttr.iDriveNoOfFATs; + iBootSector.BPB_Media = 0xF8 ; + iFatHeader.BS_DrvNum = 0x80 ; + iFatHeader.BS_BootSig = 0x29 ; + + time_t rawtime; + time(&rawtime); + *((TUint32*)iFatHeader.BS_VolID) = (TUint32)rawtime; + memcpy(iFatHeader.BS_VolLab,aAttr.iDriveVolumeLabel,sizeof(iFatHeader.BS_VolLab)); + if(aAttr.iImageSize == 0){ + if(aType == EFat32) + aAttr.iImageSize = 0x100000000LL ;// 4G + else + aAttr.iImageSize = 0x40000000LL ; // 1G + } + + TUint32 totalSectors = (TUint32)((aAttr.iImageSize + aAttr.iDriveSectorSize - 1) / aAttr.iDriveSectorSize); + if(aType == EFat32) { + InitAsFat32(totalSectors,aAttr.iSectorPerCluster ,aAttr.iDriveSectorSize); + } + else if(aType == EFat16) { + InitAsFat16(totalSectors,aAttr.iSectorPerCluster,aAttr.iDriveSectorSize); + } + if(iType == EFatUnknown) return ; + iBytsPerClus = iBootSector.BPB_SecPerClus * aAttr.iDriveSectorSize; +// if(iBytsPerClus > KMaxClusterBytes){ +// Print(EError,"Cluster too large!\n"); +// iType = EFatUnknown; +// return ; +// } + + +} +TFatImgGenerator::~TFatImgGenerator() { + if(iFatTable) + delete []iFatTable; + Interator it = iDataClusters.begin(); + while(it != iDataClusters.end()){ + TFatCluster* cluster = *it ; + delete cluster; + it++; + } +} + +void TFatImgGenerator::InitAsFat16(TUint32 aTotalSectors,TUint8 aSecPerClus,TUint16 aBytsPerSec){ + + TUint32 numOfClusters ; + if(aSecPerClus == 0) { + //Auto-calc the SecPerClus + // FAT32 ,Count of clusters must >= 4085 and < 65525 , however , to avoid the "off by xx" warning, + // proprositional value >= (4085 + 16) && < (65525 - 16) + if(aTotalSectors < (4085 + 16)) { //when SecPerClus is 1, numOfClusters eq to aTotalSectors + iType = EFatUnknown ; + Print(EError,"Size is too small for FAT16, please set a bigger size !\n"); + return ; + } + TUint8 secPerClusMax = KMaxClusterBytes / aBytsPerSec; + numOfClusters = (aTotalSectors + secPerClusMax - 1) / secPerClusMax ; + if(numOfClusters >= (65525 - 16)) { // too big + iType = EFatUnknown ; + Print(EError,"Size is too big for FAT16, please use the FAT32 format!\n"); + return ; + } + + aSecPerClus = 1; + while(aSecPerClus < secPerClusMax){ + numOfClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus ; + if (numOfClusters >= (4085 + 16) && numOfClusters < (65525 - 16)) { + break; + } + aSecPerClus <<= 1 ; + } + } + else { + if( (aSecPerClus * aBytsPerSec) > KMaxClusterBytes){ + Print(EError,"Cluster too large!\n"); + iType = EFatUnknown; + return ; + } + numOfClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus; + if(numOfClusters >= (65525 - 16)){ + Print(EError,"Cluster count is too big for FAT16, please use the FAT32 format or set a new bigger sector count of cluster!\n"); + iType = EFatUnknown ; + return ; + } + else if(numOfClusters < (4085 + 16)){ + Print(EError,"Cluster count is too small for FAT16, please set a new small sector count of cluster or set the size bigger!\n"); + iType = EFatUnknown ; + return ; + } + + } + iTotalClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus ; + iFatTableBytes = ((iTotalClusters << 1) + aBytsPerSec - 1) & (~(aBytsPerSec - 1)); + iFatTable = new(std::nothrow) char[iFatTableBytes]; + if(!iFatTable) { + Print(EError,"Memory allocation failed for FAT16 Table!\n"); + iType = EFatUnknown ; + return ; + } + memset(iFatTable,0,iFatTableBytes); + *((TUint32*)iFatTable) = 0xFFFFFFF8 ; + iBootSector.BPB_SecPerClus = aSecPerClus; + *((TUint16*)iBootSector.BPB_RsvdSecCnt) = 0x0001 ; + *((TUint16*)iBootSector.BPB_RootEntCnt) = KRootEntryCount ; + if(aTotalSectors > 0xFFFF) + *((TUint32*)iBootSector.BPB_TotSec32) = aTotalSectors; + else + *((TUint16*)iBootSector.BPB_TotSec16) = (TUint16)aTotalSectors; + TUint16 sectorsForFAT = (TUint16)((iFatTableBytes + aBytsPerSec - 1) / aBytsPerSec); + *((TUint16*)iBootSector.BPB_FATSz16) = sectorsForFAT ; + memcpy(iFatHeader.BS_FilSysType,"FAT16 ",sizeof(iFatHeader.BS_FilSysType)); +} +void TFatImgGenerator::InitAsFat32(TUint32 aTotalSectors,TUint8 aSecPerClus,TUint16 aBytsPerSec) { + + TUint32 numOfClusters; + if(aSecPerClus == 0) { + //Auto-calc the SecPerClus + // FAT32 ,Count of clusters must >= 65525, however , to avoid the "off by xx" warning, + // proprositional value >= (65525 + 16) + if(aTotalSectors < (65525 + 16)) { //when SecPerClus is 1, numOfClusters eq to aTotalSectors + iType = EFatUnknown ; + Print(EError,"Size is too small for FAT32, please use the FAT16 format, or set the data size bigger!\n"); + return ; + } + + TUint8 secPerClusMax = KMaxClusterBytes / aBytsPerSec; + aSecPerClus = secPerClusMax; + while(aSecPerClus > 1){ + numOfClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus ; + if (numOfClusters >= (65525 + 16)) { + break; + } + aSecPerClus >>= 1 ; + } + } + else { + if( (aSecPerClus * aBytsPerSec) > KMaxClusterBytes){ + Print(EError,"Cluster too large!\n"); + iType = EFatUnknown; + return ; + } + numOfClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus; + if(numOfClusters < (65525 + 16)) { + Print(EError,"Cluster count is too small for FAT32, please set a new small sector count of cluster or set the size bigger or use the FAT16 format!\n"); + iType = EFatUnknown ; + return ; + } + + } + iTotalClusters = (aTotalSectors + aSecPerClus - 1) / aSecPerClus ; + iFatTableBytes = ((iTotalClusters << 2) + aBytsPerSec - 1) & (~(aBytsPerSec - 1)); + iFatTable = new(std::nothrow) char[iFatTableBytes]; + if(!iFatTable) { + Print(EError,"Memory allocation failed for FAT32 Table!\n"); + iType = EFatUnknown ; + return ; + } + memset(iFatTable,0,iFatTableBytes); + TUint32* fat32table = reinterpret_cast(iFatTable); + fat32table[0] = 0x0FFFFFF8 ; + fat32table[1] = 0x0FFFFFFF ; + iBootSector.BPB_SecPerClus = aSecPerClus; + iBootSector.BPB_RsvdSecCnt[0] = 0x20 ; + *((TUint32*)iBootSector.BPB_TotSec32) = aTotalSectors; + *((TUint32*)iFat32Ext.BPB_FATSz32) = (iFatTableBytes + aBytsPerSec - 1) / aBytsPerSec; + *((TUint32*)iFat32Ext.BPB_RootClus) = 2 ; + *((TUint16*)iFat32Ext.BPB_FSInfo) = 1 ; + *((TUint16*)iFat32Ext.BPB_BkBootSec) = 6 ; + memcpy(iFatHeader.BS_FilSysType,"FAT32 ",sizeof(iFatHeader.BS_FilSysType)); +} + +bool TFatImgGenerator::Execute(TFSNode* aRootDir , const char* aOutputFile){ + if(EFatUnknown == iType) + return false ; + ofstream o(aOutputFile,ios_base::binary + ios_base::out + ios_base::trunc); + TUint32 writtenBytes = 0 ; + if(!o.is_open()) { + Print(EError,"Can not open \"%s\" for writing !\n",aOutputFile) ; + return false; + } + TUint16 bytsPerSector = *((TUint16*)iBootSector.BPB_BytsPerSec); + Interator it = iDataClusters.begin(); + while(it != iDataClusters.end()){ + TFatCluster* cluster = *it ; + delete cluster; + it++; + } + iDataClusters.clear(); + Print(EAlways,"Filesystem ready.\nWriting Header..."); + + if(EFat16 == iType){ + char* header = new(std::nothrow) char[bytsPerSector]; + if(!header){ + Print(EError,"Can not allocate memory for FAT16 header!\n"); + o.close(); + return false ; + } + int offset = 0; + memcpy(header,&iBootSector,sizeof(iBootSector)); + offset = sizeof(iBootSector); + memcpy(&header[offset],&iFatHeader,sizeof(iFatHeader)); + offset += sizeof(iFatHeader); + memset(&header[offset],0,bytsPerSector - offset); + *((TUint16*)(&header[510])) = 0xAA55 ; + + o.write(header,bytsPerSector); + writtenBytes += bytsPerSector; + delete []header ; + TUint16 rootDirSectors = (KRootEntryCount * 32) / bytsPerSector ; + TUint16 rootDirClusters = (rootDirSectors + iBootSector.BPB_SecPerClus - 1) /iBootSector.BPB_SecPerClus; + TUint32 rootDirBytes = KRootEntryCount * 32; + TFatCluster* rootDir = new(std::nothrow) TFatCluster(0,rootDirClusters); + rootDir->Init(rootDirBytes); + iDataClusters.push_back(rootDir); + aRootDir->WriteDirEntries(KRootClusterIndex,rootDir->GetData()); + + TUint index = 2 ; + Print(EAlways," OK.\nPreparing cluster list..."); + TFSNode* child = aRootDir->GetFirstChild() ; + while(child){ + if(!PrepareClusters(index,child)){ + Print(EAlways," Failed.\nError:Image size is expected to be big enough for all the files.\n"); + return false ; + } + child = child->GetSibling() ; + } + } + else if(EFat32 == iType){ + + TUint headerSize = ( bytsPerSector << 5 ); // 32 reserved sectors for fat32 + char* header = new(std::nothrow) char[headerSize]; + if(!header){ + Print(EError,"Can not allocate memory for FAT32 header!\n"); + o.close(); + return false ; + } + memset(header,0,headerSize); + + int offset = 0; + memcpy(header,&iBootSector,sizeof(iBootSector)); + offset = sizeof(iBootSector); + memcpy(&header[offset],&iFat32Ext,sizeof(iFat32Ext)); + offset += sizeof(iFat32Ext); + memcpy(&header[offset],&iFatHeader,sizeof(iFatHeader)); + offset += sizeof(iFatHeader); + + TFAT32FSInfoSector* fsinfo = reinterpret_cast(&header[bytsPerSector]); + *((TUint32*)fsinfo->FSI_LeadSig) = 0x41615252 ; + *((TUint32*)fsinfo->FSI_StrucSig) = 0x61417272 ; + memset(fsinfo->FSI_Free_Count,0xFF,8); + char* tailed = header + 510 ; + for(int i = 0 ; i < 32 ; i++ , tailed += bytsPerSector ) + *((TUint16*)tailed) = 0xAA55 ; + + TUint index = 2 ; + Print(EAlways," OK.\nPreparing cluster list..."); + if(!PrepareClusters(index,aRootDir)) { + Print(EAlways," Failed.\nERROR: Image size is expected to be big enough for all the files.\n"); + delete []header ; + return false; + } + + + *(TUint32*)(fsinfo->FSI_Free_Count) = iTotalClusters - index + 3; + *(TUint32*)(fsinfo->FSI_Nxt_Free) = index ; + + // write bakup boot sectors + memcpy(&header[bytsPerSector * 6],header,(bytsPerSector << 1)); + o.write(header,headerSize); + writtenBytes += headerSize; + delete []header ; + } + //iDataClusters.sort(); + it = iDataClusters.end() ; + it -- ; + int clusters = (*it)->GetIndex() + (*it)->ActualClusterCount() - 1; + + Print(EAlways," OK.\n%d clusters of data need to be written.\nWriting Fat table...",clusters); + for(TUint8 w = 0 ; w < iBootSector.BPB_NumFATs ; w++){ + o.write(iFatTable,iFatTableBytes); + if(o.bad() || o.fail()){ + Print(EAlways,"\nERROR:Writting failed. Please check the filesystem\n"); + delete []iFatTable, + o.close(); + return false ; + } + writtenBytes += iFatTableBytes; + } + char* buffer = new(std::nothrow) char[KBufferedIOBytes]; + if(!buffer){ + Print(EError,"Can not allocate memory for I/O buffer !\n"); + o.close(); + return false ; + } + o.flush(); + Print(EAlways," OK.\nWriting clusters data..."); + + int bytesInBuffer = 0; + int writeTimes = 24; + + TFatCluster* lastClust = 0 ; + for(it = iDataClusters.begin(); it != iDataClusters.end() ; it++ ){ + TFatCluster* cluster = *it ; + TUint fileSize = cluster->GetSize(); + TUint toProcess = cluster->ActualClusterCount() * iBytsPerClus ; + if(toProcess > KBufferedIOBytes){ // big file + if(bytesInBuffer > 0){ + o.write(buffer,bytesInBuffer); + if(o.bad() || o.fail()){ + Print(EError,"Writting failed.\n"); + delete []buffer, + o.close(); + return false ; + } + writtenBytes += bytesInBuffer; + bytesInBuffer = 0; + Print(EAlways,"."); + writeTimes ++ ; + if((writeTimes % KCharsOfCmdWndLine) == 0){ + o.flush(); + cout << endl ; + } + } + if(cluster->IsLazy()){ + ifstream ifs(cluster->GetFileName(), ios_base::binary + ios_base::in); + if(!ifs.is_open()){ + Print(EError,"Can not open file \"%s\"\n",cluster->GetFileName()) ; + o.close(); + delete []buffer; + return false ; + } + if(!ifs.good()) ifs.clear(); + TUint processedBytes = 0 ; + + while(processedBytes < fileSize){ + TUint ioBytes = fileSize - processedBytes ; + if(ioBytes > KBufferedIOBytes) + ioBytes = KBufferedIOBytes; + ifs.read(buffer,ioBytes); + processedBytes += ioBytes; + o.write(buffer,ioBytes); + if(o.bad() || o.fail()){ + Print(EError,"Writting failed.\n"); + delete []iFatTable, + o.close(); + return false ; + } + writtenBytes += ioBytes; + Print(EAlways,"."); + writeTimes ++ ; + if((writeTimes % KCharsOfCmdWndLine) == 0){ + o.flush(); + Print(EAlways,"\n") ; + } + + } + TUint paddingBytes = toProcess - processedBytes; + if( paddingBytes > 0 ){ + memset(buffer,0,paddingBytes); + o.write(buffer,paddingBytes); + if(o.bad() || o.fail()){ + Print(EError,"Writting failed.\n"); + delete []buffer, + o.close(); + return false ; + } + writtenBytes += paddingBytes; + } + ifs.close(); + + } + else { + // impossible + Print(EError,"Unexpected result!\n"); + o.close(); + delete []buffer; + return false ; + } + } + else { + if(toProcess > (KBufferedIOBytes - bytesInBuffer)){ + o.write(buffer,bytesInBuffer); + if(o.bad() || o.fail()){ + Print(EError,"Writting failed.\n"); + delete []buffer, + o.close(); + return false ; + } + writtenBytes += bytesInBuffer; + Print(EAlways,"."); + writeTimes ++ ; + if((writeTimes % KCharsOfCmdWndLine) == 0){ + o.flush(); + cout << endl ; + } + bytesInBuffer = 0; + } + if(cluster->IsLazy()){ + ifstream ifs(cluster->GetFileName(), ios_base::binary + ios_base::in); + if(!ifs.is_open()){ + Print(EError,"Can not open file \"%s\"\n",cluster->GetFileName()) ; + o.close(); + delete []buffer; + return false ; + } + if(!ifs.good()) ifs.clear(); + ifs.read(&buffer[bytesInBuffer],fileSize); + bytesInBuffer += fileSize; + if(toProcess > fileSize) { // fill padding bytes + memset(&buffer[bytesInBuffer],0,toProcess - fileSize); + bytesInBuffer += (toProcess - fileSize); + } + ifs.close(); + + } + else{ + if(toProcess != cluster->GetSize() && cluster->GetIndex() != KRootClusterIndex){ + Print(EError,"Unexpected size!\n"); + o.close(); + delete []buffer; + return false ; + } + memcpy(&buffer[bytesInBuffer],cluster->GetData(),cluster->GetSize()); + bytesInBuffer += cluster->GetSize(); + } + + } + lastClust = cluster ; + + } + if(bytesInBuffer > 0){ + o.write(buffer,bytesInBuffer); + if(o.bad() || o.fail()){ + Print(EError,"Writting failed.\n"); + delete []buffer, + o.close(); + return false ; + } + writtenBytes += bytesInBuffer; + o.flush(); + } + Print(EAlways,"\nDone.\n\n"); + o.close(); + + return true ; +} +bool TFatImgGenerator::PrepareClusters(TUint& aNextClusIndex,TFSNode* aNode) { + TUint sizeOfItem = aNode->GetSize(); + TUint clusters = (sizeOfItem + iBytsPerClus - 1) / iBytsPerClus; + + if(iTotalClusters < aNextClusIndex + clusters) + return false ; + + TUint16* fat16Table = reinterpret_cast(iFatTable); + TUint32* fat32Table = reinterpret_cast(iFatTable); + + for(TUint i = aNextClusIndex + clusters - 1 ; i > aNextClusIndex ; i--){ + if(iType == EFat16) + fat16Table[i - 1] = i ; + else + fat32Table[i - 1] = i ; + } + if(iType == EFat16) + fat16Table[aNextClusIndex + clusters - 1] = 0xffff ; + else + fat32Table[aNextClusIndex + clusters - 1] = 0x0fffffff ; + + TFatCluster* cluster = new TFatCluster(aNextClusIndex,clusters); + if(aNode->IsDirectory()) { + TUint bytes = clusters * iBytsPerClus ; + cluster->Init(bytes); + aNode->WriteDirEntries(aNextClusIndex,cluster->GetData()); + } + else { + cluster->LazyInit(aNode->GetPCSideName(),sizeOfItem); + aNode->WriteDirEntries(aNextClusIndex,NULL); + } + iDataClusters.push_back(cluster); + + aNextClusIndex += clusters; + if(aNode->GetFirstChild()){ + if(!PrepareClusters(aNextClusIndex,aNode->GetFirstChild())) + return false ; + } + if(aNode->GetSibling()){ + if(!PrepareClusters(aNextClusIndex,aNode->GetSibling())) + return false; + } + return true ; +}