kerneltest/f32test/filesystem/fat/t_compat32.cpp
changeset 9 96e5fb8b040d
child 6 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/filesystem/fat/t_compat32.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,565 @@
+// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// f32test\fat32\t_compat32.cpp
+//
+//
+
+#define __E32TEST_EXTENSION__
+
+#include <f32file.h>
+#include <e32test.h>
+#include <f32dbg.h>
+#include "t_server.h"
+
+#include "fat_utils.h"
+using namespace Fat_Test_Utils;
+
+RTest test(_L("T_COMPAT32"));
+
+static RRawDisk TheDisk;
+static TFatBootSector gBootSector;
+
+
+static void QuickFormat()
+    {
+    FormatFatDrive(TheFs, CurrentDrive(), ETrue);
+    }
+
+static void ReadBootSector(TFatBootSector& aBootSector)
+	{
+
+    TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, aBootSector);
+    test(nRes == KErrNone);
+
+    if(!aBootSector.IsValid())
+        {
+        test.Printf(_L("Wrong bootsector! Dump:\n"));
+        aBootSector.PrintDebugInfo();
+        test(0);
+        }
+	}
+
+
+static void GetBootInfo()
+	{
+	QuickFormat();
+	ReadBootSector(gBootSector);
+	}
+
+enum TNameCase
+	{
+	EUpper, // Test directory entries with 8.3 uppercase (no VFAT entries expected)
+	ELower, // Test directory entries with 8.3 lowercase (   VFAT entries expected)
+	EMixed  // Test directory entries with 8.3 mixed     (   VFAT entries expected)
+	};
+
+
+/**
+    Fiddles with root directory entries.
+    Creates a file, if it has 1 VFAT and 1 DOS dir. entries, places an illegal lower case
+    symbol to the DOS entry, fixing VFAT name checksums
+*/
+static void DoFiddleWithFileNames(TNameCase aCase)
+{
+	TFileName fileName = _L("\\WORD");
+	TBool expectVfatEntry = EFalse;
+
+	switch(aCase)
+		{
+		case EUpper:
+			break;
+
+		case ELower:
+			fileName = _L("\\word");
+			expectVfatEntry = ETrue;
+			break;
+
+		case EMixed:
+			fileName = _L("\\WoRd");
+			expectVfatEntry = ETrue;
+			break;
+
+		default:
+			test(0);
+			break;
+		}
+
+	RFile file;
+	TInt r=file.Create(TheFs,fileName,EFileRead);
+	test(r==KErrNone);
+	file.Close();
+//	Assume this file is the first entry in the root directory
+
+
+	r=TheDisk.Open(TheFs,CurrentDrive());
+	test(r==KErrNone);
+
+    //-- read 1st dir. entry it can be FAT or VFat , depending on the filename
+    const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
+
+    TFatDirEntry fatEntry1;
+	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
+
+    test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
+
+    if(!fatEntry1.IsVFatEntry())
+    {//-- we expected FAT entry, everything is OK
+        test(!expectVfatEntry);
+    }
+    else
+    {//-- we have 2 FAT entries, 1st is VFat, 2nd is DOS.
+     //-- put lower case letters into DOS entry( not compliant with FAT specs), correct VFat entries checksums,
+     //-- in this case the system shall correctly deal with the file, using long names.
+
+        test(expectVfatEntry);
+        test(fatEntry1.iData[0] == 0x41); //-- must have only 2 entries
+
+        //-- read DOS entry now
+        TFatDirEntry fatEntry2;
+        TPtr8 ptrEntry2((TUint8*)&fatEntry2,sizeof(TFatDirEntry));
+        const TInt posEntry2 = posEntry1 + sizeof(TFatDirEntry); //-- dir entry2 position
+
+        test(TheDisk.Read(posEntry2, ptrEntry2)==KErrNone);
+
+        //-- ensure that the name and checksum are correct
+        test(fatEntry1.iData[13] == CalculateShortNameCheckSum(fatEntry2.Name()));
+        test(fatEntry2.Name()==_L8("WORD       "));
+
+        //-- put lower case symbol to the DOS entry and fix the checksum
+        _LIT8(KBadDosName, "Word       ");
+        fatEntry2.SetName(KBadDosName);
+        fatEntry1.iData[13] = CalculateShortNameCheckSum(fatEntry2.Name());
+
+        //-- write data to the disk
+        test(TheDisk.Write(posEntry1, ptrEntry1)==KErrNone);
+        test(TheDisk.Write(posEntry2, ptrEntry2)==KErrNone);
+
+    }
+
+	TheDisk.Close();
+
+}
+
+//
+// Replace a 8.3 filename with upper and lower case letters which is, actually out of FAT specs.
+// I.e. VFAT entries are valid, but DOS entry has a lower case symbol, which is wrong.
+//
+LOCAL_C void Test1(TNameCase aCase)
+	{
+	test.Next(_L("Replace a file with a wrong DOS entry"));
+	QuickFormat();
+
+    //-- N.B. This shall be the before any dir. entries creation in the root directory
+    //-- because it directly accesses the directory's 1st file
+    DoFiddleWithFileNames(aCase);
+
+    RFile file;
+    TInt r;
+
+	r=file.Replace(TheFs,_L("\\FILE.TMP"),EFileRead);
+	test(r==KErrNone);
+	r=file.Write(_L8("Hello World"));
+	file.Close();
+
+	r=TheFs.Replace(_L("\\File.tmp"),_L("\\Word"));
+	test(r==KErrNone);
+
+	CDir* entryCount;
+	r=TheFs.GetDir(_L("\\*.*"),KEntryAttMaskSupported,ESortNone,entryCount);
+	test(r==KErrNone);
+	TInt count=entryCount->Count();
+
+	test(count==1);
+	delete entryCount;
+	}
+
+
+//
+// Renaming a 8.3 filename with upper and lower case letters which is, actually out of FAT specs.
+// I.e. VFAT entries are valid, but DOS entry has a lower case symbol, which is wrong.
+//
+LOCAL_C void Test2(TNameCase aCase)
+	{
+	test.Next(_L("Rename a file with a wrong DOS entry"));
+	QuickFormat();
+	RFile file;
+    TInt r;
+
+    //-- N.B. This shall be the before any dir. entries creation in the root dir
+    //-- because it directly accesses the directory's 1st file
+    DoFiddleWithFileNames(aCase);
+
+	r=file.Create(TheFs,_L("\\TEST"),EFileRead);
+	test(r==KErrNone);
+	file.Close();
+
+	r=TheFs.Rename(_L("\\TEST"),_L("\\Word"));
+	test(r==KErrAlreadyExists);
+	r=TheFs.Delete(_L("\\TEST"));
+	test(r==KErrNone);
+
+	CDir* entryCount;
+	r=TheFs.GetDir(_L("\\*.*"),KEntryAttMaskSupported,ESortNone,entryCount);
+	test(r==KErrNone);
+	TInt count=entryCount->Count();
+	test(count==1);
+	delete entryCount;
+	}
+
+
+//---------------------------------------------
+//! @SYMTestCaseID			PBASE-T_COMPAT32-0686
+//! @SYMTestType			CT
+//! @SYMREQ					DEF115314
+//! @SYMTestCaseDesc		Test character '`' (0x60) is recognized as a legal char for short file names.
+//! @SYMTestActions			Creates a file named "\x60\x60\x60.TXT", checks only DOS entry is created for
+//!							it and its short name equals "```.TXT" instead of "___.TXT"
+//! @SYMTestExpectedResults	The operation completes with error code KErrNone;
+//! @SYMTestPriority		High
+//! @SYMTestStatus			Implemented
+//---------------------------------------------
+void TestDEF115314()
+	{
+	test.Next(_L("Test DEF115314: TTG:<`(0x60) code cannot be used as valid Short File Name>"));
+	QuickFormat();
+	RFile file;
+    TInt r;
+
+    TFileName fn;
+    fn.Format(_L("%c:\\\x60\x60\x60.TXT"), (TUint8)gDriveToTest);
+
+    r = TheFs.Delete(fn);
+	test(r==KErrNone || r==KErrNotFound);
+
+	r = file.Create(TheFs, fn, EFileRead);
+	test(r==KErrNone);
+	file.Close();
+
+	r=TheDisk.Open(TheFs,CurrentDrive());
+	test(r==KErrNone);
+
+    //-- read 1st dir. it should be DOS Entry
+    const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
+    TFatDirEntry fatEntry1;
+	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
+    test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
+    TheDisk.Close();
+    test(!fatEntry1.IsVFatEntry());
+
+    // tests short name
+    TFileName sn;
+    r = TheFs.GetShortName(fn, sn);
+    test(r==KErrNone);
+    test(sn.Compare(_L("```.TXT"))==0);
+
+    r = TheFs.Delete(fn);
+	test(r==KErrNone);
+	}
+
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+_LIT(KTestLocale, 			"t_tlocl_cp932.dll");
+_LIT(KTestUnicodeFileName, 	"\\\x65B0\x6587\x4EF6");
+#endif //_DEBUG || _DEBUG_RELEASE
+
+//---------------------------------------------
+//! @SYMTestCaseID			PBASE-T_COMPAT32-0685
+//! @SYMTestType			CT
+//! @SYMREQ					DEF113633
+//! @SYMTestCaseDesc		Test FAT volume creates VFat entries for short unicode named files
+//! @SYMTestActions			Enables FatUtilityFunctions. Loads cp932 codepage dll. Create a file
+//!							named as "\x65B0\x6587\x4EF6", checks both a VFat entry and a DOS
+//!							entry have been created for the file.
+//! @SYMTestExpectedResults	The operation completes with error code KErrNone;
+//! @SYMTestPriority		High
+//! @SYMTestStatus			Implemented
+//---------------------------------------------
+void TestDEF113633()
+	{
+	test.Next(_L("Test DEF113633 - FAT should create VFat entries for unicode character contained file names"));
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+	QuickFormat();
+	RFile file;
+    TInt r;
+    TInt drvNum;
+
+    r = TheFs.CharToDrive(gDriveToTest,drvNum);
+	test(r==KErrNone);
+
+    // turn on FatUtilityFunctions
+    r = TheFs.ControlIo(drvNum, KControlIoEnableFatUtilityFunctions);
+	test(r==KErrNone);
+
+	// load cp932 codepage dll
+	r = UserSvr::ChangeLocale(KTestLocale);
+	test(r==KErrNone);
+
+    // create file "\x65B0\x6587\x4EF6", check DOS entry & VFat entry
+	r = file.Create(TheFs, KTestUnicodeFileName, EFileRead);
+	test(r==KErrNone);
+	file.Close();
+
+	r=TheDisk.Open(TheFs,CurrentDrive());
+	test(r==KErrNone);
+
+    //-- read 1st dir. it should be VFat
+//    const TInt posEntry1=gRootDirStart; //-- dir entry1 position
+    const TInt posEntry1=gBootSector.RootDirStartSector() << KDefaultSectorLog2; //-- dir entry1 position
+    TFatDirEntry fatEntry1;
+	TPtr8 ptrEntry1((TUint8*)&fatEntry1,sizeof(TFatDirEntry));
+
+    test(TheDisk.Read(posEntry1, ptrEntry1)==KErrNone);
+
+    test(fatEntry1.IsVFatEntry());
+
+    test(fatEntry1.iData[0] == 0x41); //-- must have only 2 entries
+
+    //-- read DOS entry now
+    TFatDirEntry fatEntry2;
+    TPtr8 ptrEntry2((TUint8*)&fatEntry2,sizeof(TFatDirEntry));
+    const TInt posEntry2 = posEntry1 + sizeof(TFatDirEntry); //-- dir entry2 position
+
+    test(TheDisk.Read(posEntry2, ptrEntry2)==KErrNone);
+
+    //-- ensure that the name and checksum are correct
+    test(!fatEntry2.IsVFatEntry());
+    test(fatEntry1.iData[13] == CalculateShortNameCheckSum(fatEntry2.Name()));
+
+    // delete file
+    TheDisk.Close();
+    r = TheFs.Delete(KTestUnicodeFileName);
+	test(r==KErrNone);
+
+	// turn off FatUtilityFunctions
+	r = TheFs.ControlIo(drvNum, KControlIoDisableFatUtilityFunctions);
+	test(r==KErrNone);
+
+#else
+	test.Printf(_L("Test only runs on DEBUG builds, see test logs of debug builds for details."));
+#endif  // _DEBUG) || _DEBUG_RELEASE
+	}
+
+
+
+
+//---------------------------------------------
+// If the parent directory of a directory is the root directory,
+// the '..' entry should point to start cluster 0 in any case
+//---------------------------------------------
+void TestPDEF116912()
+	{
+	test.Next(_L("Test PDEF116912 - Check that '..' parent cluster address is 0 after renaming\n"));
+
+  	TInt drvNum;
+	test(KErrNone == TheFs.CharToDrive(gDriveToTest, drvNum));
+
+	if(!Is_Fat32(TheFs, drvNum))
+		{
+		_LIT(KMessage, "Test only applicable to FAT32 file systems. Skipping.\n");
+		test.Printf(KMessage);
+		return;
+		}
+
+	QuickFormat();
+
+	_LIT(KDirA, "\\dirA\\");
+	_LIT(KDirB, "\\dirB\\");
+
+	test(KErrNone == TheFs.MkDir(KDirA));
+	test(KErrNone == TheFs.Rename(KDirA, KDirB));
+
+	test(gBootSector.IsValid());
+	TInt mediaPosition = gBootSector.RootDirStartSector() * gBootSector.BytesPerSector();
+
+	TFatDirEntry dirEntry;
+	TPtr8 ptrEntry((TUint8*) &dirEntry,sizeof(TFatDirEntry));
+
+	_LIT8(KDirBMatchPattern, "DIRB *");
+	_LIT8(KDotDotMatchPattern, ".. *");
+
+	const TInt KMaxEntriesToSearch = (gBootSector.SectorsPerCluster() * gBootSector.BytesPerSector()) / KSizeOfFatDirEntry;
+	test(KErrNone == TheDisk.Open(TheFs, drvNum));
+
+	for(TInt c = 0; c < KMaxEntriesToSearch; c++)
+		{
+	    test(KErrNone == TheDisk.Read(mediaPosition, ptrEntry));
+
+		if(KErrNotFound == ptrEntry.Match(KDirBMatchPattern))
+			{
+			// keep scanning
+			mediaPosition += sizeof(TFatDirEntry);
+			}
+		else
+			{
+			// found, locate '..' entry
+			test(dirEntry.StartCluster() >= KFatFirstSearchCluser);
+			mediaPosition  = gBootSector.FirstDataSector();
+			mediaPosition += (dirEntry.StartCluster() - KFatFirstSearchCluser) * gBootSector.SectorsPerCluster();
+			mediaPosition *= gBootSector.BytesPerSector();
+			mediaPosition += KSizeOfFatDirEntry; // '..' is always the 2nd entry
+
+			test(KErrNone == TheDisk.Read(mediaPosition, ptrEntry));
+
+			test(KErrNotFound != ptrEntry.Match(KDotDotMatchPattern));
+			test(dirEntry.StartCluster() == 0);
+
+			TheDisk.Close();
+			return;
+			}
+		}
+
+	// dirB entry not found - test failed
+	TheDisk.Close();
+	test(0);
+	}
+
+//---------------------------------------------
+/**
+    Test replacing files by theis short names
+*/
+void TestReplaceByShortName()
+{
+    test.Next(_L("Test replacing files using short names\n"));
+    QuickFormat();
+
+    _LIT(KLongName1,  "abcdefghi.txt");
+    _LIT(KShortName1, "ABCDEF~1.TXT");
+    const TInt KFile1Sz = 100;
+
+    _LIT(KLongName2,  "abcdefghij.txt");
+    _LIT(KShortName2, "ABCDEF~2.TXT");
+    const TInt KFile2Sz = 200;
+
+
+    TInt        nRes;
+    TFileName   fn;
+    TEntry      entry;
+
+    TheFs.SetSessionPath(_L("\\"));
+
+    nRes = CreateCheckableStuffedFile(TheFs, KLongName1, KFile1Sz);
+    test_KErrNone(nRes);
+
+    nRes = TheFs.GetShortName(KLongName1, fn);
+    test(nRes == KErrNone && fn == KShortName1); //-- just check short name generation
+
+    nRes =CreateCheckableStuffedFile(TheFs, KLongName2, KFile2Sz);
+    test_KErrNone(nRes);
+
+    nRes = TheFs.GetShortName(KLongName2, fn);
+    test(nRes == KErrNone && fn == KShortName2); //-- just check short name generation
+
+    //-- try to replace the file with itself using its short name alias
+    //-- nothing shall happen and the file must remain the same
+    nRes = TheFs.Replace(KLongName1, KShortName1);
+    test(nRes == KErrNone);
+
+    nRes = TheFs.Entry(KLongName1, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz);
+
+    nRes = TheFs.Entry(KShortName1, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz);
+
+
+    nRes = TheFs.Replace(KShortName1, KLongName1);
+    test(nRes == KErrNone);
+
+    nRes = TheFs.Entry(KLongName1, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz);
+
+    nRes = TheFs.Entry(KShortName1, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz);
+
+    nRes = VerifyCheckableFile(TheFs, KLongName1);
+    test(nRes == KErrNone);
+
+    nRes = VerifyCheckableFile(TheFs, KShortName1);
+    test(nRes == KErrNone);
+
+
+    //-- replace "abcdefghi.txt" by "ABCDEF~2.TXT" which is the alias for "abcdefghij.txt"
+    //-- expected: contents and all attributes of the "abcdefghij.txt" is replaced with "abcdefghi.txt"
+    //-- "abcdefghi.txt" entries gets deleted.
+
+    nRes = TheFs.Replace(KLongName1, KShortName2);
+    test(nRes == KErrNone);
+
+    //User::After(5*K1Sec);
+    /*
+    nRes = VerifyCheckableFile(TheFs, KLongName2);
+    test(nRes == KErrNone);
+
+    nRes = VerifyCheckableFile(TheFs, KShortName2);
+    test(nRes == KErrNone);
+    */
+
+
+    nRes = TheFs.Entry(KLongName2, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz);
+
+    nRes = TheFs.Entry(KShortName2, entry);
+    test(nRes == KErrNone);
+    test(entry.iSize == KFile1Sz && entry.iName == KLongName2);
+
+
+}
+
+
+GLDEF_C void CallTestsL()
+//
+// Call tests that may leave
+//
+	{
+
+	TInt drvNum;
+	TInt r=TheFs.CharToDrive(gDriveToTest,drvNum);
+	test(r==KErrNone);
+
+    if (!Is_Fat(TheFs,drvNum))
+		{
+		test.Printf(_L("CallTestsL: Skipped: Requires FAT filesystem to run.\n"));
+		return;
+		}
+
+
+    //-- set up console output
+    SetConsole(test.Console());
+
+    //-- print drive information
+    PrintDrvInfo(TheFs, drvNum);
+
+	GetBootInfo();
+
+	Test1(EUpper); // Test directory entries with 8.3 uppercase (no VFAT entries expected)
+	Test1(ELower); // Test directory entries with 8.3 lowercase (   VFAT entries expected)
+	Test1(EMixed); // Test directory entries with 8.3 mixed     (   VFAT entries expected)
+
+	Test2(EUpper); // Test directory entries with 8.3 uppercase (no VFAT entries expected)
+	Test2(ELower); // Test directory entries with 8.3 lowercase (   VFAT entries expected)
+	Test2(EMixed); // Test directory entries with 8.3 mixed     (   VFAT entries expected)
+
+	TestDEF115314();
+	TestDEF113633();
+	TestPDEF116912();
+
+    TestReplaceByShortName();
+
+	}
+
+
+