os/persistentdata/persistentstorage/centralrepository/convtool/src/CentRepConvTool.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/centralrepository/convtool/src/CentRepConvTool.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,474 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32const.h>
1.20 +#include <e32debug.h>
1.21 +#include <bautils.h>
1.22 +#include <s32file.h>
1.23 +#include "CentRepConvTool.h"
1.24 +#include "shrepos.h"
1.25 +#include "inifile.h"
1.26 +#include "srvres.h"
1.27 +#include "srvparams.h"
1.28 +
1.29 +
1.30 +_LIT(KCentRepConvTool, "CentRep Conversion Tool:");
1.31 +
1.32 +const TInt KNumDigitsInUID = 8;
1.33 +
1.34 +//
1.35 +// factory method
1.36 +CCentRepConvTool* CCentRepConvTool::NewL(const TDesC& aCmd, RFs& aFs, TBool aWaitForAck)
1.37 + {
1.38 + CCentRepConvTool* self = new(ELeave) CCentRepConvTool(aCmd, aFs);
1.39 + CleanupStack::PushL(self);
1.40 + self->ConstructL(aWaitForAck);
1.41 + CleanupStack::Pop(self);
1.42 + return self;
1.43 + }
1.44 +
1.45 +//
1.46 +// Constructor
1.47 +CCentRepConvTool::CCentRepConvTool(const TDesC& aCmd, RFs& aFs)
1.48 + : iCmd(aCmd), iFs(aFs), iTextToBin(ETrue), iRepUid(KNullUid),
1.49 + iMyDataCage(KNullDesC), iDefaultPath(KNullDesC)
1.50 + {
1.51 + }
1.52 +
1.53 +//
1.54 +// two phase construct
1.55 +void CCentRepConvTool::ConstructL(TBool aWaitForAck)
1.56 + {
1.57 + iScrnOutput = CConsolePrint::NewL(aWaitForAck);
1.58 + iFs.PrivatePath(iMyDataCage);
1.59 +
1.60 + // set default I/O path
1.61 + _LIT(KDefaultPathMask, "_:\\");
1.62 + iDefaultPath.Copy(KDefaultPathMask);
1.63 + iDefaultPath[0] = 'A' + static_cast<TInt>(RFs::GetSystemDrive());
1.64 + }
1.65 +
1.66 +//
1.67 +// destructor
1.68 +CCentRepConvTool::~CCentRepConvTool()
1.69 + {
1.70 + delete iScrnOutput;
1.71 + delete iCentRepShrepos;
1.72 + }
1.73 +
1.74 +//
1.75 +// setter
1.76 +void CCentRepConvTool::SetOutputMode(TBool aWaitForAck)
1.77 + {
1.78 + iScrnOutput->SetWaitMode(aWaitForAck);
1.79 + }
1.80 +
1.81 +//
1.82 +// Extract input and output path from cmd line, determine text to
1.83 +// binary or binary to text, and invoke code in CentRep server classes
1.84 +// to do conversion.
1.85 +void CCentRepConvTool::ProcessCmdL()
1.86 + {
1.87 + _LIT(KSuccessMsg,"Output saved as: %S\r\n");
1.88 +
1.89 + TPtrC inputPath(KNullDesC);
1.90 + TPtrC outputPath(KNullDesC);
1.91 + ParseCmdLineL(inputPath, outputPath);
1.92 +
1.93 + // default input & output path is system drive root folder
1.94 +
1.95 + iInputPath.Set(inputPath, NULL, NULL);
1.96 + if (!iInputPath.DrivePresent() && !iInputPath.PathPresent())
1.97 + {
1.98 + iInputPath.Set(inputPath, NULL, &iDefaultPath);
1.99 + }
1.100 +
1.101 + iOutputPath.Set(outputPath, NULL, NULL);
1.102 + if (!iOutputPath.DrivePresent() && !iOutputPath.PathPresent())
1.103 + {
1.104 + iOutputPath.Set(outputPath, NULL, &iDefaultPath);
1.105 + }
1.106 +
1.107 + // VerifyInputPathL must be call before VerifyOutputPathL!
1.108 + VerifyInputPathL();
1.109 + VerifyOutputPathL();
1.110 +
1.111 + // Get UID from input filename
1.112 + TLex lex(iInputPath.Name());
1.113 + TUint32 intvalue;
1.114 + lex.Val(intvalue, EHex);
1.115 + iRepUid.iUid = intvalue;
1.116 +
1.117 + TRAPD(err, DoConversionL());
1.118 + if (err != KErrNone)
1.119 + {
1.120 + if (err == KErrCorrupt)
1.121 + {
1.122 + _LIT(KCorruptError, "Input file contains corrupted entries.\r\n");
1.123 + RDebug::Print(KCentRepConvTool);
1.124 + RDebug::Print(KCorruptError);
1.125 + iScrnOutput->Printf(KCorruptError);
1.126 + }
1.127 + User::Leave(err);
1.128 + }
1.129 +
1.130 + // Success
1.131 + iScrnOutput->Printf(KSuccessMsg, &(iOutputPath.FullName()));
1.132 + }
1.133 +
1.134 +//
1.135 +void CCentRepConvTool::DoConversionL()
1.136 + {
1.137 + iCentRepShrepos = CSharedRepository::NewL(iRepUid);
1.138 +
1.139 + if (iTextToBin)
1.140 + {
1.141 + HBufC* tempIniFileName = iInputPath.FullName().AllocLC();
1.142 + CIniFileIn* iniFile = NULL;
1.143 + TInt ret=CIniFileIn::NewLC(iFs,iniFile,*tempIniFileName);
1.144 + if (ret==KErrCorrupt)
1.145 + User::LeaveIfError(iFs.Delete(*tempIniFileName));
1.146 + User::LeaveIfError(ret);
1.147 + User::LeaveIfError(iCentRepShrepos->ReloadContentL(*iniFile));
1.148 + CleanupStack::PopAndDestroy(2); // tempIniFileName, iniFile
1.149 + ExternalizeToCreL();
1.150 + }
1.151 + else
1.152 + {
1.153 + CDirectFileStore* store = CDirectFileStore::OpenLC(iFs,
1.154 + iInputPath.FullName(), EFileRead|EFileShareReadersOnly);
1.155 + if (store->Type()[0] != KDirectFileStoreLayoutUid)
1.156 + {
1.157 + CleanupStack::PopAndDestroy(store);
1.158 + User::Leave(KErrCorrupt);
1.159 + }
1.160 +
1.161 + // Get the root stream and attempt to read the index from it
1.162 + TStreamId rootStreamId = store->Root() ;
1.163 + RStoreReadStream rootStream ;
1.164 + rootStream.OpenLC(*store, rootStreamId);
1.165 + // Internalize the repository
1.166 +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
1.167 + TUint8 creVersion;
1.168 +#endif
1.169 + iCentRepShrepos->InternalizeCreL(rootStream
1.170 +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
1.171 + ,creVersion
1.172 +#endif
1.173 + );
1.174 + CleanupStack::PopAndDestroy(&rootStream);
1.175 + CleanupStack::PopAndDestroy(store);
1.176 +
1.177 + iCentRepShrepos->DoCommitChangesToIniFileL(iOutputPath.FullName()
1.178 +#ifdef SYMBIAN_CENTREP_SUPPORT_MULTIROFS
1.179 + ,creVersion
1.180 +#endif
1.181 + );
1.182 + }
1.183 + }
1.184 +
1.185 +//
1.186 +// Extract input path and output path from cmd line
1.187 +void CCentRepConvTool::ParseCmdLineL(TPtrC& aInputPath, TPtrC& aOutputPath)
1.188 + {
1.189 + _LIT(KNoWaitSwitch, "-nowait");
1.190 + _LIT(KOutpathSwitch, "-o");
1.191 + _LIT(KHelpSwitch, "-h");
1.192 + _LIT(KBadArg, "Bad input arguments: %S\r\nUsage: CentRepConv [-o output_path] [input_path\\]<repositoryUID>.txt\r\n");
1.193 + _LIT(KHelpMsg, "Usage: CentRepConv [-o output_path] [input_path\\]<repositoryUID>.txt\r\nDefault output_path=%S\r\nDefault input_path=%S\r\n");
1.194 +
1.195 + const TInt KMaxNumTokens = 8; // Arbitrary. only expect 4.
1.196 + TPtrC tokens[KMaxNumTokens];
1.197 + TLex lex(iCmd);
1.198 + TInt i;
1.199 + for (i = 0; !lex.Eos() && i < KMaxNumTokens; i++)
1.200 + {
1.201 + tokens[i].Set(lex.NextToken());
1.202 + }
1.203 +
1.204 + TInt numTokens = i;
1.205 +
1.206 + // Expect: [-nowait] [-o output_path] [input_path\]<rep_UID>.txt
1.207 + for (i = 0; i < numTokens; i++)
1.208 + {
1.209 + if (tokens[i].CompareF(KOutpathSwitch) == 0)
1.210 + {
1.211 + // Got the -o switch.
1.212 + if ((i+2) < numTokens)
1.213 + {
1.214 + aOutputPath.Set(tokens[i+1]);
1.215 + aInputPath.Set(tokens[i+2]);
1.216 + }
1.217 + break;
1.218 + } // tokens[i] == "-o"
1.219 + else if (tokens[i].CompareF(KNoWaitSwitch) == 0)
1.220 + {
1.221 + SetOutputMode(EFalse);
1.222 + continue;
1.223 + }
1.224 + else if (tokens[i].FindF(KHelpSwitch) == 0)
1.225 + {
1.226 + numTokens = 0; // indicator for help message
1.227 + break;
1.228 + }
1.229 + else if ('-' == tokens[i][0])
1.230 + {
1.231 + continue; // unknown switch, assume intended for system
1.232 + }
1.233 +
1.234 + // No options. Token must be input file name.
1.235 + aInputPath.Set(tokens[i]);
1.236 + break;
1.237 + } // for
1.238 +
1.239 + if (0 == numTokens)
1.240 + {
1.241 + RDebug::Print(KCentRepConvTool);
1.242 + RDebug::Print(KHelpMsg, &iDefaultPath, &iDefaultPath);
1.243 +
1.244 + iScrnOutput->Printf(KHelpMsg, &iDefaultPath, &iDefaultPath);
1.245 + User::Leave(KErrArgument);
1.246 + }
1.247 +
1.248 + // aOutputPath can be blank but aInputPath is mandatory.
1.249 + if (aInputPath.Length() == 0)
1.250 + {
1.251 + RDebug::Print(KCentRepConvTool);
1.252 + RDebug::Print(KBadArg, &iCmd);
1.253 +
1.254 + iScrnOutput->Printf(KBadArg, &iCmd);
1.255 + User::Leave(KErrArgument);
1.256 + }
1.257 + }
1.258 +
1.259 +//
1.260 +// Validate the input filenames.
1.261 +void CCentRepConvTool::VerifyInputPathL()
1.262 + {
1.263 + // Check input file is .txt or .cre
1.264 + iTextToBin = (iInputPath.Ext().CompareF(*TServerResources::iIniExt) == 0);
1.265 + TBool binInput = !iTextToBin && (iInputPath.Ext().CompareF(*TServerResources::iCreExt) == 0);
1.266 +
1.267 + if (!iTextToBin && !binInput)
1.268 + {
1.269 + _LIT(KBadExt, "Bad input filename: %S\r\nInput file extension must be %S or %S\r\n");
1.270 + RDebug::Print(KCentRepConvTool);
1.271 + RDebug::Print(KBadExt, &iCmd, TServerResources::iIniExt,
1.272 + TServerResources::iCreExt);
1.273 +
1.274 + iScrnOutput->Printf(KBadExt, &iCmd, TServerResources::iIniExt,
1.275 + TServerResources::iCreExt);
1.276 + User::Leave(KErrArgument);
1.277 + }
1.278 +
1.279 + // check input filename is 8 hex digits.
1.280 + TPtrC p(iInputPath.Name());
1.281 + TBool validName = (KNumDigitsInUID == p.Length());
1.282 +
1.283 + if (validName)
1.284 + {
1.285 + TLex lex(p);
1.286 + for (TInt i = 0; validName && i<KNumDigitsInUID; i++)
1.287 + {
1.288 + if (lex.Peek().IsHexDigit())
1.289 + {
1.290 + lex.Inc();
1.291 + }
1.292 + else
1.293 + {
1.294 + validName = EFalse;
1.295 + }
1.296 + } // for
1.297 + } // if validName
1.298 +
1.299 + if (!validName)
1.300 + {
1.301 + _LIT(KBadRepUid, "Input filename in %S is not a valid UID.\r\nExpect 8 hex digits.\r\n");
1.302 + RDebug::Print(KCentRepConvTool);
1.303 + RDebug::Print(KBadRepUid, &iCmd);
1.304 +
1.305 + iScrnOutput->Printf(KBadRepUid, &iCmd);
1.306 + User::Leave(KErrArgument);
1.307 + }
1.308 +
1.309 + p.Set(iInputPath.FullName());
1.310 +
1.311 + if ( InOthersPrivatePath(p) )
1.312 + {
1.313 + _LIT(KInfileCaged, "Cannot access input file %S because it is in private data cage.\r\n");
1.314 + RDebug::Print(KCentRepConvTool);
1.315 + RDebug::Print(KInfileCaged, &p);
1.316 +
1.317 + iScrnOutput->Printf(KInfileCaged, &p);
1.318 + User::Leave(KErrAccessDenied);
1.319 + }
1.320 +
1.321 + if (!BaflUtils::FileExists(iFs, p))
1.322 + {
1.323 + _LIT(KInFileNotExists, "Input file %S does not exist.\r\n");
1.324 + RDebug::Print(KCentRepConvTool);
1.325 + RDebug::Print(KInFileNotExists, &p);
1.326 +
1.327 + iScrnOutput->Printf(KInFileNotExists, &p);
1.328 + User::Leave(KErrNotFound);
1.329 + }
1.330 + }
1.331 +
1.332 +//
1.333 +// Validate the output filenames.
1.334 +void CCentRepConvTool::VerifyOutputPathL()
1.335 +{
1.336 + // If output filename is not specified, fill in the missing parts.
1.337 + TBool EmptyOutFileName = EFalse;
1.338 +
1.339 + TPtrC outFileName(iOutputPath.Name());
1.340 + if (outFileName.Length())
1.341 + {
1.342 + if (0 != outFileName.CompareF(iInputPath.Name()))
1.343 + {
1.344 + _LIT(KUnmatchFilenames, "Bad input: %S\r\nInput filename does not match output filename.\r\n");
1.345 + RDebug::Print(KCentRepConvTool);
1.346 + RDebug::Print(KUnmatchFilenames, &iCmd);
1.347 +
1.348 + iScrnOutput->Printf(KUnmatchFilenames, &iCmd);
1.349 + User::Leave(KErrArgument);
1.350 + }
1.351 + }
1.352 + else
1.353 + {
1.354 + EmptyOutFileName = ETrue;
1.355 + outFileName.Set(iInputPath.Name());
1.356 + }
1.357 +
1.358 +
1.359 + TPtrC correctExt(*TServerResources::iCreExt);
1.360 + TPtrC outFileExt(iOutputPath.Ext());
1.361 + if (!iTextToBin)
1.362 + {
1.363 + correctExt.Set(*TServerResources::iIniExt);
1.364 + }
1.365 +
1.366 + if (outFileExt.Length())
1.367 + {
1.368 + // If output filename is specified, extension should match conversion.
1.369 + if (0 != outFileExt.CompareF(correctExt))
1.370 + {
1.371 + _LIT(KUnmatchExt, "Bad input: %S\r\nExtension of output filename not valid.\r\n");
1.372 + RDebug::Print(KCentRepConvTool);
1.373 + RDebug::Print(KUnmatchExt, &iCmd);
1.374 +
1.375 + iScrnOutput->Printf(KUnmatchExt, &iCmd);
1.376 + User::Leave(KErrArgument);
1.377 + }
1.378 + }
1.379 + else
1.380 + {
1.381 + EmptyOutFileName = ETrue;
1.382 + outFileExt.Set(correctExt);
1.383 + }
1.384 +
1.385 + TPtrC p;
1.386 +
1.387 + if (EmptyOutFileName)
1.388 + {
1.389 + const TInt KFilePlusExtLen = KNumDigitsInUID + 4; // e.g. 01234567.cre
1.390 + TBuf<KFilePlusExtLen> newName(outFileName);
1.391 + newName.Append(correctExt);
1.392 +
1.393 + p.Set(iOutputPath.DriveAndPath());
1.394 + TParse newpath;
1.395 + newpath.Set(newName, NULL, &p);
1.396 +
1.397 + p.Set(newpath.FullName());
1.398 + iOutputPath.Set(p, NULL, NULL);
1.399 + }
1.400 +
1.401 + // Check output file is in other's private data cage
1.402 + p.Set(iOutputPath.FullName());
1.403 + if ( InOthersPrivatePath(p) )
1.404 + {
1.405 + _LIT(KOutfileInDataCage, "Cannot write output file %S because it is in private data cage.\r\n");
1.406 + RDebug::Print(KCentRepConvTool);
1.407 + RDebug::Print(KOutfileInDataCage, &p);
1.408 +
1.409 + iScrnOutput->Printf(KOutfileInDataCage, &p);
1.410 + User::Leave(KErrAccessDenied);
1.411 + }
1.412 +
1.413 + // Check saving output to read only drive.
1.414 + p.Set(iOutputPath.DriveAndPath());
1.415 + TBool isReadOnly;
1.416 + TInt ret;
1.417 + ret = BaflUtils::DiskIsReadOnly(iFs, p, isReadOnly);
1.418 + if (ret == KErrNone)
1.419 + {
1.420 + if (isReadOnly)
1.421 + {
1.422 + _LIT(KWriteToReadOnly, "Bad argument: output dir %S is in read only drive.\r\n");
1.423 + RDebug::Print(KCentRepConvTool);
1.424 + RDebug::Print(KWriteToReadOnly, &p);
1.425 +
1.426 + iScrnOutput->Printf(KWriteToReadOnly, &p);
1.427 + User::Leave(KErrArgument);
1.428 + }
1.429 + }
1.430 +
1.431 + ret = iFs.MkDirAll(p);
1.432 + if (ret != KErrNone && ret != KErrAlreadyExists)
1.433 + {
1.434 + _LIT(KCreateOutpathFail, "Create output path %S failed, err %d.\r\n");
1.435 + RDebug::Print(KCentRepConvTool);
1.436 + RDebug::Print(KCreateOutpathFail, &p, ret);
1.437 +
1.438 + iScrnOutput->Printf(KCreateOutpathFail, &p, ret);
1.439 + User::Leave(ret);
1.440 + }
1.441 + }
1.442 +
1.443 +//
1.444 +// Open a RWriteStream on top of a CDirectFileStore. Call
1.445 +// CSharedRepository's ExternalizeCre method to write the
1.446 +// settings to file.
1.447 +void CCentRepConvTool::ExternalizeToCreL()
1.448 + {
1.449 + // Create file store
1.450 + CDirectFileStore* store = CDirectFileStore::ReplaceLC(iFs,
1.451 + iOutputPath.FullName(), (EFileWrite | EFileShareExclusive));
1.452 + const TUid uid2 = KNullUid;
1.453 + store->SetTypeL(TUidType(KDirectFileStoreLayoutUid, uid2, KServerUid3)) ;
1.454 +
1.455 + // Write the stream index/dictionary as root stream within the store
1.456 + // so we can access it when we do a restore later on
1.457 + RStoreWriteStream rootStream ;
1.458 + TStreamId rootStreamId = rootStream.CreateLC(*store) ;
1.459 + iCentRepShrepos->ExternalizeCre(rootStream);
1.460 + rootStream.CommitL();
1.461 +
1.462 + CleanupStack::PopAndDestroy(&rootStream) ;
1.463 + store->SetRootL(rootStreamId);
1.464 + store->CommitL();
1.465 + CleanupStack::PopAndDestroy(store);
1.466 + }
1.467 +
1.468 +//
1.469 +// Check if given path is located in some other process's
1.470 +// private data cage
1.471 +TBool CCentRepConvTool::InOthersPrivatePath(const TDesC& aFullPathName)
1.472 + {
1.473 + _LIT(KPrivate, "\\private\\");
1.474 + const TInt KPosAfterDrive = 2;
1.475 + return aFullPathName.FindF(KPrivate) == KPosAfterDrive &&
1.476 + aFullPathName.FindF(iMyDataCage) == KErrNotFound;
1.477 + }