sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "CentRepConvTool.h" sl@0: #include "shrepos.h" sl@0: #include "inifile.h" sl@0: #include "srvres.h" sl@0: #include "srvparams.h" sl@0: sl@0: sl@0: _LIT(KCentRepConvTool, "CentRep Conversion Tool:"); sl@0: sl@0: const TInt KNumDigitsInUID = 8; sl@0: sl@0: // sl@0: // factory method sl@0: CCentRepConvTool* CCentRepConvTool::NewL(const TDesC& aCmd, RFs& aFs, TBool aWaitForAck) sl@0: { sl@0: CCentRepConvTool* self = new(ELeave) CCentRepConvTool(aCmd, aFs); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aWaitForAck); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: // sl@0: // Constructor sl@0: CCentRepConvTool::CCentRepConvTool(const TDesC& aCmd, RFs& aFs) sl@0: : iCmd(aCmd), iFs(aFs), iTextToBin(ETrue), iRepUid(KNullUid), sl@0: iMyDataCage(KNullDesC), iDefaultPath(KNullDesC) sl@0: { sl@0: } sl@0: sl@0: // sl@0: // two phase construct sl@0: void CCentRepConvTool::ConstructL(TBool aWaitForAck) sl@0: { sl@0: iScrnOutput = CConsolePrint::NewL(aWaitForAck); sl@0: iFs.PrivatePath(iMyDataCage); sl@0: sl@0: // set default I/O path sl@0: _LIT(KDefaultPathMask, "_:\\"); sl@0: iDefaultPath.Copy(KDefaultPathMask); sl@0: iDefaultPath[0] = 'A' + static_cast(RFs::GetSystemDrive()); sl@0: } sl@0: sl@0: // sl@0: // destructor sl@0: CCentRepConvTool::~CCentRepConvTool() sl@0: { sl@0: delete iScrnOutput; sl@0: delete iCentRepShrepos; sl@0: } sl@0: sl@0: // sl@0: // setter sl@0: void CCentRepConvTool::SetOutputMode(TBool aWaitForAck) sl@0: { sl@0: iScrnOutput->SetWaitMode(aWaitForAck); sl@0: } sl@0: sl@0: // sl@0: // Extract input and output path from cmd line, determine text to sl@0: // binary or binary to text, and invoke code in CentRep server classes sl@0: // to do conversion. sl@0: void CCentRepConvTool::ProcessCmdL() sl@0: { sl@0: _LIT(KSuccessMsg,"Output saved as: %S\r\n"); sl@0: sl@0: TPtrC inputPath(KNullDesC); sl@0: TPtrC outputPath(KNullDesC); sl@0: ParseCmdLineL(inputPath, outputPath); sl@0: sl@0: // default input & output path is system drive root folder sl@0: sl@0: iInputPath.Set(inputPath, NULL, NULL); sl@0: if (!iInputPath.DrivePresent() && !iInputPath.PathPresent()) sl@0: { sl@0: iInputPath.Set(inputPath, NULL, &iDefaultPath); sl@0: } sl@0: sl@0: iOutputPath.Set(outputPath, NULL, NULL); sl@0: if (!iOutputPath.DrivePresent() && !iOutputPath.PathPresent()) sl@0: { sl@0: iOutputPath.Set(outputPath, NULL, &iDefaultPath); sl@0: } sl@0: sl@0: // VerifyInputPathL must be call before VerifyOutputPathL! sl@0: VerifyInputPathL(); sl@0: VerifyOutputPathL(); sl@0: sl@0: // Get UID from input filename sl@0: TLex lex(iInputPath.Name()); sl@0: TUint32 intvalue; sl@0: lex.Val(intvalue, EHex); sl@0: iRepUid.iUid = intvalue; sl@0: sl@0: TRAPD(err, DoConversionL()); sl@0: if (err != KErrNone) sl@0: { sl@0: if (err == KErrCorrupt) sl@0: { sl@0: _LIT(KCorruptError, "Input file contains corrupted entries.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KCorruptError); sl@0: iScrnOutput->Printf(KCorruptError); sl@0: } sl@0: User::Leave(err); sl@0: } sl@0: sl@0: // Success sl@0: iScrnOutput->Printf(KSuccessMsg, &(iOutputPath.FullName())); sl@0: } sl@0: sl@0: // sl@0: void CCentRepConvTool::DoConversionL() sl@0: { sl@0: iCentRepShrepos = CSharedRepository::NewL(iRepUid); sl@0: sl@0: if (iTextToBin) sl@0: { sl@0: HBufC* tempIniFileName = iInputPath.FullName().AllocLC(); sl@0: CIniFileIn* iniFile = NULL; sl@0: TInt ret=CIniFileIn::NewLC(iFs,iniFile,*tempIniFileName); sl@0: if (ret==KErrCorrupt) sl@0: User::LeaveIfError(iFs.Delete(*tempIniFileName)); sl@0: User::LeaveIfError(ret); sl@0: User::LeaveIfError(iCentRepShrepos->ReloadContentL(*iniFile)); sl@0: CleanupStack::PopAndDestroy(2); // tempIniFileName, iniFile sl@0: ExternalizeToCreL(); sl@0: } sl@0: else sl@0: { sl@0: CDirectFileStore* store = CDirectFileStore::OpenLC(iFs, sl@0: iInputPath.FullName(), EFileRead|EFileShareReadersOnly); sl@0: if (store->Type()[0] != KDirectFileStoreLayoutUid) sl@0: { sl@0: CleanupStack::PopAndDestroy(store); sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: sl@0: // Get the root stream and attempt to read the index from it sl@0: TStreamId rootStreamId = store->Root() ; sl@0: RStoreReadStream rootStream ; sl@0: rootStream.OpenLC(*store, rootStreamId); sl@0: // Internalize the repository sl@0: #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS sl@0: TUint8 creVersion; sl@0: #endif sl@0: iCentRepShrepos->InternalizeCreL(rootStream sl@0: #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS sl@0: ,creVersion sl@0: #endif sl@0: ); sl@0: CleanupStack::PopAndDestroy(&rootStream); sl@0: CleanupStack::PopAndDestroy(store); sl@0: sl@0: iCentRepShrepos->DoCommitChangesToIniFileL(iOutputPath.FullName() sl@0: #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS sl@0: ,creVersion sl@0: #endif sl@0: ); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Extract input path and output path from cmd line sl@0: void CCentRepConvTool::ParseCmdLineL(TPtrC& aInputPath, TPtrC& aOutputPath) sl@0: { sl@0: _LIT(KNoWaitSwitch, "-nowait"); sl@0: _LIT(KOutpathSwitch, "-o"); sl@0: _LIT(KHelpSwitch, "-h"); sl@0: _LIT(KBadArg, "Bad input arguments: %S\r\nUsage: CentRepConv [-o output_path] [input_path\\].txt\r\n"); sl@0: _LIT(KHelpMsg, "Usage: CentRepConv [-o output_path] [input_path\\].txt\r\nDefault output_path=%S\r\nDefault input_path=%S\r\n"); sl@0: sl@0: const TInt KMaxNumTokens = 8; // Arbitrary. only expect 4. sl@0: TPtrC tokens[KMaxNumTokens]; sl@0: TLex lex(iCmd); sl@0: TInt i; sl@0: for (i = 0; !lex.Eos() && i < KMaxNumTokens; i++) sl@0: { sl@0: tokens[i].Set(lex.NextToken()); sl@0: } sl@0: sl@0: TInt numTokens = i; sl@0: sl@0: // Expect: [-nowait] [-o output_path] [input_path\].txt sl@0: for (i = 0; i < numTokens; i++) sl@0: { sl@0: if (tokens[i].CompareF(KOutpathSwitch) == 0) sl@0: { sl@0: // Got the -o switch. sl@0: if ((i+2) < numTokens) sl@0: { sl@0: aOutputPath.Set(tokens[i+1]); sl@0: aInputPath.Set(tokens[i+2]); sl@0: } sl@0: break; sl@0: } // tokens[i] == "-o" sl@0: else if (tokens[i].CompareF(KNoWaitSwitch) == 0) sl@0: { sl@0: SetOutputMode(EFalse); sl@0: continue; sl@0: } sl@0: else if (tokens[i].FindF(KHelpSwitch) == 0) sl@0: { sl@0: numTokens = 0; // indicator for help message sl@0: break; sl@0: } sl@0: else if ('-' == tokens[i][0]) sl@0: { sl@0: continue; // unknown switch, assume intended for system sl@0: } sl@0: sl@0: // No options. Token must be input file name. sl@0: aInputPath.Set(tokens[i]); sl@0: break; sl@0: } // for sl@0: sl@0: if (0 == numTokens) sl@0: { sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KHelpMsg, &iDefaultPath, &iDefaultPath); sl@0: sl@0: iScrnOutput->Printf(KHelpMsg, &iDefaultPath, &iDefaultPath); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: // aOutputPath can be blank but aInputPath is mandatory. sl@0: if (aInputPath.Length() == 0) sl@0: { sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KBadArg, &iCmd); sl@0: sl@0: iScrnOutput->Printf(KBadArg, &iCmd); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Validate the input filenames. sl@0: void CCentRepConvTool::VerifyInputPathL() sl@0: { sl@0: // Check input file is .txt or .cre sl@0: iTextToBin = (iInputPath.Ext().CompareF(*TServerResources::iIniExt) == 0); sl@0: TBool binInput = !iTextToBin && (iInputPath.Ext().CompareF(*TServerResources::iCreExt) == 0); sl@0: sl@0: if (!iTextToBin && !binInput) sl@0: { sl@0: _LIT(KBadExt, "Bad input filename: %S\r\nInput file extension must be %S or %S\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KBadExt, &iCmd, TServerResources::iIniExt, sl@0: TServerResources::iCreExt); sl@0: sl@0: iScrnOutput->Printf(KBadExt, &iCmd, TServerResources::iIniExt, sl@0: TServerResources::iCreExt); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: // check input filename is 8 hex digits. sl@0: TPtrC p(iInputPath.Name()); sl@0: TBool validName = (KNumDigitsInUID == p.Length()); sl@0: sl@0: if (validName) sl@0: { sl@0: TLex lex(p); sl@0: for (TInt i = 0; validName && iPrintf(KBadRepUid, &iCmd); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: sl@0: p.Set(iInputPath.FullName()); sl@0: sl@0: if ( InOthersPrivatePath(p) ) sl@0: { sl@0: _LIT(KInfileCaged, "Cannot access input file %S because it is in private data cage.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KInfileCaged, &p); sl@0: sl@0: iScrnOutput->Printf(KInfileCaged, &p); sl@0: User::Leave(KErrAccessDenied); sl@0: } sl@0: sl@0: if (!BaflUtils::FileExists(iFs, p)) sl@0: { sl@0: _LIT(KInFileNotExists, "Input file %S does not exist.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KInFileNotExists, &p); sl@0: sl@0: iScrnOutput->Printf(KInFileNotExists, &p); sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Validate the output filenames. sl@0: void CCentRepConvTool::VerifyOutputPathL() sl@0: { sl@0: // If output filename is not specified, fill in the missing parts. sl@0: TBool EmptyOutFileName = EFalse; sl@0: sl@0: TPtrC outFileName(iOutputPath.Name()); sl@0: if (outFileName.Length()) sl@0: { sl@0: if (0 != outFileName.CompareF(iInputPath.Name())) sl@0: { sl@0: _LIT(KUnmatchFilenames, "Bad input: %S\r\nInput filename does not match output filename.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KUnmatchFilenames, &iCmd); sl@0: sl@0: iScrnOutput->Printf(KUnmatchFilenames, &iCmd); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: EmptyOutFileName = ETrue; sl@0: outFileName.Set(iInputPath.Name()); sl@0: } sl@0: sl@0: sl@0: TPtrC correctExt(*TServerResources::iCreExt); sl@0: TPtrC outFileExt(iOutputPath.Ext()); sl@0: if (!iTextToBin) sl@0: { sl@0: correctExt.Set(*TServerResources::iIniExt); sl@0: } sl@0: sl@0: if (outFileExt.Length()) sl@0: { sl@0: // If output filename is specified, extension should match conversion. sl@0: if (0 != outFileExt.CompareF(correctExt)) sl@0: { sl@0: _LIT(KUnmatchExt, "Bad input: %S\r\nExtension of output filename not valid.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KUnmatchExt, &iCmd); sl@0: sl@0: iScrnOutput->Printf(KUnmatchExt, &iCmd); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: EmptyOutFileName = ETrue; sl@0: outFileExt.Set(correctExt); sl@0: } sl@0: sl@0: TPtrC p; sl@0: sl@0: if (EmptyOutFileName) sl@0: { sl@0: const TInt KFilePlusExtLen = KNumDigitsInUID + 4; // e.g. 01234567.cre sl@0: TBuf newName(outFileName); sl@0: newName.Append(correctExt); sl@0: sl@0: p.Set(iOutputPath.DriveAndPath()); sl@0: TParse newpath; sl@0: newpath.Set(newName, NULL, &p); sl@0: sl@0: p.Set(newpath.FullName()); sl@0: iOutputPath.Set(p, NULL, NULL); sl@0: } sl@0: sl@0: // Check output file is in other's private data cage sl@0: p.Set(iOutputPath.FullName()); sl@0: if ( InOthersPrivatePath(p) ) sl@0: { sl@0: _LIT(KOutfileInDataCage, "Cannot write output file %S because it is in private data cage.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KOutfileInDataCage, &p); sl@0: sl@0: iScrnOutput->Printf(KOutfileInDataCage, &p); sl@0: User::Leave(KErrAccessDenied); sl@0: } sl@0: sl@0: // Check saving output to read only drive. sl@0: p.Set(iOutputPath.DriveAndPath()); sl@0: TBool isReadOnly; sl@0: TInt ret; sl@0: ret = BaflUtils::DiskIsReadOnly(iFs, p, isReadOnly); sl@0: if (ret == KErrNone) sl@0: { sl@0: if (isReadOnly) sl@0: { sl@0: _LIT(KWriteToReadOnly, "Bad argument: output dir %S is in read only drive.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KWriteToReadOnly, &p); sl@0: sl@0: iScrnOutput->Printf(KWriteToReadOnly, &p); sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: sl@0: ret = iFs.MkDirAll(p); sl@0: if (ret != KErrNone && ret != KErrAlreadyExists) sl@0: { sl@0: _LIT(KCreateOutpathFail, "Create output path %S failed, err %d.\r\n"); sl@0: RDebug::Print(KCentRepConvTool); sl@0: RDebug::Print(KCreateOutpathFail, &p, ret); sl@0: sl@0: iScrnOutput->Printf(KCreateOutpathFail, &p, ret); sl@0: User::Leave(ret); sl@0: } sl@0: } sl@0: sl@0: // sl@0: // Open a RWriteStream on top of a CDirectFileStore. Call sl@0: // CSharedRepository's ExternalizeCre method to write the sl@0: // settings to file. sl@0: void CCentRepConvTool::ExternalizeToCreL() sl@0: { sl@0: // Create file store sl@0: CDirectFileStore* store = CDirectFileStore::ReplaceLC(iFs, sl@0: iOutputPath.FullName(), (EFileWrite | EFileShareExclusive)); sl@0: const TUid uid2 = KNullUid; sl@0: store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; sl@0: sl@0: // Write the stream index/dictionary as root stream within the store sl@0: // so we can access it when we do a restore later on sl@0: RStoreWriteStream rootStream ; sl@0: TStreamId rootStreamId = rootStream.CreateLC(*store) ; sl@0: iCentRepShrepos->ExternalizeCre(rootStream); sl@0: rootStream.CommitL(); sl@0: sl@0: CleanupStack::PopAndDestroy(&rootStream) ; sl@0: store->SetRootL(rootStreamId); sl@0: store->CommitL(); sl@0: CleanupStack::PopAndDestroy(store); sl@0: } sl@0: sl@0: // sl@0: // Check if given path is located in some other process's sl@0: // private data cage sl@0: TBool CCentRepConvTool::InOthersPrivatePath(const TDesC& aFullPathName) sl@0: { sl@0: _LIT(KPrivate, "\\private\\"); sl@0: const TInt KPosAfterDrive = 2; sl@0: return aFullPathName.FindF(KPrivate) == KPosAfterDrive && sl@0: aFullPathName.FindF(iMyDataCage) == KErrNotFound; sl@0: }