sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32test\scndrv\t_scn32dr1.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include "t_server.h" sl@0: sl@0: #include "fat_utils.h" sl@0: using namespace Fat_Test_Utils; sl@0: sl@0: #ifdef __VC32__ sl@0: // Solve compilation problem caused by non-English locale sl@0: #pragma setlocale("english") sl@0: #endif sl@0: sl@0: /* sl@0: T_testscndrv tests the scandrive utility. Errors in this test will be sl@0: introduced using the RRawdDisk class. The correct fixup is tested by rereading sl@0: the disk. Drives tested are the default path(epoc) and X: (wins). This test sl@0: returns immediately if used on the internal ram drive sl@0: */ sl@0: sl@0: /* sl@0: The initial FAT12 directory structure (with cluster number in brackets) is as follows: sl@0: sl@0: | sl@0: - scndrv (2) sl@0: | sl@0: - dir1 (3-4) sl@0: | | sl@0: | (5) sl@0: | sl@0: - dir2 (6) sl@0: | sl@0: - full (7) sl@0: | | sl@0: | | sl@0: | - (11-17) sl@0: | sl@0: - somedirwith3entries (8) sl@0: | sl@0: - somedir2with3entries (9) sl@0: | sl@0: - almostfull(10) sl@0: | sl@0: - (18+19) sl@0: sl@0: */ sl@0: sl@0: /* sl@0: The initial FAT32 directory structure (with cluster number in brackets is as follows): sl@0: sl@0: | sl@0: - scndrv (3) sl@0: | sl@0: - dir1 (4) sl@0: | | sl@0: | (5) sl@0: | sl@0: - dir2 (6) sl@0: | sl@0: - full (7) sl@0: | | sl@0: | | sl@0: | - (11-17) sl@0: | sl@0: - somedirwith3entries (8) sl@0: | sl@0: - somedir2with3entries (9) sl@0: | sl@0: - almostfull(10) sl@0: | sl@0: - (18+19) sl@0: sl@0: */ sl@0: sl@0: GLDEF_D RTest test(_L("T_SCN32DR1")); sl@0: sl@0: LOCAL_D const TInt KMaxFatEntries = 2048; sl@0: LOCAL_D const TInt KMaxFatSize = KMaxFatEntries * 4; sl@0: sl@0: LOCAL_D const TInt KDirAttrReadOnly = 0x01; sl@0: LOCAL_D const TInt KDirAttrHidden = 0x02; sl@0: LOCAL_D const TInt KDirAttrSystem = 0x04; sl@0: LOCAL_D const TInt KDirAttrVolumeId = 0x08; sl@0: LOCAL_D const TInt KDirAttrDirectory = 0x10; sl@0: LOCAL_D const TInt KDirAttrArchive = 0x20; sl@0: LOCAL_D const TInt KDirAttrLongName = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId; sl@0: LOCAL_D const TInt KDirAttrLongMask = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive; sl@0: LOCAL_D const TInt KDirLastLongEntry = 0x40; sl@0: sl@0: LOCAL_D RRawDisk TheRawDisk; sl@0: LOCAL_D TFatBootSector BootSector; sl@0: LOCAL_D TFileName TheDrive=_L("?:\\"); sl@0: LOCAL_D HBufC8* FatBufPtr = NULL; sl@0: LOCAL_D HBufC8* DirBufPtr = NULL; sl@0: LOCAL_D HBufC8* ExtBufPtr = NULL; sl@0: LOCAL_D TInt32 ExtBufAdd = 0; sl@0: LOCAL_D TInt32 ExtBufLen = 0; sl@0: LOCAL_D HBufC8* FatDiskPtr = NULL; sl@0: LOCAL_D HBufC8* DirDiskPtr = NULL; sl@0: sl@0: static TFatType gDiskType = EInvalid; sl@0: sl@0: LOCAL_D TInt gDriveNumber; sl@0: sl@0: LOCAL_D TInt gBytesPerCluster; sl@0: LOCAL_D TInt gEntriesPerCluster; sl@0: LOCAL_D TInt gRootDirSectors; sl@0: LOCAL_D TInt gRootDirEntries; sl@0: LOCAL_D TInt gRootDirStart; // in bytes sl@0: LOCAL_D TInt gRootSector; sl@0: LOCAL_D TInt gFatStartBytes; sl@0: LOCAL_D TInt gFatTestSize; // in bytes sl@0: LOCAL_D TInt gFatTestEntries; sl@0: LOCAL_D TInt gFatSizeSectors; sl@0: LOCAL_D TInt gFirstDataSector; sl@0: LOCAL_D TInt gMaxDataCluster; sl@0: LOCAL_D TInt gDataStartBytes; sl@0: LOCAL_D TInt gEndOfChain; // for FAT12/16/32 sl@0: sl@0: // cluster numbers in 1 and >1 sector per cluster modes sl@0: LOCAL_D TInt gClusterRootDir; // 2 2 sl@0: LOCAL_D TInt gClusterScnDrv; // 3 3 sl@0: LOCAL_D TInt gClusterDir1; // 4 4 sl@0: LOCAL_D TInt gClusterDir1ext; // 5 4 sl@0: LOCAL_D TInt gClusterDir2; // 7 6 sl@0: LOCAL_D TInt gClusterDir2_Full; // 8 7 sl@0: LOCAL_D TInt gClusterDir2_SD3E; // 9 8 sl@0: LOCAL_D TInt gClusterDir2_SD23E; // 10 9 sl@0: LOCAL_D TInt gClusterDir2_AFull; // 11 10 sl@0: LOCAL_D TInt gClusterEndMaxDepth; // 147 146 sl@0: sl@0: LOCAL_D TFileName LastInFull; sl@0: sl@0: class TEntryInfo sl@0: { sl@0: public: sl@0: TEntryInfo(TInt aBytePos,TInt aLength):iBytePos(aBytePos),iLength(aLength){} sl@0: TEntryInfo(){} sl@0: public: sl@0: TInt iBytePos; sl@0: TInt iLength; sl@0: }; sl@0: sl@0: sl@0: LOCAL_C TInt DirBufferSize() sl@0: // sl@0: // returns size in bytes nec for buffer to store relevant disk data sl@0: // sl@0: { sl@0: return(gMaxDataCluster*gBytesPerCluster); sl@0: } sl@0: sl@0: LOCAL_C TInt PosInBytes(TInt aFatIndex) sl@0: // sl@0: // Return number of bytes into the FAT sl@0: // sl@0: { sl@0: TInt fatPosInBytes = -1; sl@0: switch (gDiskType) sl@0: { sl@0: case EFat32: sl@0: fatPosInBytes=aFatIndex<<2; sl@0: break; sl@0: case EFat16: sl@0: fatPosInBytes=aFatIndex<<1; sl@0: break; sl@0: case EFat12: sl@0: fatPosInBytes=(aFatIndex*3>>1); sl@0: break; sl@0: default: sl@0: test(0); sl@0: } sl@0: return(fatPosInBytes); sl@0: } sl@0: sl@0: LOCAL_C TUint32 MaxClusters() sl@0: // sl@0: // Return the number of data clusters on the disk sl@0: // sl@0: { sl@0: TUint32 totSec = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors()); sl@0: TUint32 numSec = totSec - gFirstDataSector; sl@0: return numSec / BootSector.SectorsPerCluster(); sl@0: } sl@0: sl@0: LOCAL_C TInt ClusterToByte(TInt aCluster) sl@0: // sl@0: // converts cluster number to byte offset on disk sl@0: // sl@0: { sl@0: TInt pos; sl@0: if (aCluster < 2) sl@0: pos = gRootDirStart; sl@0: else sl@0: pos = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * BootSector.BytesPerSector(); sl@0: return pos; sl@0: } sl@0: sl@0: LOCAL_C TInt ByteToCluster(TInt aBytePos) sl@0: // sl@0: // Converts byte offset from root dir buffer to cluster number sl@0: // sl@0: { sl@0: if (aBytePos < gRootDirStart) sl@0: return -1; sl@0: if (aBytePos < gDataStartBytes) sl@0: return 0; sl@0: return (aBytePos - gDataStartBytes) / gBytesPerCluster + 2; sl@0: } sl@0: sl@0: LOCAL_C TInt ClusterEntryToBytes(TInt aCluster,TInt aEntry) sl@0: // sl@0: // converts position in cluster and entry number to byte pos from root directory sl@0: // sl@0: { sl@0: TInt pos; sl@0: pos = ClusterToByte(aCluster) - gRootDirStart + aEntry*KSizeOfFatDirEntry; sl@0: return pos; sl@0: } sl@0: sl@0: LOCAL_C TInt FindUnMatch(const TUint8* aBuf, const TUint8* aCmp, TInt aLen, TInt aStart=0) sl@0: // sl@0: // Return position in buffers which doesn't match, or -1 if it matches sl@0: // sl@0: { sl@0: for (TInt i = aStart; i < aStart + aLen; i++) sl@0: if (aBuf[i] != aCmp[i]) sl@0: return i; sl@0: return -1; sl@0: } sl@0: sl@0: LOCAL_C TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL) sl@0: // sl@0: // Read a single FAT entry from disk or FAT copy and return it sl@0: // sl@0: { sl@0: TInt pos = PosInBytes(aIndex); sl@0: sl@0: TUint8 data[4]; sl@0: TUint8* ptr = data; sl@0: sl@0: if (aFat) sl@0: ptr = (TUint8*)aFat + pos; sl@0: else sl@0: { sl@0: pos += BootSector.ReservedSectors() * BootSector.BytesPerSector(); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TPtr8 buf(&data[0], 4); sl@0: r=TheRawDisk.Read(pos, buf); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: } sl@0: sl@0: TUint32 val = 0; sl@0: switch (gDiskType) sl@0: { sl@0: case EFat32: sl@0: val = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24); sl@0: break; sl@0: case EFat16: sl@0: val = ptr[0] + (ptr[1] << 8); sl@0: break; sl@0: case EFat12: sl@0: val = ptr[0] + (ptr[1] << 8); sl@0: if (aIndex & 1) sl@0: val >>= 4; sl@0: val &= 0xFFF; sl@0: break; sl@0: default: sl@0: test(0); sl@0: } sl@0: return val; sl@0: } sl@0: sl@0: LOCAL_C void WriteFat(TInt aFatIndex,TInt aValue,const TUint8* aFat) sl@0: // sl@0: // Write a value to both fats starting at aFat sl@0: // sl@0: { sl@0: TUint8* p=(TUint8*)(aFat+PosInBytes(aFatIndex)); sl@0: switch (gDiskType) sl@0: { sl@0: case EFat32: sl@0: p[0] = (TUint8) (aValue); sl@0: p[1] = (TUint8) (aValue >> 8); sl@0: p[2] = (TUint8) (aValue >> 16); sl@0: p[3] = (TUint8) (aValue >> 24); sl@0: break; sl@0: case EFat16: sl@0: p[0] = (TUint8) (aValue); sl@0: p[1] = (TUint8) (aValue >> 8); sl@0: break; sl@0: case EFat12: sl@0: { sl@0: TUint8 mask=0x0F; sl@0: TBool odd=(aFatIndex)&1; sl@0: TUint8 fatVal; sl@0: TInt value=aValue; sl@0: if(odd) sl@0: { sl@0: mask<<=4; sl@0: value<<=4; sl@0: fatVal=p[0]; sl@0: fatVal&=~mask; sl@0: fatVal|=(TUint8)(value&0xFF); sl@0: p[0]=fatVal; sl@0: p[1]=(TUint8)(value>>8); sl@0: } sl@0: else sl@0: { sl@0: p[0]=(TUint8)(value&0xFF); sl@0: fatVal=p[1]; sl@0: fatVal&=~mask; sl@0: fatVal|=(TUint8)(value>>8); sl@0: p[1]=fatVal; sl@0: } sl@0: } sl@0: break; sl@0: default: sl@0: test(0); sl@0: } sl@0: return; sl@0: } sl@0: sl@0: static void DoReadBootSector() sl@0: { sl@0: sl@0: TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum< 1); sl@0: switch (gDiskType) sl@0: { sl@0: case EFat12: sl@0: case EFat16: sl@0: gRootDirEntries = BootSector.RootDirEntries(); sl@0: gRootDirSectors = ((gRootDirEntries * KSizeOfFatDirEntry + BootSector.BytesPerSector() - 1) / BootSector.BytesPerSector()); sl@0: gFatSizeSectors = BootSector.FatSectors(); sl@0: gRootSector = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors; sl@0: gFirstDataSector = gRootSector + gRootDirSectors; sl@0: gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector(); sl@0: gRootDirStart = gRootSector * BootSector.BytesPerSector(); sl@0: gClusterRootDir = (big ? 0 : 0); sl@0: gClusterScnDrv = (big ? 2 : 2); sl@0: gClusterDir1 = (big ? 3 : 3); sl@0: gClusterDir1ext = (big ? 3 : 4); sl@0: gClusterDir2 = (big ? 5 : 6); sl@0: gClusterDir2_Full = (big ? 6 : 7); sl@0: gClusterDir2_SD3E = (big ? 7 : 8); sl@0: gClusterDir2_SD23E = (big ? 8 : 9); sl@0: gClusterDir2_AFull = (big ? 9 : 10); sl@0: gClusterEndMaxDepth = (big ? 145 : 146); sl@0: break; sl@0: case EFat32: sl@0: // sl@0: // FAT32 will alway pre-allocate a single cluster for the root directory sl@0: // sl@0: // - The following calculations may look wierd (as the spec says that the FAT32 root dir sl@0: // is not fixed) but for the purposes of this test we assume that root dir is only sl@0: // one cluster in size, so we don't fill up the disk trying to fill up the root dir. sl@0: // sl@0: gRootDirEntries = gBytesPerCluster * 1 / KSizeOfFatDirEntry; // Maximum entries within default FAT32 root directory (before extension) sl@0: gRootDirSectors = 0; // FAT32 has no fixed root directory sectors over which to skip sl@0: gFatSizeSectors = BootSector.FatSectors32(); sl@0: sl@0: gRootSector = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors; sl@0: gFirstDataSector = gRootSector; sl@0: sl@0: gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector(); sl@0: gRootDirStart = (BootSector.RootClusterNum() - 2) * gBytesPerCluster + gDataStartBytes; sl@0: sl@0: gClusterRootDir = (big ? 2 : 2); sl@0: gClusterScnDrv = (big ? 3 : 3); sl@0: gClusterDir1 = (big ? 4 : 4); sl@0: gClusterDir1ext = (big ? 4 : 5); sl@0: gClusterDir2 = (big ? 6 : 7); sl@0: gClusterDir2_Full = (big ? 7 : 8); sl@0: gClusterDir2_SD3E = (big ? 8 : 9); sl@0: gClusterDir2_SD23E = (big ? 9 : 10); sl@0: gClusterDir2_AFull = (big ? 10 : 11); sl@0: gClusterEndMaxDepth = (big ? 146 : 147); sl@0: break; sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: gMaxDataCluster = gClusterDir2_AFull + 2 + (gFirstDataSector / BootSector.SectorsPerCluster() + 1); sl@0: sl@0: gFatTestEntries = MaxClusters(); sl@0: if (gFatTestEntries > KMaxFatSize) sl@0: gFatTestEntries = KMaxFatSize; sl@0: } sl@0: sl@0: sl@0: GLDEF_C void DumpBootSector() sl@0: // sl@0: // Display (in log) TFatBootSector structure sl@0: // sl@0: { sl@0: RDebug::Print(_L("iBytesPerSector = %8d"), BootSector.BytesPerSector()); sl@0: RDebug::Print(_L("iSectorsPerCluster = %8d"), BootSector.SectorsPerCluster()); sl@0: RDebug::Print(_L("iReservedSectors = %8d"), BootSector.ReservedSectors()); sl@0: RDebug::Print(_L("iNumberOfFats = %8d"), BootSector.NumberOfFats()); sl@0: RDebug::Print(_L("iRootDirEntries = %8d"), BootSector.RootDirEntries()); sl@0: RDebug::Print(_L("iTotalSectors = %8d"), BootSector.TotalSectors()); sl@0: RDebug::Print(_L("iMediaDescriptor = %8d"), BootSector.MediaDescriptor()); sl@0: RDebug::Print(_L("iFatSectors = %8d"), BootSector.FatSectors()); sl@0: RDebug::Print(_L("iSectorsPerTrack = %8d"), BootSector.SectorsPerTrack()); sl@0: RDebug::Print(_L("iNumberOfHeads = %8d"), BootSector.NumberOfHeads()); sl@0: RDebug::Print(_L("iHiddenSectors = %8d"), BootSector.HiddenSectors()); sl@0: RDebug::Print(_L("iHugeSectors = %8d"), BootSector.HugeSectors()); sl@0: sl@0: if (gDiskType == EFat32) sl@0: { sl@0: RDebug::Print(_L("iFatSectors32 = %8d"), BootSector.FatSectors32()); sl@0: RDebug::Print(_L("iFATFlags = %8d"), BootSector.FATFlags()); sl@0: RDebug::Print(_L("iVersionNumber = %8d"), BootSector.VersionNumber()); sl@0: RDebug::Print(_L("iRootClusterNum = %8d (0x%08X)"), BootSector.RootClusterNum(), gRootDirStart); sl@0: RDebug::Print(_L("iFSInfoSectorNum = %8d (0x%08X)"), BootSector.FSInfoSectorNum(), BootSector.FSInfoSectorNum() * BootSector.BytesPerSector()); sl@0: RDebug::Print(_L("iBkBootRecSector = %8d (0x%08X)"), BootSector.BkBootRecSector(), BootSector.BkBootRecSector() * BootSector.BytesPerSector()); sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void DumpFat(const TUint8* aFat=NULL) sl@0: // sl@0: // Dump to the log all those FAT entries which are non-zero sl@0: // sl@0: { sl@0: TInt32 max = MaxClusters(); sl@0: if (max > KMaxFatEntries) sl@0: max = KMaxFatEntries; sl@0: RDebug::Print(_L("---------------- DUMP OF FAT ---------------")); sl@0: for (TInt32 i = 0; i < max; i++) sl@0: { sl@0: TInt32 val = GetFatEntry(i, aFat); sl@0: TInt32 msk = 0x0FFFFFFF; sl@0: switch (gDiskType) sl@0: { sl@0: case EFat32: sl@0: msk = 0x0FFFFFFF; sl@0: break; sl@0: case EFat16: sl@0: msk = 0xFFFF; sl@0: break; sl@0: case EFat12: sl@0: msk = 0x0FFF; sl@0: break; sl@0: default: sl@0: test(0); sl@0: } sl@0: if ((val & msk) == (0x0FFFFFFF & msk)) sl@0: RDebug::Print(_L(" %8d -> EOC"), i); sl@0: else if ((val & msk) == (0x0FFFFFF8 & msk)) sl@0: RDebug::Print(_L(" %8d -> Media"), i); sl@0: else if ((val & msk) == (0x0FFFFFF7 & msk)) sl@0: RDebug::Print(_L(" %8d -> BAD"), i); sl@0: else if (val > max) sl@0: RDebug::Print(_L(" %8d -> 0x%08X"), i, val); sl@0: else if (val != 0) sl@0: RDebug::Print(_L(" %8d -> %d"), i, val); sl@0: } sl@0: RDebug::Print(_L("--------------------------------------------")); sl@0: } sl@0: sl@0: GLDEF_C TDes* DirAttributes(TInt aAttrib) sl@0: // sl@0: // Return a pointer to a local buffer containing the attribute letters. sl@0: // sl@0: { sl@0: LOCAL_D TBuf<6> str; sl@0: LOCAL_D char* atr = "RHSVDA"; sl@0: str.Fill(TText('-'), 6); sl@0: for (TInt i = 0; i < 6; i++) sl@0: if ((aAttrib >> i) & 1) sl@0: str[i] = atr[i]; sl@0: return &str; sl@0: } sl@0: sl@0: GLDEF_C TBool IsValidDirEntry(TFatDirEntry* aDir) sl@0: // sl@0: // Test whether buffer is a valid normal directory entry sl@0: // sl@0: { sl@0: // first character must be 0x05 or greater than space sl@0: if (aDir->iData[0] < 0x21 && aDir->iData[0] != 0x05) sl@0: return EFalse; sl@0: // other characters must be not less than space sl@0: for (TInt i = 1; i < 11; i++) sl@0: if (aDir->iData[i] < 0x20) sl@0: return EFalse; sl@0: return ETrue; sl@0: } sl@0: sl@0: GLDEF_C void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength) sl@0: // sl@0: // Extract part of a long name entry into the name buffer. sl@0: // sl@0: // @param aName buffer to put name sl@0: // @param aEntry directory entry raw data sl@0: // @param aPos character in buffer to start name segment sl@0: // @param aOffset offset in directory entry of the segment sl@0: // @param aLength number of characters in the segment sl@0: // sl@0: { sl@0: for (TInt i = 0; i < aLength; i++) sl@0: { sl@0: TInt at = i * 2 + aOffset; sl@0: TInt ch = aEntry[at] + aEntry[at+1] * 256; sl@0: aName[aPos++] = TText(ch); sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void ExtractNameString(TDes16& aName, const TUint8* aEntry) sl@0: // sl@0: // Extract a long name part from a directory entry, truncate it at the first sl@0: // NUL (0) character and put quotes round it. sl@0: // sl@0: { sl@0: aName.SetLength(15); sl@0: TInt len = aName.Length() - 1; sl@0: TText qu = '\''; sl@0: aName[0] = qu; sl@0: GetLongNamePart(aName, aEntry, 1, 1, 5); sl@0: GetLongNamePart(aName, aEntry, 6, 14, 6); sl@0: GetLongNamePart(aName, aEntry, 12, 28, 2); sl@0: TInt i; sl@0: for (i = 0; i < len; i++) sl@0: if (aName[i] == 0) sl@0: break; sl@0: aName[i++] = qu; sl@0: aName.SetLength(i); sl@0: } sl@0: sl@0: GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry) sl@0: // sl@0: // Dump a single directory entry to the log. Return false if it was end of sl@0: // directory or an invalid entry (and don't display it). sl@0: // sl@0: { sl@0: TFatDirEntry* d = (TFatDirEntry*)aEntry; sl@0: if (d->IsErased()) sl@0: { sl@0: //RDebug::Print(_L("%5d: ERASED"), aNum); sl@0: } sl@0: else if (d->IsEndOfDirectory()) sl@0: { sl@0: if (aNum > 0) sl@0: RDebug::Print(_L("%5d: ------------- end of directory"), aNum); sl@0: return EFalse; sl@0: } sl@0: else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName) sl@0: { sl@0: TBuf16<15> name; sl@0: ExtractNameString(name, aEntry); sl@0: TInt ord = aEntry[0]; sl@0: if (ord & KDirLastLongEntry) sl@0: RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry); sl@0: else sl@0: RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry); sl@0: } sl@0: else if (!IsValidDirEntry(d)) sl@0: { sl@0: if (aNum > 0) sl@0: RDebug::Print(_L("%5d: ============= INVALID ENTRY"), aNum); sl@0: return EFalse; sl@0: } sl@0: else sl@0: { sl@0: TBuf<11> name; sl@0: name.Copy(d->Name()); sl@0: RDebug::Print(_L("%5d: '%S' %S start %-5d size %d"), sl@0: aNum, &name, DirAttributes(d->Attributes()), d->StartCluster(), d->Size()); sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: GLDEF_C void DumpDirCluster(const TUint8* aData, TInt aCluster=0) sl@0: // sl@0: // Dump directory entries until end of cluster or invalid/end entry found. sl@0: // sl@0: { sl@0: if (aCluster > 2) sl@0: aData += (aCluster-2) * gBytesPerCluster; sl@0: for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry) sl@0: { sl@0: if (DumpDirEntry(i/KSizeOfFatDirEntry, aData)) sl@0: aData += KSizeOfFatDirEntry; sl@0: else sl@0: break; sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void DumpRootDir(const TUint8* aData) sl@0: // sl@0: // Dump the data area buffer, trying to interpret directory clusters (only look sl@0: // at clusters which are marked as 'used' in the FAT). sl@0: // sl@0: { sl@0: RDebug::Print(_L("Root dir @ 0x%08X:"), gRootDirStart); sl@0: for (TInt i = 0; i < BootSector.RootDirEntries(); i++) sl@0: { sl@0: if (DumpDirEntry(i, aData)) sl@0: aData += KSizeOfFatDirEntry; sl@0: else sl@0: break; sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void DumpData(const TUint8* aFat, const TUint8* aDir) sl@0: // sl@0: // Dump the data area buffer, trying to interpret directory clusters (only look sl@0: // at clusters which are marked as 'used' in the FAT). sl@0: // sl@0: { sl@0: RDebug::Print(_L("--------------- DATA AREA ------------------")); sl@0: if (gDiskType != EFat32) sl@0: { sl@0: DumpRootDir(aDir); sl@0: } sl@0: TInt max = (gFatTestEntries < gMaxDataCluster ? gFatTestEntries : gMaxDataCluster); sl@0: for (TInt cluster = 2; cluster < max; cluster++) sl@0: { sl@0: if (GetFatEntry(cluster, aFat) != 0) sl@0: { sl@0: RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster)); sl@0: DumpDirCluster(aDir+gDataStartBytes-gRootDirStart, cluster); sl@0: } sl@0: } sl@0: RDebug::Print(_L("--------------------------------------------")); sl@0: } sl@0: sl@0: GLDEF_C void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd = -1) sl@0: // sl@0: // Dump clusters from disk (allows dumping of clusters not in our buffers). sl@0: // Only look at clusters marked as 'used' in the FAT. Note that if aFat is sl@0: // NULL the FAT entries will also be read from disk (slower but allows for ones sl@0: // outside our copy in memory). sl@0: // sl@0: { sl@0: if (aStart > gFatTestEntries) sl@0: return; sl@0: RDebug::Print(_L("--------------- DATA AREA ------------------")); sl@0: if (aEnd > gFatTestEntries) sl@0: aEnd = gFatTestEntries; sl@0: if (aEnd < 0) sl@0: aEnd = aStart + 1; sl@0: if (aStart < 2 && gDiskType != EFat32) sl@0: { sl@0: HBufC8* buf=HBufC8::New(BootSector.RootDirEntries() * KSizeOfFatDirEntry); sl@0: test(buf != NULL); sl@0: TPtr8 ptr=buf->Des(); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: r=TheRawDisk.Read(gRootDirStart, ptr); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: DumpRootDir(buf->Ptr()); sl@0: delete(buf); sl@0: aStart = 2; sl@0: } sl@0: for (TInt cluster = aStart; cluster < aEnd; cluster++) sl@0: { sl@0: if (GetFatEntry(cluster, aFat) != 0) sl@0: { sl@0: HBufC8* buf=HBufC8::New(gBytesPerCluster); sl@0: test(buf!=NULL); sl@0: TPtr8 ptr=buf->Des(); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: r=TheRawDisk.Read(ClusterToByte(cluster), ptr); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster)); sl@0: DumpDirCluster(ptr.Ptr()); sl@0: delete buf; sl@0: } sl@0: } sl@0: RDebug::Print(_L("--------------------------------------------")); sl@0: } sl@0: sl@0: GLDEF_C void DumpHex(const TUint8* aData, TInt aLen, TInt aBase=0) sl@0: // sl@0: // Dump a block of memory to the log in hex. sl@0: // sl@0: { sl@0: for (TInt base = 0; base < aLen; base += 16) sl@0: { sl@0: TBuf<16*3+3+16+1> buf; sl@0: TInt off; sl@0: for (off = base; off < aLen && off < base + 16; off++) sl@0: { sl@0: buf.Append(TText(' ')); sl@0: buf.AppendNumFixedWidth(aData[off], EHex, 2); sl@0: } sl@0: buf.Append(_L(" |")); sl@0: for (off = base; off < aLen && off < base + 16; off++) sl@0: { sl@0: TUint8 ch = aData[off]; sl@0: buf.Append(ch < 0x20 || ch > 0x7E ? TText('_') : TText(ch)); sl@0: } sl@0: buf.Append(_L("|")); sl@0: RDebug::Print(_L("%04X: %S"), base+aBase, &buf); sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void DumpHex(const TPtrC8& aData, TInt aLen, TInt aBase=0) sl@0: // sl@0: // Dump a block of memory to the log in hex. sl@0: // sl@0: { sl@0: DumpHex(aData.Ptr(), aLen, aBase); sl@0: } sl@0: sl@0: GLDEF_C void DumpHex(TInt aPos, TInt aLen, TInt aBase=0) sl@0: // sl@0: // Dump a block of memory to the log in hex. sl@0: // sl@0: { sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: DumpHex(dirBuf.Ptr()+aPos, aLen, aBase); sl@0: } sl@0: sl@0: GLDEF_C void Dump(TEntryInfo& aEntry) sl@0: // sl@0: // Dump an entry description to the log in hex sl@0: // sl@0: { sl@0: RDebug::Print(_L("--- TEntryInfo 0x%08X, %d"), aEntry.iBytePos, aEntry.iLength); sl@0: TInt len = aEntry.iLength*KSizeOfFatDirEntry; sl@0: DumpHex(aEntry.iBytePos, len, aEntry.iBytePos); sl@0: } sl@0: sl@0: LOCAL_C TInt GetStartCluster(TInt aCluster, TInt aEntry) sl@0: // sl@0: // Get the start cluster pertaining to a directory entry in a specific sl@0: // directory cluster, return -1 if not available (invalid entry). sl@0: // sl@0: { sl@0: HBufC8* buf=HBufC8::New(gBytesPerCluster*2); sl@0: test(buf!=NULL); sl@0: TPtr8 ptr=buf->Des(); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: r=TheRawDisk.Read(ClusterToByte(aCluster), ptr); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: RDebug::Print(_L("Cluster %d @ 0x%08X:"), aCluster, ClusterToByte(aCluster)); sl@0: TFatDirEntry* d = (TFatDirEntry*)ptr.Ptr() + aEntry; sl@0: while ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName && aEntry < gEntriesPerCluster) sl@0: { sl@0: if (d->IsErased() || d->IsEndOfDirectory()) sl@0: break; sl@0: ++aEntry; sl@0: d = (TFatDirEntry*)ptr.Ptr() + aEntry; sl@0: } sl@0: TInt start = d->StartCluster(); sl@0: if (d->IsErased()) sl@0: start = -1; sl@0: else if (d->IsEndOfDirectory()) sl@0: start = -1; sl@0: else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName) sl@0: start = -1; sl@0: else if (!IsValidDirEntry(d)) sl@0: start = -1; sl@0: delete buf; sl@0: return start; sl@0: } sl@0: sl@0: LOCAL_C void Format() sl@0: { sl@0: TInt nRes; sl@0: sl@0: #if 0 sl@0: TFatFormatParam fmt; sl@0: fmt.iFatType = EFat32; sl@0: fmt.iSecPerCluster = 1; sl@0: sl@0: nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fmt); sl@0: #else sl@0: nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue); sl@0: #endif sl@0: sl@0: test(nRes == KErrNone); sl@0: sl@0: } sl@0: sl@0: LOCAL_C void CreateDeepDir(TFileName& aDir,TInt aDepth) sl@0: // sl@0: // Increase directory strucutre by aDepth starting with aDir. sl@0: // sl@0: { sl@0: TFileName num; sl@0: num.Num(1); sl@0: num+=_L("\\"); sl@0: TInt r; sl@0: while(aDepth--) sl@0: { sl@0: num[0] = TText(aDepth % 26 + 'A'); sl@0: aDir+=num; sl@0: r=TheFs.MkDir(aDir); sl@0: test(r==KErrNone); sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void DeleteDeepDir(TFileName& aDir,TInt aDepth) sl@0: // sl@0: // Delete dir structure. sl@0: // sl@0: { sl@0: TInt r; sl@0: while(aDepth--) sl@0: { sl@0: r=TheFs.RmDir(aDir); sl@0: test(r==KErrNone); sl@0: aDir.SetLength(aDir.Length()-2); sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void CreateMaxDepthDir(TFileName& aDir1,TFileName& aDir2) sl@0: // sl@0: // Create directory structure with max possible depth-1. sl@0: // Achieved by using dir names of one character. sl@0: // sl@0: { sl@0: //create dir structure with depth of 25 sl@0: CreateDeepDir(aDir1,25); sl@0: // split dir structure sl@0: aDir2=aDir1; sl@0: aDir2+=_L("a\\"); sl@0: TInt r=TheFs.MkDir(aDir2); sl@0: test(r==KErrNone); sl@0: // create dir with depth of 126 directories - one short of max depth sl@0: CreateDeepDir(aDir1,101); sl@0: // create dir with depth of 90 sl@0: CreateDeepDir(aDir2,64); sl@0: } sl@0: sl@0: LOCAL_C void DeleteMaxDepthDir(TFileName&aDir1,TFileName&aDir2) sl@0: // sl@0: // Deletes max depth dir structure. sl@0: // sl@0: { sl@0: DeleteDeepDir(aDir2,64); sl@0: TInt r=TheFs.RmDir(aDir2); sl@0: test(r==KErrNone); sl@0: aDir2.SetLength(aDir2.Length()-2); sl@0: DeleteDeepDir(aDir1,102); sl@0: DeleteDeepDir(aDir1,24); sl@0: } sl@0: sl@0: LOCAL_C void MakeVeryLongName(TFileName& aLong) sl@0: // sl@0: // appends a very long file name to aLong sl@0: // sl@0: { sl@0: // create a name to take up 18 vfat entries - (1 sector + 2 entries) sl@0: for(TInt i=0;i<234;++i) sl@0: { sl@0: TInt c='a'+i%26; sl@0: aLong.Append(c); sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void CreateLongNames(TFileName& aLong, TInt aClusters) sl@0: // sl@0: // Creates entries to fill up the number of directory clusters sl@0: // sl@0: { sl@0: TInt len = aLong.Length(); // length of directory prefix sl@0: MakeVeryLongName(aLong); sl@0: TInt count = 0; sl@0: RFile temp; sl@0: for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19) sl@0: { sl@0: aLong[len+0] = TText(count/26 + 'A'); sl@0: aLong[len+1] = TText(count%26 + 'A'); sl@0: count++; sl@0: TInt r=temp.Create(TheFs,aLong,EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: } sl@0: } sl@0: sl@0: GLDEF_C void DeleteLongNames(TFileName& aLong, TInt aClusters) sl@0: // sl@0: // Deletes entries created by CreateLongNames() sl@0: // sl@0: { sl@0: TInt len = aLong.Length(); // length of directory prefix sl@0: MakeVeryLongName(aLong); sl@0: TInt count = 0; sl@0: for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19) sl@0: { sl@0: aLong[len+0] = TText(count/26 + 'A'); sl@0: aLong[len+1] = TText(count%26 + 'A'); sl@0: count++; sl@0: TInt r=TheFs.Delete(aLong); sl@0: test(r==KErrNone || r==KErrNotFound); sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void DeleteRootDir(TInt aNum=0) sl@0: // sl@0: // Delete all entries in the root directory up to the last - aNum sl@0: // sl@0: { sl@0: test.Next(_L("Delete Root Directory Entries")); sl@0: TInt maxRootEntries = gRootDirEntries; sl@0: TFileName name=_L("\\???xxx"); sl@0: TInt count=0; sl@0: TInt entriesSoFar=2; sl@0: TInt r; sl@0: count = 0; sl@0: for (entriesSoFar=0; entriesSoFar2) sl@0: { sl@0: dir[1]=TUint16(count/26+'a'); sl@0: dir[2]=TUint16(count%26+'a'); sl@0: r=TheFs.RmDir(dir); sl@0: test(r==KErrNone); sl@0: entriesSoFar-=2; sl@0: ++count; sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void DeleteDirectoryStructure() sl@0: // sl@0: // deletes the directory structure sl@0: // sl@0: { sl@0: test.Next(_L("Delete Directory Structure")); sl@0: TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\almostfull\\")); sl@0: test(r==KErrNone); sl@0: TInt entriesNeeded=(gEntriesPerCluster-2) / 2; //7*2entries + . + .. = full sector sl@0: for (TInt i = 0; i < entriesNeeded; i++) sl@0: { sl@0: TFileName file=_L("\\scndrv\\dir2\\full\\__a"); sl@0: file.AppendNum(i); sl@0: r=TheFs.Delete(file); sl@0: test(r==KErrNone||r==KErrNotFound); sl@0: } sl@0: r=TheFs.RmDir(_L("\\scndrv\\dir2\\full\\")); sl@0: test(r==KErrNone); sl@0: r=TheFs.RmDir(_L("\\scndrv\\dir2\\")); sl@0: test(r==KErrNone); sl@0: TFileName veryLongName=(_L("\\scndrv\\dir1\\")); sl@0: MakeVeryLongName(veryLongName); sl@0: r=TheFs.Delete(veryLongName); sl@0: test(r==KErrNone); sl@0: r=TheFs.RmDir(_L("\\scndrv\\dir1\\")); sl@0: test(r==KErrNone); sl@0: r=TheFs.RmDir(_L("\\scndrv\\")); sl@0: test(r==KErrNone); sl@0: } sl@0: sl@0: LOCAL_C void CreateDirectoryStructure() sl@0: // sl@0: // creates the directory structure sl@0: // sl@0: { sl@0: test.Next(_L("Create Directory Structure")); sl@0: // cluster 3 (root dir is cluster 2) sl@0: TInt r=TheFs.MkDir(_L("\\scndrv\\")); sl@0: test(r==KErrNone); sl@0: // cluster 4 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir1\\")); sl@0: test(r==KErrNone); sl@0: TFileName veryLongName=(_L("\\scndrv\\dir1\\")); sl@0: MakeVeryLongName(veryLongName); sl@0: RFile f; sl@0: // cluster 5 sl@0: r=f.Create(TheFs,veryLongName,EFileShareAny); sl@0: test(r==KErrNone); sl@0: r=f.SetSize(512); sl@0: test(r==KErrNone); sl@0: f.Close(); sl@0: // cluster 6 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir2\\")); sl@0: test(r==KErrNone); sl@0: // cluster 7 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir2\\full\\")); sl@0: test(r==KErrNone); sl@0: // cluster 8 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); sl@0: test(r==KErrNone); sl@0: // cluster 9 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); sl@0: test(r==KErrNone); sl@0: // cluster 10 sl@0: r=TheFs.MkDir(_L("\\scndrv\\dir2\\almostfull\\")); sl@0: test(r==KErrNone); sl@0: // cluster 11-17 sl@0: TInt entriesNeeded=(gEntriesPerCluster-2) / 2; //7*2entries + . + .. = full sector sl@0: for (TInt i = 0; i < entriesNeeded; i++) sl@0: { sl@0: TFileName file=_L("\\scndrv\\dir2\\full\\__a"); sl@0: file.AppendNum(i); sl@0: LastInFull = file; sl@0: r=f.Create(TheFs,file,EFileShareAny); sl@0: test(r==KErrNone); sl@0: if (i < 7) sl@0: { sl@0: r=f.SetSize(512); sl@0: test(r==KErrNone); sl@0: } sl@0: f.Close(); sl@0: } sl@0: // cluster 18-19 sl@0: TInt charLength=13*4+1; // name to take up 6 entries sl@0: TFileName file1=_L("\\scndrv\\dir2\\almostfull\\"); sl@0: while(charLength--) sl@0: { sl@0: TInt c='A'+charLength%26; sl@0: file1.Append(c); sl@0: } sl@0: TFileName file2=file1; sl@0: file1.AppendNum(1); sl@0: file2.AppendNum(2); sl@0: r=f.Create(TheFs,file1,EFileShareAny); sl@0: test(r==KErrNone); sl@0: r=f.SetSize(512); sl@0: test(r==KErrNone); sl@0: f.Close(); sl@0: r=f.Create(TheFs,file2,EFileShareAny); sl@0: test(r==KErrNone); sl@0: r=f.SetSize(512); sl@0: test(r==KErrNone); sl@0: f.Close(); sl@0: } sl@0: sl@0: LOCAL_C TUint8* DirPtr(TInt aOffset) sl@0: // sl@0: // Return a pointer to the offset in the dir buffer, or in the special sl@0: // extension buffer if the dir buffer isn't large enough. If the extension sl@0: // buffer is needed, it is read from disk when it is created (2 clusters, to sl@0: // allow for entries spanning cluster boundaries). Errors will occur if sl@0: // another cluster is needed before the extension has been released. sl@0: // sl@0: // Note that if an extension buffer is allocated then writing a dir buffer to sl@0: // disk will also write the extension buffer and any changes made in it. sl@0: // sl@0: { sl@0: // if the offset is in store, return its byte address sl@0: if (aOffset < DirBufPtr->Des().MaxLength()) sl@0: return (TUint8*)DirBufPtr->Ptr() + aOffset; sl@0: // not in main buffer, see if extension is allocated already sl@0: if (!ExtBufPtr) sl@0: { sl@0: // allocate buffer for 2 clusters, starting at the cluster which sl@0: // contains aOffset sl@0: ExtBufLen = 2 * gBytesPerCluster; sl@0: ExtBufPtr = HBufC8::New(ExtBufLen); sl@0: test(ExtBufPtr != NULL); sl@0: // read the clusters in sl@0: ExtBufAdd = aOffset - aOffset % gBytesPerCluster; sl@0: TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2; sl@0: RDebug::Print(_L("Extension buffer for cluster %d allocated"), clust); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TPtr8 des(ExtBufPtr->Des()); sl@0: r=TheRawDisk.Read(gRootDirStart + ExtBufAdd, des); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: } sl@0: // convert to offset in the extension buffer sl@0: aOffset -= ExtBufAdd; sl@0: if (aOffset >= ExtBufLen) sl@0: { sl@0: test.Printf(_L("*** ERROR: tried to access cluster %d not in store\n"), sl@0: (aOffset + ExtBufAdd) / gBytesPerCluster + 2); sl@0: test(0); sl@0: } sl@0: return (TUint8*)ExtBufPtr->Ptr() + aOffset; sl@0: } sl@0: sl@0: LOCAL_C void DirPtrFree() sl@0: // sl@0: // Free the extension buffer and zero the references to it. sl@0: // sl@0: { sl@0: if (ExtBufPtr) sl@0: { sl@0: TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2; sl@0: RDebug::Print(_L("Extension buffer for cluster %d deleted"), clust); sl@0: delete ExtBufPtr; sl@0: ExtBufPtr = NULL; sl@0: ExtBufAdd = 0; sl@0: ExtBufLen = 0; sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void ReadDirDisk(TDes8& aDirBuf, TInt aCluster = -1) sl@0: // sl@0: // reads directory section of disk into buffer sl@0: // sl@0: { sl@0: test(aCluster != 1); sl@0: sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: sl@0: if (aCluster == -1) // all clusters ? sl@0: { sl@0: r=TheRawDisk.Read(gRootDirStart, aDirBuf); sl@0: } sl@0: else if (aCluster == 0) // root directory cluster sl@0: { sl@0: TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster); sl@0: r=TheRawDisk.Read(gRootDirStart, dirPtr); sl@0: } sl@0: else sl@0: { sl@0: // directory buffer starts at root directory, so sl@0: // calculate offset from there. sl@0: TInt pos = ((aCluster - 2) * gBytesPerCluster) + sl@0: (gRootDirSectors * BootSector.BytesPerSector()); sl@0: TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster); sl@0: r=TheRawDisk.Read(gRootDirStart + pos, dirPtr); sl@0: } sl@0: sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: } sl@0: sl@0: LOCAL_C void ReadFatDisk(TDes8& aFatBuf) sl@0: // sl@0: // reads fat section of disk info buffer sl@0: // sl@0: { sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: r=TheRawDisk.Read(gFatStartBytes, aFatBuf); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: } sl@0: sl@0: LOCAL_C void WriteDirDisk(TDes8& aDirBuf, TInt aCluster = -1) sl@0: // sl@0: // writes dir buffer to disk sl@0: // sl@0: { sl@0: test(aCluster != 1); sl@0: sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: sl@0: if (aCluster == -1) sl@0: { sl@0: r=TheRawDisk.Write(gRootDirStart, aDirBuf); sl@0: } sl@0: else if (aCluster == 0) // root directory cluster sl@0: { sl@0: TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster); sl@0: r=TheRawDisk.Write(gRootDirStart, dirPtr); sl@0: } sl@0: else sl@0: { sl@0: // directory buffer starts at root directory, so sl@0: // calculate offset from there. sl@0: TInt pos = ((aCluster - 2) * gBytesPerCluster) + sl@0: (gRootDirSectors * BootSector.BytesPerSector()); sl@0: TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster); sl@0: r=TheRawDisk.Write(gRootDirStart + pos, dirPtr); sl@0: } sl@0: sl@0: test(r==KErrNone); sl@0: if (ExtBufPtr) sl@0: { sl@0: TPtr8 des(ExtBufPtr->Des()); sl@0: r=TheRawDisk.Write(gRootDirStart + ExtBufAdd, des); sl@0: test(r==KErrNone); sl@0: } sl@0: TheRawDisk.Close(); sl@0: } sl@0: sl@0: LOCAL_C void WriteFatDisk(TDes8& aFatBuf, TInt aStart=0) sl@0: // sl@0: // writes fat buffer to disk sl@0: // sl@0: { sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TInt fatCount=BootSector.NumberOfFats() - aStart; sl@0: TInt pos = gFatStartBytes + aStart * gFatSizeSectors*BootSector.BytesPerSector(); sl@0: while(fatCount--) sl@0: { sl@0: r=TheRawDisk.Write(pos, aFatBuf); sl@0: test(r==KErrNone); sl@0: pos += gFatSizeSectors*BootSector.BytesPerSector(); sl@0: } sl@0: TheRawDisk.Close(); sl@0: } sl@0: sl@0: LOCAL_C void WriteReservedId(TInt aBytePos) sl@0: // sl@0: // write reserved id to byte 19 of entry starting at aBytePos sl@0: // sl@0: { sl@0: TUint8* pEntry=DirPtr(aBytePos); sl@0: pEntry[19]=1; sl@0: } sl@0: sl@0: LOCAL_C void WriteEndOfDir(TInt aBytePos) sl@0: // sl@0: // write end of directory marker to entry starting at aBytePos sl@0: // sl@0: { sl@0: TUint8* pEntry=DirPtr(aBytePos); sl@0: Mem::FillZ(pEntry,KFatDirNameSize); sl@0: } sl@0: sl@0: LOCAL_C void WriteDelete(TInt aBytePos,TInt aNum) sl@0: // sl@0: // writes 0xe5 to entries starting at aBytePos sl@0: // sl@0: { sl@0: TUint8* pEntry=DirPtr(aBytePos); sl@0: while(aNum--) sl@0: { sl@0: pEntry[0]=0xE5; sl@0: pEntry+=KSizeOfFatDirEntry; sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void WriteCopyDir(TInt aSrc, TInt aDst) sl@0: // sl@0: // Copy one directory entry over another sl@0: // sl@0: { sl@0: TUint8* pSrc=DirPtr(aSrc); sl@0: TUint8* pDst=DirPtr(aDst); sl@0: Mem::Copy(pDst, pSrc, KSizeOfFatDirEntry); sl@0: } sl@0: sl@0: LOCAL_C void InitialiseBuffers() sl@0: // sl@0: // reads disk into buffers sl@0: // sl@0: { sl@0: gFatTestEntries = MaxClusters(); sl@0: if (gFatTestEntries > KMaxFatSize) sl@0: gFatTestEntries = KMaxFatSize; sl@0: gFatTestSize = PosInBytes(gFatTestEntries); sl@0: FatBufPtr=HBufC8::New(gFatTestSize); sl@0: test(FatBufPtr!=NULL); sl@0: DirBufPtr=HBufC8::New(DirBufferSize()); sl@0: test(DirBufPtr!=NULL); sl@0: sl@0: // Buffers for reading from disk sl@0: FatDiskPtr=HBufC8::New(gFatTestSize); sl@0: test(FatDiskPtr!=NULL); sl@0: DirDiskPtr=HBufC8::New(DirBufferSize()); sl@0: test(DirDiskPtr!=NULL); sl@0: } sl@0: sl@0: LOCAL_C TBool IsSameAsDrive(const TDes8& aFatBuf,const TDes8& aDirBuf) sl@0: // sl@0: // compares the two bufs passed in with those on disk sl@0: // sl@0: { sl@0: TPtr8 fatDisk=FatDiskPtr->Des(); sl@0: TPtr8 dirDisk=DirDiskPtr->Des(); sl@0: ReadDirDisk(dirDisk); sl@0: ReadFatDisk(fatDisk); sl@0: TBool fatOk = (aFatBuf.Compare(fatDisk)==0); sl@0: TBool dirOk = (aDirBuf.Compare(dirDisk)==0); sl@0: if (!fatOk) sl@0: { sl@0: TInt i = FindUnMatch(aFatBuf.Ptr(), fatDisk.Ptr(), fatDisk.Length()); sl@0: switch (gDiskType) sl@0: { sl@0: case EFat32: sl@0: i /= 4; sl@0: sl@0: if(i == 1) sl@0: {//-- mismatch in FAT[1] for FAT16/FAT32 it is OK because FAT[1] is used by volume finalisation sl@0: //-- to store Volume Clean Shutdown flag sl@0: fatOk = ETrue; sl@0: } sl@0: sl@0: break; sl@0: sl@0: case EFat16: sl@0: i /= 2; sl@0: sl@0: if(i == 1) sl@0: {//-- mismatch in FAT[1] for FAT16/FAT32 it is OK because FAT[1] is used by volume finalisation sl@0: //-- to store Volume Clean Shutdown flag sl@0: fatOk = ETrue; sl@0: } sl@0: sl@0: break; sl@0: sl@0: case EFat12: sl@0: i = i*2 / 3; sl@0: if (GetFatEntry(i, aFatBuf.Ptr()) == GetFatEntry(i, fatDisk.Ptr())) sl@0: ++i; sl@0: break; sl@0: default: sl@0: test(0); sl@0: } sl@0: sl@0: if(fatOk && i==1) sl@0: { sl@0: test.Printf(_L("Skipping FAT[1] entry for FAT16/32 \n"), i); sl@0: } sl@0: else sl@0: { sl@0: test.Printf(_L("FAT entry %d different from expected\n"), i); sl@0: sl@0: RDebug::Print(_L("Expected:\n")); sl@0: DumpFat(aFatBuf.Ptr()); sl@0: RDebug::Print(_L("Actual:\n")); sl@0: DumpFat(fatDisk.Ptr()); sl@0: } sl@0: } sl@0: sl@0: if (!dirOk) sl@0: { sl@0: TInt i = FindUnMatch(aDirBuf.Ptr(), dirDisk.Ptr(), dirDisk.Length()); sl@0: TInt clust = ByteToCluster(i); sl@0: TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry; sl@0: test.Printf(_L("DIR different from expected\n")); sl@0: test.Printf(_L(" at pos %d sector %d cluster %d entry %d:\n"), i, i / BootSector.BytesPerSector(), clust, entry); sl@0: sl@0: RDebug::Print(_L("Expected:\n")); sl@0: DumpHex(aDirBuf.Ptr() + i, 32); sl@0: RDebug::Print(_L("-------------")); sl@0: RDebug::Print(_L("Actual:\n")); sl@0: DumpHex(dirDisk.Ptr() + i, 32); sl@0: sl@0: RDebug::Print(_L("Expected:\n")); sl@0: DumpData(aFatBuf.Ptr(), aDirBuf.Ptr()); sl@0: RDebug::Print(_L("Actual:\n")); sl@0: DumpData(fatDisk.Ptr(), dirDisk.Ptr()); sl@0: } sl@0: else if (ExtBufPtr) sl@0: { sl@0: HBufC8* extPtr = HBufC8::New(ExtBufLen); sl@0: test(extPtr != NULL); sl@0: TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TPtr8 des(extPtr->Des()); sl@0: r=TheRawDisk.Read(ExtBufAdd+gRootDirStart, des); sl@0: test(r==KErrNone); sl@0: TheRawDisk.Close(); sl@0: TInt i = FindUnMatch(ExtBufPtr->Ptr(), extPtr->Ptr(), ExtBufLen); sl@0: if (i >= 0) sl@0: { sl@0: TInt extcl = (ExtBufAdd - (gDataStartBytes-gRootDirStart)) / gBytesPerCluster + 2; sl@0: TInt clust = i / gBytesPerCluster; sl@0: TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry; sl@0: test.Printf(_L("DIR different from expected\n")); sl@0: test.Printf(_L(" at cluster %d entry %d:\n"), extcl+clust, entry); sl@0: DumpHex(ExtBufPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32); sl@0: RDebug::Print(_L("-------------")); sl@0: DumpHex(extPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32); sl@0: // RDebug::Print(_L("Expected:\n")); sl@0: // DumpData(aFatBuf.Ptr(), aDirBuf.Ptr()); sl@0: // RDebug::Print(_L("Actual:\n")); sl@0: // DumpData(fatDisk.Ptr(), dirDisk.Ptr()); sl@0: dirOk = EFalse; sl@0: } sl@0: delete extPtr; sl@0: } sl@0: sl@0: return(fatOk && dirOk); sl@0: } sl@0: sl@0: LOCAL_C void WriteErased(TEntryInfo aTrg,TInt aToDelete) sl@0: // sl@0: // writes erased marker, starting at dos entry and working backwards sl@0: // used to simulate a part entry40*BootSector.BytesPerSector() sl@0: // sl@0: { sl@0: TInt toStart=aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry; sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: while(aToDelete--) sl@0: { sl@0: dirBuf[toStart]=0xE5; sl@0: toStart-=KSizeOfFatDirEntry; sl@0: } sl@0: } sl@0: sl@0: LOCAL_C void CreatePartialEntry(TEntryInfo aTrg,TInt aToDelete,TBool aAddEOfDir) sl@0: // sl@0: // creates a partial entry sl@0: // sl@0: { sl@0: WriteErased(aTrg,aToDelete); sl@0: if(aAddEOfDir) sl@0: WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: WriteDirDisk(dirBuf); sl@0: } sl@0: sl@0: LOCAL_C TBool TestPartialEntry(TEntryInfo aEntry) sl@0: // sl@0: // tests that scandrive deals with a partial entry and returns the result sl@0: // sl@0: { sl@0: test.Next(_L("TestPartialEntry")); sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: WriteDelete(aEntry.iBytePos,aEntry.iLength); sl@0: sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: sl@0: TBool res=IsSameAsDrive(fatBuf,dirBuf); sl@0: return(res); sl@0: } sl@0: sl@0: LOCAL_C void CreateMatchingEntry(TEntryInfo aTrg,TEntryInfo aSrc,TBool aAddEOfDir) sl@0: // sl@0: // creates matching entry sl@0: // sl@0: { sl@0: test.Next(_L("Create entry with start cluster already used")); sl@0: TUint8* src = DirPtr(aSrc.iBytePos); sl@0: TUint8* dst = DirPtr(aTrg.iBytePos); sl@0: Mem::Copy(dst, src, aSrc.iLength*KSizeOfFatDirEntry); sl@0: WriteReservedId(aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry); sl@0: if(aAddEOfDir) sl@0: WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: WriteDirDisk(dirBuf); sl@0: } sl@0: sl@0: LOCAL_C TBool TestMatchingEntry(TEntryInfo aToDelete) sl@0: // sl@0: // tests that scandrive deals with matching entries correctly sl@0: // sl@0: { sl@0: test.Next(_L("TestMatchingEntries")); sl@0: WriteDelete(aToDelete.iBytePos,aToDelete.iLength); sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: sl@0: TBool res=IsSameAsDrive(fatBuf,dirBuf); sl@0: DirPtrFree(); sl@0: return(res); sl@0: } sl@0: sl@0: sl@0: LOCAL_C void TestExtendedChars() sl@0: // sl@0: // tests that extended characters corresponding to ISO Latin 1 sl@0: // characters 128-255 are recognised as valid by scandrive sl@0: // sl@0: { sl@0: test.Next(_L("TestExtendedChars()")); sl@0: Format(); sl@0: sl@0: _LIT(KRoot,"\\"); sl@0: CDir* dirs; sl@0: // check no entries in the root directory sl@0: TInt r=TheFs.GetDir(KRoot,KEntryAttMaskSupported,ESortNone,dirs); sl@0: test(r==KErrNone); sl@0: test(dirs->Count()==0); sl@0: delete(dirs); sl@0: dirs=NULL; sl@0: sl@0: // create file sl@0: _LIT(KOrigShortName,"P_SSI.TXT"); sl@0: sl@0: //_LIT(KTestFile,"\\p\xE4ssi.txt"); //-- this causes problems for VC6 and default locale different from English sl@0: TBuf<64> TestFileName(_L("\\p$ssi.txt")); sl@0: TestFileName[2] = 0xe4; //-- replace '$' with this code sl@0: sl@0: //_LIT(KExtShortName,"P\xC4SSI.TXT"); //-- this causes problems for VC6 and default locale different from English sl@0: TBuf<64> ExtShortName(_L("P$SSI.TXT")); sl@0: ExtShortName[1] = 0xC4; //-- replace '$' with this code sl@0: sl@0: sl@0: RFile file; sl@0: r=file.Replace(TheFs,TestFileName,EFileShareExclusive); sl@0: test(r==KErrNone); sl@0: file.Close(); sl@0: sl@0: // get short name sl@0: TFileName shortName; sl@0: r=TheFs.GetShortName(TestFileName,shortName); sl@0: test(r==KErrNone); sl@0: test(shortName==KOrigShortName); sl@0: sl@0: // must be first entry in root, modify to read like sl@0: // a windows-generated short name (ie. contains extended character) sl@0: DumpData(NULL, 0, 20); sl@0: TInt bytePos=ClusterEntryToBytes(0,1); sl@0: RRawDisk raw; sl@0: r=raw.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TBuf8<1> buf(1); sl@0: sl@0: //-- change 2nd character in the short name (Fat DOS entry) sl@0: buf[0]=(TUint8)'\xC4'; sl@0: r=raw.Write(gRootDirStart+bytePos+1,buf); sl@0: test(r==KErrNone); sl@0: sl@0: //-- fix the fiddled short name checksum in the corresponding VFat entry sl@0: bytePos=ClusterEntryToBytes(0,0); sl@0: buf[0]=(TUint8)0x2f; sl@0: r=raw.Write(gRootDirStart+bytePos+13,buf); sl@0: test(r==KErrNone); sl@0: sl@0: // retrieve short name from media. sl@0: // Note: do not use RFs::GetShortName() as its behaviours are code page dependent. sl@0: bytePos=ClusterEntryToBytes(0,1); sl@0: TBuf8<11> shortNameBuf8; sl@0: r=raw.Read(gRootDirStart+bytePos,shortNameBuf8); sl@0: test(r==KErrNone); sl@0: shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8); sl@0: shortName.Copy(shortNameBuf8); sl@0: raw.Close(); sl@0: sl@0: sl@0: test(shortName==ExtShortName); sl@0: DumpData(NULL, 0, 20); sl@0: //TheFs.SetDebugRegister(KFSYS); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: TheFs.SetDebugRegister(0); sl@0: test(r==KErrNone); sl@0: DumpData(NULL, 0, 20); sl@0: sl@0: // retrieve short name from media. sl@0: r=raw.Open(TheFs,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: bytePos=ClusterEntryToBytes(0,1); sl@0: r=raw.Read(gRootDirStart+bytePos,shortNameBuf8); sl@0: test(r==KErrNone); sl@0: shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8); sl@0: shortName.Copy(shortNameBuf8); sl@0: raw.Close(); sl@0: sl@0: test(shortName==ExtShortName); sl@0: sl@0: // delete file sl@0: r=TheFs.Delete(TestFileName); sl@0: test(r==KErrNone); sl@0: } sl@0: sl@0: LOCAL_C void TestMountAndScan() sl@0: // sl@0: // test MountFileSystemAndScan() sl@0: // sl@0: { sl@0: TFullName extName; sl@0: TBool primaryExtensionExists = EFalse; sl@0: sl@0: test.Next(_L("TestMountAndScan")); sl@0: HBufC8* newFat=HBufC8::New(gFatTestSize); sl@0: test(newFat!=NULL); sl@0: TPtr8 fat=newFat->Des(); sl@0: TPtr8 origFat=FatBufPtr->Des(); sl@0: TPtr8 origDir=DirBufPtr->Des(); sl@0: sl@0: // set cluster of \scndrv\dir1\ to a hanging cluster sl@0: ReadFatDisk(fat); sl@0: WriteFat(gClusterDir1ext,35,fat.Ptr()); sl@0: WriteFat(35,36,fat.Ptr()); sl@0: WriteFatDisk(fat); sl@0: // set the default path to something other than the current drive sl@0: TFileName fsName; sl@0: TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: TFileName origDefPath, newDefPath; sl@0: r=TheFs.SessionPath(origDefPath); sl@0: test(r==KErrNone); sl@0: newDefPath=origDefPath; sl@0: newDefPath[0]=(TText)'z'; sl@0: r=TheFs.SetSessionPath(newDefPath); sl@0: test(r==KErrNone); sl@0: r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0); sl@0: if (r == KErrNone) sl@0: { sl@0: primaryExtensionExists = ETrue; sl@0: } sl@0: r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: // mount file system and check scandrive corrects error sl@0: TBool isMount; sl@0: if (primaryExtensionExists) sl@0: r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); sl@0: else sl@0: r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); sl@0: test(isMount && r==KErrNone); sl@0: TBool res=IsSameAsDrive(origFat,origDir); sl@0: test(res); sl@0: sl@0: r=TheFs.SetSessionPath(origDefPath); sl@0: test(r==KErrNone); sl@0: delete newFat; sl@0: } sl@0: sl@0: sl@0: LOCAL_C void TestConsecutiveMountAndScans() sl@0: // sl@0: // test fix for DEF093072: [codebase]MountFileSystemAndScan returns err -21 but ok flag sl@0: // sl@0: { sl@0: TFullName extName; sl@0: TBool primaryExtensionExists = EFalse; sl@0: TFileName fsName; sl@0: TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0); sl@0: if (r == KErrNone) sl@0: { sl@0: primaryExtensionExists = ETrue; sl@0: } sl@0: r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A'); sl@0: test(r==KErrNone); sl@0: sl@0: // RFs::MountFileSystemAndScan twice consecutively sl@0: // first time sl@0: TBool isMount; sl@0: if (primaryExtensionExists) sl@0: r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); sl@0: else sl@0: r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); sl@0: test(isMount && r==KErrNone); sl@0: // and a second time sl@0: if (primaryExtensionExists) sl@0: r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); sl@0: else sl@0: r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); sl@0: test(!isMount && r==KErrAccessDenied); sl@0: } sl@0: sl@0: LOCAL_C void DoHangingClusters() sl@0: // sl@0: // Tests that scandrive removes hanging clusters sl@0: // sl@0: { sl@0: test.Next(_L("Check Hanging clusters")); sl@0: HBufC8* newFat=HBufC8::New(gFatTestSize); sl@0: test(newFat!=NULL); sl@0: TPtr8 fat=newFat->Des(); sl@0: TPtr8 origFat=FatBufPtr->Des(); sl@0: TPtr8 origDir=DirBufPtr->Des(); sl@0: sl@0: // set cluster of \scndrv\dir1\ to a hanging cluster sl@0: test.Start(_L("Test hanging cluster in \\scndrv\\dir1\\")); sl@0: ReadFatDisk(fat); sl@0: WriteFat(gClusterDir1ext,35,fat.Ptr()); sl@0: WriteFat(35,36,fat.Ptr()); sl@0: WriteFatDisk(fat); sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: TBool res=IsSameAsDrive(origFat,origDir); sl@0: test(res); sl@0: sl@0: // set cluster chain of first entry of \scndrv\dir1\ to sl@0: // larger size than file size sl@0: test.Next(_L("Test hanging cluster in first entry")); sl@0: ReadFatDisk(fat); sl@0: WriteFat(gClusterDir1ext,39,fat.Ptr()); sl@0: WriteFat(39,500,fat.Ptr()); sl@0: WriteFat(500,gEndOfChain,fat.Ptr()); sl@0: WriteFatDisk(fat); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: res=IsSameAsDrive(origFat,origDir); sl@0: test(res); sl@0: sl@0: // set cluster of \scndrv\ to a hanging cluster sl@0: test.Next(_L("Test hanging cluster of \\scndrv\\")); sl@0: ReadFatDisk(fat); sl@0: WriteFat(gClusterScnDrv,511,fat.Ptr()); sl@0: WriteFatDisk(fat); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: res=IsSameAsDrive(origFat,origDir); sl@0: test(res); sl@0: sl@0: delete newFat; sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void DoLostClusters() sl@0: // sl@0: // Tests that scandrive removes lost clusters sl@0: // sl@0: { sl@0: test.Next(_L("Check lost clusters")); sl@0: HBufC8* newFat=HBufC8::New(gFatTestSize); sl@0: test(newFat!=NULL); sl@0: TPtr8 fat=newFat->Des(); sl@0: TPtr8 origFat=FatBufPtr->Des(); sl@0: TPtr8 origDir=DirBufPtr->Des(); sl@0: ReadFatDisk(origFat); sl@0: ReadDirDisk(origDir); sl@0: sl@0: // write cluster chain sl@0: test.Start(_L("Test removal of lost cluster chain")); sl@0: ReadFatDisk(fat); sl@0: for(TInt i=25;i<35;++i) sl@0: WriteFat(i,i+1,fat.Ptr()); sl@0: WriteFat(35,gEndOfChain,fat.Ptr()); sl@0: WriteFatDisk(fat); sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: TBool res=IsSameAsDrive(origFat,origDir); sl@0: test(res); sl@0: sl@0: // write semi-random changes to first fat sl@0: test.Next(_L("Test semi-random changes to first fat")); sl@0: for(TInt j=1;jDes(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: sl@0: TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); sl@0: test(r==KErrNone || r==KErrNotFound || KErrPathNotFound); sl@0: r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); sl@0: test(r==KErrNone || r==KErrNotFound || KErrPathNotFound); sl@0: sl@0: if (BootSector.RootDirEntries() != 0) sl@0: { sl@0: // Can only do this on FAT12/16, FAT32 root directory is extensible sl@0: // partial entry that fills up the root dir sl@0: test.Next(_L("Partial entry at end of rootdir")); sl@0: FillUpRootDir(2); sl@0: r=temp.Create(TheFs,_L("\\temp"),EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: TEntryInfo partial1(ClusterEntryToBytes(gClusterRootDir,BootSector.RootDirEntries()-2),2); sl@0: CreatePartialEntry(partial1,1,EFalse); sl@0: res=TestPartialEntry(partial1); sl@0: test(res); sl@0: UnFillUpRootDir(2); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: } sl@0: sl@0: // use first entry \scndrv\dir2\almostfull\ sl@0: test.Next(_L("Partial entry in middle of subdir")); sl@0: last = GetStartCluster(gClusterDir2_AFull,7); sl@0: TEntryInfo partial2(ClusterEntryToBytes(gClusterDir2_AFull,2),6); sl@0: CreatePartialEntry(partial2,3,EFalse); sl@0: // entry has been allocated a cluster which scandrive should delete along with partial entry sl@0: if (last > 0) sl@0: WriteFat(last,0,fatBuf.Ptr()); sl@0: res=TestPartialEntry(partial2); sl@0: test(res); sl@0: sl@0: // reduce size of \scndrv\dir2\full\ sl@0: test.Next(_L("Test directory reclaim")); sl@0: last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-2); sl@0: WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2)); sl@0: WriteDirDisk(dirBuf); sl@0: TInt entry = GetFatEntry(gClusterDir2_Full, fatBuf.Ptr()); sl@0: WriteFat(gClusterDir2_Full,gEndOfChain,fatBuf.Ptr()); sl@0: while (entry && (entry & gEndOfChain) != gEndOfChain) sl@0: { sl@0: TInt next = GetFatEntry(entry, fatBuf.Ptr()); sl@0: WriteFat(entry,0,fatBuf.Ptr()); sl@0: entry = next; sl@0: } sl@0: if (last > 0) sl@0: WriteFat(last,0,fatBuf.Ptr()); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: res=IsSameAsDrive(fatBuf,dirBuf); sl@0: test(res); sl@0: sl@0: // use last entry of first cluster in \scndrv\dir2\full\ sl@0: test.Next(_L("Partial entry at end of subdir")); sl@0: r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: TEntryInfo partial3(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),2); sl@0: CreatePartialEntry(partial3,1,EFalse); sl@0: res=TestPartialEntry(partial3); sl@0: test(res); sl@0: sl@0: // use entry in \scndrv\dir2\almostfull\ sl@0: test.Next(_L("Partial entry preceeding end-of-dir marker")); sl@0: last = GetStartCluster(gClusterDir2_AFull,14); sl@0: if (last > 0) sl@0: WriteFat(last,0,fatBuf.Ptr()); sl@0: last = GetStartCluster(gClusterDir2_AFull,8); sl@0: if (last > 0) sl@0: WriteFat(last,0,fatBuf.Ptr()); sl@0: WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_AFull,14)); sl@0: WriteDirDisk(dirBuf); sl@0: TEntryInfo partial4(ClusterEntryToBytes(gClusterDir2_AFull,8),6); sl@0: CreatePartialEntry(partial4,4,EFalse); sl@0: res=TestPartialEntry(partial4); sl@0: test(res); sl@0: sl@0: // NOTE: sl@0: // Following test case is not valid anymore after fixing of sl@0: // PDEF128576: Unicode name file deleted after Scandrive sl@0: // In the fixes, we decided to discard file name checking in ScanDrive, sl@0: // as it is impossible for ScanDrive to judge if the illegal byte is part of a legal sl@0: // DBCS charater. sl@0: sl@0: // create entry in \scndrv\dir2\almostfull\ sl@0: // test.Next(_L("Partial entry with invalid dos name")); sl@0: // r=temp.Create(TheFs,_L("\\scndrv\\dir2\\almostfull\\Dodgy file name"),EFileShareAny); sl@0: // test(r==KErrNone); sl@0: // temp.Close(); sl@0: // ReadDirDisk(dirBuf); sl@0: // TInt dosStart=ClusterEntryToBytes(gClusterDir2_AFull,4); sl@0: // dirBuf[dosStart+4]=0x1; sl@0: // WriteDirDisk(dirBuf); sl@0: // r=TheFs.ScanDrive(gSessionPath); sl@0: // test(r==KErrNone); sl@0: // WriteDelete(dosStart-2*32,3); sl@0: // res=IsSameAsDrive(fatBuf,dirBuf); sl@0: // test(res); sl@0: sl@0: if (BootSector.SectorsPerCluster() == 1) sl@0: { sl@0: // use entry created in \scndrv\dir2\ sl@0: test.Next(_L("Partial entry spanning more than two clusters")); sl@0: last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-1); sl@0: WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2)); sl@0: WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-1)); sl@0: WriteDirDisk(dirBuf); sl@0: TFileName longFile=_L("\\scndrv\\dir2\\full\\"); sl@0: MakeVeryLongName(longFile); sl@0: r=temp.Create(TheFs,longFile,EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: ReadDirDisk(dirBuf); sl@0: WriteFat(gClusterDir2_Full,gClusterDir2_SD3E,fatBuf.Ptr()); sl@0: WriteFat(gClusterDir2_SD3E,gClusterDir2_SD23E,fatBuf.Ptr()); sl@0: WriteFat(gClusterDir2_SD23E,gEndOfChain,fatBuf.Ptr()); sl@0: if (last > 0) sl@0: WriteFat(last,0,fatBuf.Ptr()); sl@0: TEntryInfo partial5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19); sl@0: CreatePartialEntry(partial5,7,EFalse); sl@0: res=TestPartialEntry(partial5); sl@0: test(res); sl@0: r=TheFs.Delete(longFile); sl@0: test(r==KErrNone || r==KErrNotFound); sl@0: r=TheFs.Delete(_L("\\temp")); sl@0: test(r==KErrNone || r==KErrNotFound); sl@0: } sl@0: ReadDirDisk(dirBuf); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void DoMatchingEntries() sl@0: // sl@0: // Tests that scandrive detects/corrects entries with the same start cluster sl@0: // Copies entry to new location - replicates start cluster sl@0: // sl@0: { sl@0: test.Next(_L("Check matching entries")); sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: sl@0: // first entry in \scndrv\almostfull\ + root dir sl@0: test.Start(_L("matching entries in subdir + root dir")); sl@0: TEntryInfo from1(ClusterEntryToBytes(gClusterDir2_AFull,2),6); sl@0: TEntryInfo to1(ClusterEntryToBytes(gClusterRootDir,2),6); sl@0: CreateMatchingEntry(to1,from1,EFalse); sl@0: TBool res=TestMatchingEntry(to1); sl@0: test(res); sl@0: sl@0: // matching entries between 2 subdirs, one which has a full cluster sl@0: // first entry in \scndrv\dir2\full\ + end of \scndrv\dir2\almostfull\ sl@0: test.Next(_L("matching entries between 2 subdirs")); sl@0: TEntryInfo from2(ClusterEntryToBytes(gClusterDir2_Full,2),2); sl@0: TEntryInfo to2(ClusterEntryToBytes(gClusterDir2_AFull,14),2); sl@0: CreateMatchingEntry(to2,from2,EFalse); sl@0: res=TestMatchingEntry(to2); sl@0: test(res); sl@0: sl@0: // matching entries between two subdirs - one with end of dir marker next sl@0: // \scndrv\dir2\somedirwith3entries to \scndrv\ sl@0: test.Next(_L("matching entries between two subdirs")); sl@0: TEntryInfo from3(ClusterEntryToBytes(gClusterDir2,4),3); sl@0: TEntryInfo to3(ClusterEntryToBytes(gClusterScnDrv,6),3); sl@0: CreateMatchingEntry(to3,from3,ETrue); sl@0: res=TestMatchingEntry(to3); sl@0: test(res); sl@0: sl@0: // matching entries in same subdir, one in new cluster - irrelevant if matching names sl@0: // 1st and last entries in \scndrv\dir2\full\ sl@0: test.Next(_L("matching entries in same subdir")); sl@0: // delete entries to allow contiguous clusters in \scndrv\dir2\full directory sl@0: TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); sl@0: test(r==KErrNone); sl@0: r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); sl@0: test(r==KErrNone); sl@0: // ensure directory is expanded sl@0: RFile temp; sl@0: r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: r=TheFs.Delete(_L("\\scndrv\\dir2\\full\\temp")); sl@0: test(r==KErrNone); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: TEntryInfo from4(ClusterEntryToBytes(gClusterDir2_Full,4),2); sl@0: TEntryInfo to4(ClusterEntryToBytes(gClusterDir2_Full+1,0),2); sl@0: CreateMatchingEntry(to4,from4,ETrue); sl@0: res=TestMatchingEntry(to4); sl@0: test(res); sl@0: sl@0: // \scndrv\dir1\very long name to \\scndrv\dir2\full\ sl@0: test.Next(_L("matching entries in diff dirs + new cluster")); sl@0: // delete last entry in directory sl@0: r=TheFs.Delete(LastInFull); sl@0: test(r==KErrNone); sl@0: TFileName veryLongName=_L("\\scndrv\\dir2\\full\\"); sl@0: MakeVeryLongName(veryLongName); sl@0: r=temp.Create(TheFs,veryLongName,EFileShareAny); sl@0: test(r==KErrNone); sl@0: temp.Close(); sl@0: r=TheFs.Delete(veryLongName); sl@0: test(r==KErrNone); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: TEntryInfo from5(ClusterEntryToBytes(gClusterDir1,2),19); sl@0: TEntryInfo to5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19); sl@0: CreateMatchingEntry(to5,from5,EFalse); sl@0: res=TestMatchingEntry(to5); sl@0: test(res); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: sl@0: LOCAL_C void DoMaxDepth() sl@0: // sl@0: // Test directory structure with max possible depth sl@0: // sl@0: { sl@0: test.Next(_L("Check max directory depth")); sl@0: test.Start(_L("Using single character names")); sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: // Create dir structure sl@0: TFileName dir1=_L("\\"); sl@0: TFileName dir2; sl@0: CreateMaxDepthDir(dir1,dir2); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: // run scandisk and compare sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: TBool res=IsSameAsDrive(fatBuf,dirBuf); sl@0: test(res); sl@0: // Create a entry with matching start cluster and check fixed up sl@0: TEntryInfo from(ClusterEntryToBytes(gClusterDir2_AFull,2),6); sl@0: TEntryInfo to(ClusterEntryToBytes(gClusterEndMaxDepth,2),6); sl@0: CreateMatchingEntry(to,from,ETrue); sl@0: res=TestMatchingEntry(to); sl@0: test(res); sl@0: // DeleteMaxDepthStructure sl@0: DeleteMaxDepthDir(dir1,dir2); sl@0: test.End(); sl@0: } sl@0: sl@0: LOCAL_C void DoRootDir() sl@0: // sl@0: // Check that a full root directory is searched OK sl@0: // sl@0: { sl@0: test.Next(_L("Check a full root directory")); sl@0: FillUpRootDir(); sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: sl@0: TInt r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: sl@0: TBool res=IsSameAsDrive(fatBuf,dirBuf); sl@0: test(res); sl@0: UnFillUpRootDir(); sl@0: } sl@0: sl@0: LOCAL_C void TestNonVfatNames(const TPtrC& aDirName, TInt aDirCluster, TInt aEntry=2) sl@0: // sl@0: // Check that files without 'long' entries are kept intact. Creates files with sl@0: // a DOS type name, and for each one created except the last deletes the VFAT sl@0: // entry by copying the DOS entry over it and writing end of directory. This sl@0: // leaves a VFAT entry at the end of the directory, except when there is only sl@0: // room for one file. sl@0: // sl@0: // The layout, for 1 sector per cluster, is thus like: sl@0: // 0 . sl@0: // 1 .. sl@0: // 2 TEMPFILE.000 sl@0: // 3 TEMPFILE.001 sl@0: // ... sl@0: // 14 tempfile.012 VFAT sl@0: // 15 TEMPFILE.012 sl@0: // sl@0: // or for an almost full directory sl@0: // sl@0: // 0 . sl@0: // 1 .. sl@0: // whatever... sl@0: // 14 TEMPFILE.000 sl@0: // 15 end of directory sl@0: // sl@0: { sl@0: test.Printf(_L("Test cluster %2d, aEntry %d: %S\n"), aDirCluster, aEntry, &aDirName); sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: TInt cluster = aDirCluster; sl@0: sl@0: TInt maxEntry = gEntriesPerCluster; sl@0: if (aDirName.Compare(_L("\\")) == KErrNone) sl@0: maxEntry = Min(gRootDirEntries, gEntriesPerCluster); sl@0: sl@0: TInt entry = aEntry; sl@0: TInt r = KErrNone; sl@0: TInt i; sl@0: sl@0: while (entry > gEntriesPerCluster) sl@0: { sl@0: entry -= gEntriesPerCluster; sl@0: cluster++; sl@0: } sl@0: sl@0: TInt nFiles = maxEntry - entry - 1; sl@0: TInt startEntry = entry; sl@0: sl@0: test.Printf(_L("cluster %d, entry %d maxEntry %d, nFiles %d\n"), cluster, entry, maxEntry, nFiles); sl@0: sl@0: TBuf8<256> buf; sl@0: buf.Fill('*', 256); sl@0: sl@0: // Set up files, ignoring used slots sl@0: TInt filesThisTime = nFiles; sl@0: TInt totalFilesCreated = 0; sl@0: FOREVER sl@0: { sl@0: // sl@0: // Create a number of VFat entries sl@0: // sl@0: // - We create as many as we can fit in the cluster in one go. sl@0: // This is faster than creating a single entry then copying, as writing the sl@0: // entries one at a time using RRawDisk causes a remount of the file system, sl@0: // which can take a very long time on a large disk. sl@0: // sl@0: filesThisTime = (nFiles - totalFilesCreated) >> 1; sl@0: if(filesThisTime == 0) sl@0: { sl@0: if(nFiles == totalFilesCreated) sl@0: { sl@0: test.Printf(_L("Created all Non-VFAT entries\n")); sl@0: break; sl@0: } sl@0: sl@0: //...creating the final entry sl@0: filesThisTime = 1; sl@0: } sl@0: sl@0: for (i = 0; i < filesThisTime; i++) sl@0: { sl@0: TFileName name(aDirName); sl@0: name.Append(_L("tempfile.")); sl@0: name.AppendNumFixedWidth(i+totalFilesCreated, EHex, 3); sl@0: RFile f; sl@0: r = f.Create(TheFs, name, EFileShareAny); sl@0: test(r == KErrNone); sl@0: r = f.Write(buf); sl@0: test(r == KErrNone); sl@0: f.Close(); sl@0: } sl@0: sl@0: // sl@0: // Move DOS FAT entries up using RRawDisk, deleting the original VFAT entries sl@0: // sl@0: ReadDirDisk(dirBuf, cluster); sl@0: TInt dosEntry = entry + 1; sl@0: for (i = 0; i < filesThisTime; i++) sl@0: { sl@0: // Copy VFAT to Non-VFAT entries sl@0: if (entry+2 < maxEntry || nFiles < 2) sl@0: { sl@0: TInt posVFAT = ClusterEntryToBytes(cluster, entry); sl@0: TInt posEOD = ClusterEntryToBytes(cluster, entry+1); sl@0: TInt posDOS = ClusterEntryToBytes(cluster, dosEntry); sl@0: sl@0: WriteCopyDir(posDOS, posVFAT); // Copy the DOS entry sl@0: WriteDelete(posDOS,2); // Delete the original entry sl@0: WriteEndOfDir(posEOD); // Write End Of Directory sl@0: sl@0: entry += 1; sl@0: dosEntry += 2; sl@0: } sl@0: else sl@0: { sl@0: // last entry has VFAT intact, to fill cluster sl@0: entry += 2; sl@0: } sl@0: sl@0: } sl@0: sl@0: WriteDirDisk(dirBuf, cluster); sl@0: totalFilesCreated += filesThisTime; sl@0: test.Printf(_L(" created %d entries\n"), totalFilesCreated); sl@0: } sl@0: sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: sl@0: DumpData(NULL, aDirCluster, cluster+1); sl@0: sl@0: test.Printf(_L("Running ScanDrive\n"), filesThisTime); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: sl@0: TBool res=IsSameAsDrive(fatBuf,dirBuf); sl@0: test(res); sl@0: sl@0: test.Printf(_L("Deleting %d files\n"), nFiles); sl@0: for (i = 0; i < nFiles; i++) sl@0: { sl@0: TFileName name(aDirName); sl@0: name.Append(_L("tempfile.")); sl@0: name.AppendNumFixedWidth(i, EHex, 3); sl@0: r = TheFs.Delete(name); sl@0: test(r == KErrNone); sl@0: } sl@0: sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: WriteEndOfDir(ClusterEntryToBytes(cluster, startEntry)); sl@0: WriteDirDisk(dirBuf); sl@0: sl@0: test.Printf(_L("Running ScanDrive\n"), filesThisTime); sl@0: r=TheFs.ScanDrive(gSessionPath); sl@0: test(r==KErrNone); sl@0: res=IsSameAsDrive(fatBuf,dirBuf); sl@0: test(res); sl@0: } sl@0: sl@0: LOCAL_C void DoNonVfatNames() sl@0: // sl@0: // Check that files without 'long' entries are kept intact sl@0: // sl@0: { sl@0: test.Next(_L("Check non-VFAT file names")); sl@0: TestNonVfatNames(_L("\\"), gClusterRootDir, 2); sl@0: TestNonVfatNames(_L("\\scndrv\\dir1\\"), gClusterDir1, 2+19); sl@0: TestNonVfatNames(_L("\\scndrv\\dir2\\somedirwith3entries\\"), gClusterDir2_SD3E, 2); sl@0: TestNonVfatNames(_L("\\scndrv\\dir2\\almostfull\\"), gClusterDir2_AFull, 14); sl@0: } sl@0: sl@0: sl@0: LOCAL_C void DoTests() sl@0: { sl@0: sl@0: Format(); sl@0: DoReadBootSector(); sl@0: DumpBootSector(); sl@0: InitialiseBuffers(); sl@0: CreateRootDir(); sl@0: CreateDirectoryStructure(); sl@0: TPtr8 fatBuf=FatBufPtr->Des(); sl@0: TPtr8 dirBuf=DirBufPtr->Des(); sl@0: ReadDirDisk(dirBuf); sl@0: ReadFatDisk(fatBuf); sl@0: DumpFat(); sl@0: DumpData(NULL, DirBufPtr->Ptr()); sl@0: sl@0: DoNonVfatNames(); sl@0: DoRootDir(); sl@0: DoMaxDepth(); sl@0: DoMatchingEntries(); sl@0: DoPartEntries(); sl@0: DoLostClusters(); sl@0: DoHangingClusters(); sl@0: TestMountAndScan(); sl@0: TestConsecutiveMountAndScans(); sl@0: DeleteDirectoryStructure(); sl@0: DeleteRootDir(); sl@0: TestExtendedChars(); sl@0: sl@0: DumpBootSector(); sl@0: DumpFat(); sl@0: DumpData(NULL, 0, 200); sl@0: sl@0: delete FatDiskPtr; sl@0: delete DirDiskPtr; sl@0: delete FatBufPtr; sl@0: delete DirBufPtr; sl@0: } sl@0: sl@0: sl@0: void CallTestsL() sl@0: { sl@0: TInt r; sl@0: r = TheFs.CharToDrive(gSessionPath[0], gDriveNumber); sl@0: test( KErrNone == r ); sl@0: sl@0: sl@0: //-- set up console output sl@0: Fat_Test_Utils::SetConsole(test.Console()); sl@0: sl@0: //-- print drive information sl@0: PrintDrvInfo(TheFs, gDriveNumber); sl@0: sl@0: if (!Is_Fat(TheFs, gDriveNumber)) sl@0: { sl@0: test.Printf(_L("CallTestsL: Skipped: test requires FAT filesystem\n")); sl@0: return; sl@0: } sl@0: sl@0: // check this is not the internal ram drive sl@0: TVolumeInfo v; sl@0: r=TheFs.Volume(v); sl@0: test(r==KErrNone); sl@0: if(v.iDrive.iMediaAtt&KMediaAttVariableSize) sl@0: { sl@0: test.Printf(_L("Error: Internal ram drive not tested\n")); sl@0: return; sl@0: } sl@0: sl@0: r=TheFs.SetSessionPath(gSessionPath); sl@0: test(r==KErrNone); sl@0: sl@0: DoTests(); sl@0: sl@0: return; sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: