os/persistentdata/persistentstorage/centralrepository/convtool/src/CentRepConvTool.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32const.h>
    17 #include <e32debug.h>
    18 #include <bautils.h>
    19 #include <s32file.h>
    20 #include "CentRepConvTool.h"
    21 #include "shrepos.h"
    22 #include "inifile.h"
    23 #include "srvres.h"
    24 #include "srvparams.h"
    25 
    26 
    27 _LIT(KCentRepConvTool, "CentRep Conversion Tool:");
    28 
    29 const TInt KNumDigitsInUID = 8;
    30 
    31 //
    32 // factory method
    33 CCentRepConvTool* CCentRepConvTool::NewL(const TDesC& aCmd, RFs& aFs, TBool aWaitForAck)
    34 	{
    35 	CCentRepConvTool* self = new(ELeave) CCentRepConvTool(aCmd, aFs);
    36 	CleanupStack::PushL(self);
    37 	self->ConstructL(aWaitForAck);
    38 	CleanupStack::Pop(self);
    39 	return self;
    40 	}
    41 
    42 //
    43 // Constructor
    44 CCentRepConvTool::CCentRepConvTool(const TDesC& aCmd, RFs& aFs)
    45 	: iCmd(aCmd), iFs(aFs), iTextToBin(ETrue), iRepUid(KNullUid),
    46 	  iMyDataCage(KNullDesC), iDefaultPath(KNullDesC)
    47 	{
    48 	}
    49 
    50 //
    51 // two phase construct
    52 void CCentRepConvTool::ConstructL(TBool aWaitForAck)
    53 	{
    54 	iScrnOutput = CConsolePrint::NewL(aWaitForAck);
    55 	iFs.PrivatePath(iMyDataCage);
    56 	
    57 	// set default I/O path
    58 	_LIT(KDefaultPathMask, "_:\\");
    59 	iDefaultPath.Copy(KDefaultPathMask);
    60 	iDefaultPath[0] = 'A' + static_cast<TInt>(RFs::GetSystemDrive());
    61 	}
    62 
    63 //
    64 // destructor
    65 CCentRepConvTool::~CCentRepConvTool()
    66 	{
    67 	delete iScrnOutput;
    68 	delete iCentRepShrepos;
    69 	}
    70 
    71 //
    72 // setter
    73 void CCentRepConvTool::SetOutputMode(TBool aWaitForAck)
    74 	{
    75 	iScrnOutput->SetWaitMode(aWaitForAck);
    76 	}
    77 
    78 //
    79 // Extract input and output path from cmd line, determine text to
    80 // binary or binary to text, and invoke code in CentRep server classes
    81 // to do conversion.
    82 void CCentRepConvTool::ProcessCmdL()
    83 	{
    84 	_LIT(KSuccessMsg,"Output saved as: %S\r\n");
    85 	
    86 	TPtrC inputPath(KNullDesC);
    87 	TPtrC outputPath(KNullDesC);
    88 	ParseCmdLineL(inputPath, outputPath);
    89 
    90 	// default input & output path is system drive root folder
    91 
    92 	iInputPath.Set(inputPath, NULL, NULL);
    93 	if (!iInputPath.DrivePresent() && !iInputPath.PathPresent())
    94 		{		
    95 		iInputPath.Set(inputPath, NULL, &iDefaultPath);
    96 		}
    97 
    98 	iOutputPath.Set(outputPath, NULL, NULL);
    99 	if (!iOutputPath.DrivePresent() && !iOutputPath.PathPresent())
   100 		{		
   101 		iOutputPath.Set(outputPath, NULL, &iDefaultPath);
   102 		}
   103 
   104 	// VerifyInputPathL must be call before VerifyOutputPathL!
   105 	VerifyInputPathL();
   106 	VerifyOutputPathL();
   107 	
   108 	// Get UID from input filename
   109 	TLex lex(iInputPath.Name());
   110 	TUint32 intvalue;
   111 	lex.Val(intvalue, EHex);
   112 	iRepUid.iUid = intvalue;
   113 
   114 	TRAPD(err, DoConversionL());
   115 	if (err != KErrNone)    
   116 	    {    
   117         if (err == KErrCorrupt)    
   118             {    
   119             _LIT(KCorruptError, "Input file contains corrupted entries.\r\n");    
   120             RDebug::Print(KCentRepConvTool);    
   121             RDebug::Print(KCorruptError);    
   122             iScrnOutput->Printf(KCorruptError);    
   123             }    
   124         User::Leave(err);    
   125         } 
   126 
   127 	// Success
   128 	iScrnOutput->Printf(KSuccessMsg, &(iOutputPath.FullName()));
   129 	}
   130 
   131 //
   132 void CCentRepConvTool::DoConversionL()
   133 	{
   134 	iCentRepShrepos = CSharedRepository::NewL(iRepUid);
   135 
   136 	if (iTextToBin)
   137 		{
   138 		HBufC* tempIniFileName = iInputPath.FullName().AllocLC();
   139 		CIniFileIn* iniFile = NULL;
   140 		TInt ret=CIniFileIn::NewLC(iFs,iniFile,*tempIniFileName);
   141 		if (ret==KErrCorrupt)
   142 			User::LeaveIfError(iFs.Delete(*tempIniFileName));
   143 		User::LeaveIfError(ret);
   144 		User::LeaveIfError(iCentRepShrepos->ReloadContentL(*iniFile));
   145 		CleanupStack::PopAndDestroy(2); // tempIniFileName, iniFile
   146 		ExternalizeToCreL();
   147 		}
   148 	else
   149 		{
   150 		CDirectFileStore* store = CDirectFileStore::OpenLC(iFs,
   151 			iInputPath.FullName(), EFileRead|EFileShareReadersOnly);
   152 		if (store->Type()[0] != KDirectFileStoreLayoutUid)
   153 			{
   154 			CleanupStack::PopAndDestroy(store);
   155 			User::Leave(KErrCorrupt);
   156 			}		
   157 
   158 		// Get the root stream and attempt to read the index from it
   159 		TStreamId rootStreamId = store->Root() ;
   160 		RStoreReadStream rootStream ;
   161 		rootStream.OpenLC(*store, rootStreamId);
   162 		// Internalize the repository
   163 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS		
   164 		TUint8 creVersion;
   165 #endif		
   166 		iCentRepShrepos->InternalizeCreL(rootStream
   167 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS		
   168 		,creVersion
   169 #endif		
   170 		);
   171 		CleanupStack::PopAndDestroy(&rootStream);
   172 		CleanupStack::PopAndDestroy(store);
   173 		
   174 		iCentRepShrepos->DoCommitChangesToIniFileL(iOutputPath.FullName()
   175 #ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS		
   176 		,creVersion
   177 #endif		
   178 		);
   179 		}
   180 	}
   181 
   182 //
   183 // Extract input path and output path from cmd line
   184 void CCentRepConvTool::ParseCmdLineL(TPtrC& aInputPath, TPtrC& aOutputPath)
   185 	{
   186 	_LIT(KNoWaitSwitch, "-nowait");
   187 	_LIT(KOutpathSwitch, "-o");
   188 	_LIT(KHelpSwitch, "-h");
   189 	_LIT(KBadArg, "Bad input arguments: %S\r\nUsage: CentRepConv [-o output_path]  [input_path\\]<repositoryUID>.txt\r\n");
   190 	_LIT(KHelpMsg, "Usage: CentRepConv [-o output_path]  [input_path\\]<repositoryUID>.txt\r\nDefault output_path=%S\r\nDefault input_path=%S\r\n");
   191 	
   192 	const TInt KMaxNumTokens = 8; // Arbitrary. only expect 4. 
   193 	TPtrC tokens[KMaxNumTokens];
   194 	TLex lex(iCmd);
   195 	TInt i;
   196 	for (i = 0; !lex.Eos() && i < KMaxNumTokens; i++)
   197 		{
   198 		tokens[i].Set(lex.NextToken());
   199 		}
   200 
   201 	TInt numTokens = i;
   202 
   203 	// Expect: [-nowait] [-o output_path] [input_path\]<rep_UID>.txt
   204 	for (i = 0; i < numTokens; i++)
   205 		{
   206 		if (tokens[i].CompareF(KOutpathSwitch) == 0)
   207 			{
   208 			// Got the -o switch.
   209 			if ((i+2) < numTokens)
   210 				{
   211 				aOutputPath.Set(tokens[i+1]);
   212 				aInputPath.Set(tokens[i+2]);
   213 				}
   214 			break;	
   215 			} // tokens[i] == "-o"
   216 		else if (tokens[i].CompareF(KNoWaitSwitch) == 0)
   217 			{
   218 			SetOutputMode(EFalse);
   219 			continue;
   220 			}
   221 		else if (tokens[i].FindF(KHelpSwitch) == 0)
   222 			{
   223 			numTokens = 0; // indicator for help message
   224 			break;
   225 			}
   226 		else if ('-' == tokens[i][0])
   227 			{
   228 			continue; // unknown switch, assume intended for system
   229 			}
   230 
   231 		// No options. Token must be input file name.
   232 		aInputPath.Set(tokens[i]);
   233 		break;
   234 		} // for
   235 	
   236 	if (0 == numTokens)
   237 		{
   238 		RDebug::Print(KCentRepConvTool);
   239 		RDebug::Print(KHelpMsg, &iDefaultPath, &iDefaultPath);
   240 
   241 		iScrnOutput->Printf(KHelpMsg, &iDefaultPath, &iDefaultPath);
   242 		User::Leave(KErrArgument);
   243 		}
   244 
   245 	// aOutputPath can be blank but aInputPath is mandatory.
   246 	if (aInputPath.Length() == 0)
   247 		{
   248 		RDebug::Print(KCentRepConvTool);
   249 		RDebug::Print(KBadArg, &iCmd);
   250 
   251 		iScrnOutput->Printf(KBadArg, &iCmd);
   252 		User::Leave(KErrArgument);
   253 		}
   254 	}
   255 
   256 //
   257 // Validate the input filenames.
   258 void CCentRepConvTool::VerifyInputPathL()
   259 	{
   260 	// Check input file is .txt or .cre
   261 	iTextToBin = (iInputPath.Ext().CompareF(*TServerResources::iIniExt) == 0);
   262 	TBool binInput = !iTextToBin && (iInputPath.Ext().CompareF(*TServerResources::iCreExt) == 0);
   263 	
   264 	if (!iTextToBin && !binInput)
   265 		{
   266 		_LIT(KBadExt, "Bad input filename: %S\r\nInput file extension must be %S or %S\r\n");
   267 		RDebug::Print(KCentRepConvTool);
   268 		RDebug::Print(KBadExt, &iCmd, TServerResources::iIniExt,
   269 			TServerResources::iCreExt);
   270 
   271 		iScrnOutput->Printf(KBadExt, &iCmd, TServerResources::iIniExt,
   272 			TServerResources::iCreExt);
   273 		User::Leave(KErrArgument);	
   274 		}
   275 	
   276 	// check input filename is 8 hex digits.
   277 	TPtrC p(iInputPath.Name());
   278 	TBool validName = (KNumDigitsInUID == p.Length());
   279 	
   280 	if (validName)
   281 		{
   282 		TLex lex(p);
   283 		for (TInt i = 0; validName && i<KNumDigitsInUID; i++)
   284 			{
   285 			if (lex.Peek().IsHexDigit())
   286 				{
   287 				lex.Inc();
   288 				}
   289 			else
   290 				{
   291 				validName = EFalse;
   292 				}				
   293 			} // for
   294 		} // if validName
   295 		
   296 	if (!validName)	
   297 		{
   298 		_LIT(KBadRepUid, "Input filename in %S is not a valid UID.\r\nExpect 8 hex digits.\r\n");
   299 		RDebug::Print(KCentRepConvTool);
   300 		RDebug::Print(KBadRepUid, &iCmd);
   301 
   302 		iScrnOutput->Printf(KBadRepUid, &iCmd);
   303 		User::Leave(KErrArgument);
   304 		}
   305 		
   306 	p.Set(iInputPath.FullName());
   307 
   308 	if ( InOthersPrivatePath(p) )
   309 		{
   310 		_LIT(KInfileCaged, "Cannot access input file %S because it is in private data cage.\r\n");
   311 		RDebug::Print(KCentRepConvTool);
   312 		RDebug::Print(KInfileCaged, &p);
   313 
   314 		iScrnOutput->Printf(KInfileCaged, &p);
   315 		User::Leave(KErrAccessDenied);
   316 		}
   317 
   318 	if (!BaflUtils::FileExists(iFs, p))
   319 		{
   320 		_LIT(KInFileNotExists, "Input file %S does not exist.\r\n");
   321 		RDebug::Print(KCentRepConvTool);
   322 		RDebug::Print(KInFileNotExists, &p);
   323 
   324 		iScrnOutput->Printf(KInFileNotExists, &p);
   325 		User::Leave(KErrNotFound);
   326 		}
   327 	}
   328 
   329 //
   330 // Validate the output filenames.
   331 void CCentRepConvTool::VerifyOutputPathL()
   332 {
   333 	// If output filename is not specified, fill in the missing parts.
   334 	TBool EmptyOutFileName = EFalse;
   335 	
   336 	TPtrC outFileName(iOutputPath.Name());
   337 	if (outFileName.Length())
   338 		{
   339 		if (0 != outFileName.CompareF(iInputPath.Name()))
   340 			{
   341 			_LIT(KUnmatchFilenames, "Bad input: %S\r\nInput filename does not match output filename.\r\n");
   342 			RDebug::Print(KCentRepConvTool);
   343 			RDebug::Print(KUnmatchFilenames, &iCmd);
   344 
   345 			iScrnOutput->Printf(KUnmatchFilenames, &iCmd);
   346 			User::Leave(KErrArgument);
   347 			}
   348 		}
   349 	else
   350 		{
   351 		EmptyOutFileName = ETrue;
   352 		outFileName.Set(iInputPath.Name()); 
   353 		}
   354 	
   355 	
   356 	TPtrC correctExt(*TServerResources::iCreExt);
   357 	TPtrC outFileExt(iOutputPath.Ext());
   358 	if (!iTextToBin)
   359 		{
   360 		correctExt.Set(*TServerResources::iIniExt);
   361 		}
   362 		
   363 	if (outFileExt.Length())
   364 		{
   365 		// If output filename is specified, extension should match conversion.
   366 		if (0 != outFileExt.CompareF(correctExt))
   367 			{
   368 			_LIT(KUnmatchExt, "Bad input: %S\r\nExtension of output filename not valid.\r\n");
   369 			RDebug::Print(KCentRepConvTool);
   370 			RDebug::Print(KUnmatchExt, &iCmd);
   371 
   372 			iScrnOutput->Printf(KUnmatchExt, &iCmd);
   373 			User::Leave(KErrArgument);
   374 			}
   375 		}
   376 	else
   377 		{
   378 		EmptyOutFileName = ETrue;
   379 		outFileExt.Set(correctExt);
   380 		}
   381 		
   382 	TPtrC p;
   383 
   384 	if (EmptyOutFileName)
   385 		{
   386 		const TInt KFilePlusExtLen = KNumDigitsInUID + 4; // e.g. 01234567.cre
   387 		TBuf<KFilePlusExtLen> newName(outFileName);
   388 		newName.Append(correctExt);
   389 		
   390 		p.Set(iOutputPath.DriveAndPath());
   391 		TParse newpath;
   392 		newpath.Set(newName, NULL, &p);
   393 		
   394 		p.Set(newpath.FullName());
   395 		iOutputPath.Set(p, NULL, NULL);
   396 		}
   397 	
   398 	// Check output file is in other's private data cage
   399 	p.Set(iOutputPath.FullName());	
   400 	if ( InOthersPrivatePath(p) )
   401 		{
   402 		_LIT(KOutfileInDataCage, "Cannot write output file %S because it is in private data cage.\r\n");
   403 		RDebug::Print(KCentRepConvTool);
   404 		RDebug::Print(KOutfileInDataCage, &p);
   405 
   406 		iScrnOutput->Printf(KOutfileInDataCage, &p);
   407 		User::Leave(KErrAccessDenied);
   408 		}
   409 
   410 	// Check saving output to read only drive.
   411 	p.Set(iOutputPath.DriveAndPath());	
   412 	TBool isReadOnly;
   413 	TInt ret;
   414 	ret = BaflUtils::DiskIsReadOnly(iFs, p, isReadOnly);
   415 	if (ret == KErrNone)
   416 		{
   417 		if (isReadOnly)
   418 			{
   419 			_LIT(KWriteToReadOnly, "Bad argument: output dir %S is in read only drive.\r\n");
   420 			RDebug::Print(KCentRepConvTool);
   421 			RDebug::Print(KWriteToReadOnly, &p);
   422 
   423 			iScrnOutput->Printf(KWriteToReadOnly, &p);
   424 			User::Leave(KErrArgument);
   425 			}
   426 		}
   427 
   428 	ret = iFs.MkDirAll(p);
   429 	if (ret != KErrNone && ret != KErrAlreadyExists)
   430 		{
   431 		_LIT(KCreateOutpathFail, "Create output path %S failed, err %d.\r\n");
   432 		RDebug::Print(KCentRepConvTool);
   433 		RDebug::Print(KCreateOutpathFail, &p, ret);
   434 
   435 		iScrnOutput->Printf(KCreateOutpathFail, &p, ret);
   436 		User::Leave(ret);
   437 		}
   438 	}
   439 
   440 //
   441 // Open a RWriteStream on top of a CDirectFileStore. Call
   442 // CSharedRepository's ExternalizeCre method to write the 
   443 // settings to file.
   444 void CCentRepConvTool::ExternalizeToCreL()
   445 	{
   446 	// Create file store
   447 	CDirectFileStore* store = CDirectFileStore::ReplaceLC(iFs,
   448 		iOutputPath.FullName(), (EFileWrite | EFileShareExclusive));
   449 	const TUid uid2  = KNullUid;
   450 	store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ; 
   451 		
   452 	// Write the stream index/dictionary as root stream within the store
   453 	// so we can access it when we do a restore later on
   454 	RStoreWriteStream rootStream ;
   455 	TStreamId rootStreamId = rootStream.CreateLC(*store) ;
   456 	iCentRepShrepos->ExternalizeCre(rootStream);
   457 	rootStream.CommitL();
   458 		
   459 	CleanupStack::PopAndDestroy(&rootStream) ;
   460 	store->SetRootL(rootStreamId);
   461 	store->CommitL();
   462 	CleanupStack::PopAndDestroy(store); 	
   463 	}
   464 
   465 //
   466 // Check if given path is located in some other process's
   467 // private data cage
   468 TBool CCentRepConvTool::InOthersPrivatePath(const TDesC& aFullPathName)
   469 	{
   470 	_LIT(KPrivate, "\\private\\");
   471 	const TInt KPosAfterDrive = 2;
   472 	return aFullPathName.FindF(KPrivate) == KPosAfterDrive &&
   473 		   aFullPathName.FindF(iMyDataCage) == KErrNotFound;
   474 	}