First public contribution.
1 // Copyright (c) 2008-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
18 #include <s32fileiter.h>
20 RTest TheTest(_L("t_storetoc test"));
23 TBuf<KMaxFileName> TheFileName;
25 CPermanentFileStore* TheStore = NULL;
27 void DeleteTestFiles()
31 (void)TheFs.Delete(TheFileName);
34 ///////////////////////////////////////////////////////////////////////////////////////
35 ///////////////////////////////////////////////////////////////////////////////////////
36 //Test macros and functions
37 void Check(TInt aValue, TInt aLine)
42 TheTest(EFalse, aLine);
45 void Check(TInt aValue, TInt aExpected, TInt aLine)
47 if(aValue != aExpected)
50 TheTest.Printf(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue);
51 TheTest(EFalse, aLine);
54 #define TEST(arg) ::Check((arg), __LINE__)
55 #define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__)
57 ///////////////////////////////////////////////////////////////////////////////////////
59 void CreateTestEnv(TInt aDriveNo)
62 TInt err = TheFs.DriveToChar(aDriveNo, ch);
67 drvName[1] = TChar(':');
69 _LIT(KTestFile, "c:\\stor-tst\\t_storetoc.dat");
72 parse.Set(drvName, &KTestFile, 0);
73 const TDesC& dbFilePath = parse.FullName();
74 TheFileName.Copy(dbFilePath);
76 err = TheFs.MkDir(parse.DriveAndPath());
77 TEST(err == KErrNone || err == KErrAlreadyExists);
80 ///////////////////////////////////////////////////////////////////////////////////////
81 ////////////////////// TTocTestBase ///////////////////////////////
82 ///////////////////////////////////////////////////////////////////////////////////////
83 //Base TOC test class.
84 //It offers the folowing functions: Prepare(), Test() and Verify().
85 //The test algorithm is:
86 // =================================
87 // void TestFunc(TTocTestBase& aTestObj)
89 // aTestObj.Prepare();
90 // [simulate file system error];
91 // TInt err = aTestObj.Test();
92 // [clear file system error];
93 // aTestObj.Verify(err);
95 // =================================
96 //The class has two private pure virtual methods, which have to be overriden in derived classes:
97 // DoPrepareL() - instance specific test preparation;
98 // DoVerify() - instance specific test verification;
108 TEST(TheStore == NULL);
109 TRAPD(err, DoPrepareL());
110 TEST2(err, KErrNone);
114 TEST(TheStore != NULL);
115 TRAPD(err, {TheStore->CompactL(); TheStore->CommitL();});
120 void Verify(TInt aTestErr)
122 TEST(TheStore == NULL);
123 TRAPD(err, DoVerifyL(aTestErr));
124 TEST2(err, KErrNone);
128 TStreamId WriteNewStreamL(const TDesC8& aStreamData)
130 TEST(TheStore != NULL);
131 RStoreWriteStream stream;
132 TStreamId streamId = stream.CreateLC(*TheStore);
133 stream.WriteL(aStreamData);
136 CleanupStack::PopAndDestroy(&stream);
141 virtual void DoPrepareL() = 0;
142 virtual void DoVerifyL(TInt aTestErr) = 0;
146 ///////////////////////////////////////////////////////////////////////////////////////
147 ////////////////////// TBaseTocEntryTest ////////////////////////
148 ///////////////////////////////////////////////////////////////////////////////////////
150 //Do not change/shift the next lines, because "new line/space" characters will be inserted in the string!
151 _LIT8(KStreamData1, "-01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD");
152 _LIT8(KStreamData1_2, "ABCDEFGH-41-ABCD-42-ABCD-43-A\
153 -33-ABCD-34-ABCD-35-ABCD-36-ABCD-37-ABCD-38-ABCD-39-ABCD-40-ABCD\
154 -25-ABCD-26-ABCD-27-ABCD-28-ABCD-29-ABCD-30-ABCD-31-ABCD-32-ABCD\
155 -17-ABCD-18-ABCD-19-ABCD-20-ABCD-21-ABCD-22-ABCD-23-ABCD-24-ABCD\
156 -09-ABCD-10-ABCD-11-ABCD-12-ABCD-13-ABCD-14-ABCD-15-ABCD-16-ABCD");
157 _LIT8(KStreamData1_3, "0123456789");
159 //"Base TOC entry" test.
160 //When a stream is relocated, its base TOC entry needs 2 "file write" (for "atomic block write" media) operations, because
161 //the TOC entry is split over a block boundary.
162 //This test class uses a set of test data, which puts the TOC entry of the relocated stream at position
163 //510 in the file (TOC entry length - 5 bytes).
164 class TBaseTocEntryTest : public TTocTestBase
167 TBaseTocEntryTest() :
168 iStreamId1(KNullStreamIdValue),
169 iStreamId2(KNullStreamIdValue),
170 iStreamId3(KNullStreamIdValue)
177 TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite);
178 TheStore->SetTypeL(TheStore->Layout());
181 iStreamId1 = WriteNewStreamL(KStreamData1);
182 TheStore->SetRootL(iStreamId1);
184 iStreamId2 = WriteNewStreamL(KStreamData1_2);
185 iStreamId3 = WriteNewStreamL(KStreamData1_3);
187 TheStore->DeleteL(iStreamId2);
190 CleanupStack::Pop(TheStore);
193 virtual void DoVerifyL(TInt)
195 TEST(TheStore == NULL);
196 TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite);
197 RPermanentFileStoreIter iter;
198 iter.ResetLC(*TheStore);
200 TStreamId streamId = iter.NextL();
201 TEST(streamId == iStreamId1);
202 RStoreReadStream strm;
203 strm.OpenLC(*TheStore, streamId);
204 TEST2(strm.Source()->SizeL(), KStreamData1().Length());
205 TBuf8<sizeof(KStreamData1)> buf;
206 strm.ReadL(buf, KStreamData1().Length());
207 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData1().Ptr(), KStreamData1().Length()), 0);
208 CleanupStack::PopAndDestroy(&strm);
210 streamId = iter.NextL();
211 TEST(streamId == iStreamId3);
212 strm.OpenLC(*TheStore, streamId);
213 TEST2(strm.Source()->SizeL(), KStreamData1_3().Length());
214 strm.ReadL(buf, KStreamData1_3().Length());
215 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData1_3().Ptr(), KStreamData1_3().Length()), 0);
216 CleanupStack::PopAndDestroy(&strm);
218 streamId = iter.NextL();
219 TEST(streamId == KNullStreamIdValue);
221 CleanupStack::PopAndDestroy(&iter);
222 CleanupStack::PopAndDestroy(TheStore);
227 TStreamId iStreamId1;
228 TStreamId iStreamId2;
229 TStreamId iStreamId3;
233 ///////////////////////////////////////////////////////////////////////////////////////
234 ////////////////////// TDeltaTocEntryTest /////////////////////////
235 ///////////////////////////////////////////////////////////////////////////////////////
237 //Do not change/shift the next lines, because "new line/space" characters will be inserted in the string!
238 _LIT8(KStreamData2, "\
239 -01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD\
240 -09-ABCD-10-ABCD-11-ABCD-12");
241 _LIT8(KStreamData2_2, "ABC");
242 _LIT8(KStreamData2_3, "012345678");
244 //"Delta TOC entry" test
245 //When a stream is relocated, its delta TOC entry needs 2 "file write" (for "atomic block write" media) operations, because
246 //the TOC entry is split over a block boundary.
247 //This test class uses a set of test data, which puts the TOC entry of the relocated stream at position
248 //507 in the file (TOC entry length - 8 bytes), so the last 4 bytes (stream offset) are split.
249 class TDeltaTocEntryTest : public TTocTestBase
252 TDeltaTocEntryTest() :
253 iStreamId1(KNullStreamIdValue),
254 iStreamId2(KNullStreamIdValue),
255 iStreamId3(KNullStreamIdValue),
256 iStreamId4(KNullStreamIdValue),
257 iStreamId5(KNullStreamIdValue)
262 virtual void DoPrepareL()
264 TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite);
265 TheStore->SetTypeL(TheStore->Layout());
268 iStreamId1 = WriteNewStreamL(KStreamData2);
269 TheStore->SetRootL(iStreamId1);
271 iStreamId2 = WriteNewStreamL(KStreamData2);
272 iStreamId3 = WriteNewStreamL(KStreamData2().Left(KStreamData2().Length() - 1));
273 iStreamId4 = WriteNewStreamL(KStreamData2_2);
274 iStreamId5 = WriteNewStreamL(KStreamData2_3);
276 TheStore->DeleteL(iStreamId4);
279 CleanupStack::Pop(TheStore);
282 virtual void DoVerifyL(TInt)
284 TEST(TheStore == NULL);
285 TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite);
286 RPermanentFileStoreIter iter;
287 iter.ResetLC(*TheStore);
289 TStreamId streamId = iter.NextL();
290 TEST(streamId == iStreamId1);
291 RStoreReadStream strm;
292 strm.OpenLC(*TheStore, streamId);
293 TEST2(strm.Source()->SizeL(), KStreamData2().Length());
294 TBuf8<sizeof(KStreamData2)> buf;
295 strm.ReadL(buf, KStreamData2().Length());
296 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length()), 0);
297 CleanupStack::PopAndDestroy(&strm);
299 streamId = iter.NextL();
300 TEST(streamId == iStreamId2);
301 strm.OpenLC(*TheStore, streamId);
302 TEST2(strm.Source()->SizeL(), KStreamData2().Length());
303 strm.ReadL(buf, KStreamData2().Length());
304 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length()), 0);
305 CleanupStack::PopAndDestroy(&strm);
307 streamId = iter.NextL();
308 TEST(streamId == iStreamId3);
309 strm.OpenLC(*TheStore, streamId);
310 TEST2(strm.Source()->SizeL(), KStreamData2().Length() - 1);
311 strm.ReadL(buf, KStreamData2().Length() - 1);
312 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2().Ptr(), KStreamData2().Length() - 1), 0);
313 CleanupStack::PopAndDestroy(&strm);
315 streamId = iter.NextL();
316 TEST(streamId == iStreamId5);
317 strm.OpenLC(*TheStore, streamId);
318 TEST2(strm.Source()->SizeL(), KStreamData2_3().Length());
319 strm.ReadL(buf, KStreamData2_3().Length());
320 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData2_3().Ptr(), KStreamData2_3().Length()), 0);
321 CleanupStack::PopAndDestroy(&strm);
323 streamId = iter.NextL();
324 TEST(streamId == KNullStreamIdValue);
326 CleanupStack::PopAndDestroy(&iter);
327 CleanupStack::PopAndDestroy(TheStore);
332 TStreamId iStreamId1;
333 TStreamId iStreamId2;
334 TStreamId iStreamId3;
335 TStreamId iStreamId4;
336 TStreamId iStreamId5;
340 ///////////////////////////////////////////////////////////////////////////////////////
341 ////////////////////// TBaseTocReferenceTest //////////////////////
342 ///////////////////////////////////////////////////////////////////////////////////////
344 //Do not change/shift the next lines, because "new line/space" characters will be inserted in the string!
345 _LIT8(KStreamData3, "\
346 -01-ABCD-02-ABCD-03-ABCD-04-ABCD-05-ABCD-06-ABCD-07-ABCD-08-ABCD\
347 -09-ABCD-10-ABCD-11-ABCD-12-ABCD");
348 _LIT8(KStreamData3_2, "ABCDEFGH");
349 _LIT8(KStreamData3_3, "0123456789");
351 //"Base TOC reference" test.
352 //When the base TOC is relocated, the delta TOC reference to the base TOC has to be updated with
353 // 2 "file write" operations (for "atomic block write" media), because the reference is split over a block boundary.
354 //This test class uses a set of test data, which puts the delta TOC reference to the base TOC
355 //at position 511 in the file (reference length - 4 bytes)
356 class TBaseTocReferenceTest : public TTocTestBase
359 TBaseTocReferenceTest() :
360 iStreamId1(KNullStreamIdValue),
361 iStreamId2(KNullStreamIdValue),
362 iStreamId3(KNullStreamIdValue),
363 iStreamId4(KNullStreamIdValue),
364 iStreamId5(KNullStreamIdValue)
369 virtual void DoPrepareL()
371 TheStore = CPermanentFileStore::ReplaceLC(TheFs, TheFileName, EFileWrite);
372 TheStore->SetTypeL(TheStore->Layout());
375 iStreamId1 = WriteNewStreamL(KStreamData3);
376 TheStore->SetRootL(iStreamId1);
378 iStreamId2 = WriteNewStreamL(KStreamData3);
379 iStreamId3 = WriteNewStreamL(KStreamData3().Left(KStreamData3().Length() - 3));
380 iStreamId4 = WriteNewStreamL(KStreamData3_2);
381 iStreamId5 = WriteNewStreamL(KStreamData3_3);
383 TheStore->DeleteL(iStreamId4);
386 CleanupStack::Pop(TheStore);
389 virtual void DoVerifyL(TInt)
391 TEST(TheStore == NULL);
392 TheStore = CPermanentFileStore::OpenLC(TheFs, TheFileName, EFileWrite);
393 RPermanentFileStoreIter iter;
394 iter.ResetLC(*TheStore);
396 TStreamId streamId = iter.NextL();
397 TEST(streamId == iStreamId1);
398 RStoreReadStream strm;
399 strm.OpenLC(*TheStore, streamId);
400 TEST2(strm.Source()->SizeL(), KStreamData3().Length());
401 TBuf8<sizeof(KStreamData3)> buf;
402 strm.ReadL(buf, KStreamData3().Length());
403 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length()), 0);
404 CleanupStack::PopAndDestroy(&strm);
406 streamId = iter.NextL();
407 TEST(streamId == iStreamId2);
408 strm.OpenLC(*TheStore, streamId);
409 TEST2(strm.Source()->SizeL(), KStreamData3().Length());
410 strm.ReadL(buf, KStreamData3().Length());
411 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length()), 0);
412 CleanupStack::PopAndDestroy(&strm);
414 streamId = iter.NextL();
415 TEST(streamId == iStreamId3);
416 strm.OpenLC(*TheStore, streamId);
417 TEST2(strm.Source()->SizeL(), KStreamData3().Length() - 3);
418 strm.ReadL(buf, KStreamData3().Length() - 3);
419 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3().Ptr(), KStreamData3().Length() - 3), 0);
420 CleanupStack::PopAndDestroy(&strm);
422 streamId = iter.NextL();
423 TEST(streamId == iStreamId5);
424 strm.OpenLC(*TheStore, streamId);
425 TEST2(strm.Source()->SizeL(), KStreamData3_3().Length());
426 strm.ReadL(buf, KStreamData3_3().Length());
427 TEST2(Mem::Compare(buf.Ptr(), buf.Length(), KStreamData3_3().Ptr(), KStreamData3_3().Length()), 0);
428 CleanupStack::PopAndDestroy(&strm);
430 streamId = iter.NextL();
431 TEST(streamId == KNullStreamIdValue);
433 CleanupStack::PopAndDestroy(&iter);
434 CleanupStack::PopAndDestroy(TheStore);
439 TStreamId iStreamId1;
440 TStreamId iStreamId2;
441 TStreamId iStreamId3;
442 TStreamId iStreamId4;
443 TStreamId iStreamId5;
447 ///////////////////////////////////////////////////////////////////////////////////////
448 ///////////////////////////////////////////////////////////////////////////////////////
450 void TocTest(TTocTestBase& aTestObj)
452 TInt err = KErrGeneral;
453 for(TInt cnt=1;err!=KErrNone;++cnt)
455 TheTest.Printf(_L("%d\r"), cnt);
457 (void)TheFs.SetErrorCondition(KErrGeneral, cnt);
458 err = aTestObj.Test();
459 (void)TheFs.SetErrorCondition(KErrNone);
460 aTestObj.Verify(err);
462 TheTest.Printf(_L("\n"));
463 TEST2(err, KErrNone);
464 aTestObj.Verify(err);
468 @SYMTestCaseID SYSLIB-STORE-CT-3481
469 @SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed.
470 In a "file I/O error" simulation loop:
471 - Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
472 such that a base TOC entry is split over the block boundary;
473 - Compacts the store;
475 @SYMTestPriority High
476 @SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
477 such that a base TOC entry is split over the block boundary. When the store is compacted
478 and the used media supports atomic "block write" operations, the STORE will update
479 the base TOC entry, which requires a "file write" operation crossing the block boundary.
480 @SYMTestExpectedResults The test should not fail or panic.
483 void BaseTocEntryTest()
485 TBaseTocEntryTest baseTocEntryTestObj;
486 TocTest(baseTocEntryTestObj);
490 @SYMTestCaseID SYSLIB-STORE-CT-3482
491 @SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed.
492 In a "file I/O error" simulation loop:
493 - Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
494 such that a delta TOC entry is split over the block boundary;
495 - Compacts the store;
497 @SYMTestPriority High
498 @SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
499 such that a delta TOC entry is split over the block boundary. When the store is compacted
500 and the used media supports atomic "block write" operations, the STORE will update
501 the delta TOC entry, which requires a "file write" operation crossing the block boundary.
502 @SYMTestExpectedResults The test should not fail or panic.
505 void DeltaTocEntryTest()
507 TDeltaTocEntryTest deltaTocEntryTestObj;
508 TocTest(deltaTocEntryTestObj);
512 @SYMTestCaseID SYSLIB-STORE-CT-3483
513 @SYMTestCaseDesc The test is performed on media, where atomic "block write" operations are guaranteed.
514 In a "file I/O error" simulation loop:
515 - Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
516 such that a base TOC reference is split over the block boundary;
517 - Compacts the store;
519 @SYMTestPriority High
520 @SYMTestActions Creates a CPermanentStoreFile object, stores there carefully selected set of test data,
521 such that a base TOC reference is split over the block boundary. When the store is compacted
522 and the used media supports atomic "block write" operations, the STORE will update
523 the base TOC reference, which requires a "file write" operation crossing the block boundary.
524 @SYMTestExpectedResults The test should not fail or panic.
527 void BaseTocReferenceTest()
529 TBaseTocReferenceTest baseTocReferenceTestObj;
530 TocTest(baseTocReferenceTestObj);
533 ///////////////////////////////////////////////////////////////////////////////////////
537 TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3481 Base TOC entry test "));
540 TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3482 Delta TOC entry test "));
543 TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-STORE-CT-3483 Base TOC reference test "));
544 BaseTocReferenceTest();
547 //The function returns true, if the file system guarantees atomic "block write" operations on aDriveNo.
548 TBool IsBlockAtomic(TInt aDriveNo)
550 __ASSERT_DEBUG(aDriveNo >= EDriveA && aDriveNo <= EDriveZ, User::Invariant());
552 TVolumeIOParamInfo volInfo;
553 TInt err = TheFs.VolumeIOParam(aDriveNo, volInfo);
554 //If VolumeIOParam() succeeds, the media block size is >= 512 bytes and the media block size is power of two - report
555 //that the media supports atomic "block write" operations.
556 const TInt KDefaultMediaBlockSize = 512;
557 return err == KErrNone && volInfo.iBlockSize >= KDefaultMediaBlockSize && (volInfo.iBlockSize & (volInfo.iBlockSize - 1)) == 0;
560 //Returns the number of the drive on which atomic "block write" operations are supported.
561 TInt GetBlockAtomicDriveNo()
563 //Uncomment, if you want to do the test on drive C:
564 //(but you will need also to uncomment 2 lines in CPermanentStoreCoord::FileQoSL())
567 for(TInt driveNo=EDriveA;driveNo<=EDriveZ;++driveNo)
569 TDriveInfo driveInfo;
570 TInt err = TheFs.Drive(driveInfo, driveNo);
573 if(!(driveInfo.iDriveAtt & KDriveAttTransaction))
577 err = TheFs.FileSystemName (thefsname, driveNo);
579 if ((err == KErrNone) && (!(thefsname.MatchF(_L("NTFS"))))) // X86GCC doesn't (yet) support write operations on NTFS partitions
581 if(IsBlockAtomic(driveNo))
591 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
592 // If you want to check that the atomic "block write" optimisation works and the code change is robust, then you
594 // 1) Prove that if the the "file write" operations over a sector boundary are not done properly, the current test will crash
595 // 2) Prove that if the the "file write" operations over a sector boundary are done properly, the current test won't crash
596 // How this could be done:
597 // For (1) - Simulate that the file system for drive C: on the Emulator is transactional.
598 // In order to do that:
599 // - uncomment the "return EDriveC;" statement in the function above (GetBlockAtomicDriveNo());
600 // - go to CPermanentStoreCoord::FileQoSL() function and uncomment the first two lines:
601 // "iFileQos = ETransactional;"
602 // "return iFileQos;"
603 // So, the result of your changes will be: STORE will try to optimize the "file write" operations on drive C:,
604 // because drive C: will be reported as a "transactional" drive. Since the drive C: does not really support "transactional"
605 // operations, the optimization will cause some failures in the current test, if the data block which has to be written,
606 // is split across a sector boundary. In order to make sure that the split will hapen - do step (2).
607 // 2) Declare SYSLIBS_TEST macro in the related variant.hrh file. This change will cause RFileBuf to split the "file write"
608 // operations in two separate operations, if the data block to be written has to be split over a sector boundary.
609 // After the changes, build STORE and run the current test. You must see that the test crashes.
611 // Then, for (2) (a) restore the original code in GetBlockAtomicDriveNo() and (b) CPermanentStoreCoord::FileQoSL() and rebuild STORE.
612 // Rerun the current test and the test must pass.
613 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
619 CTrapCleanup* tc = CTrapCleanup::New();
623 TInt err = TheFs.Connect();
624 TheTest(err == KErrNone);
626 TheTest.Start(_L("Check for \"block atomic write\" drives"));
627 TInt driveNo = GetBlockAtomicDriveNo();
630 TheTest.Printf(_L("Test drive - %c:\r\n"), 'A' + driveNo);
631 TheTest.Printf(_L("The test expects that STORE component is built with SYSLIBS_TEST macro defined\r\n"));
632 CreateTestEnv(driveNo);
638 TheTest.Printf(_L("!!! No \"block atomic write\" drive found!\r\n"));
649 User::Heap().Check();