First public contribution.
1 // Copyright (c) 1998-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32test\scndrv\t_tscan32.cpp
23 #include "fat_utils.h"
24 using namespace Fat_Test_Utils;
27 Series of tests to check that the combination of a ruggedised fat file
28 system and scandisk prevents the file system from becoming corrupt in the
29 event of a power failure. CheckDisk is used to test that directory
30 structure is not corrupt. This test is only suitable with a drive that uses
31 the fat file system but not the internal ram drive (due to the indirection)
32 table. Only works with debug builds due to RFs::ControlIo only debug function
35 GLDEF_D TFileName StartupExeName=_L(""); // initialised at run time
39 GLDEF_D TInt TheFunctionNumber;
40 GLDEF_D TInt TheOpNumber;
41 GLDEF_D TInt TheFailCount;
42 GLDEF_D TBool IsReset;
43 GLDEF_D TFileName TestExeName=_L("?:\\T_SCANDR.EXE"); //Renaming it to fit in one root dir entry.
44 GLDEF_D TFileName LogFileName=_L("?:\\T_SCANDR.LOG"); //Renaming it to fit in one root dir entry.
46 const TInt KControlIoWriteFailOn=0; // commands to pass into RFs::ControlIo
47 const TInt KControlIoWriteFailOff=1;
48 const TInt KMaxFatEntries = 2048;
49 const TInt KDirAttrReadOnly = 0x01;
50 const TInt KDirAttrHidden = 0x02;
51 const TInt KDirAttrSystem = 0x04;
52 const TInt KDirAttrVolumeId = 0x08;
53 const TInt KDirAttrDirectory = 0x10;
54 const TInt KDirAttrArchive = 0x20;
55 const TInt KDirAttrLongName = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId;
56 const TInt KDirAttrLongMask = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
57 const TInt KDirLastLongEntry = 0x40;
59 GLDEF_D TInt WriteFailValue;
61 LOCAL_C TFatBootSector BootSector;
62 LOCAL_D RRawDisk TheRawDisk;
64 static TFatType gDiskType = EInvalid;
66 LOCAL_D TInt gTotalSectors;
67 LOCAL_D TInt gBytesPerCluster;
68 LOCAL_D TInt gRootDirSectors;
69 LOCAL_D TInt gRootDirEntries;
70 LOCAL_D TInt gRootDirStart;
71 LOCAL_D TInt gRootSector;
72 LOCAL_D TInt gFatStartBytes;
73 LOCAL_D TInt gFatTestEntries;
74 LOCAL_D TInt gFatSizeSectors;
75 LOCAL_D TInt gFirstDataSector;
76 LOCAL_D TInt gDataStartBytes;
77 LOCAL_D TInt gClusterCount;
79 LOCAL_D HBufC8* gFatBuf = NULL;
80 LOCAL_D TInt gFatAddr = -1;
82 enum TFatChain {EChainStd,EChainAlternate,EChainBackwards,EChainForwards};
84 LOCAL_C TBool IsInternalRam()
86 // Returns true if the selected drive is variable size (i.e. RAM drive)
90 TInt r=TheFs.Volume(v,gSessionPath[0]-'A');
92 return(v.iDrive.iMediaAtt&KMediaAttVariableSize);
95 LOCAL_C void WriteLogFile()
97 // Writes state of test to end of LogFileName
100 test.Printf(_L("Writelogfile()\n"));
102 TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive|EFileWrite);
104 test.Printf(_L("error=%d\n"),r);
111 buf[0]=(TUint8)TheFunctionNumber;
112 buf[1]=(TUint8)TheOpNumber;
113 buf[2]=(TUint8)TheFailCount;
115 r=log.Write(size,buf,buf.Length());
117 test.Printf(_L("Written func=%d,op=%d,fail=%d\n"),TheFunctionNumber,TheOpNumber,TheFailCount);
121 LOCAL_C TInt SetWriteFailOn(TInt aFailCount)
123 // Sets write to metadata to fail on aFailCount with WriteFailValue
127 TPtr8 des((TUint8*)args,4,4);
128 args[0]=(TUint16)aFailCount;
129 args[1]=(TUint16)WriteFailValue;
130 TInt r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOn,des);
134 GLDEF_C void ReadLogFile()
136 // Reads state of test from end of LogFileName and sets global variables
139 test.Next(_L("ReadLogFile"));
141 TInt r=log.Open(TheFs,LogFileName,EFileShareExclusive);
143 test.Printf(_L("error in ReadLogFile()=%d\n"),r);
147 r=log.Size(fileSize);
157 r=log.Read(fileSize-4,buf,4);
158 TheFunctionNumber=buf[0];
163 test.Printf(_L("func=%d,op=%d,fail=%d\n"),TheFunctionNumber,TheOpNumber,TheFailCount);
166 LOCAL_C TUint32 MaxClusters()
168 // Return the number of data clusters on the disk
171 TUint32 totSec = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors());
172 TUint32 numSec = totSec - gFirstDataSector;
173 return numSec / BootSector.SectorsPerCluster();
176 LOCAL_C TInt ClusterToByte(TInt aCluster)
178 // converts cluster number to byte offset on disk
181 TInt sector = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * BootSector.BytesPerSector();
186 Fill media with zeroes from aStartPos to aEndPos
188 static void DoZeroFillMedia(TInt64 aStartPos, TInt64 aEndPos, RRawDisk& aWriter)
190 test(aStartPos >=0 && aEndPos >=0 && aStartPos < aEndPos);
192 if(aStartPos == aEndPos)
198 const TUint32 KBufSz=65536*2; //-- buffer with zeroes
200 nRes = buf.CreateMax(KBufSz);
201 test(nRes == KErrNone);
205 TUint32 rem = (TUint32)(aEndPos - aStartPos);
208 const TUint32 bytesToWrite=Min(rem, KBufSz);
210 TPtrC8 ptr(buf.Ptr(), bytesToWrite);
211 nRes = aWriter.Write(aStartPos, ptr);
212 test(nRes == KErrNone || nRes == KErrDiskFull);
214 aStartPos+=bytesToWrite;
223 // Clear the disk data area to a known value which won't be confused with
224 // directory entries etc.
226 LOCAL_C void ClearDiskData()
229 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
232 TUint32 startPos = gDataStartBytes;
233 if (gDiskType == EFat32)
234 startPos += gBytesPerCluster;
236 const TUint32 endPos = startPos + gFatTestEntries*gBytesPerCluster;
238 test.Printf(_L("ClearDiskData() from pos:%u to pos:%u\n"), startPos, endPos);
240 DoZeroFillMedia(startPos, endPos, TheRawDisk);
245 LOCAL_C TInt PosInBytes(TInt aFatIndex)
247 // Return number of bytes into the FAT
250 TInt fatPosInBytes = -1;
254 fatPosInBytes=aFatIndex<<2;
257 fatPosInBytes=aFatIndex<<1;
260 fatPosInBytes=(aFatIndex*3>>1);
265 return(fatPosInBytes);
268 static void DoReadBootSector()
271 TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector);
272 test(nRes == KErrNone);
274 if(!BootSector.IsValid())
276 test.Printf(_L("Wrong bootsector! Dump:\n"));
277 BootSector.PrintDebugInfo();
280 // Calculate derived variables (fixed for a particular disk format)
281 gBytesPerCluster = BootSector.BytesPerSector() * BootSector.SectorsPerCluster();
282 gRootDirSectors = ((BootSector.RootDirEntries() * KSizeOfFatDirEntry + BootSector.BytesPerSector() - 1) / BootSector.BytesPerSector());
283 gFatStartBytes = BootSector.ReservedSectors() * BootSector.BytesPerSector();
284 gFatSizeSectors = (BootSector.FatSectors() ? BootSector.FatSectors() : BootSector.FatSectors32());
285 gRootSector = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors;
286 gRootDirStart = gRootSector * BootSector.BytesPerSector();
287 gFirstDataSector = gRootSector + gRootDirSectors;
289 gFatTestEntries = MaxClusters();
290 if (gFatTestEntries > KMaxFatEntries)
291 gFatTestEntries = KMaxFatEntries;
293 if (BootSector.RootDirEntries() == 0)
295 test.Printf(_L("**** Is Fat32\n"));
297 gRootDirEntries = BootSector.RootDirEntries();
299 else if (BootSector.FatType() == EFat16)
301 test.Printf(_L("**** Is Fat16\n"));
303 gRootDirEntries = BootSector.RootDirEntries();
307 test.Printf(_L("**** Is Fat12\n"));
309 gRootDirEntries = gBytesPerCluster * 1 / KSizeOfFatDirEntry;
311 gTotalSectors = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors());
312 gClusterCount = (gTotalSectors - gFirstDataSector) / BootSector.SectorsPerCluster();
313 gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector();
316 GLDEF_C TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL)
318 // Read a single FAT entry from disk or FAT copy and return it
325 gFatBuf=HBufC8::New(gBytesPerCluster);
334 ptr = (TUint8*)aFat + PosInBytes(aIndex);
338 TInt pos = PosInBytes(aIndex) + gFatStartBytes;
339 if (gFatAddr < 0 || pos < gFatAddr || pos >= gFatAddr + gBytesPerCluster)
341 TPtr8 ptr=gFatBuf->Des();
342 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
344 r=TheRawDisk.Read(pos, ptr);
349 ptr = gFatBuf->Ptr() + pos-gFatAddr;
356 val = *(TUint32*)ptr;
359 val = *(TUint16*)ptr;
362 val = *(TUint16*)ptr;
373 GLDEF_C void DumpBootSector()
375 // Display (in log) TFatBootSector structure
378 RDebug::Print(_L("iBytesPerSector = %8d"), BootSector.BytesPerSector());
379 RDebug::Print(_L("iSectorsPerCluster = %8d"), BootSector.SectorsPerCluster());
380 RDebug::Print(_L("iReservedSectors = %8d"), BootSector.ReservedSectors());
381 RDebug::Print(_L("iNumberOfFats = %8d"), BootSector.NumberOfFats());
382 RDebug::Print(_L("iRootDirEntries = %8d"), BootSector.RootDirEntries());
383 RDebug::Print(_L("iTotalSectors = %8d"), BootSector.TotalSectors());
384 RDebug::Print(_L("iMediaDescriptor = %8d"), BootSector.MediaDescriptor());
385 RDebug::Print(_L("iFatSectors = %8d"), BootSector.FatSectors());
386 RDebug::Print(_L("iSectorsPerTrack = %8d"), BootSector.SectorsPerTrack());
387 RDebug::Print(_L("iNumberOfHeads = %8d"), BootSector.NumberOfHeads());
388 RDebug::Print(_L("iHiddenSectors = %8d"), BootSector.HiddenSectors());
389 RDebug::Print(_L("iHugeSectors = %8d"), BootSector.HugeSectors());
393 if(BootSector.RootDirEntries() == 0) //indicates we have FAT32 volume
395 RDebug::Print(_L("FatSectors32 = %8d"), BootSector.FatSectors32());
396 RDebug::Print(_L("FATFlags = %8d"), BootSector.FATFlags());
397 RDebug::Print(_L("VersionNumber = %8d"), BootSector.VersionNumber());
398 RDebug::Print(_L("RootClusterNum = %8d (0x%08X)"), BootSector.RootClusterNum(), gRootDirStart);
399 RDebug::Print(_L("FSInfoSectorNum = %8d (0x%08X)"), BootSector.FSInfoSectorNum(), BootSector.FSInfoSectorNum() * BootSector.BytesPerSector());
400 RDebug::Print(_L("BkBootRecSector = %8d (0x%08X)"), BootSector.BkBootRecSector(), BootSector.BkBootRecSector() * BootSector.BytesPerSector());
402 TInt fatEntries = gFatSizeSectors*BootSector.BytesPerSector();
418 RDebug::Print(_L("ClusterCount = %8d (%d bytes)"), gClusterCount, gClusterCount*gBytesPerCluster);
419 RDebug::Print(_L("FatEntries = %8d (%d sectors)"), fatEntries, gFatSizeSectors);
420 RDebug::Print(_L("RootSector = %8d (0x%08X)"), gRootSector, gRootDirStart);
421 RDebug::Print(_L("FirstDataSector = %8d (0x%08X)"), gFirstDataSector, gDataStartBytes);
424 GLDEF_C void DumpFat(const TUint8* aFat=NULL)
426 // Dump to the log all those FAT entries which are non-zero
429 TInt32 max = MaxClusters();
430 if (max > KMaxFatEntries)
431 max = KMaxFatEntries;
432 RDebug::Print(_L("---------------- DUMP OF FAT ---------------"));
433 for (TInt32 i = 0; i < max; i++)
435 TInt32 val = GetFatEntry(i, aFat);
436 TInt32 msk = 0x0FFFFFFF;
451 if ((val & msk) == (0x0FFFFFFF & msk))
452 RDebug::Print(_L(" %8d -> EOC"), i);
453 else if ((val & msk) == (0x0FFFFFF8 & msk))
454 RDebug::Print(_L(" %8d -> Media"), i);
455 else if ((val & msk) == (0x0FFFFFF7 & msk))
456 RDebug::Print(_L(" %8d -> BAD"), i);
458 RDebug::Print(_L(" %8d -> 0x%08X"), i, val);
460 RDebug::Print(_L(" %8d -> %d"), i, val);
462 RDebug::Print(_L("--------------------------------------------"));
465 GLDEF_C TDes* DirAttributes(TInt aAttrib)
467 // Return a pointer to a local buffer containing the attribute letters.
470 LOCAL_D TBuf<6> str(_L("------"));
471 LOCAL_D char* atr = "RHSVDA";
472 for (TInt i = 0; i < 6; i++)
473 if ((aAttrib >> i) & 1)
478 GLDEF_C TBool IsValidDirChar(TUint8 aChar, TUint8 aMin=0x20)
480 // Test whether a character is valid as part of a short filename, aMin is to
481 // distinguish between first character (which can't be space) and later ones
482 // which can include space but nothing less. Note that E5 is a valid character
483 // in any position, even though it means 'erased' in the first character.
486 const TUint8* inval = (TUint8*)"\x22\x2A\x2B\x2C\x2E\x2F\x3A\x3B\x3C\x3D\x3E\x3F\x5B\x5C\x5D\x7C";
489 for (const TUint8* p = inval; *p; p++)
495 GLDEF_C TBool IsValidDirEntry(TFatDirEntry* aDir)
497 // Test whether buffer is a valid normal directory entry
500 // top two bits of attributes must be zero
501 if (aDir->iData[11] & 0xC0)
503 // first character must be 0x05 or greater than space
504 if (!IsValidDirChar(aDir->iData[0], 0x21) && aDir->iData[0] != 0x05)
506 // other characters in name must be not less than space
507 for (TInt i = 1; i < 11; i++)
508 if (!IsValidDirChar(aDir->iData[i]))
513 GLDEF_C void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength)
515 // Extract part of a long name entry into the name buffer.
517 // @param aName buffer to put name
518 // @param aEntry directory entry raw data
519 // @param aPos character in buffer to start name segment
520 // @param aOffset offset in directory entry of the segment
521 // @param aLength number of characters in the segment
524 for (TInt i = 0; i < aLength; i++)
526 TInt at = i * 2 + aOffset;
527 TInt ch = aEntry[at] + aEntry[at+1] * 256;
528 aName[aPos++] = TText(ch);
532 GLDEF_C void ExtractNameString(TDes16& aName, const TUint8* aEntry)
534 // Extract a long name part from a directory entry, truncate it at the first
535 // NUL (0) character and put quotes round it.
539 TInt len = aName.Length() - 1;
542 GetLongNamePart(aName, aEntry, 1, 1, 5);
543 GetLongNamePart(aName, aEntry, 6, 14, 6);
544 GetLongNamePart(aName, aEntry, 12, 28, 2);
546 for (i = 0; i < len; i++)
553 GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
555 // Dump a single directory entry to the log. Return false if it was end of
556 // directory or an invalid entry (and don't display it).
559 TFatDirEntry* d = (TFatDirEntry*)aEntry;
562 // RDebug::Print(_L("%5d: ERASED"), aNum);
564 else if (d->IsEndOfDirectory())
566 else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
569 ExtractNameString(name, aEntry);
570 TInt ord = aEntry[0];
571 if (ord & KDirLastLongEntry)
572 RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
574 RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
576 else if (!IsValidDirEntry(d))
581 name.Copy(d->Name());
582 RDebug::Print(_L("%5d: '%S' %S cluster %d"),
583 aNum, &name, DirAttributes(d->Attributes()), d->StartCluster());
588 GLDEF_C void DumpDirCluster(const TUint8* aData, TInt aCluster=0)
590 // Dump directory entries until end of cluster or invalid/end entry found.
594 aData += (aCluster-2) * gBytesPerCluster;
595 for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry)
597 if (DumpDirEntry(i/KSizeOfFatDirEntry, aData))
598 aData += KSizeOfFatDirEntry;
604 GLDEF_C void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd)
606 // Dump clusters from disk (allows dumping of clusters not in our buffers).
607 // Only look at clusters marked as 'used' in the FAT. Note that if aFat is
608 // NULL the FAT entries will also be read from disk (slower but allows for ones
609 // outside our copy in memory).
612 if (aStart > gFatTestEntries)
614 RDebug::Print(_L("--------------- DATA AREA ------------------"));
615 if (aEnd > gFatTestEntries)
616 aEnd = gFatTestEntries;
617 for (TInt cluster = aStart; cluster < aEnd; cluster++)
619 if (GetFatEntry(cluster, aFat) != 0)
621 HBufC8* buf=HBufC8::New(gBytesPerCluster);
623 TPtr8 ptr=buf->Des();
624 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A');
626 r=TheRawDisk.Read(ClusterToByte(cluster), ptr);
629 RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
630 DumpDirCluster(ptr.Ptr());
634 RDebug::Print(_L("--------------------------------------------"));
637 GLDEF_C void DumpHex(const TUint8* aData, TInt aLen)
639 // Dump a block of memory to the log in hex.
642 for (TInt base = 0; base < aLen; base += 16)
646 for (off = base; off < aLen && off < base + 16; off++)
648 buf.Append(TText(' '));
649 buf.AppendNumFixedWidth(aData[off], EHex, 2);
651 RDebug::Print(_L("%04X: %S"), off, &buf);
655 static void QuickFormat()
659 fmt.iFatType = EFat32;
660 fmt.iSecPerCluster =1;
661 FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fmt);
663 FormatFatDrive(TheFs, CurrentDrive(), ETrue);
667 LOCAL_C void MakeVeryLongName(TFileName& aLong)
669 // appends a very long file name to aLong
672 // create a name to take up 18 vfat entries - (1 sector + 2 entries)
673 for(TInt i=0;i<234;++i)
680 LOCAL_C void MakeEntryName(TFileName& aName,TInt aLength)
682 // Appends aLength characters to aName
685 for(TInt i=0;i<aLength;++i)
692 LOCAL_C void FillUpRootDir(TInt aFree=0)
694 // Fill up root directory
697 TInt maxRootEntries = gRootDirEntries -aFree;
698 TFileName dir=_L("\\??\\");
702 entriesSoFar=2+2+2+2; // \\t_scn32dr3.exe + \\sys + \\t_scn32dr3.log + \\f32-tst
706 while(entriesSoFar<maxRootEntries)
708 dir[1]=TUint16(count/26+'a');
709 dir[2]=TUint16(count%26+'a');
717 LOCAL_C void UnFillUpRootDir(TInt aFree=0)
719 // Reverse changes from FillUpRootDir()
722 TFileName dir=_L("\\??\\");
723 TInt entriesSoFar=gRootDirEntries -aFree;
728 existing=2+2+2+2; // \\t_scn32dr3.exe + \\sys + \\t_scn32dr3.log + \\f32-tst
731 while(entriesSoFar>existing)
733 dir[1]=TUint16(count/26+'a');
734 dir[2]=TUint16(count%26+'a');
742 void InitialiseWriteBuffer(TDes8& buf)
747 for(TInt i=0;i<buf.Length();++i)
748 buf[i]=(TUint8)('a'+i%26);
751 LOCAL_C TBool EntryExists(const TDesC& aName)
753 // Returns ETrue if aName is found
757 TInt r=TheFs.Entry(aName,entry);
758 test(r==KErrNone||r==KErrNotFound);
759 return(r==KErrNone?(TBool)ETrue:(TBool)EFalse);
762 LOCAL_C TInt EntriesPerFatSector()
764 // Returns number of entries in one fat table sector
770 return(BootSector.BytesPerSector()/4);
772 return(BootSector.BytesPerSector()/2);
774 return(BootSector.BytesPerSector()*2/3);
781 LOCAL_C TBool OneEntryExists(const TDesC& aOldName,const TDesC& aNewName)
783 // Returns ETrue if only one of two entries exists
786 TBool oldExists=EntryExists(aOldName);
787 TBool newExists=EntryExists(aNewName);
788 return((!oldExists&&newExists)||(oldExists&&!newExists));
791 LOCAL_C void GetEntryDetails(const TDesC& aName,TEntry& aEntry)
793 // returns entry details for the entry with aName
796 TInt r=TheFs.Entry(aName,aEntry);
800 LOCAL_C TBool IsSameEntryDetails(TEntry aOldEntry,TEntry aNewEntry)
805 return(aOldEntry.iAtt==aNewEntry.iAtt&&aOldEntry.iSize==aNewEntry.iSize&&aOldEntry.iModified==aNewEntry.iModified);
808 LOCAL_C void CreateAlternate(const TDesC& aNameOne,const TDesC& aNameTwo)
810 // Creates altenate entries which take up one sector of fat table.
811 // By subsequently deleting one of these entries a new entry can be made
812 // with cluster chain that is not contiguous.
815 TInt entries=EntriesPerFatSector();
819 TInt r=file1.Create(TheFs,aNameOne,EFileShareAny);
821 r=file2.Create(TheFs,aNameTwo,EFileShareAny);
823 // one entry for file1 for every 40 entries for file2
824 // if file 1 subseqently deleted then 7 entries available
825 // in that fat sector - ~3.5kb file size - for fat16
832 size1+=gBytesPerCluster;
833 r=file1.SetSize(size1);
840 size2+=gBytesPerCluster*ratio;
841 r=file1.SetSize(size1);
851 LOCAL_C TInt ThrottleDirEntries(TInt aDirEntries)
853 // throttle the number of entries needed, since for large cluster
854 // sizes, this can take forever (eg 2GB card -> a cluster size of 32K
855 // -> 1024 entries per cluster
856 const TInt KMaxDirEntries = 2048;
857 if (aDirEntries > KMaxDirEntries)
859 RDebug::Print(_L("Reducing directory entries from %d to %d"),
860 aDirEntries, KMaxDirEntries);
861 aDirEntries = KMaxDirEntries;
867 LOCAL_C void CleanDirectory(const TDesC& aName,TInt aClusters)
869 // Removes entries in the directory
874 TInt entriesPerCluster=gBytesPerCluster/32;
875 TInt entriesNeeded = entriesPerCluster * aClusters;
877 entriesNeeded = ThrottleDirEntries(entriesNeeded);
879 TInt maxFileNameLen = 250 - aName.Length();
880 TInt nameEntries = 1 + (maxFileNameLen+12) / 13;
881 TInt namesNeeded = (entriesNeeded + nameEntries-1) / nameEntries;
883 for(TInt i = 0; i < namesNeeded; ++i)
885 if (entriesNeeded - entry < nameEntries)
886 maxFileNameLen = (entriesNeeded - entry - 1) * 13;
890 while (fn.Length() < maxFileNameLen)
892 TFileName fullName(aName);
894 TInt r = TheFs.Delete(fullName);
896 entry += 1 + (fn.Length() + 12) / 13;
898 RDebug::Print(_L("CleanDirectory(%S, %d)"), &aName, aClusters);
901 LOCAL_C void ExpandDirectory(const TDesC& aName,TInt aClusters)
903 // Expands the directory by aClusters
908 TInt entriesPerCluster=gBytesPerCluster/32;
909 TInt entriesNeeded = entriesPerCluster * aClusters;
911 entriesNeeded = ThrottleDirEntries(entriesNeeded);
913 TInt maxFileNameLen = 250 - aName.Length();
914 TInt nameEntries = 1 + (maxFileNameLen+12) / 13;
915 TInt namesNeeded = (entriesNeeded + nameEntries-1) / nameEntries;
917 for(TInt i = 0; i < namesNeeded; ++i)
919 if (entriesNeeded - entry < nameEntries)
920 maxFileNameLen = (entriesNeeded - entry - 1) * 13;
924 while (fn.Length() < maxFileNameLen)
926 TFileName fullName(aName);
929 TInt r = file.Create(TheFs,fullName,EFileShareAny);
932 entry += 1 + (fn.Length() + 12) / 13;
934 // to leave a directory expanded by aClusters but with no additional entries
935 RDebug::Print(_L("ExpandDirectory(%S, %d)"), &aName, aClusters);
936 CleanDirectory(aName,aClusters);
939 LOCAL_C TInt DeleteAlternateEntry(const TDesC& aName,TBool aIsDir)
941 // Deletes entry aName and corresponding entries created for EChainAlternate
944 TInt r=TheFs.Delete(_L("\\fat\\file2"));
945 test(r==KErrNone||KErrNotFound);
947 return(TheFs.RmDir(aName));
949 return(TheFs.Delete(aName));
952 LOCAL_C TInt CreateAlternateEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
954 // Creates entry with aName where cluster chain grows forward but not contiguously.
955 // Assumes that no holes in fat clusters.
958 TInt r=DeleteAlternateEntry(aName,aIsDir);
959 test(r==KErrNone||r==KErrNotFound);
963 r=TheFs.MkDir(aName);
969 r=file.Create(TheFs,aName,EFileShareAny);
972 r=file.SetSize(1); //ensure file allocated a start cluster
975 CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
976 r=TheFs.Delete(_L("\\fat\\file1"));
979 ExpandDirectory(aName,aSize);
982 r=file.SetSize(aSize);
989 LOCAL_C TInt DeleteForwardEntry(const TDesC& aName,TBool aIsDir)
991 // Deletes entry with aName and corresponding entries created for EChainForward
994 TInt r=TheFs.Delete(_L("\\fat\\file2"));
995 test(r==KErrNone||r==KErrNotFound);
996 r=TheFs.Delete(_L("\\fat\\file4"));
997 test(r==KErrNone||r==KErrNotFound);
998 r=TheFs.Delete(_L("\\fat\\file5"));
999 test(r==KErrNone||r==KErrNotFound);
1001 r=TheFs.RmDir(aName);
1003 r=TheFs.Delete(aName);
1007 LOCAL_C TInt CreateForwardEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
1009 // Creates an entry whose cluster chain first goes forward (upto 3.5kb for fat16 file)
1010 // and then backwards
1013 TInt r=DeleteForwardEntry(aName,aIsDir);
1014 test(r==KErrNone||r==KErrNotFound);
1015 RFile file1,file2,entry;
1016 r=file1.Create(TheFs,_L("\\fat\\file1"),EFileShareAny);
1018 r=file1.SetSize(EntriesPerFatSector()*gBytesPerCluster);
1020 r=file2.Create(TheFs,_L("\\fat\\file2"),EFileShareAny);
1022 r=file2.SetSize(EntriesPerFatSector()*gBytesPerCluster);
1026 r=TheFs.MkDir(aName);
1032 r=entry.Create(TheFs,aName,EFileShareAny);
1035 r=entry.SetSize(1); // ensure entry has start cluster allocated
1038 CreateAlternate(_L("\\fat\\file3"),_L("\\fat\\file4"));
1040 r=file5.Create(TheFs,_L("\\fat\\file5"),EFileShareAny);
1042 r=file5.SetSize(EntriesPerFatSector()*gBytesPerCluster*2);
1047 r=TheFs.Delete(_L("\\fat\\file1"));
1049 r=TheFs.Delete(_L("\\fat\\file3"));
1052 ExpandDirectory(aName,aSize);
1055 r=entry.SetSize(aSize);
1062 LOCAL_C TInt DeleteBackwardEntry(const TDesC& aName,TBool aIsDir)
1064 // Deletes entry with aName and corresponding entries created for EChainBackwards
1067 TInt r=TheFs.Delete(_L("\\fat\\file2"));
1068 test(r==KErrNone||r==KErrNotFound);
1069 r=TheFs.Delete(_L("\\fat\\file3"));
1070 test(r==KErrNone||r==KErrNotFound);
1072 r=TheFs.RmDir(aName);
1074 r=TheFs.Delete(aName);
1078 LOCAL_C TInt CreateBackwardEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
1080 // Creates an entry whose fat cluster chain first goes backwards(upto 3.5kb for fat16 file)
1081 // and then forwards
1084 TInt r=DeleteBackwardEntry(aName,aIsDir);
1085 test(r==KErrNone||r==KErrNotFound);
1086 CreateAlternate(_L("\\fat\\file1"),_L("\\fat\\file2"));
1090 r=TheFs.MkDir(aName);
1096 r=entry.Create(TheFs,aName,EFileShareAny);
1103 r=file3.Create(TheFs,_L("\\fat\\file3"),EFileShareAny);
1105 r=file3.SetSize(EntriesPerFatSector()*gBytesPerCluster);
1107 r=TheFs.Delete(_L("\\fat\\file1"));
1111 ExpandDirectory(aName,aSize);
1114 r=entry.SetSize(aSize);
1121 LOCAL_C TInt DeleteStdEntry(const TDesC& aName,TBool aIsDir)
1123 // Deletes entry with aName
1127 return(TheFs.RmDir(aName));
1129 return(TheFs.Delete(aName));
1132 LOCAL_C TInt CreateStdEntry(const TDesC& aName,TBool aIsDir,TInt aSize)
1134 // Creates entry with aName where the cluster chain grows contiguously
1137 TInt r=DeleteStdEntry(aName,aIsDir);
1138 test(r==KErrNone||r==KErrNotFound);
1141 r=TheFs.MkDir(aName);
1143 ExpandDirectory(aName,aSize);
1149 r=file.Create(TheFs,aName,EFileShareAny);
1152 r=file.SetSize(aSize);
1155 else if(r==KErrAlreadyExists)
1157 TInt res =file.Open(TheFs,aName,EFileShareAny);
1158 test(res==KErrNone);
1167 LOCAL_C TInt CreateEntry(const TDesC& aName,TBool aIsDir,TFatChain aChain,TInt aSize)
1169 // Creates entry with aName whose fat cluster chain characteristics determined by aChain
1174 case(EChainStd):return(CreateStdEntry(aName,aIsDir,aSize));
1175 case(EChainAlternate):return(CreateAlternateEntry(aName,aIsDir,aSize));
1176 case(EChainBackwards):return(CreateBackwardEntry(aName,aIsDir,aSize));
1177 case(EChainForwards):return(CreateForwardEntry(aName,aIsDir,aSize));
1178 default:return(KErrGeneral);
1182 LOCAL_C TInt DeleteEntry(const TDesC& aName,TBool aIsDir,TFatChain aChain)
1184 // Delete entry with aName
1189 case(EChainStd):return(DeleteStdEntry(aName,aIsDir));
1190 case(EChainAlternate):return(DeleteAlternateEntry(aName,aIsDir));
1191 case(EChainBackwards):return(DeleteBackwardEntry(aName,aIsDir));
1192 case(EChainForwards):return(DeleteForwardEntry(aName,aIsDir));
1193 default:return(KErrGeneral);
1197 LOCAL_C void TestRFsDelete(const TDesC& aName,TFatChain aChain,TInt aFileSize)
1202 TInt failCount=TheFailCount;
1204 test.Start(_L("TestRFsDelete"));
1207 test.Printf(_L("failCount=%d\n"),failCount);
1208 r=CreateEntry(aName,EFalse,aChain,aFileSize);
1209 test(r==KErrNone||r==KErrAlreadyExists);
1215 r=SetWriteFailOn(failCount);
1217 r=TheFs.Delete(aName);
1220 test(r==WriteFailValue);
1221 r=TheFs.ScanDrive(gSessionPath);
1223 r=TheFs.CheckDisk(gSessionPath);
1227 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1229 r=TheFs.CheckDisk(gSessionPath);
1231 test(!EntryExists(aName));
1236 LOCAL_C void TestRFsRmDir(const TDesC& aName,TFatChain aChain,TInt aDirSize)
1241 TInt failCount=TheFailCount;
1243 test.Next(_L("TestRFsRmDir"));
1247 RDebug::Print(_L("Chain Std %S size %d"), &aName, aDirSize);
1249 case EChainAlternate:
1250 RDebug::Print(_L("Chain Alternate %S size %d"), &aName, aDirSize);
1252 case EChainBackwards:
1253 RDebug::Print(_L("Chain Backwards %S size %d"), &aName, aDirSize);
1255 case EChainForwards:
1256 RDebug::Print(_L("Chain Forwards %S size %d"), &aName, aDirSize);
1263 test.Printf(_L("failCount=%d\n"),failCount);
1264 r=CreateEntry(aName,ETrue,aChain,aDirSize);
1265 test(r==KErrNone||r==KErrAlreadyExists);
1271 r=SetWriteFailOn(failCount);
1273 r=TheFs.RmDir(aName);
1276 test(r==WriteFailValue);
1277 r=TheFs.ScanDrive(gSessionPath);
1278 RDebug::Print(_L("%6d: ScanDrive = %d"), __LINE__, r);
1281 RDebug::Print(_L("ScanDrive fail %d"), r);
1283 DumpData(NULL, 0, 200);
1286 r=TheFs.CheckDisk(gSessionPath);
1287 RDebug::Print(_L("%6d: CheckDisk = %d"), __LINE__, r);
1291 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1293 r=TheFs.CheckDisk(gSessionPath);
1295 test(!EntryExists(aName));
1300 LOCAL_C void TestRFsMkDir(const TDesC& aName)
1305 TInt failCount=TheFailCount;
1307 test.Next(_L("TestRFsMkDir"));
1310 test.Printf(_L("failCount=%d\n"),failCount);
1311 r=DeleteEntry(aName,ETrue,EChainStd);
1312 test(r==KErrNone||r==KErrNotFound);
1318 r=SetWriteFailOn(failCount);
1320 r=TheFs.MkDir(aName);
1323 test(r==WriteFailValue);
1324 r=TheFs.ScanDrive(gSessionPath);
1326 r=TheFs.CheckDisk(gSessionPath);
1330 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1332 r=TheFs.CheckDisk(gSessionPath);
1334 test(EntryExists(aName));
1335 r=DeleteEntry(aName,ETrue,EChainStd);
1341 LOCAL_C void TestRFsRename(const TDesC& aOldName,const TDesC& aNewName,TBool aIsDir,TFatChain aChain,TInt aSize)
1346 test.Next(_L("TestRFsRename"));
1347 TInt failCount=TheFailCount;
1349 TEntry oldEntryInfo,newEntryInfo;
1352 test.Printf(_L("failCount=%d\n"),failCount);
1353 r=CreateEntry(aOldName,aIsDir,aChain,aSize);
1354 test(r==KErrNone||r==KErrAlreadyExists);
1355 r=DeleteEntry(aNewName,aIsDir,aChain);
1356 test(r==KErrNone||r==KErrNotFound);
1357 GetEntryDetails(aOldName,oldEntryInfo);
1363 r=SetWriteFailOn(failCount);
1365 r=TheFs.Rename(aOldName,aNewName);
1368 if(r!=WriteFailValue)
1370 test.Printf(_L("r=%d\n"),r);
1373 test(r==WriteFailValue);
1374 r=TheFs.ScanDrive(gSessionPath);
1376 r=TheFs.CheckDisk(gSessionPath);
1378 // no start cluster if aSize==0
1380 test(OneEntryExists(aOldName,aNewName));
1383 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1385 r=TheFs.CheckDisk(gSessionPath);
1387 test(EntryExists(aNewName) && !EntryExists(aOldName));
1388 GetEntryDetails(aNewName,newEntryInfo);
1389 test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
1390 r=DeleteEntry(aNewName,aIsDir,aChain);
1396 LOCAL_C void TestRFsReplace(const TDesC& aOldName, const TDesC& aNewName,TBool aBothExist,TFatChain aChain,TInt aFileSize)
1398 // test RFs::Replace
1402 TInt failCount=TheFailCount;
1405 test.Next(_L("TestRFsReplace with new name existing"));
1407 test.Next(_L("TestRFsReplace with new name not existing"));
1408 TEntry oldEntryInfo,newEntryInfo;
1411 test.Printf(_L("failCount=%d\n"),failCount);
1412 r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
1413 test(r==KErrNone||r==KErrAlreadyExists);
1416 r=CreateEntry(aNewName,EFalse,aChain,aFileSize);
1417 test(r==KErrNone||r==KErrAlreadyExists);
1421 r=DeleteEntry(aNewName,EFalse,aChain);
1422 test(r==KErrNone||r==KErrNotFound);
1424 GetEntryDetails(aOldName,oldEntryInfo);
1430 r=SetWriteFailOn(failCount);
1432 r=TheFs.Replace(aOldName,aNewName);
1435 test(r==WriteFailValue);
1436 r=TheFs.ScanDrive(gSessionPath);
1438 r=TheFs.CheckDisk(gSessionPath);
1440 if(!aBothExist && aFileSize!=0)
1441 test(OneEntryExists(aOldName,aNewName));
1443 test(EntryExists(aOldName)||EntryExists(aNewName));
1446 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1448 r=TheFs.CheckDisk(gSessionPath);
1450 test(EntryExists(aNewName) && !EntryExists(aOldName));
1451 GetEntryDetails(aNewName,newEntryInfo);
1452 test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
1453 r=DeleteEntry(aNewName,EFalse,aChain);
1459 LOCAL_C void TestRFileCreate(const TDesC& aName)
1461 // test RFile::Create
1464 TInt failCount=TheFailCount;
1466 test.Next(_L("TestRFileCreate"));
1469 test.Printf(_L("failCount=%d\n"),failCount);
1470 r=DeleteEntry(aName,EFalse,EChainStd);
1471 test(r==KErrNone||r==KErrNotFound);
1477 r=SetWriteFailOn(failCount);
1480 r=file.Create(TheFs,aName,EFileShareAny);
1483 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1488 test(r==WriteFailValue);
1489 r=TheFs.ScanDrive(gSessionPath);
1491 r=TheFs.CheckDisk(gSessionPath);
1495 r=TheFs.CheckDisk(gSessionPath);
1497 test(EntryExists(aName));
1498 r=DeleteEntry(aName,EFalse,EChainStd);
1504 LOCAL_C void TestRFileTemp(const TDesC& aPath)
1509 TInt failCount=TheFailCount;
1511 test.Next(_L("TestRFileTemp"));
1515 test.Printf(_L("failCount=%d\n"),failCount);
1521 r=SetWriteFailOn(failCount);
1524 r=file.Temp(TheFs,aPath,temp,EFileShareAny);
1527 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1532 test(r==WriteFailValue);
1533 r=TheFs.ScanDrive(gSessionPath);
1535 r=TheFs.CheckDisk(gSessionPath);
1539 r=TheFs.CheckDisk(gSessionPath);
1541 test(EntryExists(temp));
1542 r=DeleteEntry(temp,EFalse,EChainStd);
1548 LOCAL_C void TestRFileRename(const TDesC& aOldName, const TDesC& aNewName,TFatChain aChain,TInt aFileSize)
1550 // test RFile::Rename
1553 TInt failCount=TheFailCount;
1555 test.Next(_L("TestRFileRename"));
1556 TEntry oldEntryInfo,newEntryInfo;
1559 test.Printf(_L("failCount=%d\n"),failCount);
1560 r=CreateEntry(aOldName,EFalse,aChain,aFileSize);
1561 test(r==KErrNone||r==KErrAlreadyExists);
1562 r=DeleteEntry(aNewName,EFalse,aChain);
1563 test(r==KErrNone||r==KErrNotFound);
1564 GetEntryDetails(aOldName,oldEntryInfo);
1571 r=file.Open(TheFs,aOldName,EFileShareExclusive|EFileWrite);
1573 r=SetWriteFailOn(failCount);
1575 r=file.Rename(aNewName);
1578 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1583 test(r==WriteFailValue);
1585 r=TheFs.ScanDrive(gSessionPath);
1587 r=TheFs.CheckDisk(gSessionPath);
1590 test(OneEntryExists(aOldName,aNewName));
1593 r=TheFs.CheckDisk(gSessionPath);
1595 test(EntryExists(aNewName) && !EntryExists(aOldName));
1596 GetEntryDetails(aNewName,newEntryInfo);
1597 test(IsSameEntryDetails(oldEntryInfo,newEntryInfo));
1598 r=DeleteEntry(aNewName,EFalse,aChain);
1604 LOCAL_C void TestRFileReplace(const TDesC& aName,TBool aAlreadyExists,TFatChain aChain,TInt aFileSize)
1606 // test RFile::Replace
1609 TInt failCount=TheFailCount;
1611 test.Next(_L("TestRFileReplace"));
1614 test.Printf(_L("failCount=%d\n"),failCount);
1617 r=CreateEntry(aName,EFalse,aChain,aFileSize);
1618 test(r==KErrNone||r==KErrAlreadyExists);
1622 r=DeleteEntry(aName,EFalse,aChain);
1623 test(r==KErrNone||r==KErrNotFound);
1630 r=SetWriteFailOn(failCount);
1633 r=file.Replace(TheFs,aName,EFileShareAny);
1636 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1641 test(r==WriteFailValue);
1642 r=TheFs.ScanDrive(gSessionPath);
1644 r=TheFs.CheckDisk(gSessionPath);
1648 r=TheFs.CheckDisk(gSessionPath);
1650 test(EntryExists(aName));
1651 r=DeleteEntry(aName,EFalse,aChain);
1660 ++TheFunctionNumber;
1661 TheOpNumber=TheFailCount=0;
1665 LOCAL_C void TestRFileSetSize(const TDesC& aName,TFatChain aChain,TInt aOldFileSize,TInt aNewFileSize)
1667 // test RFile::SetSize
1670 TInt failCount=TheFailCount;
1672 test.Next(_L("TestRFileSetSize"));
1673 test.Printf(_L("old size=%d new size=%d\n"),aOldFileSize,aNewFileSize);
1676 test.Printf(_L("failCount=%d\n"),failCount);
1677 r=CreateEntry(aName,EFalse,aChain,aOldFileSize);
1678 test(r==KErrNone||r==KErrAlreadyExists);
1684 r=SetWriteFailOn(failCount);
1687 r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
1689 r=file.SetSize(aNewFileSize);
1690 // close the file before testing the return value!
1694 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1700 test(r==WriteFailValue);
1701 r=TheFs.ScanDrive(gSessionPath);
1703 r=TheFs.CheckDisk(gSessionPath);
1705 r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
1710 test(size==aNewFileSize||size==aOldFileSize);
1714 r=TheFs.CheckDisk(gSessionPath);
1717 r=file.Open(TheFs,aName,EFileShareAny);
1720 r=file.Size(fileSize);
1722 test(aNewFileSize==fileSize);
1724 r=DeleteEntry(aName,EFalse,aChain);
1726 ++TheFunctionNumber;
1730 LOCAL_C void TestRFileWrite(const TDesC& aName,TFatChain aChain,TInt aFileSize,TInt aPos,TInt aLength)
1732 // test RFile::Write
1735 TInt failCount=TheFailCount;
1737 test.Next(_L("TestRFileWrite"));
1738 test.Printf(_L("aFileSize=%d,aPos=%d,aLength=%d\n"),aFileSize,aPos,aLength);
1739 TInt newSize=(aFileSize>=aPos+aLength)?aFileSize:aPos+aLength;
1741 desPtr=HBufC8::New(aLength);
1743 TPtr8 des=desPtr->Des();
1744 des.SetLength(aLength);
1745 InitialiseWriteBuffer(des);
1748 test.Printf(_L("failCount=%d\n"),failCount);
1749 r=CreateEntry(aName,EFalse,aChain,aFileSize);
1750 test(r==KErrNone||r==KErrAlreadyExists);
1756 r=SetWriteFailOn(failCount);
1759 r=file.Open(TheFs,aName,EFileShareAny|EFileWrite);
1761 r=file.Write(aPos,des,aLength);
1764 r=TheFs.ControlIo(gSessionPath[0]-'A',KControlIoWriteFailOff);
1769 test(r==WriteFailValue);
1771 r=TheFs.ScanDrive(gSessionPath);
1773 r=TheFs.CheckDisk(gSessionPath);
1775 file.Open(TheFs,aName,EFileShareAny);
1778 r=file.Size(fileSize);
1779 // with fair scheduling enabled it's possible for the file
1780 // size to grow even if the write appears to have failed...
1781 // test(fileSize==aFileSize||fileSize==newSize);
1782 test(fileSize>=aFileSize && fileSize <= newSize);
1787 r=TheFs.CheckDisk(gSessionPath);
1790 r=file.Open(TheFs,aName,EFileShareAny);
1793 r=file.Size(fileSize);
1795 test(newSize==fileSize);
1797 desPtr2=HBufC8::New(aLength);
1798 test(desPtr2!=NULL);
1799 TPtr8 des2=desPtr2->Des();
1800 des2.SetLength(aLength);
1801 r=file.Read(aPos,des2,des2.Length());
1803 r=des2.Compare(des);
1806 r=DeleteEntry(aName,EFalse,aChain);
1810 ++TheFunctionNumber;
1815 LOCAL_C void TestOperations(const TDesC& aOldName,const TDesC& aNewName,TFatChain aChain,TInt aFileSize, TInt aDirClusters)
1817 // Tests the specified operations
1820 TFileName oldDirName=aOldName;
1821 TFileName newDirName=aNewName;
1822 // create directory for directory operations
1823 oldDirName+=_L("\\");
1824 newDirName+=_L("\\");
1825 // locate path for RFile::Temp
1826 TInt pathPos=aOldName.LocateReverse('\\')+1;
1827 TFileName tempPath=aOldName.Left(pathPos);
1828 test.Printf(_L("aOldName=%S\n"),&aOldName);
1829 test.Printf(_L("aNewName=%S\n"),&aNewName);
1830 test.Printf(_L("tempPath=%S\n"),&tempPath);
1833 case(0):TestRFsDelete(aOldName,aChain,aFileSize);
1834 case(1):TestRFsRmDir(oldDirName,aChain,aDirClusters);
1835 case(2):TestRFsMkDir(oldDirName);
1836 case(3):TestRFsRename(aOldName,aNewName,EFalse,aChain,aFileSize);
1837 case(4):TestRFsRename(oldDirName,newDirName,ETrue,aChain,aDirClusters);
1838 case(5):TestRFsReplace(aOldName,aNewName,EFalse,aChain,aFileSize);
1839 case(6):TestRFsReplace(aOldName,aNewName,ETrue,aChain,aFileSize);
1840 case(7):TestRFileCreate(aOldName);
1841 case(8):TestRFileTemp(tempPath);
1842 case(9):TestRFileRename(aOldName,aNewName,aChain,aFileSize);
1843 case(10):TestRFileReplace(aOldName,EFalse,aChain,aFileSize);
1844 case(11):TestRFileReplace(aOldName,ETrue,aChain,aFileSize);break;
1845 default:test(EFalse);
1850 LOCAL_C void TestOperation0()
1855 // tests entries in root directory
1856 test.Next(_L("TestOperation0"));
1857 TestOperations(_L("\\entryWithTwoVfats"),_L("\\anotherEntryWithTwo"),EChainStd,0,0);
1860 LOCAL_C void TestOperation1()
1865 // tests entries in a full root directory
1866 test.Next(_L("TestOperation1"));
1869 TestOperations(_L("\\entryOne"),_L("\\entryTwo"),EChainStd,512,0);
1873 LOCAL_C void TestOperation2()
1878 // tests entries in same subdir
1879 test.Next(_L("TestOperation2"));
1880 TestOperations(_L("\\test\\subdir1\\NameWithFourVFatEntriesWaffle"),_L("\\test\\subdir1\\aEntry"),EChainAlternate,5120,1);
1884 LOCAL_C void TestOperation3()
1889 // tests entries in different subdir
1890 test.Next(_L("TestOperation3"));
1891 TestOperations(_L("\\test\\subdir1\\NameWithThreeEntries"),_L("\\ANother\\aEntrytwo"),EChainAlternate,15000,10);
1895 LOCAL_C void TestOperation4()
1900 // tests entries with cluster chain of EChainForwards
1901 test.Next(_L("TestOperation4"));
1902 TestOperations(_L("\\test\\subdir1\\aEntry"),_L("\\aEntry"),EChainForwards,12799,25);
1906 LOCAL_C void TestOperation5()
1911 // tests entries with cluster chain of EChainBackwards
1912 test.Next(_L("TestOperation5"));
1913 TestOperations(_L("\\test\\subdir1\\aEntry"),_L("\\ANother\\EntrywithThree"),EChainBackwards,51199,10);
1916 LOCAL_C void TestOperation6()
1921 // tests entries where old name has a very long name
1922 test.Next(_L("TestOperation6"));
1923 TFileName longName=_L("\\test\\subdir1\\");
1924 MakeVeryLongName(longName);
1925 TestOperations(longName,_L("\\ANother\\e1"),EChainAlternate,5100,0);
1928 LOCAL_C void TestOperation7()
1933 // tests entries where new name fills up subdir cluster
1934 test.Next(_L("TestOperation7"));
1935 TFileName name=_L("\\test\\subdir2\\");
1936 // add entry with 7 vfat entries
1937 MakeEntryName(name,80);
1939 CreateEntry(name,EFalse,EChainStd,1);
1940 TestOperations(_L("\\test\\subdir2\\EntryWithThree"),_L("\\test\\subdir2\\EntryWithThree-"),EChainStd,512,0);
1941 DeleteEntry(name,EFalse,EChainStd);
1944 LOCAL_C void TestOperation8()
1949 // tests entries where new name is first entry in new subdir cluster
1950 test.Next(_L("TestOperation8"));
1951 TFileName name=_L("\\test\\subdir2\\");
1952 // add entry with 10 vfat entries
1953 MakeEntryName(name,125);
1955 CreateEntry(name,EFalse,EChainStd,175000);
1956 TestOperations(_L("\\test\\subdir2\\Entrywith3three"),_L("\\test\\subdir2\\entrywiththree-"),EChainStd,512,1);
1957 DeleteEntry(name,EFalse,EChainStd);
1960 GLDEF_C void DoTests()
1963 if(!IsReset && IsInternalRam())
1965 test.Printf(_L("Error: Internal ram drive not tested\n"));
1975 r=TheFs.SetSessionPath(gSessionPath);
1978 switch(TheFunctionNumber)
1980 case(0):TestOperation0();
1983 r=TheFs.MkDir(_L("\\fat\\"));
1985 r=TheFs.MkDir(_L("\\test\\"));
1987 r=TheFs.MkDir(_L("\\ANother\\"));
1989 r=TheFs.MkDir(_L("\\test\\subdir1\\"));
1991 r=TheFs.MkDir(_L("\\test\\subdir2\\"));
1995 // add some filler files
1996 CreateEntry(_L("\\test\\subdir1\\FillerOne"),EFalse,EChainStd,512);
1997 CreateEntry(_L("\\test\\subdir1\\FillerTwo"),EFalse,EChainStd,1024);}
1998 case(3):TestOperation3();
2001 // add some filler files
2002 CreateEntry(_L("\\ANother\\FillerThree"),EFalse,EChainStd,1536);
2003 CreateEntry(_L("\\test\\subdir1\\FillerFour"),EFalse,EChainStd,2048);}
2004 case(5):TestOperation5();
2005 case(6):TestOperation6();
2006 case(7):TestOperation7();
2007 case(8):TestOperation8();
2008 // increase size of file
2009 case(9):TestRFileSetSize(_L("\\entry1"),EChainStd,0,512);
2010 case(10):TestRFileSetSize(_L("\\entry1"),EChainAlternate,0,1025);
2011 case(11):TestRFileSetSize(_L("\\entry1"),EChainStd,1,512);
2012 // seek index (of CFatFileCB) resized
2013 case(12):TestRFileSetSize(_L("\\entry1"),EChainForwards,512,66666);
2014 // seek index resized
2015 case(13):TestRFileSetSize(_L("\\entry1"),EChainBackwards,32779,131074);
2016 // decrease size of file
2017 // seek index resized
2018 case(14):TestRFileSetSize(_L("\\entry1"),EChainForwards,133000,32768);
2019 // seek index resized
2020 case(15):TestRFileSetSize(_L("\\entry1"),EChainBackwards,65536,1);
2021 // seek index resized
2022 case(16):TestRFileSetSize(_L("\\entry1"),EChainAlternate,66554,0);
2023 case(17):TestRFileSetSize(_L("\\entry1"),EChainStd,1024,1);
2024 case(18):TestRFileSetSize(_L("\\entry1"),EChainAlternate,512,0);
2025 case(19):TestRFileWrite(_L("\\entry2"),EChainStd,0,0,512);
2026 case(20):TestRFileWrite(_L("\\entry2"),EChainAlternate,5120,512,1024);
2027 case(21):TestRFileWrite(_L("\\entry2"),EChainForwards,3584,3584,5000);
2028 case(22):TestRFileWrite(_L("\\entry2"),EChainBackwards,3000,2999,2000);
2029 // seek index resized
2030 case(23):TestRFileWrite(_L("\\entry2"),EChainBackwards,64000,64000,3000);
2031 // seek index resized
2032 case(24):TestRFileWrite(_L("\\entry2"),EChainForwards,131072,2,4000);break;
2033 default:test(EFalse);
2035 DeleteEntry(_L("\\test\\subdir1\\FillerFour"),EFalse,EChainStd);
2036 DeleteEntry(_L("\\ANother\\FillerThree"),EFalse,EChainStd);
2037 DeleteEntry(_L("\\test\\subdir1\\FillerTwo"),EFalse,EChainStd);
2038 DeleteEntry(_L("\\test\\subdir1\\FillerOne"),EFalse,EChainStd);
2039 r=TheFs.RmDir(_L("\\test\\subdir2\\"));
2041 r=TheFs.RmDir(_L("\\test\\subdir1\\"));
2043 r=TheFs.RmDir(_L("\\ANother\\"));
2045 r=TheFs.RmDir(_L("\\test\\"));
2047 r=TheFs.RmDir(_L("\\fat\\"));