|
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 } |