os/kernelhwsrv/kerneltest/f32test/filesystem/fat/t_compat32.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1996-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 the License "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 // f32test\fat32\t_compat32.cpp
    15 //
    16 //
    17 
    18 #define __E32TEST_EXTENSION__
    19 
    20 #include <f32file.h>
    21 #include <e32svr.h>
    22 #include <e32test.h>
    23 #include <f32dbg.h>
    24 #include "t_server.h"
    25 
    26 #include "fat_utils.h"
    27 using namespace Fat_Test_Utils;
    28 
    29 RTest test(_L("T_COMPAT32"));
    30 
    31 static RRawDisk TheDisk;
    32 static TFatBootSector gBootSector;
    33 
    34 
    35 static void QuickFormat()
    36     {
    37     FormatFatDrive(TheFs, CurrentDrive(), ETrue);
    38     }
    39 
    40 static void ReadBootSector(TFatBootSector& aBootSector)
    41 	{
    42 
    43     TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, aBootSector);
    44     test(nRes == KErrNone);
    45 
    46     if(!aBootSector.IsValid())
    47         {
    48         test.Printf(_L("Wrong bootsector! Dump:\n"));
    49         aBootSector.PrintDebugInfo();
    50         test(0);
    51         }
    52 	}
    53 
    54 
    55 static void GetBootInfo()
    56 	{
    57 	QuickFormat();
    58 	ReadBootSector(gBootSector);
    59 	}
    60 
    61 enum TNameCase
    62 	{
    63 	EUpper, // Test directory entries with 8.3 uppercase (no VFAT entries expected)
    64 	ELower, // Test directory entries with 8.3 lowercase (   VFAT entries expected)
    65 	EMixed  // Test directory entries with 8.3 mixed     (   VFAT entries expected)
    66 	};
    67 
    68 
    69 /**
    70     Fiddles with root directory entries.
    71     Creates a file, if it has 1 VFAT and 1 DOS dir. entries, places an illegal lower case
    72     symbol to the DOS entry, fixing VFAT name checksums
    73 */
    74 static void DoFiddleWithFileNames(TNameCase aCase)
    75 {
    76 	TFileName fileName = _L("\\WORD");
    77 	TBool expectVfatEntry = EFalse;
    78 
    79 	switch(aCase)
    80 		{
    81 		case EUpper:
    82 			break;
    83 
    84 		case ELower:
    85 			fileName = _L("\\word");
    86 			expectVfatEntry = ETrue;
    87 			break;
    88 
    89 		case EMixed:
    90 			fileName = _L("\\WoRd");
    91 			expectVfatEntry = ETrue;
    92 			break;
    93 
    94 		default:
    95 			test(0);
    96 			break;
    97 		}
    98 
    99 	RFile file;
   100 	TInt r=file.Create(TheFs,fileName,EFileRead);
   101 	test(r==KErrNone);
   102 	file.Close();
   103 //	Assume this file is the first entry in the root directory
   104 
   105 
   106 	r=TheDisk.Open(TheFs,CurrentDrive());
   107 	test(r==KErrNone);
   108 
   109     //-- read 1st dir. entry it can be FAT or VFat , depending on the filename
   110     const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
   111 
   112     TFatDirEntry fatEntry1;
   113 	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
   114 
   115     test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
   116 
   117     if(!fatEntry1.IsVFatEntry())
   118     {//-- we expected FAT entry, everything is OK
   119         test(!expectVfatEntry);
   120     }
   121     else
   122     {//-- we have 2 FAT entries, 1st is VFat, 2nd is DOS.
   123      //-- put lower case letters into DOS entry( not compliant with FAT specs), correct VFat entries checksums,
   124      //-- in this case the system shall correctly deal with the file, using long names.
   125 
   126         test(expectVfatEntry);
   127         test(fatEntry1.iData[0] == 0x41); //-- must have only 2 entries
   128 
   129         //-- read DOS entry now
   130         TFatDirEntry fatEntry2;
   131         TPtr8 ptrEntry2((TUint8*)&fatEntry2,sizeof(TFatDirEntry));
   132         const TInt posEntry2 = posEntry1 + sizeof(TFatDirEntry); //-- dir entry2 position
   133 
   134         test(TheDisk.Read(posEntry2, ptrEntry2)==KErrNone);
   135 
   136         //-- ensure that the name and checksum are correct
   137         test(fatEntry1.iData[13] == CalculateShortNameCheckSum(fatEntry2.Name()));
   138         test(fatEntry2.Name()==_L8("WORD       "));
   139 
   140         //-- put lower case symbol to the DOS entry and fix the checksum
   141         _LIT8(KBadDosName, "Word       ");
   142         fatEntry2.SetName(KBadDosName);
   143         fatEntry1.iData[13] = CalculateShortNameCheckSum(fatEntry2.Name());
   144 
   145         //-- write data to the disk
   146         test(TheDisk.Write(posEntry1, ptrEntry1)==KErrNone);
   147         test(TheDisk.Write(posEntry2, ptrEntry2)==KErrNone);
   148 
   149     }
   150 
   151 	TheDisk.Close();
   152 
   153 }
   154 
   155 //
   156 // Replace a 8.3 filename with upper and lower case letters which is, actually out of FAT specs.
   157 // I.e. VFAT entries are valid, but DOS entry has a lower case symbol, which is wrong.
   158 //
   159 LOCAL_C void Test1(TNameCase aCase)
   160 	{
   161 	test.Next(_L("Replace a file with a wrong DOS entry"));
   162 	QuickFormat();
   163 
   164     //-- N.B. This shall be the before any dir. entries creation in the root directory
   165     //-- because it directly accesses the directory's 1st file
   166     DoFiddleWithFileNames(aCase);
   167 
   168     RFile file;
   169     TInt r;
   170 
   171 	r=file.Replace(TheFs,_L("\\FILE.TMP"),EFileRead);
   172 	test(r==KErrNone);
   173 	r=file.Write(_L8("Hello World"));
   174 	file.Close();
   175 
   176 	r=TheFs.Replace(_L("\\File.tmp"),_L("\\Word"));
   177 	test(r==KErrNone);
   178 
   179 	CDir* entryCount;
   180 	r=TheFs.GetDir(_L("\\*.*"),KEntryAttMaskSupported,ESortNone,entryCount);
   181 	test(r==KErrNone);
   182 	TInt count=entryCount->Count();
   183 
   184 	test(count==1);
   185 	delete entryCount;
   186 	}
   187 
   188 
   189 //
   190 // Renaming a 8.3 filename with upper and lower case letters which is, actually out of FAT specs.
   191 // I.e. VFAT entries are valid, but DOS entry has a lower case symbol, which is wrong.
   192 //
   193 LOCAL_C void Test2(TNameCase aCase)
   194 	{
   195 	test.Next(_L("Rename a file with a wrong DOS entry"));
   196 	QuickFormat();
   197 	RFile file;
   198     TInt r;
   199 
   200     //-- N.B. This shall be the before any dir. entries creation in the root dir
   201     //-- because it directly accesses the directory's 1st file
   202     DoFiddleWithFileNames(aCase);
   203 
   204 	r=file.Create(TheFs,_L("\\TEST"),EFileRead);
   205 	test(r==KErrNone);
   206 	file.Close();
   207 
   208 	r=TheFs.Rename(_L("\\TEST"),_L("\\Word"));
   209 	test(r==KErrAlreadyExists);
   210 	r=TheFs.Delete(_L("\\TEST"));
   211 	test(r==KErrNone);
   212 
   213 	CDir* entryCount;
   214 	r=TheFs.GetDir(_L("\\*.*"),KEntryAttMaskSupported,ESortNone,entryCount);
   215 	test(r==KErrNone);
   216 	TInt count=entryCount->Count();
   217 	test(count==1);
   218 	delete entryCount;
   219 	}
   220 
   221 
   222 //---------------------------------------------
   223 //! @SYMTestCaseID			PBASE-T_COMPAT32-0686
   224 //! @SYMTestType			CT
   225 //! @SYMREQ					DEF115314
   226 //! @SYMTestCaseDesc		Test character '`' (0x60) is recognized as a legal char for short file names.
   227 //! @SYMTestActions			Creates a file named "\x60\x60\x60.TXT", checks only DOS entry is created for
   228 //!							it and its short name equals "```.TXT" instead of "___.TXT"
   229 //! @SYMTestExpectedResults	The operation completes with error code KErrNone;
   230 //! @SYMTestPriority		High
   231 //! @SYMTestStatus			Implemented
   232 //---------------------------------------------
   233 void TestDEF115314()
   234 	{
   235 	test.Next(_L("Test DEF115314: TTG:<`(0x60) code cannot be used as valid Short File Name>"));
   236 	QuickFormat();
   237 	RFile file;
   238     TInt r;
   239 
   240     TFileName fn;
   241     fn.Format(_L("%c:\\\x60\x60\x60.TXT"), (TUint8)gDriveToTest);
   242 
   243     r = TheFs.Delete(fn);
   244 	test(r==KErrNone || r==KErrNotFound);
   245 
   246 	r = file.Create(TheFs, fn, EFileRead);
   247 	test(r==KErrNone);
   248 	file.Close();
   249 
   250 	r=TheDisk.Open(TheFs,CurrentDrive());
   251 	test(r==KErrNone);
   252 
   253     //-- read 1st dir. it should be DOS Entry
   254     const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
   255     TFatDirEntry fatEntry1;
   256 	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
   257     test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
   258     TheDisk.Close();
   259     test(!fatEntry1.IsVFatEntry());
   260 
   261     // tests short name
   262     TFileName sn;
   263     r = TheFs.GetShortName(fn, sn);
   264     test(r==KErrNone);
   265     test(sn.Compare(_L("```.TXT"))==0);
   266 
   267     r = TheFs.Delete(fn);
   268 	test(r==KErrNone);
   269 	}
   270 
   271 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
   272 _LIT(KTestLocale, 			"t_tlocl_cp932.dll");
   273 _LIT(KTestUnicodeFileName, 	"\\\x65B0\x6587\x4EF6");
   274 #endif //_DEBUG || _DEBUG_RELEASE
   275 
   276 //---------------------------------------------
   277 //! @SYMTestCaseID			PBASE-T_COMPAT32-0685
   278 //! @SYMTestType			CT
   279 //! @SYMREQ					DEF113633
   280 //! @SYMTestCaseDesc		Test FAT volume creates VFat entries for short unicode named files
   281 //! @SYMTestActions			Enables FatUtilityFunctions. Loads cp932 codepage dll. Create a file
   282 //!							named as "\x65B0\x6587\x4EF6", checks both a VFat entry and a DOS
   283 //!							entry have been created for the file.
   284 //! @SYMTestExpectedResults	The operation completes with error code KErrNone;
   285 //! @SYMTestPriority		High
   286 //! @SYMTestStatus			Implemented
   287 //---------------------------------------------
   288 void TestDEF113633()
   289 	{
   290 	test.Next(_L("Test DEF113633 - FAT should create VFat entries for unicode character contained file names"));
   291 #if defined(_DEBUG) || defined(_DEBUG_RELEASE)
   292 	QuickFormat();
   293 	RFile file;
   294     TInt r;
   295     TInt drvNum;
   296 
   297     r = TheFs.CharToDrive(gDriveToTest,drvNum);
   298 	test(r==KErrNone);
   299 
   300     // turn on FatUtilityFunctions
   301     r = TheFs.ControlIo(drvNum, KControlIoEnableFatUtilityFunctions);
   302 	test(r==KErrNone);
   303 
   304 	// load cp932 codepage dll
   305 	r = UserSvr::ChangeLocale(KTestLocale);
   306 	test(r==KErrNone);
   307 
   308     // create file "\x65B0\x6587\x4EF6", check DOS entry & VFat entry
   309 	r = file.Create(TheFs, KTestUnicodeFileName, EFileRead);
   310 	test(r==KErrNone);
   311 	file.Close();
   312 
   313 	r=TheDisk.Open(TheFs,CurrentDrive());
   314 	test(r==KErrNone);
   315 
   316     //-- read 1st dir. it should be VFat
   317 //    const TInt posEntry1=gRootDirStart; //-- dir entry1 position
   318     const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
   319     TFatDirEntry fatEntry1;
   320 	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
   321 
   322     test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
   323 
   324     test(fatEntry1.IsVFatEntry());
   325 
   326     test(fatEntry1.iData[0] == 0x41); //-- must have only 2 entries
   327 
   328     //-- read DOS entry now
   329     TFatDirEntry fatEntry2;
   330     TPtr8 ptrEntry2((TUint8*)&fatEntry2,sizeof(TFatDirEntry));
   331     const TInt posEntry2 = posEntry1 + sizeof(TFatDirEntry); //-- dir entry2 position
   332 
   333     test(TheDisk.Read(posEntry2, ptrEntry2)==KErrNone);
   334 
   335     //-- ensure that the name and checksum are correct
   336     test(!fatEntry2.IsVFatEntry());
   337     test(fatEntry1.iData[13] == CalculateShortNameCheckSum(fatEntry2.Name()));
   338 
   339     // delete file
   340     TheDisk.Close();
   341     r = TheFs.Delete(KTestUnicodeFileName);
   342 	test(r==KErrNone);
   343 
   344 	// turn off FatUtilityFunctions
   345 	r = TheFs.ControlIo(drvNum, KControlIoDisableFatUtilityFunctions);
   346 	test(r==KErrNone);
   347 
   348 #else
   349 	test.Printf(_L("Test only runs on DEBUG builds, see test logs of debug builds for details."));
   350 #endif  // _DEBUG) || _DEBUG_RELEASE
   351 	}
   352 
   353 
   354 
   355 
   356 //---------------------------------------------
   357 // If the parent directory of a directory is the root directory,
   358 // the '..' entry should point to start cluster 0 in any case
   359 //---------------------------------------------
   360 void TestPDEF116912()
   361 	{
   362 	test.Next(_L("Test PDEF116912 - Check that '..' parent cluster address is 0 after renaming\n"));
   363 
   364   	TInt drvNum;
   365 	test(KErrNone == TheFs.CharToDrive(gDriveToTest, drvNum));
   366 
   367 	if(!Is_Fat32(TheFs, drvNum))
   368 		{
   369 		_LIT(KMessage, "Test only applicable to FAT32 file systems. Skipping.\n");
   370 		test.Printf(KMessage);
   371 		return;
   372 		}
   373 
   374 	QuickFormat();
   375 
   376 	_LIT(KDirA, "\\dirA\\");
   377 	_LIT(KDirB, "\\dirB\\");
   378 
   379 	test(KErrNone == TheFs.MkDir(KDirA));
   380 	test(KErrNone == TheFs.Rename(KDirA, KDirB));
   381 
   382 	test(gBootSector.IsValid());
   383 	TInt mediaPosition = gBootSector.RootDirStartSector() * gBootSector.BytesPerSector();
   384 
   385 	TFatDirEntry dirEntry;
   386 	TPtr8 ptrEntry((TUint8*) &dirEntry,sizeof(TFatDirEntry));
   387 
   388 	_LIT8(KDirBMatchPattern, "DIRB *");
   389 	_LIT8(KDotDotMatchPattern, ".. *");
   390 
   391 	const TInt KMaxEntriesToSearch = (gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector()) / KSizeOfFatDirEntry;
   392 	test(KErrNone == TheDisk.Open(TheFs, drvNum));
   393 
   394 	for(TInt c = 0; c < KMaxEntriesToSearch; c++)
   395 		{
   396 	    test(KErrNone == TheDisk.Read(mediaPosition, ptrEntry));
   397 
   398 		if(KErrNotFound == ptrEntry.Match(KDirBMatchPattern))
   399 			{
   400 			// keep scanning
   401 			mediaPosition += sizeof(TFatDirEntry);
   402 			}
   403 		else
   404 			{
   405 			// found, locate '..' entry
   406 			test(dirEntry.StartCluster() >= KFatFirstSearchCluser);
   407 			mediaPosition  = gBootSector.FirstDataSector();
   408 			mediaPosition += (dirEntry.StartCluster() - KFatFirstSearchCluser) * gBootSector.SectorsPerCluster();
   409 			mediaPosition *= gBootSector.BytesPerSector();
   410 			mediaPosition += KSizeOfFatDirEntry; // '..' is always the 2nd entry
   411 
   412 			test(KErrNone == TheDisk.Read(mediaPosition, ptrEntry));
   413 
   414 			test(KErrNotFound != ptrEntry.Match(KDotDotMatchPattern));
   415 			test(dirEntry.StartCluster() == 0);
   416 
   417 			TheDisk.Close();
   418 			return;
   419 			}
   420 		}
   421 
   422 	// dirB entry not found - test failed
   423 	TheDisk.Close();
   424 	test(0);
   425 	}
   426 
   427 //---------------------------------------------
   428 /**
   429     Test replacing files by theis short names
   430 */
   431 void TestReplaceByShortName()
   432 {
   433     test.Next(_L("Test replacing files using short names\n"));
   434     QuickFormat();
   435 
   436     _LIT(KLongName1,  "abcdefghi.txt");
   437     _LIT(KShortName1, "ABCDEF~1.TXT");
   438     const TInt KFile1Sz = 100;
   439 
   440     _LIT(KLongName2,  "abcdefghij.txt");
   441     _LIT(KShortName2, "ABCDEF~2.TXT");
   442     const TInt KFile2Sz = 200;
   443 
   444 
   445     TInt        nRes;
   446     TFileName   fn;
   447     TEntry      entry;
   448 
   449     TheFs.SetSessionPath(_L("\\"));
   450 
   451     nRes = CreateCheckableStuffedFile(TheFs, KLongName1, KFile1Sz);
   452     test_KErrNone(nRes);
   453 
   454     nRes = TheFs.GetShortName(KLongName1, fn);
   455     test(nRes == KErrNone && fn == KShortName1); //-- just check short name generation
   456 
   457     nRes =CreateCheckableStuffedFile(TheFs, KLongName2, KFile2Sz);
   458     test_KErrNone(nRes);
   459 
   460     nRes = TheFs.GetShortName(KLongName2, fn);
   461     test(nRes == KErrNone && fn == KShortName2); //-- just check short name generation
   462 
   463     //-- try to replace the file with itself using its short name alias
   464     //-- nothing shall happen and the file must remain the same
   465     nRes = TheFs.Replace(KLongName1, KShortName1);
   466     test(nRes == KErrNone);
   467 
   468     nRes = TheFs.Entry(KLongName1, entry);
   469     test(nRes == KErrNone);
   470     test(entry.iSize == KFile1Sz);
   471 
   472     nRes = TheFs.Entry(KShortName1, entry);
   473     test(nRes == KErrNone);
   474     test(entry.iSize == KFile1Sz);
   475 
   476 
   477     nRes = TheFs.Replace(KShortName1, KLongName1);
   478     test(nRes == KErrNone);
   479 
   480     nRes = TheFs.Entry(KLongName1, entry);
   481     test(nRes == KErrNone);
   482     test(entry.iSize == KFile1Sz);
   483 
   484     nRes = TheFs.Entry(KShortName1, entry);
   485     test(nRes == KErrNone);
   486     test(entry.iSize == KFile1Sz);
   487 
   488     nRes = VerifyCheckableFile(TheFs, KLongName1);
   489     test(nRes == KErrNone);
   490 
   491     nRes = VerifyCheckableFile(TheFs, KShortName1);
   492     test(nRes == KErrNone);
   493 
   494 
   495     //-- replace "abcdefghi.txt" by "ABCDEF~2.TXT" which is the alias for "abcdefghij.txt"
   496     //-- expected: contents and all attributes of the "abcdefghij.txt" is replaced with "abcdefghi.txt"
   497     //-- "abcdefghi.txt" entries gets deleted.
   498 
   499     nRes = TheFs.Replace(KLongName1, KShortName2);
   500     test(nRes == KErrNone);
   501 
   502     //User::After(5*K1Sec);
   503     /*
   504     nRes = VerifyCheckableFile(TheFs, KLongName2);
   505     test(nRes == KErrNone);
   506 
   507     nRes = VerifyCheckableFile(TheFs, KShortName2);
   508     test(nRes == KErrNone);
   509     */
   510 
   511 
   512     nRes = TheFs.Entry(KLongName2, entry);
   513     test(nRes == KErrNone);
   514     test(entry.iSize == KFile1Sz);
   515 
   516     nRes = TheFs.Entry(KShortName2, entry);
   517     test(nRes == KErrNone);
   518     test(entry.iSize == KFile1Sz && entry.iName == KLongName2);
   519 
   520 
   521 }
   522 
   523 
   524 GLDEF_C void CallTestsL()
   525 //
   526 // Call tests that may leave
   527 //
   528 	{
   529 
   530 	TInt drvNum;
   531 	TInt r=TheFs.CharToDrive(gDriveToTest,drvNum);
   532 	test(r==KErrNone);
   533 
   534     if (!Is_Fat(TheFs,drvNum))
   535 		{
   536 		test.Printf(_L("CallTestsL: Skipped: Requires FAT filesystem to run.\n"));
   537 		return;
   538 		}
   539 
   540 
   541     //-- set up console output
   542     SetConsole(test.Console());
   543 
   544     //-- print drive information
   545     PrintDrvInfo(TheFs, drvNum);
   546 
   547 	GetBootInfo();
   548 
   549 	Test1(EUpper); // Test directory entries with 8.3 uppercase (no VFAT entries expected)
   550 	Test1(ELower); // Test directory entries with 8.3 lowercase (   VFAT entries expected)
   551 	Test1(EMixed); // Test directory entries with 8.3 mixed     (   VFAT entries expected)
   552 
   553 	Test2(EUpper); // Test directory entries with 8.3 uppercase (no VFAT entries expected)
   554 	Test2(ELower); // Test directory entries with 8.3 lowercase (   VFAT entries expected)
   555 	Test2(EMixed); // Test directory entries with 8.3 mixed     (   VFAT entries expected)
   556 
   557 	TestDEF115314();
   558 	TestDEF113633();
   559 	TestPDEF116912();
   560 
   561     TestReplaceByShortName();
   562 
   563 	}
   564 
   565 
   566