0
|
1 |
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
2 |
// All rights reserved.
|
|
3 |
// This component and the accompanying materials are made available
|
|
4 |
// under the terms of the License "Eclipse Public License v1.0"
|
|
5 |
// which accompanies this distribution, and is available
|
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
7 |
//
|
|
8 |
// Initial Contributors:
|
|
9 |
// Nokia Corporation - initial contribution.
|
|
10 |
//
|
|
11 |
// Contributors:
|
|
12 |
//
|
|
13 |
// Description:
|
|
14 |
// f32test\server\b_fat32.cpp
|
|
15 |
//
|
|
16 |
//
|
|
17 |
|
|
18 |
#include <f32file.h>
|
|
19 |
#include <e32test.h>
|
|
20 |
#include <e32math.h>
|
|
21 |
|
|
22 |
#include "fat_utils.h"
|
|
23 |
#include "t_server.h"
|
|
24 |
|
|
25 |
using namespace Fat_Test_Utils;
|
|
26 |
|
|
27 |
|
|
28 |
RTest test(_L("B_FAT32"));
|
|
29 |
|
|
30 |
static RRawDisk TheDisk;
|
|
31 |
static RFile TheFile;
|
|
32 |
static RDir TheDir;
|
|
33 |
static TEntry TheEntry;
|
|
34 |
static TFileName TheFileName;
|
|
35 |
static TBuf<16> TheDrive;
|
|
36 |
|
|
37 |
static HBufC8* pBuffer1=NULL;
|
|
38 |
static HBufC8* pBuffer2=NULL;
|
|
39 |
static TBuf8<0x800> TheBuffer;
|
|
40 |
static TEntry TheFileInfo;
|
|
41 |
static TVolumeInfo TheVolumeInfo;
|
|
42 |
static TBuf<8> ThePddName;
|
|
43 |
static TFatBootSector TheBootSector;
|
|
44 |
|
|
45 |
static TInt64 rndSeed;
|
|
46 |
static TFatType gDiskType = EInvalid;
|
|
47 |
|
|
48 |
static TInt gFatBits = 0;
|
|
49 |
static TInt gBytesPerCluster;
|
|
50 |
static TInt gEntriesPerCluster;
|
|
51 |
static TInt gDataStartBytes;
|
|
52 |
static TInt gRootDirSectors;
|
|
53 |
static TInt gTotalSectors;
|
|
54 |
static TInt gRootDirStart;
|
|
55 |
static TInt gRootSector;
|
|
56 |
static TInt gRootCluster;
|
|
57 |
static TInt gFatTestEntries;
|
|
58 |
static TInt gFatSizeSectors;
|
|
59 |
static TInt gFirstDataSector;
|
|
60 |
static TInt gFirstDataCluster;
|
|
61 |
static TInt gClusterCount;
|
|
62 |
static TInt gEndOfChain; // for FAT12/16/32
|
|
63 |
|
|
64 |
const TInt KMaxFatEntries = 2048;
|
|
65 |
const TInt KMaxFatSize = KMaxFatEntries * 4;
|
|
66 |
const TInt KDirAttrReadOnly = 0x01;
|
|
67 |
const TInt KDirAttrHidden = 0x02;
|
|
68 |
const TInt KDirAttrSystem = 0x04;
|
|
69 |
const TInt KDirAttrVolumeId = 0x08;
|
|
70 |
const TInt KDirAttrDirectory = 0x10;
|
|
71 |
const TInt KDirAttrArchive = 0x20;
|
|
72 |
const TInt KDirAttrLongName = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId;
|
|
73 |
const TInt KDirAttrLongMask = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive;
|
|
74 |
const TInt KDirLastLongEntry = 0x40;
|
|
75 |
|
|
76 |
void CreateFatEntry(const TDesC& aDir, TBool aVFatEntry, TDes *apFileName=NULL);
|
|
77 |
|
|
78 |
#define Error(aMess,aErr) PutError(__FILE__, __LINE__, aMess,aErr)
|
|
79 |
static void PutError(const char* aFile, TInt aLine, const TDesC& aMessage,TInt anErr)
|
|
80 |
{
|
|
81 |
TFileName buf;
|
|
82 |
TPtrC8 ptr((const TUint8*)aFile);
|
|
83 |
buf.Copy(ptr);
|
|
84 |
test.Printf(_L("%S failed - %d\n"), &aMessage,anErr);
|
|
85 |
test.Printf(_L("In %S line %d\n"), &buf, aLine);
|
|
86 |
test(0);
|
|
87 |
}
|
|
88 |
|
|
89 |
|
|
90 |
//
|
|
91 |
// Position calculation and disk reading routines
|
|
92 |
// Return number of bytes into the FAT
|
|
93 |
static TInt PosInBytes(TInt aFatIndex)
|
|
94 |
{
|
|
95 |
TInt fatPosInBytes = -1;
|
|
96 |
switch (gDiskType)
|
|
97 |
{
|
|
98 |
case EFat32:
|
|
99 |
fatPosInBytes=aFatIndex<<2;
|
|
100 |
break;
|
|
101 |
case EFat16:
|
|
102 |
fatPosInBytes=aFatIndex<<1;
|
|
103 |
break;
|
|
104 |
case EFat12:
|
|
105 |
fatPosInBytes=(aFatIndex*3>>1);
|
|
106 |
break;
|
|
107 |
default:
|
|
108 |
test(0);
|
|
109 |
}
|
|
110 |
return(fatPosInBytes);
|
|
111 |
}
|
|
112 |
|
|
113 |
static TUint32 MaxClusters()
|
|
114 |
//
|
|
115 |
// Return the number of data clusters on the disk
|
|
116 |
//
|
|
117 |
{
|
|
118 |
TUint32 totSec = (TheBootSector.TotalSectors() ? TheBootSector.TotalSectors() : TheBootSector.HugeSectors());
|
|
119 |
TUint32 numSec = totSec - gFirstDataSector;
|
|
120 |
return numSec / TheBootSector.SectorsPerCluster();
|
|
121 |
}
|
|
122 |
|
|
123 |
static TInt ClusterToByte(TInt aCluster)
|
|
124 |
//
|
|
125 |
// converts cluster number to byte offset on disk
|
|
126 |
//
|
|
127 |
{
|
|
128 |
if (aCluster < 2)
|
|
129 |
return gRootDirStart;
|
|
130 |
TInt sector = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * TheBootSector.BytesPerSector();
|
|
131 |
return sector;
|
|
132 |
}
|
|
133 |
|
|
134 |
TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL)
|
|
135 |
//
|
|
136 |
// Read a single FAT entry from disk or FAT copy and return it
|
|
137 |
//
|
|
138 |
{
|
|
139 |
TInt pos = PosInBytes(aIndex);
|
|
140 |
|
|
141 |
TUint8 data[4];
|
|
142 |
TUint8* ptr = data;
|
|
143 |
|
|
144 |
if (aFat)
|
|
145 |
ptr = (TUint8*)aFat + pos;
|
|
146 |
else
|
|
147 |
{
|
|
148 |
pos += TheBootSector.ReservedSectors() * TheBootSector.BytesPerSector();
|
|
149 |
TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
|
|
150 |
test(r==KErrNone);
|
|
151 |
TPtr8 buf(&data[0], 4);
|
|
152 |
r=TheDisk.Read(pos, buf);
|
|
153 |
test(r==KErrNone);
|
|
154 |
TheDisk.Close();
|
|
155 |
}
|
|
156 |
|
|
157 |
TUint32 val = 0;
|
|
158 |
switch (gDiskType)
|
|
159 |
{
|
|
160 |
case EFat32:
|
|
161 |
val = *(TUint32*)ptr;
|
|
162 |
break;
|
|
163 |
case EFat16:
|
|
164 |
val = *(TUint16*)ptr;
|
|
165 |
break;
|
|
166 |
case EFat12:
|
|
167 |
val = *(TUint16*)ptr;
|
|
168 |
if (aIndex & 1)
|
|
169 |
val >>= 4;
|
|
170 |
val &= 0xFFF;
|
|
171 |
break;
|
|
172 |
default:
|
|
173 |
test(0);
|
|
174 |
}
|
|
175 |
return val;
|
|
176 |
}
|
|
177 |
|
|
178 |
void MarkFatEntry(TUint32 aIndex)
|
|
179 |
//
|
|
180 |
// Marks a single FAT entry by modifying it's top 4 bits to
|
|
181 |
//
|
|
182 |
{
|
|
183 |
TInt pos = PosInBytes(aIndex);
|
|
184 |
pos += TheBootSector.ReservedSectors() * TheBootSector.BytesPerSector();
|
|
185 |
|
|
186 |
TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
|
|
187 |
test(r==KErrNone);
|
|
188 |
TUint8 data[4];
|
|
189 |
TPtr8 buf(&data[0], 4);
|
|
190 |
r=TheDisk.Read(pos, buf);
|
|
191 |
test(r==KErrNone);
|
|
192 |
data[3] &= 0x0F;
|
|
193 |
data[3] |= 0xA0;
|
|
194 |
r=TheDisk.Write(pos, buf);
|
|
195 |
test(r==KErrNone);
|
|
196 |
TheDisk.Close();
|
|
197 |
}
|
|
198 |
|
|
199 |
void DumpBootSector()
|
|
200 |
//
|
|
201 |
// Display (in log) TFatBootSector structure
|
|
202 |
//
|
|
203 |
{
|
|
204 |
RDebug::Print(_L("BytesPerSector = %8d"), TheBootSector.BytesPerSector());
|
|
205 |
RDebug::Print(_L("SectorsPerCluster = %8d (%d bytes)"),
|
|
206 |
TheBootSector.SectorsPerCluster(), gBytesPerCluster);
|
|
207 |
RDebug::Print(_L("ReservedSectors = %8d"), TheBootSector.ReservedSectors());
|
|
208 |
RDebug::Print(_L("NumberOfFats = %8d"), TheBootSector.NumberOfFats());
|
|
209 |
RDebug::Print(_L("RootDirEntries = %8d"), TheBootSector.RootDirEntries());
|
|
210 |
RDebug::Print(_L("TotalSectors = %8d"), TheBootSector.TotalSectors());
|
|
211 |
RDebug::Print(_L("MediaDescriptor = %8d"), TheBootSector.MediaDescriptor());
|
|
212 |
RDebug::Print(_L("FatSectors = %8d"), TheBootSector.FatSectors());
|
|
213 |
RDebug::Print(_L("SectorsPerTrack = %8d"), TheBootSector.SectorsPerTrack());
|
|
214 |
RDebug::Print(_L("NumberOfHeads = %8d"), TheBootSector.NumberOfHeads());
|
|
215 |
RDebug::Print(_L("HiddenSectors = %8d"), TheBootSector.HiddenSectors());
|
|
216 |
RDebug::Print(_L("HugeSectors = %8d"), TheBootSector.HugeSectors());
|
|
217 |
|
|
218 |
//New for FAT32
|
|
219 |
|
|
220 |
if(TheBootSector.RootDirEntries() == 0) //indicates we have FAT32 volume
|
|
221 |
{
|
|
222 |
RDebug::Print(_L("FatSectors32 = %8d"), TheBootSector.FatSectors32());
|
|
223 |
RDebug::Print(_L("FATFlags = %8d"), TheBootSector.FATFlags());
|
|
224 |
RDebug::Print(_L("VersionNumber = %8d"), TheBootSector.VersionNumber());
|
|
225 |
RDebug::Print(_L("RootClusterNum = %8d (0x%08X)"),
|
|
226 |
TheBootSector.RootClusterNum(),
|
|
227 |
gRootDirStart);
|
|
228 |
RDebug::Print(_L("FSInfoSectorNum = %8d (0x%08X)"),
|
|
229 |
TheBootSector.FSInfoSectorNum(),
|
|
230 |
TheBootSector.FSInfoSectorNum() * TheBootSector.BytesPerSector());
|
|
231 |
RDebug::Print(_L("BkBootRecSector = %8d (0x%08X)"),
|
|
232 |
TheBootSector.BkBootRecSector(),
|
|
233 |
TheBootSector.BkBootRecSector() * TheBootSector.BytesPerSector());
|
|
234 |
}
|
|
235 |
|
|
236 |
TInt fatEntries = gFatSizeSectors*TheBootSector.BytesPerSector();
|
|
237 |
switch (gDiskType)
|
|
238 |
{
|
|
239 |
case EFat32:
|
|
240 |
fatEntries /= 4;
|
|
241 |
break;
|
|
242 |
case EFat16:
|
|
243 |
fatEntries /= 2;
|
|
244 |
break;
|
|
245 |
case EFat12:
|
|
246 |
fatEntries *= 3;
|
|
247 |
fatEntries /= 2;
|
|
248 |
break;
|
|
249 |
default:
|
|
250 |
test(0);
|
|
251 |
}
|
|
252 |
|
|
253 |
RDebug::Print(_L("ClusterCount = %8d (%ld bytes)"), gClusterCount, ((TInt64)gClusterCount)*gBytesPerCluster);
|
|
254 |
RDebug::Print(_L("FatEntries = %8d (%d sectors)"), fatEntries, gFatSizeSectors);
|
|
255 |
RDebug::Print(_L("RootSector = %8d (0x%08X)"), gRootSector, gRootDirStart);
|
|
256 |
RDebug::Print(_L("FirstDataSector = %8d (0x%08X)"), gFirstDataSector, gDataStartBytes);
|
|
257 |
}
|
|
258 |
|
|
259 |
void DumpFat(const TUint8* aFat=NULL)
|
|
260 |
//
|
|
261 |
// Dump to the log all those FAT entries which are non-zero
|
|
262 |
//
|
|
263 |
{
|
|
264 |
TInt32 max = MaxClusters();
|
|
265 |
if (max > KMaxFatEntries)
|
|
266 |
max = KMaxFatEntries;
|
|
267 |
RDebug::Print(_L("---------------- DUMP OF FAT ---------------"));
|
|
268 |
for (TInt32 i = 0; i < max; i++)
|
|
269 |
{
|
|
270 |
TInt32 val = GetFatEntry(i, aFat);
|
|
271 |
TInt32 msk = 0x0FFFFFFF;
|
|
272 |
switch (gDiskType)
|
|
273 |
{
|
|
274 |
case EFat32:
|
|
275 |
msk = 0x0FFFFFFF;
|
|
276 |
break;
|
|
277 |
case EFat16:
|
|
278 |
msk = 0xFFFF;
|
|
279 |
break;
|
|
280 |
case EFat12:
|
|
281 |
msk = 0x0FFF;
|
|
282 |
break;
|
|
283 |
default:
|
|
284 |
test(0);
|
|
285 |
}
|
|
286 |
if ((val & msk) == (0x0FFFFFFF & msk))
|
|
287 |
RDebug::Print(_L(" %8d -> EOC"), i);
|
|
288 |
else if ((val & msk) == (0x0FFFFFF8 & msk))
|
|
289 |
RDebug::Print(_L(" %8d -> Media"), i);
|
|
290 |
else if ((val & msk) == (0x0FFFFFF7 & msk))
|
|
291 |
RDebug::Print(_L(" %8d -> BAD"), i);
|
|
292 |
else if (val > max)
|
|
293 |
RDebug::Print(_L(" %8d -> 0x%08X"), i, val);
|
|
294 |
else if (val != 0)
|
|
295 |
RDebug::Print(_L(" %8d -> %d"), i, val);
|
|
296 |
}
|
|
297 |
RDebug::Print(_L("--------------------------------------------"));
|
|
298 |
}
|
|
299 |
|
|
300 |
TDes* DirAttributes(TInt aAttrib)
|
|
301 |
//
|
|
302 |
// Return a pointer to a local buffer containing the attribute letters.
|
|
303 |
//
|
|
304 |
{
|
|
305 |
static TBuf<6> str(_L("------"));
|
|
306 |
static char* atr = "RHSVDA";
|
|
307 |
for (TInt i = 0; i < 6; i++)
|
|
308 |
if ((aAttrib >> i) & 1)
|
|
309 |
str[i] = atr[i];
|
|
310 |
return &str;
|
|
311 |
}
|
|
312 |
|
|
313 |
TBool IsValidDirChar(TUint8 aChar, TUint8 aMin=0x20)
|
|
314 |
//
|
|
315 |
// Test whether a character is valid as part of a short filename, aMin is to
|
|
316 |
// distinguish between first character (which can't be space) and later ones
|
|
317 |
// which can include space but nothing less. Note that E5 is a valid character
|
|
318 |
// in any position, even though it means 'erased' in the first character.
|
|
319 |
//
|
|
320 |
{
|
|
321 |
const TUint8* inval = (TUint8*)"\x22\x2A\x2B\x2C\x2F\x3A\x3B\x3C\x3D\x3E\x3F\x5B\x5C\x5D\x7C";
|
|
322 |
if (aChar < aMin)
|
|
323 |
return EFalse;
|
|
324 |
for (const TUint8* p = inval; *p; p++)
|
|
325 |
if (aChar == *p)
|
|
326 |
return EFalse;
|
|
327 |
return ETrue;
|
|
328 |
}
|
|
329 |
|
|
330 |
TBool IsValidDirEntry(TFatDirEntry* aDir)
|
|
331 |
//
|
|
332 |
// Test whether buffer is a valid normal directory entry
|
|
333 |
//
|
|
334 |
{
|
|
335 |
// top two bits of attributes must be zero
|
|
336 |
if (aDir->iData[11] & 0xC0)
|
|
337 |
return EFalse;
|
|
338 |
// first character must be 0x05 or greater than space
|
|
339 |
if (!IsValidDirChar(aDir->iData[0], 0x21) && aDir->iData[0] != 0x05)
|
|
340 |
return EFalse;
|
|
341 |
// other characters in name must be not less than space
|
|
342 |
for (TInt i = 1; i < 11; i++)
|
|
343 |
if (!IsValidDirChar(aDir->iData[i]))
|
|
344 |
return EFalse;
|
|
345 |
return ETrue;
|
|
346 |
}
|
|
347 |
|
|
348 |
void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength)
|
|
349 |
//
|
|
350 |
// Extract part of a long name entry into the name buffer.
|
|
351 |
//
|
|
352 |
// @param aName buffer to put name
|
|
353 |
// @param aEntry directory entry raw data
|
|
354 |
// @param aPos character in buffer to start name segment
|
|
355 |
// @param aOffset offset in directory entry of the segment
|
|
356 |
// @param aLength number of characters in the segment
|
|
357 |
//
|
|
358 |
{
|
|
359 |
for (TInt i = 0; i < aLength; i++)
|
|
360 |
{
|
|
361 |
TInt at = i * 2 + aOffset;
|
|
362 |
TInt ch = aEntry[at] + aEntry[at+1] * 256;
|
|
363 |
aName[aPos++] = TText(ch);
|
|
364 |
}
|
|
365 |
}
|
|
366 |
|
|
367 |
void ExtractNameString(TDes16& aName, const TUint8* aEntry)
|
|
368 |
//
|
|
369 |
// Extract a long name part from a directory entry, truncate it at the first
|
|
370 |
// NUL (0) character and put quotes round it.
|
|
371 |
//
|
|
372 |
{
|
|
373 |
aName.SetLength(15);
|
|
374 |
TInt len = aName.Length() - 1;
|
|
375 |
TText qu = '\'';
|
|
376 |
aName[0] = qu;
|
|
377 |
GetLongNamePart(aName, aEntry, 1, 1, 5);
|
|
378 |
GetLongNamePart(aName, aEntry, 6, 14, 6);
|
|
379 |
GetLongNamePart(aName, aEntry, 12, 28, 2);
|
|
380 |
TInt i;
|
|
381 |
for (i = 0; i < len; i++)
|
|
382 |
if (aName[i] == 0)
|
|
383 |
break;
|
|
384 |
aName[i++] = qu;
|
|
385 |
aName.SetLength(i);
|
|
386 |
}
|
|
387 |
|
|
388 |
TBool DumpDirEntry(TInt aNum, const TUint8* aEntry)
|
|
389 |
//
|
|
390 |
// Dump a single directory entry to the log. Return false if it was end of
|
|
391 |
// directory or an invalid entry (and don't display it).
|
|
392 |
//
|
|
393 |
{
|
|
394 |
TFatDirEntry* d = (TFatDirEntry*)aEntry;
|
|
395 |
if (d->IsErased())
|
|
396 |
{
|
|
397 |
// RDebug::Print(_L("%5d: ERASED"), aNum);
|
|
398 |
}
|
|
399 |
else if (d->IsEndOfDirectory())
|
|
400 |
{
|
|
401 |
RDebug::Print(_L("%5d: END-OF-DIRECTORY"), aNum);
|
|
402 |
return EFalse;
|
|
403 |
}
|
|
404 |
else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName)
|
|
405 |
{
|
|
406 |
TBuf16<15> name;
|
|
407 |
ExtractNameString(name, aEntry);
|
|
408 |
TInt ord = aEntry[0];
|
|
409 |
if (ord & KDirLastLongEntry)
|
|
410 |
RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry);
|
|
411 |
else
|
|
412 |
RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry);
|
|
413 |
}
|
|
414 |
else if (!IsValidDirEntry(d))
|
|
415 |
{
|
|
416 |
RDebug::Print(_L("%5d: not valid"), aNum);
|
|
417 |
return EFalse;
|
|
418 |
}
|
|
419 |
else
|
|
420 |
{
|
|
421 |
TBuf<11> name;
|
|
422 |
name.Copy(d->Name());
|
|
423 |
RDebug::Print(_L("%5d: '%S' %S cluster %d"),
|
|
424 |
aNum, &name, DirAttributes(d->Attributes()), d->StartCluster());
|
|
425 |
}
|
|
426 |
return ETrue;
|
|
427 |
}
|
|
428 |
|
|
429 |
void DumpDirCluster(const TUint8* aData, TInt aCluster=0)
|
|
430 |
//
|
|
431 |
// Dump directory entries until end of cluster or invalid/end entry found.
|
|
432 |
//
|
|
433 |
{
|
|
434 |
if (aCluster > 2)
|
|
435 |
aData += (aCluster-2) * gBytesPerCluster;
|
|
436 |
for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry)
|
|
437 |
{
|
|
438 |
if (DumpDirEntry(i/KSizeOfFatDirEntry, aData))
|
|
439 |
aData += KSizeOfFatDirEntry;
|
|
440 |
else
|
|
441 |
break;
|
|
442 |
}
|
|
443 |
}
|
|
444 |
|
|
445 |
void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd=-1)
|
|
446 |
//
|
|
447 |
// Dump clusters from disk (allows dumping of clusters not in our buffers).
|
|
448 |
// Only look at clusters marked as 'used' in the FAT. Note that if aFat is
|
|
449 |
// NULL the FAT entries will also be read from disk (slower but allows for ones
|
|
450 |
// outside our copy in memory).
|
|
451 |
//
|
|
452 |
{
|
|
453 |
if (aStart > gFatTestEntries)
|
|
454 |
return;
|
|
455 |
if (aEnd > gFatTestEntries)
|
|
456 |
aEnd = gFatTestEntries;
|
|
457 |
if (aEnd <= 0)
|
|
458 |
aEnd = aStart + 1;
|
|
459 |
RDebug::Print(_L("--------------- DATA AREA ------------------"));
|
|
460 |
if (aEnd > gFatTestEntries)
|
|
461 |
aEnd = gFatTestEntries;
|
|
462 |
for (TInt cluster = aStart; cluster < aEnd; cluster++)
|
|
463 |
{
|
|
464 |
if (GetFatEntry(cluster, aFat) != 0)
|
|
465 |
{
|
|
466 |
HBufC8* buf=HBufC8::New(gBytesPerCluster);
|
|
467 |
test(buf!=NULL);
|
|
468 |
TPtr8 ptr=buf->Des();
|
|
469 |
TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
|
|
470 |
test(r==KErrNone);
|
|
471 |
r=TheDisk.Read(ClusterToByte(cluster), ptr);
|
|
472 |
test(r==KErrNone);
|
|
473 |
TheDisk.Close();
|
|
474 |
RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster));
|
|
475 |
DumpDirCluster(ptr.Ptr());
|
|
476 |
delete buf;
|
|
477 |
}
|
|
478 |
}
|
|
479 |
RDebug::Print(_L("--------------------------------------------"));
|
|
480 |
}
|
|
481 |
|
|
482 |
void DumpData(TInt aStart=0, TInt aEnd=0)
|
|
483 |
//
|
|
484 |
// Dump clusters from disk (allows dumping of clusters not in our buffers).
|
|
485 |
// Only look at clusters marked as 'used' in the FAT. Note that if aFat is
|
|
486 |
// NULL the FAT entries will also be read from disk (slower but allows for ones
|
|
487 |
// outside our copy in memory).
|
|
488 |
//
|
|
489 |
{
|
|
490 |
if (aStart == 0)
|
|
491 |
{
|
|
492 |
if (aEnd <= 0)
|
|
493 |
aEnd = 1;
|
|
494 |
TInt num = (gDiskType == EFat32 ? aEnd*gEntriesPerCluster : TheBootSector.RootDirEntries());
|
|
495 |
TInt pos = gRootDirStart;
|
|
496 |
TInt ent = 0;
|
|
497 |
HBufC8* buf=HBufC8::New(KSizeOfFatDirEntry);
|
|
498 |
test(buf!=NULL);
|
|
499 |
TPtr8 ptr=buf->Des();
|
|
500 |
TInt r=TheDisk.Open(TheFs,gSessionPath[0]-'A');
|
|
501 |
test(r==KErrNone);
|
|
502 |
RDebug::Print(_L("--------------- ROOT DIR ------------------"));
|
|
503 |
for (TInt i = 0; i < num; i++)
|
|
504 |
{
|
|
505 |
r=TheDisk.Read(pos, ptr);
|
|
506 |
test(r==KErrNone);
|
|
507 |
if (!DumpDirEntry(ent, ptr.Ptr()))
|
|
508 |
break;
|
|
509 |
pos += KSizeOfFatDirEntry;
|
|
510 |
}
|
|
511 |
RDebug::Print(_L("-------------------------------------------"));
|
|
512 |
TheDisk.Close();
|
|
513 |
delete buf;
|
|
514 |
}
|
|
515 |
else if (aStart == 1)
|
|
516 |
{
|
|
517 |
DumpData(0, 1);
|
|
518 |
DumpData(NULL, gFirstDataCluster, aEnd);
|
|
519 |
}
|
|
520 |
else
|
|
521 |
{
|
|
522 |
DumpData(NULL, aStart, aEnd);
|
|
523 |
}
|
|
524 |
}
|
|
525 |
|
|
526 |
void DumpHex(const TUint8* aData, TInt aLen)
|
|
527 |
//
|
|
528 |
// Dump a block of memory to the log in hex.
|
|
529 |
//
|
|
530 |
{
|
|
531 |
for (TInt base = 0; base < aLen; base += 16)
|
|
532 |
{
|
|
533 |
TBuf<16*3> buf;
|
|
534 |
TInt off;
|
|
535 |
for (off = base; off < aLen && off < base + 16; off++)
|
|
536 |
{
|
|
537 |
buf.Append(TText(' '));
|
|
538 |
buf.AppendNumFixedWidth(aData[off], EHex, 2);
|
|
539 |
}
|
|
540 |
RDebug::Print(_L("%04X: %S"), base, &buf);
|
|
541 |
}
|
|
542 |
}
|
|
543 |
|
|
544 |
|
|
545 |
//---------------------------------------------------------------------------------------------------------------
|
|
546 |
|
|
547 |
static void DoReadBootSector(TFatBootSector& aBootSector)
|
|
548 |
{
|
|
549 |
TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, aBootSector);
|
|
550 |
test(nRes == KErrNone);
|
|
551 |
|
|
552 |
if(!aBootSector.IsValid())
|
|
553 |
{
|
|
554 |
test.Printf(_L("Wrong bootsector! Dump:\n"));
|
|
555 |
aBootSector.PrintDebugInfo();
|
|
556 |
test(0);
|
|
557 |
}
|
|
558 |
|
|
559 |
// Calculate derived variables (fixed for a particular disk format)
|
|
560 |
|
|
561 |
if (TheBootSector.FatType() == EFat32)
|
|
562 |
{
|
|
563 |
gDiskType = EFat32;
|
|
564 |
gFatBits = 32;
|
|
565 |
gEndOfChain = 0x0FFFFFFF;
|
|
566 |
}
|
|
567 |
else if (TheBootSector.FatType() == EFat16)
|
|
568 |
{
|
|
569 |
gDiskType = EFat16;
|
|
570 |
gFatBits = 16;
|
|
571 |
gEndOfChain = 0xFFFF;
|
|
572 |
}
|
|
573 |
else
|
|
574 |
{
|
|
575 |
gDiskType = EFat12;
|
|
576 |
gFatBits = 12;
|
|
577 |
gEndOfChain = 0x0FFF;
|
|
578 |
}
|
|
579 |
|
|
580 |
gBytesPerCluster = TheBootSector.BytesPerSector() * TheBootSector.SectorsPerCluster();
|
|
581 |
gRootDirSectors = ((TheBootSector.RootDirEntries() * KSizeOfFatDirEntry + TheBootSector.BytesPerSector() - 1) /
|
|
582 |
TheBootSector.BytesPerSector());
|
|
583 |
gEntriesPerCluster = gBytesPerCluster / KSizeOfFatDirEntry;
|
|
584 |
gTotalSectors = (TheBootSector.TotalSectors() ? TheBootSector.TotalSectors() : TheBootSector.HugeSectors());
|
|
585 |
|
|
586 |
switch (gDiskType)
|
|
587 |
{
|
|
588 |
case EFat12:
|
|
589 |
case EFat16:
|
|
590 |
gFatSizeSectors = TheBootSector.FatSectors();
|
|
591 |
gRootSector = TheBootSector.ReservedSectors() + TheBootSector.NumberOfFats() * gFatSizeSectors;
|
|
592 |
gFirstDataSector = gRootSector + gRootDirSectors;
|
|
593 |
gRootCluster = 0;
|
|
594 |
gFirstDataCluster = 2;
|
|
595 |
gDataStartBytes = gFirstDataSector * TheBootSector.BytesPerSector();
|
|
596 |
gRootDirStart = gRootSector * TheBootSector.BytesPerSector();
|
|
597 |
break;
|
|
598 |
case EFat32:
|
|
599 |
gFatSizeSectors = TheBootSector.FatSectors32();
|
|
600 |
gRootSector = TheBootSector.ReservedSectors() + TheBootSector.NumberOfFats() * gFatSizeSectors;
|
|
601 |
gFirstDataSector = gRootSector + gRootDirSectors;
|
|
602 |
gRootCluster = 2;
|
|
603 |
gFirstDataCluster = 3;
|
|
604 |
gDataStartBytes = gFirstDataSector * TheBootSector.BytesPerSector();
|
|
605 |
gRootDirStart = (TheBootSector.RootClusterNum() - 2) * gBytesPerCluster + gDataStartBytes;
|
|
606 |
break;
|
|
607 |
default:
|
|
608 |
break;
|
|
609 |
}
|
|
610 |
|
|
611 |
gClusterCount = (gTotalSectors - gFirstDataSector) / TheBootSector.SectorsPerCluster();
|
|
612 |
|
|
613 |
gFatTestEntries = MaxClusters();
|
|
614 |
if (gFatTestEntries > KMaxFatSize)
|
|
615 |
gFatTestEntries = KMaxFatSize;
|
|
616 |
}
|
|
617 |
|
|
618 |
|
|
619 |
static TInt CalcShifts(TInt aSize)
|
|
620 |
//
|
|
621 |
// Calculate the number of shifts to get >= aSize (aSize should be a power of 2
|
|
622 |
// anyway).
|
|
623 |
//
|
|
624 |
{
|
|
625 |
TInt x=0;
|
|
626 |
while (aSize>>=1)
|
|
627 |
x++;
|
|
628 |
return(x);
|
|
629 |
}
|
|
630 |
|
|
631 |
static TInt SectorShifts()
|
|
632 |
//
|
|
633 |
// Calculate number of shifts for sector size.
|
|
634 |
//
|
|
635 |
{
|
|
636 |
return(CalcShifts(TheBootSector.BytesPerSector()));
|
|
637 |
}
|
|
638 |
|
|
639 |
static TInt ClusterShifts()
|
|
640 |
//
|
|
641 |
// Calculate number of shifts for cluster size.
|
|
642 |
//
|
|
643 |
{
|
|
644 |
return(CalcShifts(TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()));
|
|
645 |
}
|
|
646 |
|
|
647 |
|
|
648 |
//
|
|
649 |
// Quick Format the disk
|
|
650 |
//
|
|
651 |
static void FormatPack()
|
|
652 |
{
|
|
653 |
|
|
654 |
#if 0
|
|
655 |
//-- FAT32 SPC:1; for the FAT32 testing on the emulator
|
|
656 |
TFatFormatParam fp;
|
|
657 |
fp.iFatType = EFat32;
|
|
658 |
fp.iSecPerCluster = 1;
|
|
659 |
FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fp);
|
|
660 |
#else
|
|
661 |
|
|
662 |
FormatFatDrive(TheFs, CurrentDrive(), ETrue);
|
|
663 |
|
|
664 |
#endif
|
|
665 |
|
|
666 |
DoReadBootSector(TheBootSector);
|
|
667 |
|
|
668 |
}
|
|
669 |
|
|
670 |
|
|
671 |
|
|
672 |
static void TestReadWrite(TInt64 aPos,TInt aLen,TInt anErr)
|
|
673 |
//
|
|
674 |
// Read and write to the disk
|
|
675 |
//
|
|
676 |
{
|
|
677 |
TPtr8 buffer((TUint8*)pBuffer1->Ptr(),aLen);
|
|
678 |
test.Printf(_L("TestReadWrite pos=0x%lx,len=%d\n"),aPos,aLen);
|
|
679 |
TInt r;
|
|
680 |
if ((r=TheDisk.Read(aPos,buffer))!=anErr)
|
|
681 |
{
|
|
682 |
test.Printf(_L("ERROR: anErr=%d ret=%d\n"),anErr,r);
|
|
683 |
test(EFalse);
|
|
684 |
}
|
|
685 |
buffer.SetLength(aLen);
|
|
686 |
if ((r=TheDisk.Write(aPos,buffer))!=anErr)
|
|
687 |
{
|
|
688 |
test.Printf(_L("ERROR: anErr=%d ret=%d\n"),anErr,r);
|
|
689 |
test(EFalse);
|
|
690 |
}
|
|
691 |
}
|
|
692 |
|
|
693 |
static TInt ReadWriteWord(TInt64 aPos,TInt aMask,TInt aValue)
|
|
694 |
//
|
|
695 |
// Read 2 bytes from aPos and Write over masked bits with aValue
|
|
696 |
//
|
|
697 |
{
|
|
698 |
TUint16 word;
|
|
699 |
TPtr8 buffer((TUint8*)&word,sizeof(word));
|
|
700 |
|
|
701 |
TInt r=TheDisk.Read(aPos,buffer);
|
|
702 |
if (r!=KErrNone)
|
|
703 |
return(r);
|
|
704 |
|
|
705 |
word&=((aValue&aMask)|~aMask);
|
|
706 |
word|=(aValue&aMask);
|
|
707 |
|
|
708 |
r=TheDisk.Write(aPos,buffer);
|
|
709 |
return(r);
|
|
710 |
}
|
|
711 |
|
|
712 |
static TInt ReadWriteDWord(TInt64 aPos,TInt aMask,TInt aValue)
|
|
713 |
//
|
|
714 |
// Read 4 bytes from aPos and Write over masked bits with aValue
|
|
715 |
//
|
|
716 |
{
|
|
717 |
TUint32 word;
|
|
718 |
TPtr8 buffer((TUint8*)&word,sizeof(word));
|
|
719 |
|
|
720 |
TInt r=TheDisk.Read(aPos,buffer);
|
|
721 |
if (r!=KErrNone)
|
|
722 |
return(r);
|
|
723 |
|
|
724 |
word&=((aValue&aMask)|~aMask);
|
|
725 |
word|=(aValue&aMask);
|
|
726 |
|
|
727 |
r=TheDisk.Write(aPos,buffer);
|
|
728 |
return(r);
|
|
729 |
}
|
|
730 |
|
|
731 |
static void FatWrite(TInt aCluster,TInt aValue)
|
|
732 |
//
|
|
733 |
//
|
|
734 |
//
|
|
735 |
{
|
|
736 |
TInt pos=0;
|
|
737 |
TInt mask=0;
|
|
738 |
|
|
739 |
const TUint32 KFirstFatSectorPos = TheBootSector.FirstFatSector() * TheBootSector.BytesPerSector();
|
|
740 |
|
|
741 |
switch (gDiskType)
|
|
742 |
{
|
|
743 |
case EFat32:
|
|
744 |
mask=0xffffffff;
|
|
745 |
pos=KFirstFatSectorPos+(aCluster<<2);
|
|
746 |
break;
|
|
747 |
case EFat16:
|
|
748 |
mask=0xffff;
|
|
749 |
pos=KFirstFatSectorPos+(aCluster<<1);
|
|
750 |
break;
|
|
751 |
case EFat12:
|
|
752 |
mask=0x0fff;
|
|
753 |
pos=KFirstFatSectorPos+aCluster+(aCluster>>1);
|
|
754 |
if (aCluster & 1)
|
|
755 |
{
|
|
756 |
mask=0xfff0;
|
|
757 |
aValue<<=4;
|
|
758 |
}
|
|
759 |
break;
|
|
760 |
default:
|
|
761 |
test(0);
|
|
762 |
}
|
|
763 |
|
|
764 |
TInt r=TheDisk.Open(TheFs,CurrentDrive());
|
|
765 |
test(r==KErrNone);
|
|
766 |
test(ReadWriteDWord(pos,mask,aValue)==KErrNone);
|
|
767 |
TheDisk.Close();
|
|
768 |
}
|
|
769 |
|
|
770 |
static void TestRwWord(TInt64 aPos,TInt anErr)
|
|
771 |
//
|
|
772 |
//
|
|
773 |
//
|
|
774 |
{
|
|
775 |
TInt r;
|
|
776 |
TUint16 wBuf;
|
|
777 |
TUint16 rBuf;
|
|
778 |
TUint16 mask=0;
|
|
779 |
TUint16 value=0;
|
|
780 |
|
|
781 |
test.Printf(_L("Test read and write value to 0x%lx\n"),aPos);
|
|
782 |
|
|
783 |
if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
|
|
784 |
{
|
|
785 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
786 |
test(EFalse);
|
|
787 |
}
|
|
788 |
|
|
789 |
if (anErr==KErrNone && aPos==0)
|
|
790 |
{
|
|
791 |
wBuf=0xff00;
|
|
792 |
TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
|
|
793 |
test(TheDisk.Write(aPos,writebuf)==KErrNone);
|
|
794 |
|
|
795 |
mask=0x0505;
|
|
796 |
value=0xa4a4;
|
|
797 |
test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
|
|
798 |
if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
|
|
799 |
{
|
|
800 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
801 |
test(EFalse);
|
|
802 |
}
|
|
803 |
|
|
804 |
TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
|
|
805 |
if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
|
|
806 |
{
|
|
807 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
808 |
test(EFalse);
|
|
809 |
}
|
|
810 |
test(rBuf==0xfe04);
|
|
811 |
}
|
|
812 |
|
|
813 |
if (anErr==KErrNone && aPos==1)
|
|
814 |
{
|
|
815 |
wBuf=0xff00;
|
|
816 |
TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
|
|
817 |
test(TheDisk.Write(aPos,writebuf)==KErrNone);
|
|
818 |
|
|
819 |
mask=0xffff;
|
|
820 |
value=0xa3a3;
|
|
821 |
test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
|
|
822 |
if ((r=ReadWriteWord(aPos,mask,value))!=anErr)
|
|
823 |
{
|
|
824 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
825 |
test(EFalse);
|
|
826 |
}
|
|
827 |
|
|
828 |
TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
|
|
829 |
if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
|
|
830 |
{
|
|
831 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
832 |
test(EFalse);
|
|
833 |
}
|
|
834 |
test(rBuf==0xa3a3);
|
|
835 |
}
|
|
836 |
}
|
|
837 |
|
|
838 |
static void TestRwDWord(TInt64 aPos,TInt anErr)
|
|
839 |
//
|
|
840 |
//
|
|
841 |
//
|
|
842 |
{
|
|
843 |
TInt r;
|
|
844 |
TUint32 wBuf;
|
|
845 |
TUint32 rBuf;
|
|
846 |
TUint32 mask=0;
|
|
847 |
TUint32 value=0;
|
|
848 |
|
|
849 |
test.Printf(_L("Test read and write value to 0x%lx\n"),aPos);
|
|
850 |
|
|
851 |
if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
|
|
852 |
{
|
|
853 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
854 |
test(EFalse);
|
|
855 |
}
|
|
856 |
|
|
857 |
if (anErr==KErrNone && aPos==0)
|
|
858 |
{
|
|
859 |
wBuf=0xff00ff00;
|
|
860 |
TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
|
|
861 |
test(TheDisk.Write(aPos,writebuf)==KErrNone);
|
|
862 |
|
|
863 |
mask = 0x0505195c;
|
|
864 |
value = 0xa4a4c634;
|
|
865 |
test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
|
|
866 |
if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
|
|
867 |
{
|
|
868 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
869 |
test(EFalse);
|
|
870 |
}
|
|
871 |
|
|
872 |
TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
|
|
873 |
if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
|
|
874 |
{
|
|
875 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
876 |
test(EFalse);
|
|
877 |
}
|
|
878 |
test(rBuf==0xfe04e614);
|
|
879 |
}
|
|
880 |
|
|
881 |
if (anErr==KErrNone && aPos==1)
|
|
882 |
{
|
|
883 |
wBuf=0xff0000ff;
|
|
884 |
TPtrC8 writebuf((TUint8*)&wBuf,sizeof(wBuf));
|
|
885 |
test(TheDisk.Write(aPos,writebuf)==KErrNone);
|
|
886 |
|
|
887 |
mask=0xffffffff;
|
|
888 |
value=0xa3a3dead;
|
|
889 |
test.Printf(_L("Test RWW mask=%04x value%04x\n"),mask,value);
|
|
890 |
if ((r=ReadWriteDWord(aPos,mask,value))!=anErr)
|
|
891 |
{
|
|
892 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
893 |
test(EFalse);
|
|
894 |
}
|
|
895 |
|
|
896 |
TPtr8 readBuf((TUint8*)&rBuf,sizeof(rBuf));
|
|
897 |
if ((r=TheDisk.Read(aPos,readBuf))!=KErrNone)
|
|
898 |
{
|
|
899 |
test.Printf(_L("ERROR: anErr=%d, ret=%d\n"),anErr,r);
|
|
900 |
test(EFalse);
|
|
901 |
}
|
|
902 |
test(rBuf==0xa3a3dead);
|
|
903 |
}
|
|
904 |
}
|
|
905 |
|
|
906 |
|
|
907 |
static TInt ThrottleDirEntries(TInt aDirEntries, TInt aRemainder)
|
|
908 |
{
|
|
909 |
// throttle the number of entries needed, since for large cluster
|
|
910 |
// sizes, this can take forever (eg 2GB card -> a cluster size of 32K
|
|
911 |
// -> 1024 entries per cluster
|
|
912 |
const TInt KMaxDirEntries = 2048;
|
|
913 |
test(aRemainder < KMaxDirEntries);
|
|
914 |
TInt maxDirEntries = KMaxDirEntries - aRemainder;
|
|
915 |
|
|
916 |
if (aDirEntries > maxDirEntries)
|
|
917 |
{
|
|
918 |
RDebug::Print(_L("Reducing directory entries from %d to %d"), aDirEntries, maxDirEntries);
|
|
919 |
aDirEntries = maxDirEntries;
|
|
920 |
}
|
|
921 |
|
|
922 |
return aDirEntries;
|
|
923 |
}
|
|
924 |
|
|
925 |
static void TestLoopedSubDir()
|
|
926 |
//
|
|
927 |
//
|
|
928 |
{
|
|
929 |
test.Printf(_L("Test looped sub-dir\n"));
|
|
930 |
FormatPack();
|
|
931 |
TInt r=TheFs.MkDir(_L("\\D\\"));
|
|
932 |
if (r!=KErrNone && r!=KErrAlreadyExists)
|
|
933 |
Error(_L("Failed to make directory"),r);
|
|
934 |
TheFileName=_L("\\D\\");
|
|
935 |
|
|
936 |
TInt i=0;
|
|
937 |
TInt dirEntriesNeeded = ((TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()/KSizeOfFatDirEntry)-2);
|
|
938 |
dirEntriesNeeded = ThrottleDirEntries(dirEntriesNeeded, 2);
|
|
939 |
|
|
940 |
|
|
941 |
//-- generate some number of VFAT dir. entries by creating 8.3 temp. files in a lower case
|
|
942 |
for (i=0;i<dirEntriesNeeded;i++)
|
|
943 |
{
|
|
944 |
CreateFatEntry(TheFileName, ETrue);
|
|
945 |
}
|
|
946 |
|
|
947 |
test.Printf(_L("Test dir with no match\n"));
|
|
948 |
FatWrite(gFirstDataCluster,gFirstDataCluster);
|
|
949 |
if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
|
|
950 |
Error(_L("Failed Directory open"),r);
|
|
951 |
if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
|
|
952 |
Error(_L("Failed Directory read"),r);
|
|
953 |
TheDir.Close();
|
|
954 |
|
|
955 |
test.Printf(_L("Test dir with match\n"));
|
|
956 |
if ((r=TheDir.Open(TheFs,_L("\\D\\*.*"),KEntryAttMaskSupported))!=KErrNone)
|
|
957 |
Error(_L("Failed Directory open"),r);
|
|
958 |
if ((r=TheDir.Read(TheEntry))!=KErrNone)
|
|
959 |
Error(_L("Failed Directory read"),r);
|
|
960 |
TheDir.Close();
|
|
961 |
|
|
962 |
test.Printf(_L("Test dir without loop\n"));
|
|
963 |
FatWrite(gFirstDataCluster,gEndOfChain);
|
|
964 |
if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
|
|
965 |
Error(_L("Directory open"),r);
|
|
966 |
if ((r=TheDir.Read(TheEntry))!=KErrEof)
|
|
967 |
Error(_L("Reading empty dir returned"),r);
|
|
968 |
TheDir.Close();
|
|
969 |
|
|
970 |
test.Printf(_L("Test dir with long filenames\n"));
|
|
971 |
|
|
972 |
FormatPack();
|
|
973 |
r=TheFs.MkDir(_L("\\D\\"));
|
|
974 |
if (r!=KErrNone && r!=KErrAlreadyExists)
|
|
975 |
Error(_L("Failed to make directory"),r);
|
|
976 |
TheFileName=_L("\\D\\");
|
|
977 |
|
|
978 |
dirEntriesNeeded = ((TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()/KSizeOfFatDirEntry)-3);
|
|
979 |
dirEntriesNeeded = ThrottleDirEntries(dirEntriesNeeded, 3);
|
|
980 |
|
|
981 |
//-- generate some number of VFAT dir. entries by creating 8.3 temp. files in a lower case
|
|
982 |
for (i=0;i<dirEntriesNeeded;i++)
|
|
983 |
{
|
|
984 |
CreateFatEntry(TheFileName, ETrue);
|
|
985 |
}
|
|
986 |
|
|
987 |
MakeFile(_L("\\D\\longfileName.Long"));
|
|
988 |
|
|
989 |
test.Printf(_L("Test dir with no match\n"));
|
|
990 |
FatWrite(gFirstDataCluster,gFirstDataCluster);
|
|
991 |
if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
|
|
992 |
Error(_L("Failed Directory open"),r);
|
|
993 |
if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
|
|
994 |
Error(_L("Failed Directory read"),r);
|
|
995 |
TheDir.Close();
|
|
996 |
|
|
997 |
test.Printf(_L("Test dir with match\n"));
|
|
998 |
if ((r=TheDir.Open(TheFs,_L("\\D\\*.*"),KEntryAttMaskSupported))!=KErrNone)
|
|
999 |
Error(_L("Failed Directory open"),r);
|
|
1000 |
if ((r=TheDir.Read(TheEntry))!=KErrNone)
|
|
1001 |
Error(_L("Failed Directory read"),r);
|
|
1002 |
TheDir.Close();
|
|
1003 |
|
|
1004 |
test.Printf(_L("Test dir without loop\n"));
|
|
1005 |
FatWrite(gFirstDataCluster,gEndOfChain);
|
|
1006 |
if ((r=TheDir.Open(TheFs,_L("\\D\\nomatch"),KEntryAttMaskSupported))!=KErrNone)
|
|
1007 |
Error(_L("Directory open"),r);
|
|
1008 |
|
|
1009 |
#if !defined _UNICODE
|
|
1010 |
if ((r=TheDir.Read(TheEntry))!=KErrCorrupt)
|
|
1011 |
Error(_L("Reading empty dir returned"),r);
|
|
1012 |
#endif
|
|
1013 |
TheDir.Close();
|
|
1014 |
}
|
|
1015 |
|
|
1016 |
static void TestLoopedFile()
|
|
1017 |
//
|
|
1018 |
// Test Looped file
|
|
1019 |
//
|
|
1020 |
{
|
|
1021 |
test.Printf(_L("Test looped file\n"));
|
|
1022 |
FormatPack();
|
|
1023 |
TInt r;
|
|
1024 |
|
|
1025 |
|
|
1026 |
|
|
1027 |
test.Next(_L("CreateFile"));
|
|
1028 |
test(TheFile.Replace(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite)==KErrNone);
|
|
1029 |
TPtr8 buf=pBuffer1->Des();
|
|
1030 |
|
|
1031 |
test(TheFile.Write(buf,TheBootSector.BytesPerSector()-1)==KErrNone);
|
|
1032 |
TheFile.Close();
|
|
1033 |
|
|
1034 |
test.Next(_L("Write 1 cluster loop"));
|
|
1035 |
FatWrite(gFirstDataCluster,gFirstDataCluster); /* tiny loop */
|
|
1036 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
|
|
1037 |
Error(_L("Error opening corrupt file"),r);
|
|
1038 |
FatWrite(gFirstDataCluster,0);
|
|
1039 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
|
|
1040 |
Error(_L("Error opening corrupt file"),r);
|
|
1041 |
FatWrite(gFirstDataCluster,gEndOfChain);
|
|
1042 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrNone)
|
|
1043 |
Error(_L("Error opening file"),r);
|
|
1044 |
if ((r=TheFile.Write(buf,TheBootSector.BytesPerSector()*TheBootSector.SectorsPerCluster()*2-1))!=0)
|
|
1045 |
Error(_L("Error writing to file"),r);
|
|
1046 |
TheFile.Close();
|
|
1047 |
|
|
1048 |
test.Next(_L("Write 2 cluster loop"));
|
|
1049 |
FatWrite(gFirstDataCluster+1,gFirstDataCluster); /* 2 cluster loop */
|
|
1050 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
|
|
1051 |
Error(_L("Error opening corrupt file"),r);
|
|
1052 |
FatWrite(gFirstDataCluster+1,gEndOfChain);
|
|
1053 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrNone)
|
|
1054 |
Error(_L("Error opening file"),r);
|
|
1055 |
|
|
1056 |
TInt len=16384;
|
|
1057 |
TInt size=0L;
|
|
1058 |
while (size < gBytesPerCluster * 500)
|
|
1059 |
{
|
|
1060 |
test.Printf(_L("\rWriting %d "),size);
|
|
1061 |
if ((r=TheFile.Write(buf,len))!=KErrNone)
|
|
1062 |
{
|
|
1063 |
if (r!=KErrDiskFull)
|
|
1064 |
Error(_L("File write error"),r);
|
|
1065 |
len>>=1;
|
|
1066 |
if (len==0)
|
|
1067 |
break;
|
|
1068 |
}
|
|
1069 |
else
|
|
1070 |
size+=len;
|
|
1071 |
}
|
|
1072 |
test.Printf(_L("\n"));
|
|
1073 |
TheFile.Close();
|
|
1074 |
|
|
1075 |
RDebug::Print(_L("File created size %d"), size);
|
|
1076 |
TInt clust=((size-1)>>ClusterShifts())+gFirstDataCluster;
|
|
1077 |
FatWrite(clust,gFirstDataCluster);
|
|
1078 |
if ((r=TheFile.Open(TheFs,_L("\\LOOPED1.TMP"),EFileRead|EFileWrite))!=KErrCorrupt)
|
|
1079 |
Error(_L("Error opening corrupt file"),r);
|
|
1080 |
FatWrite(clust,gEndOfChain);
|
|
1081 |
if ((r=TheFs.Delete(_L("\\LOOPED1.TMP")))!=KErrNone)
|
|
1082 |
Error(_L("Error deleting file"),r);
|
|
1083 |
RDebug::Print(_L("File removed"));
|
|
1084 |
r=TheFs.CheckDisk(gSessionPath);
|
|
1085 |
test(r==KErrNone);
|
|
1086 |
}
|
|
1087 |
|
|
1088 |
static void TestFatEntry(TUint16 aFileSize,TInt aCorruptFatCluster)
|
|
1089 |
//
|
|
1090 |
// Test fat entry
|
|
1091 |
//
|
|
1092 |
{
|
|
1093 |
TInt r;
|
|
1094 |
test.Printf(_L("File size=%d, cluster value=0x%x\n"),aFileSize,aCorruptFatCluster);
|
|
1095 |
FormatPack();
|
|
1096 |
|
|
1097 |
r=TheFile.Replace(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
|
|
1098 |
test(r==KErrNone);
|
|
1099 |
TheBuffer.SetLength(aFileSize);
|
|
1100 |
Mem::Fill(&TheBuffer[0],aFileSize,'A');
|
|
1101 |
r=TheFile.Write(TheBuffer);
|
|
1102 |
test(r==KErrNone);
|
|
1103 |
TheFile.Close();
|
|
1104 |
|
|
1105 |
FatWrite(gFirstDataCluster,aCorruptFatCluster);
|
|
1106 |
|
|
1107 |
TInt pos=0;
|
|
1108 |
r=TheFile.Open(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
|
|
1109 |
test(r==KErrNone || r==KErrCorrupt);
|
|
1110 |
if (r==KErrNone)
|
|
1111 |
{
|
|
1112 |
r=TheFile.Seek(ESeekStart,pos);
|
|
1113 |
test(r==KErrNone);
|
|
1114 |
r=TheFile.Write(TheBuffer);
|
|
1115 |
|
|
1116 |
if ((gDriveCacheFlags & EFileCacheWriteOn) && (r == KErrNone))
|
|
1117 |
r = TheFile.Flush();
|
|
1118 |
|
|
1119 |
if (r != KErrCorrupt)
|
|
1120 |
{
|
|
1121 |
test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
|
|
1122 |
Error(_L("Failed write"),r);
|
|
1123 |
}
|
|
1124 |
TheFile.Close();
|
|
1125 |
}
|
|
1126 |
|
|
1127 |
FatWrite(gFirstDataCluster,gEndOfChain);
|
|
1128 |
|
|
1129 |
pos=0;
|
|
1130 |
r=TheFile.Open(TheFs,_L("\\CORRUPT2.TMP"),EFileRead|EFileWrite);
|
|
1131 |
test(r==KErrNone);
|
|
1132 |
r=TheFile.Seek(ESeekStart,pos);
|
|
1133 |
test(r==KErrNone);
|
|
1134 |
r=TheFile.Write(TheBuffer);
|
|
1135 |
|
|
1136 |
if ((gDriveCacheFlags & EFileCacheWriteOn) && (r == KErrNone))
|
|
1137 |
r = TheFile.Flush();
|
|
1138 |
|
|
1139 |
// if the file size <= cluster size then writing last cluster marker to
|
|
1140 |
// cluster 2 should have no effect
|
|
1141 |
if(aFileSize>TheBootSector.SectorsPerCluster()<<SectorShifts())
|
|
1142 |
{
|
|
1143 |
if (r!=KErrCorrupt)
|
|
1144 |
{
|
|
1145 |
test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
|
|
1146 |
Error(_L("Failed write"),r);
|
|
1147 |
}
|
|
1148 |
}
|
|
1149 |
else
|
|
1150 |
{
|
|
1151 |
if (r!=KErrNone)
|
|
1152 |
{
|
|
1153 |
test.Printf(_L("Predicted error %d Actual error %d\n"),KErrNone,r);
|
|
1154 |
Error(_L("Failed write"),r);
|
|
1155 |
}
|
|
1156 |
}
|
|
1157 |
TheFile.Close();
|
|
1158 |
}
|
|
1159 |
|
|
1160 |
static void TestDirEntry(TInt anInitialSize,TInt aWriteLen,TInt aCorruptStartCluster)
|
|
1161 |
//
|
|
1162 |
// Test directory entry
|
|
1163 |
//
|
|
1164 |
{
|
|
1165 |
test.Printf(_L("Initial size=%d, len=%d, start cluster=0x%x\n"),anInitialSize,aWriteLen,aCorruptStartCluster);
|
|
1166 |
FormatPack();
|
|
1167 |
TInt r;
|
|
1168 |
|
|
1169 |
test(TheFile.Create(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite)==KErrNone);
|
|
1170 |
TheBuffer.SetLength(anInitialSize);
|
|
1171 |
Mem::Fill(&TheBuffer[0],anInitialSize,'A');
|
|
1172 |
r=TheFile.Write(TheBuffer);
|
|
1173 |
test(r==KErrNone);
|
|
1174 |
TheFile.Close();
|
|
1175 |
|
|
1176 |
r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1177 |
test(r==KErrNone);
|
|
1178 |
TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),TheBootSector.BytesPerSector());
|
|
1179 |
TInt pos = gRootDirStart;
|
|
1180 |
r=TheDisk.Read(pos,sectorBuf);
|
|
1181 |
test(r==KErrNone);
|
|
1182 |
TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
|
|
1183 |
while (pE->IsVFatEntry()) // UNICODE entries are VFat by definition
|
|
1184 |
pE++;
|
|
1185 |
|
|
1186 |
pE->SetStartCluster(aCorruptStartCluster);
|
|
1187 |
test(TheDisk.Write(pos,sectorBuf)==KErrNone);
|
|
1188 |
|
|
1189 |
|
|
1190 |
//-- a small hack to avoid problems with the fact that FAT[1] entry
|
|
1191 |
//-- is now used for marking volume as clean. TheDisk.Close() cause volume remout and
|
|
1192 |
//-- the data
|
|
1193 |
TheDisk.Close();
|
|
1194 |
r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1195 |
test(r==KErrNone);
|
|
1196 |
|
|
1197 |
|
|
1198 |
pos=0;
|
|
1199 |
TPtr8 buffer1(pBuffer1->Des());
|
|
1200 |
r=TheDisk.Read(pos,buffer1);
|
|
1201 |
test(r==KErrNone);
|
|
1202 |
TheDisk.Close();
|
|
1203 |
r=TheFs.Entry(_L("\\CORRUPT1.TMP"),TheEntry);
|
|
1204 |
test(r==KErrNone || r==KErrCorrupt);
|
|
1205 |
TTime saveTime=TheEntry.iModified;
|
|
1206 |
if (r!=KErrNone)
|
|
1207 |
saveTime.HomeTime();
|
|
1208 |
|
|
1209 |
r=TheFile.Open(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite);
|
|
1210 |
if (r==KErrNone)
|
|
1211 |
{
|
|
1212 |
TheBuffer.SetLength(aWriteLen);
|
|
1213 |
Mem::Fill(&TheBuffer[0],aWriteLen,'B');
|
|
1214 |
if ((r=TheFile.Write(TheBuffer))!=KErrCorrupt)
|
|
1215 |
{
|
|
1216 |
test.Printf(_L("Predicted error %d Actual error %d\n"),KErrCorrupt,r);
|
|
1217 |
Error(_L("Failed write"),r);
|
|
1218 |
}
|
|
1219 |
TheFile.Close();
|
|
1220 |
}
|
|
1221 |
|
|
1222 |
r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1223 |
test(r==KErrNone);
|
|
1224 |
pos=0;
|
|
1225 |
TPtr8 buffer2(pBuffer2->Des());
|
|
1226 |
r=TheDisk.Read(pos,buffer2);
|
|
1227 |
test(r==KErrNone);
|
|
1228 |
|
|
1229 |
//-- this bit is dodgy. The buffers may differ because of volume finalisation stuff
|
|
1230 |
//-- FAT[1] and FSInfo sectors
|
|
1231 |
test(buffer1==buffer2);
|
|
1232 |
TheDisk.Close();
|
|
1233 |
|
|
1234 |
r=TheFs.SetModified(_L("\\CORRUPT1.TMP"),saveTime);
|
|
1235 |
test(r==KErrNone || r==KErrCorrupt);
|
|
1236 |
r=TheFs.Entry(_L("\\CORRUPT1.TMP"),TheEntry);
|
|
1237 |
test(r==KErrNone || r==KErrCorrupt);
|
|
1238 |
}
|
|
1239 |
|
|
1240 |
static void TestBounds()
|
|
1241 |
//
|
|
1242 |
// Test reading/writing past the end of a drive
|
|
1243 |
//
|
|
1244 |
{
|
|
1245 |
test.Next(_L("Test read/write past boundaries"));
|
|
1246 |
test(TheFs.Volume(TheVolumeInfo,CurrentDrive())==KErrNone);
|
|
1247 |
TInt64 size=TheVolumeInfo.iSize;
|
|
1248 |
TInt r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1249 |
test(r==KErrNone);
|
|
1250 |
TPtr8 buffer(pBuffer1->Des());
|
|
1251 |
TInt64 pos=size - 2*buffer.MaxLength();
|
|
1252 |
TInt inc=buffer.MaxLength();
|
|
1253 |
FOREVER
|
|
1254 |
{
|
|
1255 |
TPtr8 tempbuf((TUint8*)pBuffer1->Ptr(),inc);
|
|
1256 |
r=TheDisk.Read(pos,tempbuf);
|
|
1257 |
test.Printf(_L("Read %08X:%08X len %d r %d\r"), I64HIGH(pos),I64LOW(pos), inc, r);
|
|
1258 |
test(r==KErrNone || r==KErrCorrupt);
|
|
1259 |
if (r==KErrNone)
|
|
1260 |
pos+=inc;
|
|
1261 |
else
|
|
1262 |
{
|
|
1263 |
inc>>=1;
|
|
1264 |
if (inc==0)
|
|
1265 |
break;
|
|
1266 |
}
|
|
1267 |
test(pos<2*size);
|
|
1268 |
}
|
|
1269 |
|
|
1270 |
TInt64 maxcalc= TInt64(gTotalSectors) * TInt64(TheBootSector.BytesPerSector());
|
|
1271 |
|
|
1272 |
test.Printf(_L("\n"));
|
|
1273 |
test.Printf(_L("Volume size = %ld\n"), size);
|
|
1274 |
test.Printf(_L("RawDiskSize = %ld\n"), maxcalc);
|
|
1275 |
test.Printf(_L("MaxReadPos = %ld\n"), pos);
|
|
1276 |
|
|
1277 |
TInt64 maxpos = pos;
|
|
1278 |
|
|
1279 |
// check that the calculated raw size of the disk is equal to the MaxReadPos that
|
|
1280 |
// has just been discovered by trial and error
|
|
1281 |
test(maxcalc == maxpos);
|
|
1282 |
|
|
1283 |
for (TInt64 bsize = 1; bsize < 8; bsize++)
|
|
1284 |
{
|
|
1285 |
test.Printf(_L("\n"));
|
|
1286 |
test.Printf(_L("Buffer size %d\n"), bsize);
|
|
1287 |
for (TInt64 bpos = MAKE_TINT64(0, 0x1000); bpos < MAKE_TINT64(0x3FFFFFFF,0); bpos<<=1)
|
|
1288 |
{
|
|
1289 |
TInt64 endPos = (bpos + 1);
|
|
1290 |
for (TInt64 lpos = bpos - bsize; lpos <= endPos; lpos++)
|
|
1291 |
{
|
|
1292 |
TPtr8 temp((TUint8*) (pBuffer1->Ptr()), (TInt) bsize);
|
|
1293 |
TInt expect = (lpos+bsize-1 < maxpos ? KErrNone : KErrCorrupt);
|
|
1294 |
r=TheDisk.Read(lpos, temp);
|
|
1295 |
RDebug::Print(_L("Read %08X:%08X result %d \r"), I64HIGH(lpos), I64LOW(lpos), r);
|
|
1296 |
test(r==expect);
|
|
1297 |
}
|
|
1298 |
}
|
|
1299 |
}
|
|
1300 |
|
|
1301 |
RDebug::Print(_L("\n"));
|
|
1302 |
|
|
1303 |
TestReadWrite(0L,0,0);
|
|
1304 |
TestReadWrite(0L,1,0);
|
|
1305 |
TestReadWrite(pos-1,1,0);
|
|
1306 |
TestReadWrite(pos-0x100,0x100,0);
|
|
1307 |
TestReadWrite(pos-1,2,KErrCorrupt);
|
|
1308 |
TestReadWrite(pos-0x100,0x101,KErrCorrupt);
|
|
1309 |
TestReadWrite(pos-0xff,0x100,KErrCorrupt);
|
|
1310 |
TestReadWrite(pos,0,0);
|
|
1311 |
TestReadWrite(pos,1,KErrCorrupt);
|
|
1312 |
|
|
1313 |
TestReadWrite(pos-16384,16384,0);
|
|
1314 |
TestReadWrite(pos-16384,16385,KErrCorrupt);
|
|
1315 |
|
|
1316 |
TInt errVal=(pos>32768+0x100) ? KErrNone : KErrCorrupt;
|
|
1317 |
TestReadWrite(32768L,0x100,errVal);
|
|
1318 |
errVal=(pos>32768+0x101) ? KErrNone : KErrCorrupt;
|
|
1319 |
TestReadWrite(32768L,0x101,errVal);
|
|
1320 |
errVal=(pos>32768+0x1ff) ? KErrNone : KErrCorrupt;
|
|
1321 |
TestReadWrite(32768L,0xff,errVal);
|
|
1322 |
errVal=(pos>65000+0x100) ? KErrNone : KErrCorrupt;
|
|
1323 |
TestReadWrite(65000L,0x100,errVal);
|
|
1324 |
|
|
1325 |
errVal=(pos>0x2000000+1) ? KErrNone : KErrCorrupt;
|
|
1326 |
TestReadWrite(0x2000000L,1,errVal);
|
|
1327 |
|
|
1328 |
TestRwWord(0L,0);
|
|
1329 |
TestRwWord(1L,0);
|
|
1330 |
TestRwWord(pos-2,0);
|
|
1331 |
TestRwWord(pos-1,KErrCorrupt);
|
|
1332 |
TestRwWord(pos,KErrCorrupt);
|
|
1333 |
TestRwWord(pos+1,KErrCorrupt);
|
|
1334 |
|
|
1335 |
TestRwDWord(0L,0);
|
|
1336 |
TestRwDWord(1L,0);
|
|
1337 |
TestRwDWord(2L,0);
|
|
1338 |
TestRwDWord(3L,0);
|
|
1339 |
TestRwDWord(pos-4,0);
|
|
1340 |
TestRwDWord(pos-3,KErrCorrupt);
|
|
1341 |
TestRwDWord(pos-2,KErrCorrupt);
|
|
1342 |
TestRwDWord(pos-1,KErrCorrupt);
|
|
1343 |
TestRwDWord(pos,KErrCorrupt);
|
|
1344 |
TestRwDWord(pos+1,KErrCorrupt);
|
|
1345 |
|
|
1346 |
TheDisk.Close();
|
|
1347 |
}
|
|
1348 |
|
|
1349 |
static void TestClusters()
|
|
1350 |
{
|
|
1351 |
test.Next(_L("Test corrupt start cluster"));
|
|
1352 |
// Initial Write Corrupt
|
|
1353 |
// Size Len Cluster
|
|
1354 |
TestDirEntry(1024, 513, 0);
|
|
1355 |
TestDirEntry( 512, 512, 0);
|
|
1356 |
TestDirEntry(1024, 513, 1);
|
|
1357 |
TestDirEntry( 512, 512, 1);
|
|
1358 |
TestDirEntry(1024, 513, 0xff0);
|
|
1359 |
|
|
1360 |
test.Printf(_L("Test corrupt chain\n"));
|
|
1361 |
TestFatEntry(1536,0);
|
|
1362 |
TestFatEntry(1536,1);
|
|
1363 |
|
|
1364 |
// TInt fatCacheSize=FatCacheSize();
|
|
1365 |
// TUint16 cluster16=(TUint16)(fatCacheSize/2);
|
|
1366 |
// TUint16 cluster12=(TUint16)((fatCacheSize/3)*2);
|
|
1367 |
// TestFatEntry(1536,cluster12);
|
|
1368 |
// TestFatEntry(1536,cluster16);
|
|
1369 |
TestFatEntry(1536,0xff0);
|
|
1370 |
// don't test when only one cluster for the file
|
|
1371 |
if(1536>gBytesPerCluster)
|
|
1372 |
TestFatEntry(1536,gEndOfChain);
|
|
1373 |
|
|
1374 |
TestLoopedFile();
|
|
1375 |
TestLoopedSubDir();
|
|
1376 |
}
|
|
1377 |
|
|
1378 |
|
|
1379 |
static void TestClusterAllocation()
|
|
1380 |
//
|
|
1381 |
// Test number of clusters allocated
|
|
1382 |
//
|
|
1383 |
{
|
|
1384 |
test.Next(_L("Test number of clusters allocated is correct"));
|
|
1385 |
|
|
1386 |
FormatPack();
|
|
1387 |
|
|
1388 |
RFile f;
|
|
1389 |
TInt r;
|
|
1390 |
|
|
1391 |
r=f.Replace(TheFs,_L("\\GOBLIN.TMP"),EFileRead|EFileWrite);
|
|
1392 |
test(r==KErrNone);
|
|
1393 |
f.SetSize(4*gBytesPerCluster); // 4 Clusters
|
|
1394 |
f.Close();
|
|
1395 |
|
|
1396 |
r=f.Replace(TheFs,_L("\\WIZARD.TMP"),EFileRead|EFileWrite);
|
|
1397 |
test(r==KErrNone);
|
|
1398 |
f.SetSize(5*gBytesPerCluster); // 5 Clusters
|
|
1399 |
f.Close();
|
|
1400 |
|
|
1401 |
r=f.Replace(TheFs,_L("\\TROLL.TMP"),EFileRead|EFileWrite);
|
|
1402 |
test(r==KErrNone);
|
|
1403 |
f.SetSize(3*gBytesPerCluster); // 3 Clusters
|
|
1404 |
f.Close();
|
|
1405 |
|
|
1406 |
r=f.Replace(TheFs,_L("\\GNOME.TMP"),EFileRead|EFileWrite);
|
|
1407 |
test(r==KErrNone);
|
|
1408 |
f.SetSize(10*gBytesPerCluster); // 10 Clusters
|
|
1409 |
f.Close();
|
|
1410 |
|
|
1411 |
r=f.Replace(TheFs,_L("\\CYCLOPS.TMP"),EFileRead|EFileWrite);
|
|
1412 |
test(r==KErrNone);
|
|
1413 |
f.SetSize(gBytesPerCluster); // 1 Cluster
|
|
1414 |
f.Close();
|
|
1415 |
|
|
1416 |
r=f.Replace(TheFs,_L("\\PIXIE.TMP"),EFileRead|EFileWrite);
|
|
1417 |
test(r==KErrNone);
|
|
1418 |
f.SetSize(gBytesPerCluster); // 1 Cluster
|
|
1419 |
f.Close();
|
|
1420 |
|
|
1421 |
r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1422 |
test(r==KErrNone);
|
|
1423 |
TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),TheBootSector.BytesPerSector());
|
|
1424 |
TInt pos = gRootDirStart;
|
|
1425 |
test(TheDisk.Read(pos,sectorBuf)==KErrNone);
|
|
1426 |
TheDisk.Close();
|
|
1427 |
|
|
1428 |
TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
|
|
1429 |
while (pE->IsVFatEntry()) // UNICODE 8.3 filenames are VFAT by definition
|
|
1430 |
pE++;
|
|
1431 |
|
|
1432 |
TInt cluster=pE->StartCluster();
|
|
1433 |
TBuf8<15> name=pE->Name();
|
|
1434 |
test(name==_L8("GOBLIN TMP"));
|
|
1435 |
|
|
1436 |
pE++;
|
|
1437 |
while (pE->IsVFatEntry())
|
|
1438 |
pE++;
|
|
1439 |
|
|
1440 |
test((pE->StartCluster()-cluster)==4);
|
|
1441 |
cluster=pE->StartCluster();
|
|
1442 |
name=pE->Name();
|
|
1443 |
test(name==_L8("WIZARD TMP"));
|
|
1444 |
|
|
1445 |
pE++;
|
|
1446 |
while (pE->IsVFatEntry())
|
|
1447 |
pE++;
|
|
1448 |
|
|
1449 |
test((pE->StartCluster()-cluster)==5);
|
|
1450 |
cluster=pE->StartCluster();
|
|
1451 |
name=pE->Name();
|
|
1452 |
test(name==_L8("TROLL TMP"));
|
|
1453 |
|
|
1454 |
pE++;
|
|
1455 |
while (pE->IsVFatEntry())
|
|
1456 |
pE++;
|
|
1457 |
|
|
1458 |
test((pE->StartCluster()-cluster)==3);
|
|
1459 |
cluster=pE->StartCluster();
|
|
1460 |
name=pE->Name();
|
|
1461 |
test(name==_L8("GNOME TMP"));
|
|
1462 |
|
|
1463 |
pE++;
|
|
1464 |
while (pE->IsVFatEntry())
|
|
1465 |
pE++;
|
|
1466 |
|
|
1467 |
test ((pE->StartCluster()-cluster)==10);
|
|
1468 |
cluster=pE->StartCluster();
|
|
1469 |
name=pE->Name();
|
|
1470 |
test(name==_L8("CYCLOPS TMP"));
|
|
1471 |
|
|
1472 |
pE++;
|
|
1473 |
while (pE->IsVFatEntry())
|
|
1474 |
pE++;
|
|
1475 |
|
|
1476 |
test((pE->StartCluster()-cluster)==1);
|
|
1477 |
name=pE->Name();
|
|
1478 |
test(name==_L8("PIXIE TMP"));
|
|
1479 |
|
|
1480 |
r=TheFs.Delete(_L("\\GOBLIN.TMP"));
|
|
1481 |
test(r==KErrNone);
|
|
1482 |
r=TheFs.Delete(_L("\\WIZARD.TMP"));
|
|
1483 |
test(r==KErrNone);
|
|
1484 |
r=TheFs.Delete(_L("\\TROLL.TMP"));
|
|
1485 |
test(r==KErrNone);
|
|
1486 |
r=TheFs.Delete(_L("\\GNOME.TMP"));
|
|
1487 |
test(r==KErrNone);
|
|
1488 |
r=TheFs.Delete(_L("\\CYCLOPS.TMP"));
|
|
1489 |
test(r==KErrNone);
|
|
1490 |
r=TheFs.Delete(_L("\\PIXIE.TMP"));
|
|
1491 |
test(r==KErrNone);
|
|
1492 |
|
|
1493 |
FormatPack();
|
|
1494 |
|
|
1495 |
}
|
|
1496 |
|
|
1497 |
|
|
1498 |
static void TestMakeDir(const TDesC& aName,TInt aNewClust,TInt aParentClust)
|
|
1499 |
//
|
|
1500 |
// Test make dir
|
|
1501 |
//
|
|
1502 |
{
|
|
1503 |
test.Printf(_L("Checking cluster %02d, parent %d: \"%S\"\n"), aNewClust, aParentClust, &aName);
|
|
1504 |
|
|
1505 |
TInt r=TheFs.MkDir(aName);
|
|
1506 |
test(r==KErrNone || r==KErrAlreadyExists);
|
|
1507 |
|
|
1508 |
TInt pos=ClusterToByte(aNewClust);
|
|
1509 |
TPtr8 sectorBuf((TUint8*)pBuffer1->Ptr(),gBytesPerCluster);
|
|
1510 |
|
|
1511 |
r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1512 |
if ((r=TheDisk.Read(pos,sectorBuf))!=KErrNone)
|
|
1513 |
Error(_L("Reading data"),r);
|
|
1514 |
TheDisk.Close();
|
|
1515 |
|
|
1516 |
TFatDirEntry* pE=(TFatDirEntry*)pBuffer1->Ptr();
|
|
1517 |
if (pE->Name()[0]!='.' || pE->Name()[1]!=' ')
|
|
1518 |
{
|
|
1519 |
while (pE->IsVFatEntry())
|
|
1520 |
pE++;
|
|
1521 |
if (pE->Name()[0]!='.' || pE->Name()[1]!=' ')
|
|
1522 |
Error(_L("Failed to find '.' entry"),KErrNone);
|
|
1523 |
}
|
|
1524 |
if (pE->StartCluster()!=aNewClust)
|
|
1525 |
Error(_L("Bad directory start cluster"),KErrNone);
|
|
1526 |
pE++;
|
|
1527 |
if (pE->Name()[0]!='.' || pE->Name()[1]!='.')
|
|
1528 |
Error(_L("Second entry is not '..'"),KErrNone);
|
|
1529 |
if (pE->StartCluster() != ((aParentClust==gRootCluster)?0:aParentClust))
|
|
1530 |
Error(_L("Start cluster of .. is not parent directory"),KErrNone);
|
|
1531 |
}
|
|
1532 |
|
|
1533 |
|
|
1534 |
|
|
1535 |
static void TestParentDir(TBool aUseVfat)
|
|
1536 |
{
|
|
1537 |
|
|
1538 |
test.Next(_L("TestParentDir()"));
|
|
1539 |
|
|
1540 |
TInt root = gRootCluster;
|
|
1541 |
TInt cl = gFirstDataCluster;
|
|
1542 |
TInt p1 = cl;
|
|
1543 |
|
|
1544 |
FormatPack();
|
|
1545 |
|
|
1546 |
TestMakeDir(_L("\\P1\\"), cl++, root);
|
|
1547 |
|
|
1548 |
|
|
1549 |
const TInt nDirEntries= gBytesPerCluster / KSizeOfFatDirEntry; //-- number of dir. entries to fill 1 cluster
|
|
1550 |
const TInt nFiles = aUseVfat ? nDirEntries/2 : nDirEntries; //-- number of 8.3 files to fill 1 cluster
|
|
1551 |
|
|
1552 |
cl++;
|
|
1553 |
for (TInt i=0;i<nFiles;i++)
|
|
1554 |
{
|
|
1555 |
CreateFatEntry(_L("\\P1\\"), aUseVfat);
|
|
1556 |
}
|
|
1557 |
|
|
1558 |
|
|
1559 |
TInt p1p2 = cl;
|
|
1560 |
if(aUseVfat)
|
|
1561 |
{
|
|
1562 |
TestMakeDir(_L("\\p1\\p2\\"), cl++, p1);
|
|
1563 |
TestMakeDir(_L("\\p1\\p21\\"), cl++, p1);
|
|
1564 |
TestMakeDir(_L("\\p1\\p2\\p3\\"), cl++, p1p2);
|
|
1565 |
TestMakeDir(_L("\\p1\\p2\\p33\\"), cl++, p1p2);
|
|
1566 |
TestMakeDir(_L("\\p1\\p2\\p34\\"), cl++, p1p2);
|
|
1567 |
TestMakeDir(_L("\\p1\\p2\\p35\\"), cl++, p1p2);
|
|
1568 |
TestMakeDir(_L("\\p1\\p2\\p36\\"), cl++, p1p2);
|
|
1569 |
TestMakeDir(_L("\\p1\\p2\\p37\\"), cl++, p1p2);
|
|
1570 |
TestMakeDir(_L("\\p1\\p2\\p38\\"), cl++, p1p2);
|
|
1571 |
}
|
|
1572 |
else
|
|
1573 |
{
|
|
1574 |
TestMakeDir(_L("\\P1\\P2\\"), cl++, p1);
|
|
1575 |
TestMakeDir(_L("\\P1\\P21\\"), cl++, p1);
|
|
1576 |
TestMakeDir(_L("\\P1\\P2\\P3\\"), cl++, p1p2);
|
|
1577 |
TestMakeDir(_L("\\P1\\P2\\P33\\"), cl++, p1p2);
|
|
1578 |
TestMakeDir(_L("\\P1\\P2\\P34\\"), cl++, p1p2);
|
|
1579 |
TestMakeDir(_L("\\P1\\P2\\P35\\"), cl++, p1p2);
|
|
1580 |
TestMakeDir(_L("\\P1\\P2\\P36\\"), cl++, p1p2);
|
|
1581 |
TestMakeDir(_L("\\P1\\P2\\P37\\"), cl++, p1p2);
|
|
1582 |
TestMakeDir(_L("\\P1\\P2\\P38\\"), cl++, p1p2);
|
|
1583 |
|
|
1584 |
TestMakeDir(_L("\\P1\\P2\\P39\\"), cl++, p1p2);
|
|
1585 |
TestMakeDir(_L("\\P1\\P2\\P40\\"), cl++, p1p2);
|
|
1586 |
TestMakeDir(_L("\\P1\\P2\\P41\\"), cl++, p1p2);
|
|
1587 |
TestMakeDir(_L("\\P1\\P2\\P42\\"), cl++, p1p2);
|
|
1588 |
TestMakeDir(_L("\\P1\\P2\\P43\\"), cl++, p1p2);
|
|
1589 |
TestMakeDir(_L("\\P1\\P2\\P44\\"), cl++, p1p2);
|
|
1590 |
TestMakeDir(_L("\\P1\\P2\\P45\\"), cl++, p1p2);
|
|
1591 |
}
|
|
1592 |
|
|
1593 |
// if sectors/cluster == 1 then the directory \p1\p2\ will now have to
|
|
1594 |
// allocate another cluster
|
|
1595 |
if(TheBootSector.SectorsPerCluster()==1)
|
|
1596 |
++cl;
|
|
1597 |
if(aUseVfat)
|
|
1598 |
{
|
|
1599 |
TestMakeDir(_L("\\p1\\p2\\p310\\"), cl++, p1p2);
|
|
1600 |
TestMakeDir(_L("\\p1\\p2\\p311\\"), cl++, p1p2);
|
|
1601 |
TestMakeDir(_L("\\p1\\p2\\p312\\"), cl++, p1p2);
|
|
1602 |
TestMakeDir(_L("\\p1\\p2\\p313\\"), cl++, p1p2);
|
|
1603 |
TestMakeDir(_L("\\p1\\p2\\p314\\"), cl++, p1p2);
|
|
1604 |
TestMakeDir(_L("\\p1\\p2\\p315\\"), cl++, p1p2);
|
|
1605 |
TestMakeDir(_L("\\p1\\p2\\p316\\"), cl++, p1p2);
|
|
1606 |
TestMakeDir(_L("\\p1\\p2\\p317\\"), cl++, p1p2);
|
|
1607 |
}
|
|
1608 |
else
|
|
1609 |
{
|
|
1610 |
TestMakeDir(_L("\\P1\\P2\\P310\\"), cl++, p1p2);
|
|
1611 |
TestMakeDir(_L("\\P1\\P2\\P311\\"), cl++, p1p2);
|
|
1612 |
TestMakeDir(_L("\\P1\\P2\\P312\\"), cl++, p1p2);
|
|
1613 |
TestMakeDir(_L("\\P1\\P2\\P313\\"), cl++, p1p2);
|
|
1614 |
TestMakeDir(_L("\\P1\\P2\\P314\\"), cl++, p1p2);
|
|
1615 |
TestMakeDir(_L("\\P1\\P2\\P315\\"), cl++, p1p2);
|
|
1616 |
TestMakeDir(_L("\\P1\\P2\\P316\\"), cl++, p1p2);
|
|
1617 |
TestMakeDir(_L("\\P1\\P2\\P317\\"), cl++, p1p2);
|
|
1618 |
|
|
1619 |
TestMakeDir(_L("\\P1\\P2\\P318\\"), cl++, p1p2);
|
|
1620 |
TestMakeDir(_L("\\P1\\P2\\P319\\"), cl++, p1p2);
|
|
1621 |
TestMakeDir(_L("\\P1\\P2\\P320\\"), cl++, p1p2);
|
|
1622 |
TestMakeDir(_L("\\P1\\P2\\P321\\"), cl++, p1p2);
|
|
1623 |
TestMakeDir(_L("\\P1\\P2\\P322\\"), cl++, p1p2);
|
|
1624 |
TestMakeDir(_L("\\P1\\P2\\P323\\"), cl++, p1p2);
|
|
1625 |
TestMakeDir(_L("\\P1\\P2\\P324\\"), cl++, p1p2);
|
|
1626 |
TestMakeDir(_L("\\P1\\P2\\P325\\"), cl++, p1p2);
|
|
1627 |
}
|
|
1628 |
|
|
1629 |
// if sectors/cluster <= 2 then the directory \p1\p2\ will have to
|
|
1630 |
// allocate another cluster
|
|
1631 |
if(TheBootSector.SectorsPerCluster()<=2)
|
|
1632 |
++cl;
|
|
1633 |
TestMakeDir(_L("\\P1\\P2\\P330\\"), cl++, p1p2);
|
|
1634 |
TestMakeDir(_L("\\P11\\"), cl++, root);
|
|
1635 |
}
|
|
1636 |
|
|
1637 |
static const TInt KMaxFiles=5;
|
|
1638 |
|
|
1639 |
//
|
|
1640 |
// Test root dir size
|
|
1641 |
//
|
|
1642 |
static void TestRoot()
|
|
1643 |
{
|
|
1644 |
test.Next(_L("Test root dir size"));
|
|
1645 |
|
|
1646 |
if (gDiskType == EFat32)
|
|
1647 |
{
|
|
1648 |
test.Printf(_L("Not possible on FAT32 filesystem\n"));
|
|
1649 |
return;
|
|
1650 |
}
|
|
1651 |
|
|
1652 |
FormatPack();
|
|
1653 |
TInt rootEntries=TheBootSector.RootDirEntries();
|
|
1654 |
test.Printf(_L("Total root entries allowed = %d\n"),rootEntries);
|
|
1655 |
TFileName fileName[KMaxFiles]; // KMaxFiles=5 in this test
|
|
1656 |
TFileName tempName;
|
|
1657 |
TInt numberOfEntries=rootEntries;
|
|
1658 |
TInt r;
|
|
1659 |
RFile f;
|
|
1660 |
|
|
1661 |
//-- generate 8.3 FAT entries, temp files created in upper-case, otherwise it will be 2 vFAT entries
|
|
1662 |
while(numberOfEntries--)
|
|
1663 |
{
|
|
1664 |
if (numberOfEntries<KMaxFiles)
|
|
1665 |
CreateFatEntry(_L("\\"), EFalse, &fileName[numberOfEntries]);
|
|
1666 |
else
|
|
1667 |
CreateFatEntry(_L("\\"), EFalse);
|
|
1668 |
|
|
1669 |
}
|
|
1670 |
|
|
1671 |
r = f.Create(TheFs, _L("\\123456.78"), EFileRead|EFileWrite);
|
|
1672 |
test(r==KErrDirFull);
|
|
1673 |
f.Close();
|
|
1674 |
|
|
1675 |
|
|
1676 |
TInt i=0;
|
|
1677 |
for (i=0;i<KMaxFiles;i++)
|
|
1678 |
{
|
|
1679 |
r=TheFs.Delete(fileName[i]);
|
|
1680 |
test(r==KErrNone);
|
|
1681 |
}
|
|
1682 |
|
|
1683 |
r=TheFs.SetSessionPath(_L("\\"));
|
|
1684 |
test(r==KErrNone);
|
|
1685 |
|
|
1686 |
TInt nameLength=(KMaxFiles-1)*13; // -1 for zero terminator
|
|
1687 |
CreateLongName(tempName,gSeed,nameLength*2);
|
|
1688 |
r=f.Create(TheFs,tempName,0); // Needs 9 free entries - there are only 5 available
|
|
1689 |
test(r==KErrDirFull);
|
|
1690 |
tempName.SetLength(nameLength+1);
|
|
1691 |
r=f.Create(TheFs,tempName,0); // Needs 6 free entries - there are only 5 available
|
|
1692 |
test(r==KErrDirFull);
|
|
1693 |
tempName.SetLength(nameLength);
|
|
1694 |
r=f.Create(TheFs,tempName,0); // Needs 5 free entries - there are 5 available
|
|
1695 |
test(r==KErrNone);
|
|
1696 |
f.Close();
|
|
1697 |
|
|
1698 |
#if 0 // This is the old test that assumed UNICODE builds
|
|
1699 |
// which created VFAT entries even for uppercase 8.3 file names
|
|
1700 |
TInt i=0;
|
|
1701 |
for (i=0;i<KMaxFiles-2;i++)
|
|
1702 |
{
|
|
1703 |
r=TheFs.Delete(fileName[i]); // UNICODE build - free 6 entries (delete 3 files)
|
|
1704 |
test(r==KErrNone);
|
|
1705 |
}
|
|
1706 |
|
|
1707 |
r=TheFs.SetSessionPath(_L("\\"));
|
|
1708 |
test(r==KErrNone);
|
|
1709 |
|
|
1710 |
TInt vFatUnitNameSize=13;
|
|
1711 |
TInt nameLength=(KMaxFiles-1)*vFatUnitNameSize-1; //
|
|
1712 |
CreateLongName(tempName,gSeed,nameLength*2);
|
|
1713 |
r=f.Create(TheFs,tempName,0); // Needs 9 free entries
|
|
1714 |
test(r==KErrDirFull);
|
|
1715 |
|
|
1716 |
nameLength=(KMaxFiles)*vFatUnitNameSize;
|
|
1717 |
tempName.SetLength(nameLength+1);
|
|
1718 |
r=f.Create(TheFs,tempName,0); // Needs 7 free entries
|
|
1719 |
test(r==KErrDirFull);
|
|
1720 |
tempName.SetLength(nameLength);
|
|
1721 |
r=f.Create(TheFs,tempName,0); // Needs 6 free entries
|
|
1722 |
test(r==KErrNone);
|
|
1723 |
f.Close();
|
|
1724 |
#endif
|
|
1725 |
|
|
1726 |
TheFs.Delete(tempName);
|
|
1727 |
tempName.SetLength(nameLength-7);
|
|
1728 |
r=f.Create(TheFs,tempName,0);
|
|
1729 |
test(r==KErrNone);
|
|
1730 |
f.Close();
|
|
1731 |
|
|
1732 |
r=f.Create(TheFs,_L("ASDF"),0);
|
|
1733 |
test(r==KErrDirFull);
|
|
1734 |
|
|
1735 |
TheFs.Delete(tempName);
|
|
1736 |
tempName.SetLength(nameLength-15);
|
|
1737 |
r=f.Create(TheFs,tempName,0);
|
|
1738 |
test(r==KErrNone);
|
|
1739 |
f.Close();
|
|
1740 |
|
|
1741 |
tempName=_L("testname");
|
|
1742 |
r=f.Create(TheFs,tempName,0);
|
|
1743 |
test(r==KErrDirFull);
|
|
1744 |
tempName.UpperCase();
|
|
1745 |
r=f.Create(TheFs,tempName,0);
|
|
1746 |
test(r==KErrNone);
|
|
1747 |
f.Close();
|
|
1748 |
|
|
1749 |
|
|
1750 |
r=TheFs.SetSessionPath(gSessionPath);
|
|
1751 |
test(r==KErrNone);
|
|
1752 |
}
|
|
1753 |
|
|
1754 |
static void TestVolumeSize()
|
|
1755 |
//
|
|
1756 |
// Test the volume size is zero when empty
|
|
1757 |
//
|
|
1758 |
{
|
|
1759 |
test.Next(_L("Test the volume size"));
|
|
1760 |
FormatPack();
|
|
1761 |
|
|
1762 |
TVolumeInfo volInfo;
|
|
1763 |
TInt r=TheFs.Volume(volInfo);
|
|
1764 |
test(r==KErrNone);
|
|
1765 |
TInt64 calcsize = MAKE_TINT64(0, gClusterCount)*gBytesPerCluster;
|
|
1766 |
if (volInfo.iSize > calcsize)
|
|
1767 |
{
|
|
1768 |
test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
|
|
1769 |
test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
|
|
1770 |
test.Printf(_L("calculated = %ld\n"), calcsize);
|
|
1771 |
TInt diff = I64LOW(volInfo.iSize-calcsize);
|
|
1772 |
test.Printf(_L("difference = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
|
|
1773 |
test(0);
|
|
1774 |
}
|
|
1775 |
if (gDiskType == EFat32)
|
|
1776 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1777 |
if (volInfo.iSize != volInfo.iFree)
|
|
1778 |
{
|
|
1779 |
test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
|
|
1780 |
test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
|
|
1781 |
TInt diff = I64LOW(volInfo.iSize-volInfo.iFree);
|
|
1782 |
test.Printf(_L("difference = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
|
|
1783 |
DumpData();
|
|
1784 |
DumpFat();
|
|
1785 |
test(0);
|
|
1786 |
}
|
|
1787 |
|
|
1788 |
RFile f[KMaxFiles];
|
|
1789 |
TFileName fileName;
|
|
1790 |
TInt i=0;
|
|
1791 |
for (i=0;i<KMaxFiles;i++)
|
|
1792 |
{
|
|
1793 |
fileName=_L("\\File");
|
|
1794 |
fileName.AppendNum(i);
|
|
1795 |
r=f[i].Create(TheFs,fileName,0);
|
|
1796 |
test(r==KErrNone);
|
|
1797 |
}
|
|
1798 |
|
|
1799 |
TInt maxTotalSize=1048576;
|
|
1800 |
TInt maxFileSize=maxTotalSize/KMaxFiles;
|
|
1801 |
TInt maxIterations=20;
|
|
1802 |
|
|
1803 |
while(maxIterations--)
|
|
1804 |
{
|
|
1805 |
for (i=0;i<KMaxFiles;i++)
|
|
1806 |
{
|
|
1807 |
TInt randSize=Math::Rand(gSeed)%maxFileSize;
|
|
1808 |
r=f[i].SetSize(randSize);
|
|
1809 |
test(r==KErrNone);
|
|
1810 |
}
|
|
1811 |
test.Printf(_L("Countdown .. %d \r"),maxIterations);
|
|
1812 |
}
|
|
1813 |
|
|
1814 |
test.Printf(_L("\n"));
|
|
1815 |
|
|
1816 |
TInt totalSize=0;
|
|
1817 |
|
|
1818 |
for (i=0;i<KMaxFiles;i++)
|
|
1819 |
{
|
|
1820 |
TInt size=0;
|
|
1821 |
r=f[i].Size(size);
|
|
1822 |
test(r==KErrNone);
|
|
1823 |
totalSize+=((size+gBytesPerCluster-1)/gBytesPerCluster)*gBytesPerCluster;
|
|
1824 |
}
|
|
1825 |
|
|
1826 |
r=TheFs.Volume(volInfo);
|
|
1827 |
test(r==KErrNone);
|
|
1828 |
if (gDiskType == EFat32)
|
|
1829 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1830 |
if (volInfo.iSize-volInfo.iFree!=totalSize)
|
|
1831 |
{
|
|
1832 |
test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
|
|
1833 |
test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
|
|
1834 |
test.Printf(_L("totalSize = %ld\n"), totalSize);
|
|
1835 |
TInt diff = I64LOW(volInfo.iSize-volInfo.iFree) - totalSize;
|
|
1836 |
test.Printf(_L("difference = %d (%d clusters)\n"), diff, diff/gBytesPerCluster);
|
|
1837 |
}
|
|
1838 |
test(volInfo.iSize-volInfo.iFree==totalSize);
|
|
1839 |
|
|
1840 |
for (i=0;i<KMaxFiles;i++)
|
|
1841 |
f[i].Close();
|
|
1842 |
|
|
1843 |
for (i=0;i<KMaxFiles;i++)
|
|
1844 |
{
|
|
1845 |
fileName=_L("\\File");
|
|
1846 |
fileName.AppendNum(i);
|
|
1847 |
r=TheFs.Delete(fileName);
|
|
1848 |
test(r==KErrNone);
|
|
1849 |
}
|
|
1850 |
|
|
1851 |
r=TheFs.Volume(volInfo);
|
|
1852 |
if (gDiskType == EFat32)
|
|
1853 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1854 |
test(r==KErrNone);
|
|
1855 |
test(volInfo.iSize-volInfo.iFree==0);
|
|
1856 |
|
|
1857 |
MakeDir(gSessionPath);
|
|
1858 |
|
|
1859 |
TInt entries=(gBytesPerCluster/KSizeOfFatDirEntry)*5-2;
|
|
1860 |
entries = ThrottleDirEntries(entries, 2);
|
|
1861 |
|
|
1862 |
TInt clusters = ((entries * KSizeOfFatDirEntry) + gBytesPerCluster-1) / gBytesPerCluster;
|
|
1863 |
|
|
1864 |
//-- create "entries" FAT dir. entries by creating 8.3 files in upper case
|
|
1865 |
while(entries--)
|
|
1866 |
{
|
|
1867 |
CreateFatEntry(gSessionPath, EFalse);
|
|
1868 |
}
|
|
1869 |
|
|
1870 |
|
|
1871 |
r=TheFs.Volume(volInfo);
|
|
1872 |
test(r==KErrNone);
|
|
1873 |
if (gDiskType == EFat32)
|
|
1874 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1875 |
test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
|
|
1876 |
test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
|
|
1877 |
if (volInfo.iSize-volInfo.iFree!=clusters*gBytesPerCluster)
|
|
1878 |
{
|
|
1879 |
DumpFat();
|
|
1880 |
DumpData(1, 200);
|
|
1881 |
}
|
|
1882 |
test(volInfo.iSize-volInfo.iFree==clusters*gBytesPerCluster);
|
|
1883 |
|
|
1884 |
//-- create 1 FAT dir. entry
|
|
1885 |
CreateFatEntry(gSessionPath, EFalse);
|
|
1886 |
|
|
1887 |
r=TheFs.Volume(volInfo);
|
|
1888 |
test(r==KErrNone);
|
|
1889 |
if (gDiskType == EFat32)
|
|
1890 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1891 |
test.Printf(_L("volInfo.iSize = %ld\n"), volInfo.iSize);
|
|
1892 |
test.Printf(_L("volInfo.iFree = %ld\n"), volInfo.iFree);
|
|
1893 |
if (volInfo.iSize-volInfo.iFree!=(clusters+1)*gBytesPerCluster)
|
|
1894 |
{
|
|
1895 |
DumpFat();
|
|
1896 |
DumpData(1, 200);
|
|
1897 |
}
|
|
1898 |
test(volInfo.iSize-volInfo.iFree==(clusters+1)*gBytesPerCluster);
|
|
1899 |
|
|
1900 |
CFileMan* fMan=CFileMan::NewL(TheFs);
|
|
1901 |
r=fMan->RmDir(gSessionPath);
|
|
1902 |
test(r==KErrNone);
|
|
1903 |
delete fMan;
|
|
1904 |
r=TheFs.Volume(volInfo);
|
|
1905 |
test(r==KErrNone);
|
|
1906 |
if (gDiskType == EFat32)
|
|
1907 |
volInfo.iSize -= gBytesPerCluster; // root dir is part of the 'size'
|
|
1908 |
if (volInfo.iSize-volInfo.iFree!=0)
|
|
1909 |
{
|
|
1910 |
DumpFat();
|
|
1911 |
DumpData(1, 200);
|
|
1912 |
}
|
|
1913 |
test(volInfo.iSize-volInfo.iFree==0);
|
|
1914 |
}
|
|
1915 |
|
|
1916 |
|
|
1917 |
//
|
|
1918 |
// Writes a standard dos entry to the disk and checks that this can be read
|
|
1919 |
// (in Unicode build)
|
|
1920 |
//
|
|
1921 |
static void TestUnicodeEntry()
|
|
1922 |
{
|
|
1923 |
test.Next(_L("Test Unicode entry"));
|
|
1924 |
|
|
1925 |
const TInt KDirEntrySize=32;
|
|
1926 |
|
|
1927 |
FormatPack();
|
|
1928 |
DoReadBootSector(TheBootSector);
|
|
1929 |
TInt pos=gRootDirStart;
|
|
1930 |
|
|
1931 |
TBuf8<KDirEntrySize> buffer;
|
|
1932 |
buffer.SetLength(KDirEntrySize);
|
|
1933 |
buffer.FillZ();
|
|
1934 |
buffer.Replace(0,11,_L8("TEST1 "));
|
|
1935 |
|
|
1936 |
TInt r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1937 |
test(r==KErrNone);
|
|
1938 |
r=TheDisk.Write(pos,buffer);
|
|
1939 |
test(r==KErrNone);
|
|
1940 |
TheDisk.Close();
|
|
1941 |
|
|
1942 |
r=TheDir.Open(TheFs,_L("\\"),KEntryAttMaskSupported);
|
|
1943 |
test(r==KErrNone);
|
|
1944 |
r=TheDir.Read(TheEntry);
|
|
1945 |
test(r==KErrNone);
|
|
1946 |
test(TheEntry.iName==_L("TEST1"));
|
|
1947 |
r=TheDir.Read(TheEntry);
|
|
1948 |
test(r==KErrEof);
|
|
1949 |
TheDir.Close();
|
|
1950 |
|
|
1951 |
r=TheFs.SetSessionPath(_L("\\"));
|
|
1952 |
test(r==KErrNone);
|
|
1953 |
TEntry e;
|
|
1954 |
r=TheFs.Entry(_L("TEST1"),e);
|
|
1955 |
if(e.iName!=_L("TEST1"))
|
|
1956 |
{
|
|
1957 |
test.Printf(_L("e.iName = %S\n"),&e.iName);
|
|
1958 |
test(EFalse);
|
|
1959 |
}
|
|
1960 |
}
|
|
1961 |
|
|
1962 |
static TUint32 GetValue(const TPtrC8& aData, TInt aOffset, TInt aLength)
|
|
1963 |
{
|
|
1964 |
TUint32 val = 0;
|
|
1965 |
while (aLength-- > 0)
|
|
1966 |
val = val * 256 + aData[aOffset+aLength];
|
|
1967 |
return val;
|
|
1968 |
}
|
|
1969 |
|
|
1970 |
static void TestDiskIntegrity(TBool aTestOnly=EFalse)
|
|
1971 |
//
|
|
1972 |
// Does 'sanity checking' on the BPB and other areas
|
|
1973 |
//
|
|
1974 |
{
|
|
1975 |
if (!aTestOnly)
|
|
1976 |
test.Next(_L("Test disk boot area integrity"));
|
|
1977 |
TInt seclen = TheBootSector.BytesPerSector();
|
|
1978 |
HBufC8 *bootp = HBufC8::NewL(seclen);
|
|
1979 |
TPtr8 boot((TUint8*)bootp, seclen);
|
|
1980 |
HBufC8 *backp = HBufC8::NewL(seclen);
|
|
1981 |
TPtr8 back((TUint8*)backp, seclen);
|
|
1982 |
HBufC8 *infop = HBufC8::NewL(seclen);
|
|
1983 |
TPtr8 info((TUint8*)bootp, seclen);
|
|
1984 |
TInt r=TheDisk.Open(TheFs,CurrentDrive());
|
|
1985 |
if (r != KErrNone)
|
|
1986 |
test.Printf(_L("Error %d opening on %C"), r, (TUint)gDriveToTest);
|
|
1987 |
test(r==KErrNone);
|
|
1988 |
r=TheDisk.Read(0, boot);
|
|
1989 |
test(r==KErrNone);
|
|
1990 |
TUint32 val = GetValue(boot, 510, 2);
|
|
1991 |
RDebug::Print(_L("BPB magic number = 0x%X\n"), val);
|
|
1992 |
test(aTestOnly || val == 0xAA55);
|
|
1993 |
switch (boot[0])
|
|
1994 |
{
|
|
1995 |
case 0xEB:
|
|
1996 |
RDebug::Print(_L("Jump %02X 0x%02X\n"), boot[0], boot[1]);
|
|
1997 |
test(aTestOnly || boot[2] == 0x90);
|
|
1998 |
break;
|
|
1999 |
case 0xE9:
|
|
2000 |
RDebug::Print(_L("Jump %02X 0x%02X%02X\n"), boot[0], boot[2], boot[1]);
|
|
2001 |
break;
|
|
2002 |
default:
|
|
2003 |
RDebug::Print(_L("Invalid boot start: %02X %02X %02X\n"), boot[0], boot[1], boot[2]);
|
|
2004 |
test(aTestOnly);
|
|
2005 |
}
|
|
2006 |
switch (gDiskType)
|
|
2007 |
{
|
|
2008 |
case EFat12:
|
|
2009 |
test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
|
|
2010 |
test.Printf(_L("BPB sector OK\n"));
|
|
2011 |
break;
|
|
2012 |
case EFat16:
|
|
2013 |
test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
|
|
2014 |
test.Printf(_L("BPB sector OK\n"));
|
|
2015 |
break;
|
|
2016 |
default:
|
|
2017 |
test(aTestOnly || TheBootSector.ReservedSectors() >= 1);
|
|
2018 |
test(aTestOnly || TheBootSector.ReservedSectors() > TheBootSector.BkBootRecSector());
|
|
2019 |
test(aTestOnly || TheBootSector.ReservedSectors() > TheBootSector.FSInfoSectorNum());
|
|
2020 |
test.Printf(_L("BPB sector OK\n"));
|
|
2021 |
if (TheBootSector.BkBootRecSector() > 0)
|
|
2022 |
{
|
|
2023 |
r=TheDisk.Read(TheBootSector.BkBootRecSector()*seclen, back);
|
|
2024 |
test(aTestOnly || r==KErrNone);
|
|
2025 |
if (boot != back)
|
|
2026 |
{
|
|
2027 |
RDebug::Print(_L("Boot sector != backup\n"));
|
|
2028 |
RDebug::Print(_L("Sector 0: Boot sector\n"));
|
|
2029 |
DumpHex(boot.Ptr(), seclen);
|
|
2030 |
RDebug::Print(_L("Sector %d: Backup sector\n"), TheBootSector.BkBootRecSector());
|
|
2031 |
DumpHex(back.Ptr(), seclen);
|
|
2032 |
test(aTestOnly);
|
|
2033 |
}
|
|
2034 |
test.Printf(_L("Backup BPB sector OK\n"));
|
|
2035 |
}
|
|
2036 |
else
|
|
2037 |
test.Printf(_L("Backup BPB not present\n"));
|
|
2038 |
if (TheBootSector.FSInfoSectorNum() > 0)
|
|
2039 |
{
|
|
2040 |
r=TheDisk.Read(TheBootSector.FSInfoSectorNum()*seclen, info);
|
|
2041 |
test(aTestOnly || r==KErrNone);
|
|
2042 |
// Test the 'magic numbers' (signatures) as specified
|
|
2043 |
val = GetValue(info, 0, 4);
|
|
2044 |
RDebug::Print(_L("FSI signature 1 = 0x%X\n"), val);
|
|
2045 |
test(aTestOnly || val == 0x41615252);
|
|
2046 |
val = GetValue(info, 484, 4);
|
|
2047 |
RDebug::Print(_L("FSI signature 2 = 0x%X\n"), val);
|
|
2048 |
test(aTestOnly || val == 0x61417272);
|
|
2049 |
val = GetValue(info, 508, 4);
|
|
2050 |
RDebug::Print(_L("FSI magic number = 0x%X\n"), val);
|
|
2051 |
test(aTestOnly || val == 0xAA550000);
|
|
2052 |
// Check the last known free count and the next free cluster value. If
|
|
2053 |
// they are not calculated they should be 0xFFFFFFFF, otherwise must be
|
|
2054 |
// less than the number of clusters.
|
|
2055 |
val = GetValue(info, 488, 4);
|
|
2056 |
RDebug::Print(_L("FSI last free # = 0x%X\n"), val);
|
|
2057 |
test(aTestOnly || val == 0xFFFFFFFF || val <= (TUint32)gClusterCount);
|
|
2058 |
val = GetValue(info, 492, 4);
|
|
2059 |
RDebug::Print(_L("FSI next free # = 0x%X\n"), val);
|
|
2060 |
test(aTestOnly || val == 0xFFFFFFFF || val < (TUint32)gClusterCount);
|
|
2061 |
test.Printf(_L("FSInfo sector OK\n"));
|
|
2062 |
}
|
|
2063 |
break;
|
|
2064 |
}
|
|
2065 |
TheDisk.Close();
|
|
2066 |
delete bootp;
|
|
2067 |
delete backp;
|
|
2068 |
delete infop;
|
|
2069 |
}
|
|
2070 |
|
|
2071 |
static void TestFATTableEntries()
|
|
2072 |
//
|
|
2073 |
// Test that reading/writing FAT table entries preserves the upper 4 bits of data.
|
|
2074 |
//
|
|
2075 |
{
|
|
2076 |
test.Next(_L("Test reading/writing FAT table entries"));
|
|
2077 |
FormatPack();
|
|
2078 |
|
|
2079 |
TUint32 buf[16];
|
|
2080 |
TInt i=0;
|
|
2081 |
TInt r=KErrNone;
|
|
2082 |
|
|
2083 |
for (i=0; i <=7; i++)
|
|
2084 |
{
|
|
2085 |
buf[i] = GetFatEntry(i);
|
|
2086 |
}
|
|
2087 |
|
|
2088 |
test.Printf(_L("First 8 FAT Entries before signature: \n"));
|
|
2089 |
test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
|
|
2090 |
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
|
2091 |
|
|
2092 |
for (i=0; i <=7; i++)
|
|
2093 |
{
|
|
2094 |
MarkFatEntry(i);
|
|
2095 |
}
|
|
2096 |
|
|
2097 |
for (i=0; i <=7; i++)
|
|
2098 |
{
|
|
2099 |
buf[i] = GetFatEntry(i);
|
|
2100 |
}
|
|
2101 |
|
|
2102 |
test.Printf(_L("First 8 FAT Entries after signature: \n"));
|
|
2103 |
test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
|
|
2104 |
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
|
2105 |
|
|
2106 |
|
|
2107 |
test(TheFile.Create(TheFs,_L("\\CORRUPT1.TMP"),EFileRead|EFileWrite)==KErrNone);
|
|
2108 |
|
|
2109 |
TheBuffer.SetLength(2048);
|
|
2110 |
Mem::Fill(&TheBuffer[0],2048,'X');
|
|
2111 |
|
|
2112 |
for(i=0; i<=20; i++)
|
|
2113 |
{
|
|
2114 |
r = TheFile.Write(TheBuffer);
|
|
2115 |
test(r==KErrNone);
|
|
2116 |
}
|
|
2117 |
|
|
2118 |
TheFile.Close();
|
|
2119 |
|
|
2120 |
for (i=8; i <=15; i++)
|
|
2121 |
{
|
|
2122 |
buf[i] = GetFatEntry(i-8);
|
|
2123 |
}
|
|
2124 |
|
|
2125 |
test.Printf(_L("First 8 FAT Entries after file write: \n"));
|
|
2126 |
test.Printf(_L("%08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x\n"),
|
|
2127 |
buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
|
|
2128 |
|
|
2129 |
for (i=0; i<=7; i++)
|
|
2130 |
{
|
|
2131 |
test((buf[i] & 0xF0000000) == (buf[i+8] & 0xF0000000));
|
|
2132 |
}
|
|
2133 |
|
|
2134 |
test.Printf(_L("Top 4 bits of first 8 FAT Entries have been preserved.\n"));
|
|
2135 |
}
|
|
2136 |
|
|
2137 |
|
|
2138 |
//-----------------------------------------------------------------------------
|
|
2139 |
/**
|
|
2140 |
Test that FAT[0] and FAT[1] just after formatting are compliant to FAT specs.
|
|
2141 |
So that this test step shall be called just after the volume formatted.
|
|
2142 |
*/
|
|
2143 |
static void TestFirst2FatEntries()
|
|
2144 |
{
|
|
2145 |
test.Next(_L("Test FAT[0] and FAT[1] after formatting"));
|
|
2146 |
|
|
2147 |
TInt nRes;
|
|
2148 |
TBuf8<8> fat1Buf; //-- buffer for FAT[0] & FAT[1] read from 1st FAT copy
|
|
2149 |
TBuf8<8> fatBufCurr;
|
|
2150 |
|
|
2151 |
//-- read first several FAT entries from FAT1
|
|
2152 |
const TUint32 posFat1Start = TheBootSector.FirstFatSector() * TheBootSector.BytesPerSector();
|
|
2153 |
const TUint32 fatSize = TheBootSector.TotalFatSectors() * TheBootSector.BytesPerSector();
|
|
2154 |
const TInt numFATs = TheBootSector.NumberOfFats();
|
|
2155 |
|
|
2156 |
|
|
2157 |
nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start, 8, fat1Buf);
|
|
2158 |
test(nRes==KErrNone);
|
|
2159 |
|
|
2160 |
switch(gDiskType)
|
|
2161 |
{
|
|
2162 |
//----------- FAT12 ---------------------
|
|
2163 |
case EFat12:
|
|
2164 |
{
|
|
2165 |
fat1Buf.SetLength(3); //-- FAT12 entry occupies 1.5 bytes
|
|
2166 |
test.Printf(_L("FAT12, first 2 entries: %x %x %x\n"), fat1Buf[0], fat1Buf[1], fat1Buf[2]);
|
|
2167 |
|
|
2168 |
test(fat1Buf[0]==0xF8 && fat1Buf[1]==0xFF && fat1Buf[2]==0xFF); //-- see FAT specs, these are first 2 entries
|
|
2169 |
|
|
2170 |
//-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
|
|
2171 |
for(TInt i=1; i<numFATs; ++i)
|
|
2172 |
{
|
|
2173 |
nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
|
|
2174 |
test(nRes==KErrNone);
|
|
2175 |
|
|
2176 |
fatBufCurr.SetLength(3);
|
|
2177 |
|
|
2178 |
if(fatBufCurr != fat1Buf)
|
|
2179 |
{
|
|
2180 |
test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
|
|
2181 |
test(0);
|
|
2182 |
}
|
|
2183 |
}
|
|
2184 |
|
|
2185 |
|
|
2186 |
}
|
|
2187 |
break;
|
|
2188 |
|
|
2189 |
//----------- FAT16 ---------------------
|
|
2190 |
case EFat16:
|
|
2191 |
{
|
|
2192 |
typedef TUint16 TFat16Entry;
|
|
2193 |
|
|
2194 |
fat1Buf.SetLength(2*sizeof(TFat16Entry));
|
|
2195 |
const TFat16Entry* pFat = (const TFat16Entry*)fat1Buf.Ptr();
|
|
2196 |
|
|
2197 |
const TFat16Entry fatEntry_0 = pFat[0]; //-- do not mask entries
|
|
2198 |
const TFat16Entry fatEntry_1 = pFat[1]; //-- do not mask entries
|
|
2199 |
|
|
2200 |
test.Printf(_L("FAT16[0]=0x%x, FAT16[1]=0x%x\n"), fatEntry_0, fatEntry_1);
|
|
2201 |
|
|
2202 |
test(fatEntry_0 == 0xFFF8); //-- see FAT specs
|
|
2203 |
test(fatEntry_1 == 0xFFFF); //-- the volume shall be clean just after the formatting. It can be 0x7FFF if a write to the volume occured.
|
|
2204 |
|
|
2205 |
//-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
|
|
2206 |
for(TInt i=1; i<numFATs; ++i)
|
|
2207 |
{
|
|
2208 |
nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
|
|
2209 |
test(nRes==KErrNone);
|
|
2210 |
|
|
2211 |
fatBufCurr.SetLength(2*sizeof(TFat16Entry));
|
|
2212 |
|
|
2213 |
if(fatBufCurr != fat1Buf)
|
|
2214 |
{
|
|
2215 |
test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
|
|
2216 |
test(0);
|
|
2217 |
}
|
|
2218 |
}
|
|
2219 |
|
|
2220 |
}
|
|
2221 |
break;
|
|
2222 |
|
|
2223 |
//----------- FAT32 ---------------------
|
|
2224 |
case EFat32:
|
|
2225 |
{
|
|
2226 |
typedef TUint32 TFat32Entry;
|
|
2227 |
|
|
2228 |
fat1Buf.SetLength(2*sizeof(TFat32Entry));
|
|
2229 |
const TFat32Entry* pFat = (const TFat32Entry*)fat1Buf.Ptr();
|
|
2230 |
|
|
2231 |
const TFat32Entry fatEntry_0 = pFat[0]; //-- do not mask entries
|
|
2232 |
const TFat32Entry fatEntry_1 = pFat[1]; //-- do not mask entries
|
|
2233 |
|
|
2234 |
test.Printf(_L("FAT32[0]=0x%x, FAT32[1]=0x%x\n"), fatEntry_0, fatEntry_1);
|
|
2235 |
|
|
2236 |
test(fatEntry_0 == 0x0FFFFFF8); //-- see FAT specs
|
|
2237 |
test(fatEntry_1 == 0x0FFFFFFF); //-- the volume shall be clean just after the formatting. It can be 0x07FFFFFF if a write to the volume occured.
|
|
2238 |
|
|
2239 |
//-- test that all copies of FAT have the same values in FAT[0] & FAT[1]
|
|
2240 |
for(TInt i=1; i<numFATs; ++i)
|
|
2241 |
{
|
|
2242 |
nRes = MediaRawRead(TheFs, CurrentDrive(), posFat1Start + i*fatSize, 8, fatBufCurr);
|
|
2243 |
test(nRes==KErrNone);
|
|
2244 |
|
|
2245 |
fatBufCurr.SetLength(2*sizeof(TFat32Entry));
|
|
2246 |
|
|
2247 |
if(fatBufCurr != fat1Buf)
|
|
2248 |
{
|
|
2249 |
test.Printf(_L("1st 2 FAT entries in FAT#%d are different from FAT1!\n"), i);
|
|
2250 |
test(0);
|
|
2251 |
}
|
|
2252 |
}
|
|
2253 |
}
|
|
2254 |
break;
|
|
2255 |
|
|
2256 |
default:
|
|
2257 |
test(0);
|
|
2258 |
break;
|
|
2259 |
|
|
2260 |
};//switch(gDiskType)
|
|
2261 |
|
|
2262 |
|
|
2263 |
|
|
2264 |
}
|
|
2265 |
|
|
2266 |
|
|
2267 |
/**
|
|
2268 |
Exhaustive test of Data alignmemnt calculation
|
|
2269 |
in this code the function
|
|
2270 |
TInt TFatAlignment::AdjustFirstDataSectorAlignment(TInt aBlockSize)
|
|
2271 |
should be exactly the same as
|
|
2272 |
TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aBlockSize)
|
|
2273 |
*/
|
|
2274 |
class TFatAlignment
|
|
2275 |
{
|
|
2276 |
public:
|
|
2277 |
enum {KDefFatResvdSec = 1, KDefFat32ResvdSec = 32}; ///< default number of FAT32 reserved sectors
|
|
2278 |
public:
|
|
2279 |
TFatAlignment();
|
|
2280 |
void Init(TBool aFat32, TInt aNumberOfFats, TInt aMaxDiskSectors, TInt aSectorsPerCluster, TInt aRootDirEntries);
|
|
2281 |
TUint32 MaxFat32Sectors() const;
|
|
2282 |
TInt MaxFat16Sectors() const;
|
|
2283 |
TInt MaxFat12Sectors() const;
|
|
2284 |
TUint32 RootDirSectors() const;
|
|
2285 |
TInt FirstDataSector() const;
|
|
2286 |
TBool Is32BitFat() const;
|
|
2287 |
TBool Is16BitFat() const;
|
|
2288 |
|
|
2289 |
TInt AdjustFirstDataSectorAlignment(TInt aBlockSize);
|
|
2290 |
void Display();
|
|
2291 |
public:
|
|
2292 |
TInt iBytesPerSector;
|
|
2293 |
TInt iNumberOfFats;
|
|
2294 |
TInt iMaxDiskSectors;
|
|
2295 |
TInt iSectorsPerCluster;
|
|
2296 |
TInt iReservedSectors;
|
|
2297 |
TInt iSectorsPerFat;
|
|
2298 |
TInt iRootDirEntries;
|
|
2299 |
|
|
2300 |
TBool iFat32; // 0 = FAT16, 1 = FAT32
|
|
2301 |
TInt iMaxIterations;
|
|
2302 |
};
|
|
2303 |
|
|
2304 |
TFatAlignment::TFatAlignment()
|
|
2305 |
{
|
|
2306 |
iMaxIterations = 0;
|
|
2307 |
}
|
|
2308 |
|
|
2309 |
void TFatAlignment::Init(TBool aFat32, TInt aNumberOfFats, TInt aMaxDiskSectors, TInt aSectorsPerCluster, TInt aRootDirEntries)
|
|
2310 |
{
|
|
2311 |
iBytesPerSector = 512;
|
|
2312 |
iFat32 = aFat32;
|
|
2313 |
iNumberOfFats = aNumberOfFats;
|
|
2314 |
iMaxDiskSectors = aMaxDiskSectors;
|
|
2315 |
iSectorsPerCluster = aSectorsPerCluster;
|
|
2316 |
iRootDirEntries = aRootDirEntries;
|
|
2317 |
|
|
2318 |
iReservedSectors = iFat32 ? KDefFat32ResvdSec : KDefFatResvdSec;
|
|
2319 |
iSectorsPerFat = iFat32 ? MaxFat32Sectors() : MaxFat16Sectors();
|
|
2320 |
}
|
|
2321 |
|
|
2322 |
void TFatAlignment::Display()
|
|
2323 |
{
|
|
2324 |
RDebug::Print(_L("iFat32 %u iNumberOfFats %u,iMaxDiskSectors %u,iSectorsPerCluster %u,iReservedSectors %u,iSectorsPerFat %u, iRootDirEntries %u, FirstDataSector %08X"),
|
|
2325 |
iFat32,
|
|
2326 |
iNumberOfFats,
|
|
2327 |
iMaxDiskSectors,
|
|
2328 |
iSectorsPerCluster,
|
|
2329 |
iReservedSectors,
|
|
2330 |
iSectorsPerFat,
|
|
2331 |
iRootDirEntries,
|
|
2332 |
FirstDataSector());
|
|
2333 |
}
|
|
2334 |
|
|
2335 |
TInt TFatAlignment::MaxFat16Sectors() const
|
|
2336 |
{
|
|
2337 |
|
|
2338 |
TInt fatSizeInBytes=(2*iMaxDiskSectors)/iSectorsPerCluster+(iBytesPerSector-1);
|
|
2339 |
return(fatSizeInBytes/iBytesPerSector);
|
|
2340 |
}
|
|
2341 |
|
|
2342 |
|
|
2343 |
TInt TFatAlignment::MaxFat12Sectors() const
|
|
2344 |
{
|
|
2345 |
TInt maxDiskClusters=iMaxDiskSectors/iSectorsPerCluster;
|
|
2346 |
TInt fatSizeInBytes=maxDiskClusters+(maxDiskClusters>>1)+(iBytesPerSector-1);
|
|
2347 |
return(fatSizeInBytes/iBytesPerSector);
|
|
2348 |
}
|
|
2349 |
|
|
2350 |
|
|
2351 |
TUint32 TFatAlignment::MaxFat32Sectors() const
|
|
2352 |
{
|
|
2353 |
TUint32 calc1 = iMaxDiskSectors - iReservedSectors;
|
|
2354 |
TUint32 calc2 = (256 * iSectorsPerCluster) + iNumberOfFats;
|
|
2355 |
calc2 = calc2 >> 1;
|
|
2356 |
return (calc1 + (calc2 - 1))/calc2;
|
|
2357 |
}
|
|
2358 |
|
|
2359 |
|
|
2360 |
/**
|
|
2361 |
@return Number of sectors in root directory. 0 for FAT32
|
|
2362 |
*/
|
|
2363 |
TUint32 TFatAlignment::RootDirSectors() const
|
|
2364 |
{
|
|
2365 |
const TInt KSizeOfFatDirEntry =32; ///< Size in bytes of a Fat directry entry
|
|
2366 |
|
|
2367 |
return ( (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector );
|
|
2368 |
}
|
|
2369 |
|
|
2370 |
TInt TFatAlignment::FirstDataSector() const
|
|
2371 |
{
|
|
2372 |
return( iReservedSectors + iNumberOfFats * iSectorsPerFat + RootDirSectors());
|
|
2373 |
}
|
|
2374 |
|
|
2375 |
TBool TFatAlignment::Is32BitFat() const
|
|
2376 |
{
|
|
2377 |
return iFat32;
|
|
2378 |
}
|
|
2379 |
|
|
2380 |
TBool TFatAlignment::Is16BitFat() const
|
|
2381 |
{
|
|
2382 |
return !iFat32;
|
|
2383 |
}
|
|
2384 |
|
|
2385 |
#define __PRINT1
|
|
2386 |
|
|
2387 |
|
|
2388 |
// AdjustFirstDataSectorAlignment()
|
|
2389 |
// Attempts to align the first data sector on an erase block boundary by modifying the
|
|
2390 |
// number of reserved sectors.
|
|
2391 |
TInt TFatAlignment::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors)
|
|
2392 |
{
|
|
2393 |
const TBool bFat16 = Is16BitFat();
|
|
2394 |
const TBool bFat32 = Is32BitFat();
|
|
2395 |
|
|
2396 |
// Save these 2 values in the event of a convergence failure; this should
|
|
2397 |
// hopefully never happen, but we will cater for this in release mode to be safe,
|
|
2398 |
TInt reservedSectorsSaved = iReservedSectors;
|
|
2399 |
TInt sectorsPerFatSaved = iSectorsPerFat;
|
|
2400 |
|
|
2401 |
TInt reservedSectorsOld = 0;
|
|
2402 |
|
|
2403 |
// zero for FAT32
|
|
2404 |
TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector;
|
|
2405 |
TInt fatSectors = 0;
|
|
2406 |
|
|
2407 |
TInt KMaxIterations = 10;
|
|
2408 |
TInt n;
|
|
2409 |
for (n=0; n<KMaxIterations && reservedSectorsOld != iReservedSectors; n++)
|
|
2410 |
{
|
|
2411 |
reservedSectorsOld = iReservedSectors;
|
|
2412 |
|
|
2413 |
iSectorsPerFat = bFat32 ? MaxFat32Sectors() : bFat16 ? MaxFat16Sectors() : MaxFat12Sectors();
|
|
2414 |
|
|
2415 |
fatSectors = iSectorsPerFat * iNumberOfFats;
|
|
2416 |
|
|
2417 |
// calculate number of blocks
|
|
2418 |
TInt nBlocks = (iReservedSectors + fatSectors + rootDirSectors + aEraseBlockSizeInSectors-1) / aEraseBlockSizeInSectors;
|
|
2419 |
|
|
2420 |
iReservedSectors = (nBlocks * aEraseBlockSizeInSectors) - rootDirSectors - fatSectors;
|
|
2421 |
}
|
|
2422 |
|
|
2423 |
ASSERT(iReservedSectors >= (TInt) (bFat32 ? KDefFat32ResvdSec : KDefFatResvdSec));
|
|
2424 |
|
|
2425 |
if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0)
|
|
2426 |
{
|
|
2427 |
return KErrNone;
|
|
2428 |
}
|
|
2429 |
else
|
|
2430 |
{
|
|
2431 |
iReservedSectors = reservedSectorsSaved;
|
|
2432 |
iSectorsPerFat = sectorsPerFatSaved;
|
|
2433 |
return KErrGeneral;
|
|
2434 |
}
|
|
2435 |
}
|
|
2436 |
|
|
2437 |
|
|
2438 |
void TestFirstDataSectorAlignment()
|
|
2439 |
{
|
|
2440 |
test.Start(_L("Exhaustive test of data alignment calculation"));
|
|
2441 |
|
|
2442 |
typedef struct
|
|
2443 |
{
|
|
2444 |
TInt iNumberOfFats;
|
|
2445 |
TInt iMaxDiskSectors;
|
|
2446 |
TInt iSectorsPerCluster;
|
|
2447 |
TInt iBlockSize;
|
|
2448 |
TInt iRootDirEntries;
|
|
2449 |
} STestVal;
|
|
2450 |
STestVal testVals[] =
|
|
2451 |
{
|
|
2452 |
{2, 15720448, 32, 16*1024, 0}, // 4GB MoviNand, cluster size = 16K
|
|
2453 |
{2, 106496, 2, 2048, 512}, // diskSize = 54MB, = block size = 1MB
|
|
2454 |
{2, 1048576, 8, 2048, 0}, // diskSize = 512 MB
|
|
2455 |
{2, 1048578, 8, 2048, 0}, // Doesn't converge with original algorithm
|
|
2456 |
};
|
|
2457 |
|
|
2458 |
TFatAlignment fatAlignment;
|
|
2459 |
TInt numOfTests = sizeof(testVals) / sizeof(STestVal);
|
|
2460 |
for (TInt n=0; n<numOfTests; n++)
|
|
2461 |
{
|
|
2462 |
STestVal& testVal = testVals[n];
|
|
2463 |
TBool fat32 = testVal.iMaxDiskSectors >= 1048576;
|
|
2464 |
|
|
2465 |
fatAlignment.Init(
|
|
2466 |
fat32,
|
|
2467 |
testVal.iNumberOfFats,
|
|
2468 |
testVal.iMaxDiskSectors,
|
|
2469 |
testVal.iSectorsPerCluster,
|
|
2470 |
testVal.iRootDirEntries);
|
|
2471 |
TInt r = fatAlignment.AdjustFirstDataSectorAlignment(testVal.iBlockSize);
|
|
2472 |
test (r == KErrNone);
|
|
2473 |
fatAlignment.Display();
|
|
2474 |
}
|
|
2475 |
|
|
2476 |
const TInt64 KOneMByte = 1024*1024;
|
|
2477 |
const TInt64 KOneGByte = 1024*KOneMByte;
|
|
2478 |
const TInt64 KLastSizeToTest = 32*KOneGByte;
|
|
2479 |
TInt iteration=0;
|
|
2480 |
TInt64 diskSize;
|
|
2481 |
|
|
2482 |
|
|
2483 |
|
|
2484 |
TInt successes = 0;
|
|
2485 |
TInt failures = 0;
|
|
2486 |
|
|
2487 |
for (iteration=0, diskSize = 16*KOneMByte; diskSize < KLastSizeToTest; iteration++, diskSize+=512)
|
|
2488 |
{
|
|
2489 |
TInt diskSizeInSectors = (TInt) (diskSize >> 9);
|
|
2490 |
|
|
2491 |
const TInt KMaxFAT16Entries=0xFFF0; ///< Maximum number of clusters in a Fat16 Fat table, 65520
|
|
2492 |
|
|
2493 |
TBool fat32 = EFalse;
|
|
2494 |
TInt numberOfFats = 2;
|
|
2495 |
TInt rootDirEntries;
|
|
2496 |
TInt sectorsPerCluster;
|
|
2497 |
TInt blockSizeInSectors = 32; // 16K for FAT16
|
|
2498 |
|
|
2499 |
if (diskSizeInSectors<4096) // < 2MB
|
|
2500 |
{
|
|
2501 |
rootDirEntries=128;
|
|
2502 |
sectorsPerCluster=1;
|
|
2503 |
}
|
|
2504 |
else if (diskSizeInSectors<8400) // < 4MB
|
|
2505 |
{
|
|
2506 |
rootDirEntries=256;
|
|
2507 |
sectorsPerCluster=2;
|
|
2508 |
}
|
|
2509 |
else if (diskSizeInSectors<16384) // < 8MB
|
|
2510 |
{
|
|
2511 |
rootDirEntries=512;
|
|
2512 |
sectorsPerCluster=4;
|
|
2513 |
}
|
|
2514 |
else if (diskSizeInSectors<32680) // < 16MB
|
|
2515 |
{
|
|
2516 |
rootDirEntries=512;
|
|
2517 |
sectorsPerCluster=8;
|
|
2518 |
}
|
|
2519 |
else if(diskSizeInSectors<1048576) // >= 16Mb - FAT16 < (1048576) 512MB
|
|
2520 |
{
|
|
2521 |
TInt minSectorsPerCluster=(diskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries;
|
|
2522 |
rootDirEntries=512;
|
|
2523 |
sectorsPerCluster=1;
|
|
2524 |
while (minSectorsPerCluster>sectorsPerCluster)
|
|
2525 |
sectorsPerCluster<<=1;
|
|
2526 |
}
|
|
2527 |
else //use FAT32
|
|
2528 |
{
|
|
2529 |
rootDirEntries=0; //this is always the case for fat32
|
|
2530 |
if(diskSizeInSectors < 16777216) //8GB in 512byte sectors
|
|
2531 |
sectorsPerCluster=8;
|
|
2532 |
else if(diskSizeInSectors < 33554432) //16GB in 512byte sectors
|
|
2533 |
sectorsPerCluster=16;
|
|
2534 |
else if(diskSizeInSectors < 67108864) //32GB in 512byte sectors
|
|
2535 |
sectorsPerCluster=32;
|
|
2536 |
else
|
|
2537 |
sectorsPerCluster=64; //Anything >= 32GB uses a 32K cluster size
|
|
2538 |
blockSizeInSectors = 2048; // 1MB for FAT32
|
|
2539 |
fat32 = ETrue;
|
|
2540 |
}
|
|
2541 |
|
|
2542 |
|
|
2543 |
fatAlignment.Init(
|
|
2544 |
fat32,
|
|
2545 |
numberOfFats,
|
|
2546 |
diskSizeInSectors,
|
|
2547 |
sectorsPerCluster,
|
|
2548 |
rootDirEntries);
|
|
2549 |
TInt r = fatAlignment.AdjustFirstDataSectorAlignment(blockSizeInSectors);
|
|
2550 |
if (r == KErrNone)
|
|
2551 |
successes++;
|
|
2552 |
else
|
|
2553 |
failures++;
|
|
2554 |
|
|
2555 |
|
|
2556 |
// if (diskSize % 0x08000000 == 0)
|
|
2557 |
// {
|
|
2558 |
// RDebug::Print(_L("Iter %10lX of %10lX"), diskSize, KLastSizeToTest);
|
|
2559 |
// fatAlignment.Display();
|
|
2560 |
// }
|
|
2561 |
}
|
|
2562 |
RDebug::Print(_L("Total iterations %u"), iteration);
|
|
2563 |
RDebug::Print(_L("Max loop count %u"), fatAlignment.iMaxIterations);
|
|
2564 |
RDebug::Print(_L("successes %d failures %d, success rate %ld"),
|
|
2565 |
successes, failures, (TInt64(successes) * 100) / TInt64(successes + failures));
|
|
2566 |
test (failures == 0);
|
|
2567 |
|
|
2568 |
}
|
|
2569 |
|
|
2570 |
|
|
2571 |
static void TestZeroLengthFile()
|
|
2572 |
//
|
|
2573 |
// Test what happens if you write more to a zero length file than
|
|
2574 |
// will fit in the filesystem.
|
|
2575 |
//
|
|
2576 |
{
|
|
2577 |
test.Next(_L("Test behaviour of extending a zero length file"));
|
|
2578 |
|
|
2579 |
FormatPack();
|
|
2580 |
|
|
2581 |
TInt r;
|
|
2582 |
|
|
2583 |
TVolumeInfo volInfo;
|
|
2584 |
r=TheFs.Volume(volInfo);
|
|
2585 |
test(r==KErrNone);
|
|
2586 |
|
|
2587 |
TInt64 spaceToUse = volInfo.iFree - gBytesPerCluster; // whole disk except 1 cluster
|
|
2588 |
|
|
2589 |
test.Printf(_L("spaceToUse %ld gClusterCount %d gBytesPerCluster %d\n"), spaceToUse, gClusterCount, gBytesPerCluster);
|
|
2590 |
test.Printf(_L("Before fill, volInfo.iSize %ld volInfo.iFree %ld\n"), volInfo.iSize, volInfo.iFree);
|
|
2591 |
|
|
2592 |
RFile f;
|
|
2593 |
|
|
2594 |
TInt tempfiles = 0;
|
|
2595 |
while (spaceToUse > K1GigaByte)
|
|
2596 |
{
|
|
2597 |
TFileName tempName;
|
|
2598 |
r=f.Temp(TheFs,_L("\\"),tempName,EFileRead|EFileWrite);
|
|
2599 |
test(r==KErrNone);
|
|
2600 |
r=f.SetSize(K1GigaByte);
|
|
2601 |
test(r==KErrNone);
|
|
2602 |
f.Close();
|
|
2603 |
spaceToUse -= K1GigaByte;
|
|
2604 |
tempfiles++;
|
|
2605 |
}
|
|
2606 |
|
|
2607 |
r=f.Replace(TheFs,_L("\\USESPACE.TMP"),EFileRead|EFileWrite);
|
|
2608 |
test(r==KErrNone);
|
|
2609 |
r=f.SetSize((TInt)spaceToUse);
|
|
2610 |
test(r==KErrNone);
|
|
2611 |
f.Close();
|
|
2612 |
|
|
2613 |
r=TheFs.Volume(volInfo);
|
|
2614 |
test(r==KErrNone);
|
|
2615 |
test.Printf(_L("After fill, volInfo.iSize %ld volInfo.iFree %ld\n"), volInfo.iSize, volInfo.iFree);
|
|
2616 |
|
|
2617 |
test(volInfo.iFree==gBytesPerCluster); // check we have 1 cluster free
|
|
2618 |
|
|
2619 |
r=f.Replace(TheFs,_L("\\FILE.TMP"),EFileRead|EFileWrite);
|
|
2620 |
test(r==KErrNone);
|
|
2621 |
r=f.SetSize(2*gBytesPerCluster); // 2 clusters (will fail since there's not space)
|
|
2622 |
test(r==KErrDiskFull);
|
|
2623 |
f.Close();
|
|
2624 |
|
|
2625 |
r=TheFs.Volume(volInfo);
|
|
2626 |
test(r==KErrNone);
|
|
2627 |
test(volInfo.iFree==gBytesPerCluster); // check we still have 1 cluster free
|
|
2628 |
|
|
2629 |
r=f.Replace(TheFs,_L("\\USESPACE.TMP"),EFileRead|EFileWrite); // truncate file to 0
|
|
2630 |
test(r==KErrNone);
|
|
2631 |
f.Close();
|
|
2632 |
|
|
2633 |
r=TheFs.Volume(volInfo);
|
|
2634 |
test(r==KErrNone);
|
|
2635 |
test(volInfo.iFree==(spaceToUse+gBytesPerCluster)); // check we've freed up the space from USESPACE plus one cluster
|
|
2636 |
|
|
2637 |
|
|
2638 |
test(TheBootSector.IsValid()); //-- TheBootSector is read after formatting
|
|
2639 |
TInt64 rootDirpos = gRootDirStart;
|
|
2640 |
|
|
2641 |
|
|
2642 |
//-- read 1 sector of the root dir.
|
|
2643 |
r = MediaRawRead(TheFs, CurrentDrive(), rootDirpos, TheBootSector.BytesPerSector(), TheBuffer);
|
|
2644 |
test(r == KErrNone);
|
|
2645 |
|
|
2646 |
const TFatDirEntry* pE=(TFatDirEntry*)TheBuffer.Ptr();
|
|
2647 |
while (tempfiles-- > 0)
|
|
2648 |
{
|
|
2649 |
while (pE->IsVFatEntry())
|
|
2650 |
pE++;
|
|
2651 |
test(pE->Size()==(TUint)K1GigaByte);
|
|
2652 |
pE++;
|
|
2653 |
}
|
|
2654 |
|
|
2655 |
while (pE->IsVFatEntry())
|
|
2656 |
pE++;
|
|
2657 |
|
|
2658 |
TBuf8<15> name=pE->Name();
|
|
2659 |
test(name==_L8("USESPACETMP"));
|
|
2660 |
test(pE->StartCluster()==0);
|
|
2661 |
|
|
2662 |
pE++;
|
|
2663 |
while (pE->IsVFatEntry())
|
|
2664 |
pE++;
|
|
2665 |
|
|
2666 |
name=pE->Name();
|
|
2667 |
test(name==_L8("FILE TMP"));
|
|
2668 |
test(pE->StartCluster()==0);
|
|
2669 |
|
|
2670 |
FormatPack();
|
|
2671 |
|
|
2672 |
}
|
|
2673 |
|
|
2674 |
|
|
2675 |
//
|
|
2676 |
// Call tests that may leave
|
|
2677 |
//
|
|
2678 |
void CallTestsL()
|
|
2679 |
{
|
|
2680 |
|
|
2681 |
//-- init random generator
|
|
2682 |
rndSeed = Math::Random();
|
|
2683 |
|
|
2684 |
//-- set up console output
|
|
2685 |
Fat_Test_Utils::SetConsole(test.Console());
|
|
2686 |
|
|
2687 |
|
|
2688 |
|
|
2689 |
TInt drvNum;
|
|
2690 |
TInt r=TheFs.CharToDrive(gDriveToTest,drvNum);
|
|
2691 |
test(r==KErrNone);
|
|
2692 |
|
|
2693 |
if (!Is_Fat(TheFs,drvNum))
|
|
2694 |
{
|
|
2695 |
test.Printf(_L("CallTestsL: Skipped: test requires FAT filesystem\n"));
|
|
2696 |
return;
|
|
2697 |
}
|
|
2698 |
|
|
2699 |
|
|
2700 |
//-- print drive information
|
|
2701 |
PrintDrvInfo(TheFs, drvNum);
|
|
2702 |
|
|
2703 |
// check this is not the internal ram drive
|
|
2704 |
TVolumeInfo v;
|
|
2705 |
r=TheFs.Volume(v, drvNum);
|
|
2706 |
test(r==KErrNone);
|
|
2707 |
TBool isRamDrive = v.iDrive.iMediaAtt&KMediaAttVariableSize;
|
|
2708 |
|
|
2709 |
gSessionPath[0] = (TText)gDriveToTest;
|
|
2710 |
// verify that the drive is large enough for proper testing
|
|
2711 |
if (v.iSize<512*1024)
|
|
2712 |
{
|
|
2713 |
test.Printf(_L("CallTestsL: Skipped: test not supported on drives smaller than 512 KB\n"));
|
|
2714 |
return;
|
|
2715 |
}
|
|
2716 |
|
|
2717 |
FormatPack();
|
|
2718 |
DumpBootSector();
|
|
2719 |
|
|
2720 |
test.Printf(_L("TotalSectors = %u (%u bytes)\n"),gTotalSectors,gTotalSectors*TheBootSector.BytesPerSector());
|
|
2721 |
test.Printf(_L("Sector size = %u\n"),TheBootSector.BytesPerSector());
|
|
2722 |
test.Printf(_L("Cluster size = %u sectors\n"),TheBootSector.SectorsPerCluster());
|
|
2723 |
test.Printf(_L("Alloc unit = %u\n"), gBytesPerCluster);
|
|
2724 |
test.Printf(_L("Fat is %u bit\n"), gFatBits);
|
|
2725 |
User::After(200000); // 1/5 secs
|
|
2726 |
|
|
2727 |
// set up buffers
|
|
2728 |
TInt bufLen = 16*gBytesPerCluster;
|
|
2729 |
if (bufLen < 16*1024)
|
|
2730 |
bufLen = 16*1024;
|
|
2731 |
pBuffer1=HBufC8::NewL(bufLen);
|
|
2732 |
pBuffer2=HBufC8::NewL(bufLen);
|
|
2733 |
|
|
2734 |
if (pBuffer1==NULL || pBuffer2==NULL)
|
|
2735 |
Error(_L("OOM"),KErrNoMemory);
|
|
2736 |
|
|
2737 |
|
|
2738 |
pBuffer1->Des().Zero();
|
|
2739 |
pBuffer1->Des().SetLength(bufLen);
|
|
2740 |
|
|
2741 |
pBuffer2->Des().Zero();
|
|
2742 |
pBuffer2->Des().SetLength(bufLen);
|
|
2743 |
|
|
2744 |
if (isRamDrive)
|
|
2745 |
{
|
|
2746 |
User::After(200000); // 1/5 secs
|
|
2747 |
test.Printf(_L("*** Tests not valid on internal ram drive %C:\n"), (TUint)gDriveToTest);
|
|
2748 |
User::After(200000); // 1/5 secs
|
|
2749 |
}
|
|
2750 |
else
|
|
2751 |
{
|
|
2752 |
TestZeroLengthFile();
|
|
2753 |
|
|
2754 |
#if defined(__WINS__)
|
|
2755 |
TestFirstDataSectorAlignment();
|
|
2756 |
#endif
|
|
2757 |
|
|
2758 |
TestFirst2FatEntries();
|
|
2759 |
|
|
2760 |
TestDiskIntegrity();
|
|
2761 |
|
|
2762 |
TestBounds();
|
|
2763 |
TestUnicodeEntry();
|
|
2764 |
|
|
2765 |
TestClusters();
|
|
2766 |
|
|
2767 |
TestClusterAllocation();
|
|
2768 |
|
|
2769 |
|
|
2770 |
TestParentDir(EFalse); // Test without VFAT entries
|
|
2771 |
TestParentDir(ETrue); // Test with VFAT entries
|
|
2772 |
|
|
2773 |
TestRoot();
|
|
2774 |
TestVolumeSize();
|
|
2775 |
TestFATTableEntries();
|
|
2776 |
|
|
2777 |
FormatPack();
|
|
2778 |
|
|
2779 |
}
|
|
2780 |
delete pBuffer1;
|
|
2781 |
delete pBuffer2;
|
|
2782 |
}
|
|
2783 |
|
|
2784 |
|
|
2785 |
/**
|
|
2786 |
Generate unique temp file name in upper (FAT entry) or lower case (2 VFAT entries)
|
|
2787 |
@param aFN descriptor for the file name
|
|
2788 |
@param aUpperCase if ETrue, the file name will be in upper case, in a lower case otherwise.
|
|
2789 |
|
|
2790 |
*/
|
|
2791 |
void GenerateTmpFileName(TDes& aFN, TBool aUpperCase)
|
|
2792 |
{
|
|
2793 |
const TInt rnd = Math::Rand(rndSeed);
|
|
2794 |
|
|
2795 |
aFN.Format(_L("%08x.tmp"), rnd);
|
|
2796 |
|
|
2797 |
if(aUpperCase)
|
|
2798 |
aFN.UpperCase();
|
|
2799 |
else
|
|
2800 |
aFN.LowerCase();
|
|
2801 |
|
|
2802 |
}
|
|
2803 |
|
|
2804 |
/**
|
|
2805 |
Create FAT or VFAT entry in a speciified directory
|
|
2806 |
|
|
2807 |
@param aDir specifies the directory where enntry will be created
|
|
2808 |
@param aVFatEntry if true, VFAT entry will be created (2 FAT entries, actually), otherwise - FAT entry
|
|
2809 |
@param apFileName in !=NULL there will be placed the name of the file created
|
|
2810 |
*/
|
|
2811 |
void CreateFatEntry(const TDesC& aDir, TBool aVFatEntry, TDes *apFileName/*=NULL*/)
|
|
2812 |
{
|
|
2813 |
TFileName tmpFN;
|
|
2814 |
RFile file;
|
|
2815 |
TInt nRes;
|
|
2816 |
|
|
2817 |
do
|
|
2818 |
{
|
|
2819 |
GenerateTmpFileName(tmpFN, !aVFatEntry); //-- generates 8.3 file name FAT (1 entry) or VFAT (2 entries)
|
|
2820 |
tmpFN.Insert(0, aDir);
|
|
2821 |
|
|
2822 |
nRes = file.Create(TheFs, tmpFN, EFileRead|EFileWrite);
|
|
2823 |
|
|
2824 |
if(nRes == KErrAlreadyExists)
|
|
2825 |
continue; //-- current random name generator isn't perfect...
|
|
2826 |
|
|
2827 |
if(nRes != KErrNone)
|
|
2828 |
Error(_L("Error creating a file"),nRes);
|
|
2829 |
|
|
2830 |
file.Close();
|
|
2831 |
|
|
2832 |
}while(nRes != KErrNone);
|
|
2833 |
|
|
2834 |
if(apFileName)
|
|
2835 |
*apFileName = tmpFN;
|
|
2836 |
|
|
2837 |
}
|
|
2838 |
|
|
2839 |
|