|
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 |