|
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // f32test\scndrv\t_scn32dr1.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <f32file.h> |
|
19 #include <e32test.h> |
|
20 |
|
21 #include "t_server.h" |
|
22 |
|
23 #include "fat_utils.h" |
|
24 using namespace Fat_Test_Utils; |
|
25 |
|
26 #ifdef __VC32__ |
|
27 // Solve compilation problem caused by non-English locale |
|
28 #pragma setlocale("english") |
|
29 #endif |
|
30 |
|
31 /* |
|
32 T_testscndrv tests the scandrive utility. Errors in this test will be |
|
33 introduced using the RRawdDisk class. The correct fixup is tested by rereading |
|
34 the disk. Drives tested are the default path(epoc) and X: (wins). This test |
|
35 returns immediately if used on the internal ram drive |
|
36 */ |
|
37 |
|
38 /* |
|
39 The initial FAT12 directory structure (with cluster number in brackets) is as follows: |
|
40 |
|
41 | |
|
42 - scndrv (2) |
|
43 | |
|
44 - dir1 (3-4) |
|
45 | | |
|
46 | <a very long file name (19 entries)> (5) |
|
47 | |
|
48 - dir2 (6) |
|
49 | |
|
50 - full (7) |
|
51 | | |
|
52 | | |
|
53 | - <seven 2*32 bytes entries> (11-17) |
|
54 | |
|
55 - somedirwith3entries (8) |
|
56 | |
|
57 - somedir2with3entries (9) |
|
58 | |
|
59 - almostfull(10) |
|
60 | |
|
61 - <two lots of 6*32 bytes entries> (18+19) |
|
62 |
|
63 */ |
|
64 |
|
65 /* |
|
66 The initial FAT32 directory structure (with cluster number in brackets is as follows): |
|
67 |
|
68 | |
|
69 - scndrv (3) |
|
70 | |
|
71 - dir1 (4) |
|
72 | | |
|
73 | <a very long file name (19 entries)> (5) |
|
74 | |
|
75 - dir2 (6) |
|
76 | |
|
77 - full (7) |
|
78 | | |
|
79 | | |
|
80 | - <seven 2*32 bytes entries> (11-17) |
|
81 | |
|
82 - somedirwith3entries (8) |
|
83 | |
|
84 - somedir2with3entries (9) |
|
85 | |
|
86 - almostfull(10) |
|
87 | |
|
88 - <two lots of 6*32 bytes entries> (18+19) |
|
89 |
|
90 */ |
|
91 |
|
92 GLDEF_D RTest test(_L("T_SCN32DR1")); |
|
93 |
|
94 LOCAL_D const TInt KMaxFatEntries = 2048; |
|
95 LOCAL_D const TInt KMaxFatSize = KMaxFatEntries * 4; |
|
96 |
|
97 LOCAL_D const TInt KDirAttrReadOnly = 0x01; |
|
98 LOCAL_D const TInt KDirAttrHidden = 0x02; |
|
99 LOCAL_D const TInt KDirAttrSystem = 0x04; |
|
100 LOCAL_D const TInt KDirAttrVolumeId = 0x08; |
|
101 LOCAL_D const TInt KDirAttrDirectory = 0x10; |
|
102 LOCAL_D const TInt KDirAttrArchive = 0x20; |
|
103 LOCAL_D const TInt KDirAttrLongName = KDirAttrReadOnly | KDirAttrHidden | KDirAttrSystem | KDirAttrVolumeId; |
|
104 LOCAL_D const TInt KDirAttrLongMask = KDirAttrLongName | KDirAttrDirectory | KDirAttrArchive; |
|
105 LOCAL_D const TInt KDirLastLongEntry = 0x40; |
|
106 |
|
107 LOCAL_D RRawDisk TheRawDisk; |
|
108 LOCAL_D TFatBootSector BootSector; |
|
109 LOCAL_D TFileName TheDrive=_L("?:\\"); |
|
110 LOCAL_D HBufC8* FatBufPtr = NULL; |
|
111 LOCAL_D HBufC8* DirBufPtr = NULL; |
|
112 LOCAL_D HBufC8* ExtBufPtr = NULL; |
|
113 LOCAL_D TInt32 ExtBufAdd = 0; |
|
114 LOCAL_D TInt32 ExtBufLen = 0; |
|
115 LOCAL_D HBufC8* FatDiskPtr = NULL; |
|
116 LOCAL_D HBufC8* DirDiskPtr = NULL; |
|
117 |
|
118 static TFatType gDiskType = EInvalid; |
|
119 |
|
120 LOCAL_D TInt gDriveNumber; |
|
121 |
|
122 LOCAL_D TInt gBytesPerCluster; |
|
123 LOCAL_D TInt gEntriesPerCluster; |
|
124 LOCAL_D TInt gRootDirSectors; |
|
125 LOCAL_D TInt gRootDirEntries; |
|
126 LOCAL_D TInt gRootDirStart; // in bytes |
|
127 LOCAL_D TInt gRootSector; |
|
128 LOCAL_D TInt gFatStartBytes; |
|
129 LOCAL_D TInt gFatTestSize; // in bytes |
|
130 LOCAL_D TInt gFatTestEntries; |
|
131 LOCAL_D TInt gFatSizeSectors; |
|
132 LOCAL_D TInt gFirstDataSector; |
|
133 LOCAL_D TInt gMaxDataCluster; |
|
134 LOCAL_D TInt gDataStartBytes; |
|
135 LOCAL_D TInt gEndOfChain; // for FAT12/16/32 |
|
136 |
|
137 // cluster numbers in 1 and >1 sector per cluster modes |
|
138 LOCAL_D TInt gClusterRootDir; // 2 2 |
|
139 LOCAL_D TInt gClusterScnDrv; // 3 3 |
|
140 LOCAL_D TInt gClusterDir1; // 4 4 |
|
141 LOCAL_D TInt gClusterDir1ext; // 5 4 |
|
142 LOCAL_D TInt gClusterDir2; // 7 6 |
|
143 LOCAL_D TInt gClusterDir2_Full; // 8 7 |
|
144 LOCAL_D TInt gClusterDir2_SD3E; // 9 8 |
|
145 LOCAL_D TInt gClusterDir2_SD23E; // 10 9 |
|
146 LOCAL_D TInt gClusterDir2_AFull; // 11 10 |
|
147 LOCAL_D TInt gClusterEndMaxDepth; // 147 146 |
|
148 |
|
149 LOCAL_D TFileName LastInFull; |
|
150 |
|
151 class TEntryInfo |
|
152 { |
|
153 public: |
|
154 TEntryInfo(TInt aBytePos,TInt aLength):iBytePos(aBytePos),iLength(aLength){} |
|
155 TEntryInfo(){} |
|
156 public: |
|
157 TInt iBytePos; |
|
158 TInt iLength; |
|
159 }; |
|
160 |
|
161 |
|
162 LOCAL_C TInt DirBufferSize() |
|
163 // |
|
164 // returns size in bytes nec for buffer to store relevant disk data |
|
165 // |
|
166 { |
|
167 return(gMaxDataCluster*gBytesPerCluster); |
|
168 } |
|
169 |
|
170 LOCAL_C TInt PosInBytes(TInt aFatIndex) |
|
171 // |
|
172 // Return number of bytes into the FAT |
|
173 // |
|
174 { |
|
175 TInt fatPosInBytes = -1; |
|
176 switch (gDiskType) |
|
177 { |
|
178 case EFat32: |
|
179 fatPosInBytes=aFatIndex<<2; |
|
180 break; |
|
181 case EFat16: |
|
182 fatPosInBytes=aFatIndex<<1; |
|
183 break; |
|
184 case EFat12: |
|
185 fatPosInBytes=(aFatIndex*3>>1); |
|
186 break; |
|
187 default: |
|
188 test(0); |
|
189 } |
|
190 return(fatPosInBytes); |
|
191 } |
|
192 |
|
193 LOCAL_C TUint32 MaxClusters() |
|
194 // |
|
195 // Return the number of data clusters on the disk |
|
196 // |
|
197 { |
|
198 TUint32 totSec = (BootSector.TotalSectors() ? BootSector.TotalSectors() : BootSector.HugeSectors()); |
|
199 TUint32 numSec = totSec - gFirstDataSector; |
|
200 return numSec / BootSector.SectorsPerCluster(); |
|
201 } |
|
202 |
|
203 LOCAL_C TInt ClusterToByte(TInt aCluster) |
|
204 // |
|
205 // converts cluster number to byte offset on disk |
|
206 // |
|
207 { |
|
208 TInt pos; |
|
209 if (aCluster < 2) |
|
210 pos = gRootDirStart; |
|
211 else |
|
212 pos = (aCluster - 2) * gBytesPerCluster + gFirstDataSector * BootSector.BytesPerSector(); |
|
213 return pos; |
|
214 } |
|
215 |
|
216 LOCAL_C TInt ByteToCluster(TInt aBytePos) |
|
217 // |
|
218 // Converts byte offset from root dir buffer to cluster number |
|
219 // |
|
220 { |
|
221 if (aBytePos < gRootDirStart) |
|
222 return -1; |
|
223 if (aBytePos < gDataStartBytes) |
|
224 return 0; |
|
225 return (aBytePos - gDataStartBytes) / gBytesPerCluster + 2; |
|
226 } |
|
227 |
|
228 LOCAL_C TInt ClusterEntryToBytes(TInt aCluster,TInt aEntry) |
|
229 // |
|
230 // converts position in cluster and entry number to byte pos from root directory |
|
231 // |
|
232 { |
|
233 TInt pos; |
|
234 pos = ClusterToByte(aCluster) - gRootDirStart + aEntry*KSizeOfFatDirEntry; |
|
235 return pos; |
|
236 } |
|
237 |
|
238 LOCAL_C TInt FindUnMatch(const TUint8* aBuf, const TUint8* aCmp, TInt aLen, TInt aStart=0) |
|
239 // |
|
240 // Return position in buffers which doesn't match, or -1 if it matches |
|
241 // |
|
242 { |
|
243 for (TInt i = aStart; i < aStart + aLen; i++) |
|
244 if (aBuf[i] != aCmp[i]) |
|
245 return i; |
|
246 return -1; |
|
247 } |
|
248 |
|
249 LOCAL_C TUint32 GetFatEntry(TUint32 aIndex, const TUint8* aFat=NULL) |
|
250 // |
|
251 // Read a single FAT entry from disk or FAT copy and return it |
|
252 // |
|
253 { |
|
254 TInt pos = PosInBytes(aIndex); |
|
255 |
|
256 TUint8 data[4]; |
|
257 TUint8* ptr = data; |
|
258 |
|
259 if (aFat) |
|
260 ptr = (TUint8*)aFat + pos; |
|
261 else |
|
262 { |
|
263 pos += BootSector.ReservedSectors() * BootSector.BytesPerSector(); |
|
264 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
265 test(r==KErrNone); |
|
266 TPtr8 buf(&data[0], 4); |
|
267 r=TheRawDisk.Read(pos, buf); |
|
268 test(r==KErrNone); |
|
269 TheRawDisk.Close(); |
|
270 } |
|
271 |
|
272 TUint32 val = 0; |
|
273 switch (gDiskType) |
|
274 { |
|
275 case EFat32: |
|
276 val = ptr[0] + (ptr[1] << 8) + (ptr[2] << 16) + (ptr[3] << 24); |
|
277 break; |
|
278 case EFat16: |
|
279 val = ptr[0] + (ptr[1] << 8); |
|
280 break; |
|
281 case EFat12: |
|
282 val = ptr[0] + (ptr[1] << 8); |
|
283 if (aIndex & 1) |
|
284 val >>= 4; |
|
285 val &= 0xFFF; |
|
286 break; |
|
287 default: |
|
288 test(0); |
|
289 } |
|
290 return val; |
|
291 } |
|
292 |
|
293 LOCAL_C void WriteFat(TInt aFatIndex,TInt aValue,const TUint8* aFat) |
|
294 // |
|
295 // Write a value to both fats starting at aFat |
|
296 // |
|
297 { |
|
298 TUint8* p=(TUint8*)(aFat+PosInBytes(aFatIndex)); |
|
299 switch (gDiskType) |
|
300 { |
|
301 case EFat32: |
|
302 p[0] = (TUint8) (aValue); |
|
303 p[1] = (TUint8) (aValue >> 8); |
|
304 p[2] = (TUint8) (aValue >> 16); |
|
305 p[3] = (TUint8) (aValue >> 24); |
|
306 break; |
|
307 case EFat16: |
|
308 p[0] = (TUint8) (aValue); |
|
309 p[1] = (TUint8) (aValue >> 8); |
|
310 break; |
|
311 case EFat12: |
|
312 { |
|
313 TUint8 mask=0x0F; |
|
314 TBool odd=(aFatIndex)&1; |
|
315 TUint8 fatVal; |
|
316 TInt value=aValue; |
|
317 if(odd) |
|
318 { |
|
319 mask<<=4; |
|
320 value<<=4; |
|
321 fatVal=p[0]; |
|
322 fatVal&=~mask; |
|
323 fatVal|=(TUint8)(value&0xFF); |
|
324 p[0]=fatVal; |
|
325 p[1]=(TUint8)(value>>8); |
|
326 } |
|
327 else |
|
328 { |
|
329 p[0]=(TUint8)(value&0xFF); |
|
330 fatVal=p[1]; |
|
331 fatVal&=~mask; |
|
332 fatVal|=(TUint8)(value>>8); |
|
333 p[1]=fatVal; |
|
334 } |
|
335 } |
|
336 break; |
|
337 default: |
|
338 test(0); |
|
339 } |
|
340 return; |
|
341 } |
|
342 |
|
343 static void DoReadBootSector() |
|
344 { |
|
345 |
|
346 TInt nRes = ReadBootSector(TheFs, CurrentDrive(), KBootSectorNum<<KDefaultSectorLog2, BootSector); |
|
347 test(nRes == KErrNone); |
|
348 |
|
349 if(!BootSector.IsValid()) |
|
350 { |
|
351 test.Printf(_L("Wrong bootsector! Dump:\n")); |
|
352 BootSector.PrintDebugInfo(); |
|
353 test(0); |
|
354 } |
|
355 |
|
356 // Calculate derived variables (fixed for a particular disk format) |
|
357 if (BootSector.RootDirEntries() == 0) |
|
358 { |
|
359 test.Printf(_L("Disk is FAT32\n")); |
|
360 gDiskType = EFat32; |
|
361 gEndOfChain = 0x0FFFFFFF; |
|
362 } |
|
363 else if (BootSector.FatType() == EFat16) |
|
364 { |
|
365 test.Printf(_L("Disk is FAT16\n")); |
|
366 gDiskType = EFat16; |
|
367 gEndOfChain = 0xFFFF; |
|
368 } |
|
369 else |
|
370 { |
|
371 test.Printf(_L("Disk is FAT12\n")); |
|
372 gDiskType = EFat12; |
|
373 gEndOfChain = 0x0FFF; |
|
374 } |
|
375 |
|
376 gBytesPerCluster = BootSector.BytesPerSector() * BootSector.SectorsPerCluster(); |
|
377 gFatStartBytes = BootSector.ReservedSectors() * BootSector.BytesPerSector(); |
|
378 gEntriesPerCluster = gBytesPerCluster / KSizeOfFatDirEntry; |
|
379 |
|
380 TBool big = (BootSector.SectorsPerCluster() > 1); |
|
381 switch (gDiskType) |
|
382 { |
|
383 case EFat12: |
|
384 case EFat16: |
|
385 gRootDirEntries = BootSector.RootDirEntries(); |
|
386 gRootDirSectors = ((gRootDirEntries * KSizeOfFatDirEntry + BootSector.BytesPerSector() - 1) / BootSector.BytesPerSector()); |
|
387 gFatSizeSectors = BootSector.FatSectors(); |
|
388 gRootSector = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors; |
|
389 gFirstDataSector = gRootSector + gRootDirSectors; |
|
390 gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector(); |
|
391 gRootDirStart = gRootSector * BootSector.BytesPerSector(); |
|
392 gClusterRootDir = (big ? 0 : 0); |
|
393 gClusterScnDrv = (big ? 2 : 2); |
|
394 gClusterDir1 = (big ? 3 : 3); |
|
395 gClusterDir1ext = (big ? 3 : 4); |
|
396 gClusterDir2 = (big ? 5 : 6); |
|
397 gClusterDir2_Full = (big ? 6 : 7); |
|
398 gClusterDir2_SD3E = (big ? 7 : 8); |
|
399 gClusterDir2_SD23E = (big ? 8 : 9); |
|
400 gClusterDir2_AFull = (big ? 9 : 10); |
|
401 gClusterEndMaxDepth = (big ? 145 : 146); |
|
402 break; |
|
403 case EFat32: |
|
404 // |
|
405 // FAT32 will alway pre-allocate a single cluster for the root directory |
|
406 // |
|
407 // - The following calculations may look wierd (as the spec says that the FAT32 root dir |
|
408 // is not fixed) but for the purposes of this test we assume that root dir is only |
|
409 // one cluster in size, so we don't fill up the disk trying to fill up the root dir. |
|
410 // |
|
411 gRootDirEntries = gBytesPerCluster * 1 / KSizeOfFatDirEntry; // Maximum entries within default FAT32 root directory (before extension) |
|
412 gRootDirSectors = 0; // FAT32 has no fixed root directory sectors over which to skip |
|
413 gFatSizeSectors = BootSector.FatSectors32(); |
|
414 |
|
415 gRootSector = BootSector.ReservedSectors() + BootSector.NumberOfFats() * gFatSizeSectors; |
|
416 gFirstDataSector = gRootSector; |
|
417 |
|
418 gDataStartBytes = gFirstDataSector * BootSector.BytesPerSector(); |
|
419 gRootDirStart = (BootSector.RootClusterNum() - 2) * gBytesPerCluster + gDataStartBytes; |
|
420 |
|
421 gClusterRootDir = (big ? 2 : 2); |
|
422 gClusterScnDrv = (big ? 3 : 3); |
|
423 gClusterDir1 = (big ? 4 : 4); |
|
424 gClusterDir1ext = (big ? 4 : 5); |
|
425 gClusterDir2 = (big ? 6 : 7); |
|
426 gClusterDir2_Full = (big ? 7 : 8); |
|
427 gClusterDir2_SD3E = (big ? 8 : 9); |
|
428 gClusterDir2_SD23E = (big ? 9 : 10); |
|
429 gClusterDir2_AFull = (big ? 10 : 11); |
|
430 gClusterEndMaxDepth = (big ? 146 : 147); |
|
431 break; |
|
432 default: |
|
433 break; |
|
434 } |
|
435 |
|
436 gMaxDataCluster = gClusterDir2_AFull + 2 + (gFirstDataSector / BootSector.SectorsPerCluster() + 1); |
|
437 |
|
438 gFatTestEntries = MaxClusters(); |
|
439 if (gFatTestEntries > KMaxFatSize) |
|
440 gFatTestEntries = KMaxFatSize; |
|
441 } |
|
442 |
|
443 |
|
444 GLDEF_C void DumpBootSector() |
|
445 // |
|
446 // Display (in log) TFatBootSector structure |
|
447 // |
|
448 { |
|
449 RDebug::Print(_L("iBytesPerSector = %8d"), BootSector.BytesPerSector()); |
|
450 RDebug::Print(_L("iSectorsPerCluster = %8d"), BootSector.SectorsPerCluster()); |
|
451 RDebug::Print(_L("iReservedSectors = %8d"), BootSector.ReservedSectors()); |
|
452 RDebug::Print(_L("iNumberOfFats = %8d"), BootSector.NumberOfFats()); |
|
453 RDebug::Print(_L("iRootDirEntries = %8d"), BootSector.RootDirEntries()); |
|
454 RDebug::Print(_L("iTotalSectors = %8d"), BootSector.TotalSectors()); |
|
455 RDebug::Print(_L("iMediaDescriptor = %8d"), BootSector.MediaDescriptor()); |
|
456 RDebug::Print(_L("iFatSectors = %8d"), BootSector.FatSectors()); |
|
457 RDebug::Print(_L("iSectorsPerTrack = %8d"), BootSector.SectorsPerTrack()); |
|
458 RDebug::Print(_L("iNumberOfHeads = %8d"), BootSector.NumberOfHeads()); |
|
459 RDebug::Print(_L("iHiddenSectors = %8d"), BootSector.HiddenSectors()); |
|
460 RDebug::Print(_L("iHugeSectors = %8d"), BootSector.HugeSectors()); |
|
461 |
|
462 if (gDiskType == EFat32) |
|
463 { |
|
464 RDebug::Print(_L("iFatSectors32 = %8d"), BootSector.FatSectors32()); |
|
465 RDebug::Print(_L("iFATFlags = %8d"), BootSector.FATFlags()); |
|
466 RDebug::Print(_L("iVersionNumber = %8d"), BootSector.VersionNumber()); |
|
467 RDebug::Print(_L("iRootClusterNum = %8d (0x%08X)"), BootSector.RootClusterNum(), gRootDirStart); |
|
468 RDebug::Print(_L("iFSInfoSectorNum = %8d (0x%08X)"), BootSector.FSInfoSectorNum(), BootSector.FSInfoSectorNum() * BootSector.BytesPerSector()); |
|
469 RDebug::Print(_L("iBkBootRecSector = %8d (0x%08X)"), BootSector.BkBootRecSector(), BootSector.BkBootRecSector() * BootSector.BytesPerSector()); |
|
470 } |
|
471 } |
|
472 |
|
473 GLDEF_C void DumpFat(const TUint8* aFat=NULL) |
|
474 // |
|
475 // Dump to the log all those FAT entries which are non-zero |
|
476 // |
|
477 { |
|
478 TInt32 max = MaxClusters(); |
|
479 if (max > KMaxFatEntries) |
|
480 max = KMaxFatEntries; |
|
481 RDebug::Print(_L("---------------- DUMP OF FAT ---------------")); |
|
482 for (TInt32 i = 0; i < max; i++) |
|
483 { |
|
484 TInt32 val = GetFatEntry(i, aFat); |
|
485 TInt32 msk = 0x0FFFFFFF; |
|
486 switch (gDiskType) |
|
487 { |
|
488 case EFat32: |
|
489 msk = 0x0FFFFFFF; |
|
490 break; |
|
491 case EFat16: |
|
492 msk = 0xFFFF; |
|
493 break; |
|
494 case EFat12: |
|
495 msk = 0x0FFF; |
|
496 break; |
|
497 default: |
|
498 test(0); |
|
499 } |
|
500 if ((val & msk) == (0x0FFFFFFF & msk)) |
|
501 RDebug::Print(_L(" %8d -> EOC"), i); |
|
502 else if ((val & msk) == (0x0FFFFFF8 & msk)) |
|
503 RDebug::Print(_L(" %8d -> Media"), i); |
|
504 else if ((val & msk) == (0x0FFFFFF7 & msk)) |
|
505 RDebug::Print(_L(" %8d -> BAD"), i); |
|
506 else if (val > max) |
|
507 RDebug::Print(_L(" %8d -> 0x%08X"), i, val); |
|
508 else if (val != 0) |
|
509 RDebug::Print(_L(" %8d -> %d"), i, val); |
|
510 } |
|
511 RDebug::Print(_L("--------------------------------------------")); |
|
512 } |
|
513 |
|
514 GLDEF_C TDes* DirAttributes(TInt aAttrib) |
|
515 // |
|
516 // Return a pointer to a local buffer containing the attribute letters. |
|
517 // |
|
518 { |
|
519 LOCAL_D TBuf<6> str; |
|
520 LOCAL_D char* atr = "RHSVDA"; |
|
521 str.Fill(TText('-'), 6); |
|
522 for (TInt i = 0; i < 6; i++) |
|
523 if ((aAttrib >> i) & 1) |
|
524 str[i] = atr[i]; |
|
525 return &str; |
|
526 } |
|
527 |
|
528 GLDEF_C TBool IsValidDirEntry(TFatDirEntry* aDir) |
|
529 // |
|
530 // Test whether buffer is a valid normal directory entry |
|
531 // |
|
532 { |
|
533 // first character must be 0x05 or greater than space |
|
534 if (aDir->iData[0] < 0x21 && aDir->iData[0] != 0x05) |
|
535 return EFalse; |
|
536 // other characters must be not less than space |
|
537 for (TInt i = 1; i < 11; i++) |
|
538 if (aDir->iData[i] < 0x20) |
|
539 return EFalse; |
|
540 return ETrue; |
|
541 } |
|
542 |
|
543 GLDEF_C void GetLongNamePart(TDes16& aName, const TUint8* aEntry, TInt aPos, TInt aOffset, TInt aLength) |
|
544 // |
|
545 // Extract part of a long name entry into the name buffer. |
|
546 // |
|
547 // @param aName buffer to put name |
|
548 // @param aEntry directory entry raw data |
|
549 // @param aPos character in buffer to start name segment |
|
550 // @param aOffset offset in directory entry of the segment |
|
551 // @param aLength number of characters in the segment |
|
552 // |
|
553 { |
|
554 for (TInt i = 0; i < aLength; i++) |
|
555 { |
|
556 TInt at = i * 2 + aOffset; |
|
557 TInt ch = aEntry[at] + aEntry[at+1] * 256; |
|
558 aName[aPos++] = TText(ch); |
|
559 } |
|
560 } |
|
561 |
|
562 GLDEF_C void ExtractNameString(TDes16& aName, const TUint8* aEntry) |
|
563 // |
|
564 // Extract a long name part from a directory entry, truncate it at the first |
|
565 // NUL (0) character and put quotes round it. |
|
566 // |
|
567 { |
|
568 aName.SetLength(15); |
|
569 TInt len = aName.Length() - 1; |
|
570 TText qu = '\''; |
|
571 aName[0] = qu; |
|
572 GetLongNamePart(aName, aEntry, 1, 1, 5); |
|
573 GetLongNamePart(aName, aEntry, 6, 14, 6); |
|
574 GetLongNamePart(aName, aEntry, 12, 28, 2); |
|
575 TInt i; |
|
576 for (i = 0; i < len; i++) |
|
577 if (aName[i] == 0) |
|
578 break; |
|
579 aName[i++] = qu; |
|
580 aName.SetLength(i); |
|
581 } |
|
582 |
|
583 GLDEF_C TBool DumpDirEntry(TInt aNum, const TUint8* aEntry) |
|
584 // |
|
585 // Dump a single directory entry to the log. Return false if it was end of |
|
586 // directory or an invalid entry (and don't display it). |
|
587 // |
|
588 { |
|
589 TFatDirEntry* d = (TFatDirEntry*)aEntry; |
|
590 if (d->IsErased()) |
|
591 { |
|
592 //RDebug::Print(_L("%5d: ERASED"), aNum); |
|
593 } |
|
594 else if (d->IsEndOfDirectory()) |
|
595 { |
|
596 if (aNum > 0) |
|
597 RDebug::Print(_L("%5d: ------------- end of directory"), aNum); |
|
598 return EFalse; |
|
599 } |
|
600 else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName) |
|
601 { |
|
602 TBuf16<15> name; |
|
603 ExtractNameString(name, aEntry); |
|
604 TInt ord = aEntry[0]; |
|
605 if (ord & KDirLastLongEntry) |
|
606 RDebug::Print(_L("%5d: %-15S #%-2d LAST"), aNum, &name, ord & ~KDirLastLongEntry); |
|
607 else |
|
608 RDebug::Print(_L("%5d: %-15S #%-2d"), aNum, &name, ord & ~KDirLastLongEntry); |
|
609 } |
|
610 else if (!IsValidDirEntry(d)) |
|
611 { |
|
612 if (aNum > 0) |
|
613 RDebug::Print(_L("%5d: ============= INVALID ENTRY"), aNum); |
|
614 return EFalse; |
|
615 } |
|
616 else |
|
617 { |
|
618 TBuf<11> name; |
|
619 name.Copy(d->Name()); |
|
620 RDebug::Print(_L("%5d: '%S' %S start %-5d size %d"), |
|
621 aNum, &name, DirAttributes(d->Attributes()), d->StartCluster(), d->Size()); |
|
622 } |
|
623 return ETrue; |
|
624 } |
|
625 |
|
626 GLDEF_C void DumpDirCluster(const TUint8* aData, TInt aCluster=0) |
|
627 // |
|
628 // Dump directory entries until end of cluster or invalid/end entry found. |
|
629 // |
|
630 { |
|
631 if (aCluster > 2) |
|
632 aData += (aCluster-2) * gBytesPerCluster; |
|
633 for (TInt i = 0; i < gBytesPerCluster; i += KSizeOfFatDirEntry) |
|
634 { |
|
635 if (DumpDirEntry(i/KSizeOfFatDirEntry, aData)) |
|
636 aData += KSizeOfFatDirEntry; |
|
637 else |
|
638 break; |
|
639 } |
|
640 } |
|
641 |
|
642 GLDEF_C void DumpRootDir(const TUint8* aData) |
|
643 // |
|
644 // Dump the data area buffer, trying to interpret directory clusters (only look |
|
645 // at clusters which are marked as 'used' in the FAT). |
|
646 // |
|
647 { |
|
648 RDebug::Print(_L("Root dir @ 0x%08X:"), gRootDirStart); |
|
649 for (TInt i = 0; i < BootSector.RootDirEntries(); i++) |
|
650 { |
|
651 if (DumpDirEntry(i, aData)) |
|
652 aData += KSizeOfFatDirEntry; |
|
653 else |
|
654 break; |
|
655 } |
|
656 } |
|
657 |
|
658 GLDEF_C void DumpData(const TUint8* aFat, const TUint8* aDir) |
|
659 // |
|
660 // Dump the data area buffer, trying to interpret directory clusters (only look |
|
661 // at clusters which are marked as 'used' in the FAT). |
|
662 // |
|
663 { |
|
664 RDebug::Print(_L("--------------- DATA AREA ------------------")); |
|
665 if (gDiskType != EFat32) |
|
666 { |
|
667 DumpRootDir(aDir); |
|
668 } |
|
669 TInt max = (gFatTestEntries < gMaxDataCluster ? gFatTestEntries : gMaxDataCluster); |
|
670 for (TInt cluster = 2; cluster < max; cluster++) |
|
671 { |
|
672 if (GetFatEntry(cluster, aFat) != 0) |
|
673 { |
|
674 RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster)); |
|
675 DumpDirCluster(aDir+gDataStartBytes-gRootDirStart, cluster); |
|
676 } |
|
677 } |
|
678 RDebug::Print(_L("--------------------------------------------")); |
|
679 } |
|
680 |
|
681 GLDEF_C void DumpData(const TUint8* aFat, TInt aStart, TInt aEnd = -1) |
|
682 // |
|
683 // Dump clusters from disk (allows dumping of clusters not in our buffers). |
|
684 // Only look at clusters marked as 'used' in the FAT. Note that if aFat is |
|
685 // NULL the FAT entries will also be read from disk (slower but allows for ones |
|
686 // outside our copy in memory). |
|
687 // |
|
688 { |
|
689 if (aStart > gFatTestEntries) |
|
690 return; |
|
691 RDebug::Print(_L("--------------- DATA AREA ------------------")); |
|
692 if (aEnd > gFatTestEntries) |
|
693 aEnd = gFatTestEntries; |
|
694 if (aEnd < 0) |
|
695 aEnd = aStart + 1; |
|
696 if (aStart < 2 && gDiskType != EFat32) |
|
697 { |
|
698 HBufC8* buf=HBufC8::New(BootSector.RootDirEntries() * KSizeOfFatDirEntry); |
|
699 test(buf != NULL); |
|
700 TPtr8 ptr=buf->Des(); |
|
701 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
702 test(r==KErrNone); |
|
703 r=TheRawDisk.Read(gRootDirStart, ptr); |
|
704 test(r==KErrNone); |
|
705 TheRawDisk.Close(); |
|
706 DumpRootDir(buf->Ptr()); |
|
707 delete(buf); |
|
708 aStart = 2; |
|
709 } |
|
710 for (TInt cluster = aStart; cluster < aEnd; cluster++) |
|
711 { |
|
712 if (GetFatEntry(cluster, aFat) != 0) |
|
713 { |
|
714 HBufC8* buf=HBufC8::New(gBytesPerCluster); |
|
715 test(buf!=NULL); |
|
716 TPtr8 ptr=buf->Des(); |
|
717 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
718 test(r==KErrNone); |
|
719 r=TheRawDisk.Read(ClusterToByte(cluster), ptr); |
|
720 test(r==KErrNone); |
|
721 TheRawDisk.Close(); |
|
722 RDebug::Print(_L("Cluster %d @ 0x%08X:"), cluster, ClusterToByte(cluster)); |
|
723 DumpDirCluster(ptr.Ptr()); |
|
724 delete buf; |
|
725 } |
|
726 } |
|
727 RDebug::Print(_L("--------------------------------------------")); |
|
728 } |
|
729 |
|
730 GLDEF_C void DumpHex(const TUint8* aData, TInt aLen, TInt aBase=0) |
|
731 // |
|
732 // Dump a block of memory to the log in hex. |
|
733 // |
|
734 { |
|
735 for (TInt base = 0; base < aLen; base += 16) |
|
736 { |
|
737 TBuf<16*3+3+16+1> buf; |
|
738 TInt off; |
|
739 for (off = base; off < aLen && off < base + 16; off++) |
|
740 { |
|
741 buf.Append(TText(' ')); |
|
742 buf.AppendNumFixedWidth(aData[off], EHex, 2); |
|
743 } |
|
744 buf.Append(_L(" |")); |
|
745 for (off = base; off < aLen && off < base + 16; off++) |
|
746 { |
|
747 TUint8 ch = aData[off]; |
|
748 buf.Append(ch < 0x20 || ch > 0x7E ? TText('_') : TText(ch)); |
|
749 } |
|
750 buf.Append(_L("|")); |
|
751 RDebug::Print(_L("%04X: %S"), base+aBase, &buf); |
|
752 } |
|
753 } |
|
754 |
|
755 GLDEF_C void DumpHex(const TPtrC8& aData, TInt aLen, TInt aBase=0) |
|
756 // |
|
757 // Dump a block of memory to the log in hex. |
|
758 // |
|
759 { |
|
760 DumpHex(aData.Ptr(), aLen, aBase); |
|
761 } |
|
762 |
|
763 GLDEF_C void DumpHex(TInt aPos, TInt aLen, TInt aBase=0) |
|
764 // |
|
765 // Dump a block of memory to the log in hex. |
|
766 // |
|
767 { |
|
768 TPtr8 dirBuf=DirBufPtr->Des(); |
|
769 DumpHex(dirBuf.Ptr()+aPos, aLen, aBase); |
|
770 } |
|
771 |
|
772 GLDEF_C void Dump(TEntryInfo& aEntry) |
|
773 // |
|
774 // Dump an entry description to the log in hex |
|
775 // |
|
776 { |
|
777 RDebug::Print(_L("--- TEntryInfo 0x%08X, %d"), aEntry.iBytePos, aEntry.iLength); |
|
778 TInt len = aEntry.iLength*KSizeOfFatDirEntry; |
|
779 DumpHex(aEntry.iBytePos, len, aEntry.iBytePos); |
|
780 } |
|
781 |
|
782 LOCAL_C TInt GetStartCluster(TInt aCluster, TInt aEntry) |
|
783 // |
|
784 // Get the start cluster pertaining to a directory entry in a specific |
|
785 // directory cluster, return -1 if not available (invalid entry). |
|
786 // |
|
787 { |
|
788 HBufC8* buf=HBufC8::New(gBytesPerCluster*2); |
|
789 test(buf!=NULL); |
|
790 TPtr8 ptr=buf->Des(); |
|
791 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
792 test(r==KErrNone); |
|
793 r=TheRawDisk.Read(ClusterToByte(aCluster), ptr); |
|
794 test(r==KErrNone); |
|
795 TheRawDisk.Close(); |
|
796 RDebug::Print(_L("Cluster %d @ 0x%08X:"), aCluster, ClusterToByte(aCluster)); |
|
797 TFatDirEntry* d = (TFatDirEntry*)ptr.Ptr() + aEntry; |
|
798 while ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName && aEntry < gEntriesPerCluster) |
|
799 { |
|
800 if (d->IsErased() || d->IsEndOfDirectory()) |
|
801 break; |
|
802 ++aEntry; |
|
803 d = (TFatDirEntry*)ptr.Ptr() + aEntry; |
|
804 } |
|
805 TInt start = d->StartCluster(); |
|
806 if (d->IsErased()) |
|
807 start = -1; |
|
808 else if (d->IsEndOfDirectory()) |
|
809 start = -1; |
|
810 else if ((d->Attributes() & KDirAttrLongMask) == KDirAttrLongName) |
|
811 start = -1; |
|
812 else if (!IsValidDirEntry(d)) |
|
813 start = -1; |
|
814 delete buf; |
|
815 return start; |
|
816 } |
|
817 |
|
818 LOCAL_C void Format() |
|
819 { |
|
820 TInt nRes; |
|
821 |
|
822 #if 0 |
|
823 TFatFormatParam fmt; |
|
824 fmt.iFatType = EFat32; |
|
825 fmt.iSecPerCluster = 1; |
|
826 |
|
827 nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue, &fmt); |
|
828 #else |
|
829 nRes = FormatFatDrive(TheFs, CurrentDrive(), ETrue); |
|
830 #endif |
|
831 |
|
832 test(nRes == KErrNone); |
|
833 |
|
834 } |
|
835 |
|
836 LOCAL_C void CreateDeepDir(TFileName& aDir,TInt aDepth) |
|
837 // |
|
838 // Increase directory strucutre by aDepth starting with aDir. |
|
839 // |
|
840 { |
|
841 TFileName num; |
|
842 num.Num(1); |
|
843 num+=_L("\\"); |
|
844 TInt r; |
|
845 while(aDepth--) |
|
846 { |
|
847 num[0] = TText(aDepth % 26 + 'A'); |
|
848 aDir+=num; |
|
849 r=TheFs.MkDir(aDir); |
|
850 test(r==KErrNone); |
|
851 } |
|
852 } |
|
853 |
|
854 LOCAL_C void DeleteDeepDir(TFileName& aDir,TInt aDepth) |
|
855 // |
|
856 // Delete dir structure. |
|
857 // |
|
858 { |
|
859 TInt r; |
|
860 while(aDepth--) |
|
861 { |
|
862 r=TheFs.RmDir(aDir); |
|
863 test(r==KErrNone); |
|
864 aDir.SetLength(aDir.Length()-2); |
|
865 } |
|
866 } |
|
867 |
|
868 LOCAL_C void CreateMaxDepthDir(TFileName& aDir1,TFileName& aDir2) |
|
869 // |
|
870 // Create directory structure with max possible depth-1. |
|
871 // Achieved by using dir names of one character. |
|
872 // |
|
873 { |
|
874 //create dir structure with depth of 25 |
|
875 CreateDeepDir(aDir1,25); |
|
876 // split dir structure |
|
877 aDir2=aDir1; |
|
878 aDir2+=_L("a\\"); |
|
879 TInt r=TheFs.MkDir(aDir2); |
|
880 test(r==KErrNone); |
|
881 // create dir with depth of 126 directories - one short of max depth |
|
882 CreateDeepDir(aDir1,101); |
|
883 // create dir with depth of 90 |
|
884 CreateDeepDir(aDir2,64); |
|
885 } |
|
886 |
|
887 LOCAL_C void DeleteMaxDepthDir(TFileName&aDir1,TFileName&aDir2) |
|
888 // |
|
889 // Deletes max depth dir structure. |
|
890 // |
|
891 { |
|
892 DeleteDeepDir(aDir2,64); |
|
893 TInt r=TheFs.RmDir(aDir2); |
|
894 test(r==KErrNone); |
|
895 aDir2.SetLength(aDir2.Length()-2); |
|
896 DeleteDeepDir(aDir1,102); |
|
897 DeleteDeepDir(aDir1,24); |
|
898 } |
|
899 |
|
900 LOCAL_C void MakeVeryLongName(TFileName& aLong) |
|
901 // |
|
902 // appends a very long file name to aLong |
|
903 // |
|
904 { |
|
905 // create a name to take up 18 vfat entries - (1 sector + 2 entries) |
|
906 for(TInt i=0;i<234;++i) |
|
907 { |
|
908 TInt c='a'+i%26; |
|
909 aLong.Append(c); |
|
910 } |
|
911 } |
|
912 |
|
913 GLDEF_C void CreateLongNames(TFileName& aLong, TInt aClusters) |
|
914 // |
|
915 // Creates entries to fill up the number of directory clusters |
|
916 // |
|
917 { |
|
918 TInt len = aLong.Length(); // length of directory prefix |
|
919 MakeVeryLongName(aLong); |
|
920 TInt count = 0; |
|
921 RFile temp; |
|
922 for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19) |
|
923 { |
|
924 aLong[len+0] = TText(count/26 + 'A'); |
|
925 aLong[len+1] = TText(count%26 + 'A'); |
|
926 count++; |
|
927 TInt r=temp.Create(TheFs,aLong,EFileShareAny); |
|
928 test(r==KErrNone); |
|
929 temp.Close(); |
|
930 } |
|
931 } |
|
932 |
|
933 GLDEF_C void DeleteLongNames(TFileName& aLong, TInt aClusters) |
|
934 // |
|
935 // Deletes entries created by CreateLongNames() |
|
936 // |
|
937 { |
|
938 TInt len = aLong.Length(); // length of directory prefix |
|
939 MakeVeryLongName(aLong); |
|
940 TInt count = 0; |
|
941 for (TInt i = 0; i < aClusters * gEntriesPerCluster; i += 19) |
|
942 { |
|
943 aLong[len+0] = TText(count/26 + 'A'); |
|
944 aLong[len+1] = TText(count%26 + 'A'); |
|
945 count++; |
|
946 TInt r=TheFs.Delete(aLong); |
|
947 test(r==KErrNone || r==KErrNotFound); |
|
948 } |
|
949 } |
|
950 |
|
951 LOCAL_C void DeleteRootDir(TInt aNum=0) |
|
952 // |
|
953 // Delete all entries in the root directory up to the last - aNum |
|
954 // |
|
955 { |
|
956 test.Next(_L("Delete Root Directory Entries")); |
|
957 TInt maxRootEntries = gRootDirEntries; |
|
958 TFileName name=_L("\\???xxx"); |
|
959 TInt count=0; |
|
960 TInt entriesSoFar=2; |
|
961 TInt r; |
|
962 count = 0; |
|
963 for (entriesSoFar=0; entriesSoFar<maxRootEntries - aNum; entriesSoFar+=2) |
|
964 { |
|
965 name[1]=(TUint16)(count/26/26+'a'); |
|
966 name[2]=(TUint16)(count/26%26+'a'); |
|
967 name[3]=(TUint16)(count%26+'a'); |
|
968 r=TheFs.Delete(name); |
|
969 test(r==KErrNone || r==KErrNotFound); |
|
970 ++count; |
|
971 } |
|
972 } |
|
973 |
|
974 LOCAL_C void CreateRootDir() |
|
975 // |
|
976 // fill up root directory to 1 clusters by creating entries and then deleting |
|
977 // them except the last. |
|
978 // |
|
979 { |
|
980 test.Next(_L("Create Root Directory Entries")); |
|
981 TInt maxRootEntries = gRootDirEntries; |
|
982 TFileName name=_L("\\???xxx"); |
|
983 TInt count=0; |
|
984 TInt entriesSoFar=2; |
|
985 TInt r; |
|
986 RFile f; |
|
987 for (entriesSoFar=0; entriesSoFar<maxRootEntries; entriesSoFar+=2) |
|
988 { |
|
989 name[1]=(TUint16)(count/26/26+'a'); |
|
990 name[2]=(TUint16)(count/26%26+'a'); |
|
991 name[3]=(TUint16)(count%26+'a'); |
|
992 r=f.Create(TheFs, name, EFileWrite); |
|
993 test(r==KErrNone); |
|
994 f.Close(); |
|
995 ++count; |
|
996 } |
|
997 DeleteRootDir(1); |
|
998 } |
|
999 |
|
1000 LOCAL_C void FillUpRootDir(TInt aFree=0) |
|
1001 // |
|
1002 // fill up root directory |
|
1003 // |
|
1004 { |
|
1005 TInt maxRootEntries = gRootDirEntries - aFree; |
|
1006 TFileName dir=_L("\\??\\"); |
|
1007 TInt count=0; |
|
1008 TInt entriesSoFar=2; |
|
1009 TInt r; |
|
1010 while(entriesSoFar<maxRootEntries) |
|
1011 { |
|
1012 dir[1]=(TUint16)(count/26+'a'); |
|
1013 dir[2]=(TUint16)(count%26+'a'); |
|
1014 r=TheFs.MkDir(dir); |
|
1015 test(r==KErrNone); |
|
1016 entriesSoFar+=2; |
|
1017 ++count; |
|
1018 } |
|
1019 } |
|
1020 |
|
1021 LOCAL_C void UnFillUpRootDir(TInt aFree=0) |
|
1022 // |
|
1023 // reverse changes from FillUpRootDir() |
|
1024 // |
|
1025 { |
|
1026 TFileName dir=_L("\\??\\"); |
|
1027 TInt entriesSoFar=gRootDirEntries-aFree; |
|
1028 TInt count=0; |
|
1029 TInt r; |
|
1030 while(entriesSoFar>2) |
|
1031 { |
|
1032 dir[1]=TUint16(count/26+'a'); |
|
1033 dir[2]=TUint16(count%26+'a'); |
|
1034 r=TheFs.RmDir(dir); |
|
1035 test(r==KErrNone); |
|
1036 entriesSoFar-=2; |
|
1037 ++count; |
|
1038 } |
|
1039 } |
|
1040 |
|
1041 LOCAL_C void DeleteDirectoryStructure() |
|
1042 // |
|
1043 // deletes the directory structure |
|
1044 // |
|
1045 { |
|
1046 test.Next(_L("Delete Directory Structure")); |
|
1047 TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\almostfull\\")); |
|
1048 test(r==KErrNone); |
|
1049 TInt entriesNeeded=(gEntriesPerCluster-2) / 2; //7*2entries + . + .. = full sector |
|
1050 for (TInt i = 0; i < entriesNeeded; i++) |
|
1051 { |
|
1052 TFileName file=_L("\\scndrv\\dir2\\full\\__a"); |
|
1053 file.AppendNum(i); |
|
1054 r=TheFs.Delete(file); |
|
1055 test(r==KErrNone||r==KErrNotFound); |
|
1056 } |
|
1057 r=TheFs.RmDir(_L("\\scndrv\\dir2\\full\\")); |
|
1058 test(r==KErrNone); |
|
1059 r=TheFs.RmDir(_L("\\scndrv\\dir2\\")); |
|
1060 test(r==KErrNone); |
|
1061 TFileName veryLongName=(_L("\\scndrv\\dir1\\")); |
|
1062 MakeVeryLongName(veryLongName); |
|
1063 r=TheFs.Delete(veryLongName); |
|
1064 test(r==KErrNone); |
|
1065 r=TheFs.RmDir(_L("\\scndrv\\dir1\\")); |
|
1066 test(r==KErrNone); |
|
1067 r=TheFs.RmDir(_L("\\scndrv\\")); |
|
1068 test(r==KErrNone); |
|
1069 } |
|
1070 |
|
1071 LOCAL_C void CreateDirectoryStructure() |
|
1072 // |
|
1073 // creates the directory structure |
|
1074 // |
|
1075 { |
|
1076 test.Next(_L("Create Directory Structure")); |
|
1077 // cluster 3 (root dir is cluster 2) |
|
1078 TInt r=TheFs.MkDir(_L("\\scndrv\\")); |
|
1079 test(r==KErrNone); |
|
1080 // cluster 4 |
|
1081 r=TheFs.MkDir(_L("\\scndrv\\dir1\\")); |
|
1082 test(r==KErrNone); |
|
1083 TFileName veryLongName=(_L("\\scndrv\\dir1\\")); |
|
1084 MakeVeryLongName(veryLongName); |
|
1085 RFile f; |
|
1086 // cluster 5 |
|
1087 r=f.Create(TheFs,veryLongName,EFileShareAny); |
|
1088 test(r==KErrNone); |
|
1089 r=f.SetSize(512); |
|
1090 test(r==KErrNone); |
|
1091 f.Close(); |
|
1092 // cluster 6 |
|
1093 r=TheFs.MkDir(_L("\\scndrv\\dir2\\")); |
|
1094 test(r==KErrNone); |
|
1095 // cluster 7 |
|
1096 r=TheFs.MkDir(_L("\\scndrv\\dir2\\full\\")); |
|
1097 test(r==KErrNone); |
|
1098 // cluster 8 |
|
1099 r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); |
|
1100 test(r==KErrNone); |
|
1101 // cluster 9 |
|
1102 r=TheFs.MkDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); |
|
1103 test(r==KErrNone); |
|
1104 // cluster 10 |
|
1105 r=TheFs.MkDir(_L("\\scndrv\\dir2\\almostfull\\")); |
|
1106 test(r==KErrNone); |
|
1107 // cluster 11-17 |
|
1108 TInt entriesNeeded=(gEntriesPerCluster-2) / 2; //7*2entries + . + .. = full sector |
|
1109 for (TInt i = 0; i < entriesNeeded; i++) |
|
1110 { |
|
1111 TFileName file=_L("\\scndrv\\dir2\\full\\__a"); |
|
1112 file.AppendNum(i); |
|
1113 LastInFull = file; |
|
1114 r=f.Create(TheFs,file,EFileShareAny); |
|
1115 test(r==KErrNone); |
|
1116 if (i < 7) |
|
1117 { |
|
1118 r=f.SetSize(512); |
|
1119 test(r==KErrNone); |
|
1120 } |
|
1121 f.Close(); |
|
1122 } |
|
1123 // cluster 18-19 |
|
1124 TInt charLength=13*4+1; // name to take up 6 entries |
|
1125 TFileName file1=_L("\\scndrv\\dir2\\almostfull\\"); |
|
1126 while(charLength--) |
|
1127 { |
|
1128 TInt c='A'+charLength%26; |
|
1129 file1.Append(c); |
|
1130 } |
|
1131 TFileName file2=file1; |
|
1132 file1.AppendNum(1); |
|
1133 file2.AppendNum(2); |
|
1134 r=f.Create(TheFs,file1,EFileShareAny); |
|
1135 test(r==KErrNone); |
|
1136 r=f.SetSize(512); |
|
1137 test(r==KErrNone); |
|
1138 f.Close(); |
|
1139 r=f.Create(TheFs,file2,EFileShareAny); |
|
1140 test(r==KErrNone); |
|
1141 r=f.SetSize(512); |
|
1142 test(r==KErrNone); |
|
1143 f.Close(); |
|
1144 } |
|
1145 |
|
1146 LOCAL_C TUint8* DirPtr(TInt aOffset) |
|
1147 // |
|
1148 // Return a pointer to the offset in the dir buffer, or in the special |
|
1149 // extension buffer if the dir buffer isn't large enough. If the extension |
|
1150 // buffer is needed, it is read from disk when it is created (2 clusters, to |
|
1151 // allow for entries spanning cluster boundaries). Errors will occur if |
|
1152 // another cluster is needed before the extension has been released. |
|
1153 // |
|
1154 // Note that if an extension buffer is allocated then writing a dir buffer to |
|
1155 // disk will also write the extension buffer and any changes made in it. |
|
1156 // |
|
1157 { |
|
1158 // if the offset is in store, return its byte address |
|
1159 if (aOffset < DirBufPtr->Des().MaxLength()) |
|
1160 return (TUint8*)DirBufPtr->Ptr() + aOffset; |
|
1161 // not in main buffer, see if extension is allocated already |
|
1162 if (!ExtBufPtr) |
|
1163 { |
|
1164 // allocate buffer for 2 clusters, starting at the cluster which |
|
1165 // contains aOffset |
|
1166 ExtBufLen = 2 * gBytesPerCluster; |
|
1167 ExtBufPtr = HBufC8::New(ExtBufLen); |
|
1168 test(ExtBufPtr != NULL); |
|
1169 // read the clusters in |
|
1170 ExtBufAdd = aOffset - aOffset % gBytesPerCluster; |
|
1171 TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2; |
|
1172 RDebug::Print(_L("Extension buffer for cluster %d allocated"), clust); |
|
1173 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1174 test(r==KErrNone); |
|
1175 TPtr8 des(ExtBufPtr->Des()); |
|
1176 r=TheRawDisk.Read(gRootDirStart + ExtBufAdd, des); |
|
1177 test(r==KErrNone); |
|
1178 TheRawDisk.Close(); |
|
1179 } |
|
1180 // convert to offset in the extension buffer |
|
1181 aOffset -= ExtBufAdd; |
|
1182 if (aOffset >= ExtBufLen) |
|
1183 { |
|
1184 test.Printf(_L("*** ERROR: tried to access cluster %d not in store\n"), |
|
1185 (aOffset + ExtBufAdd) / gBytesPerCluster + 2); |
|
1186 test(0); |
|
1187 } |
|
1188 return (TUint8*)ExtBufPtr->Ptr() + aOffset; |
|
1189 } |
|
1190 |
|
1191 LOCAL_C void DirPtrFree() |
|
1192 // |
|
1193 // Free the extension buffer and zero the references to it. |
|
1194 // |
|
1195 { |
|
1196 if (ExtBufPtr) |
|
1197 { |
|
1198 TInt clust = (ExtBufAdd - (gDataStartBytes - gRootDirStart)) /gBytesPerCluster + 2; |
|
1199 RDebug::Print(_L("Extension buffer for cluster %d deleted"), clust); |
|
1200 delete ExtBufPtr; |
|
1201 ExtBufPtr = NULL; |
|
1202 ExtBufAdd = 0; |
|
1203 ExtBufLen = 0; |
|
1204 } |
|
1205 } |
|
1206 |
|
1207 LOCAL_C void ReadDirDisk(TDes8& aDirBuf, TInt aCluster = -1) |
|
1208 // |
|
1209 // reads directory section of disk into buffer |
|
1210 // |
|
1211 { |
|
1212 test(aCluster != 1); |
|
1213 |
|
1214 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1215 test(r==KErrNone); |
|
1216 |
|
1217 if (aCluster == -1) // all clusters ? |
|
1218 { |
|
1219 r=TheRawDisk.Read(gRootDirStart, aDirBuf); |
|
1220 } |
|
1221 else if (aCluster == 0) // root directory cluster |
|
1222 { |
|
1223 TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster); |
|
1224 r=TheRawDisk.Read(gRootDirStart, dirPtr); |
|
1225 } |
|
1226 else |
|
1227 { |
|
1228 // directory buffer starts at root directory, so |
|
1229 // calculate offset from there. |
|
1230 TInt pos = ((aCluster - 2) * gBytesPerCluster) + |
|
1231 (gRootDirSectors * BootSector.BytesPerSector()); |
|
1232 TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster); |
|
1233 r=TheRawDisk.Read(gRootDirStart + pos, dirPtr); |
|
1234 } |
|
1235 |
|
1236 test(r==KErrNone); |
|
1237 TheRawDisk.Close(); |
|
1238 } |
|
1239 |
|
1240 LOCAL_C void ReadFatDisk(TDes8& aFatBuf) |
|
1241 // |
|
1242 // reads fat section of disk info buffer |
|
1243 // |
|
1244 { |
|
1245 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1246 test(r==KErrNone); |
|
1247 r=TheRawDisk.Read(gFatStartBytes, aFatBuf); |
|
1248 test(r==KErrNone); |
|
1249 TheRawDisk.Close(); |
|
1250 } |
|
1251 |
|
1252 LOCAL_C void WriteDirDisk(TDes8& aDirBuf, TInt aCluster = -1) |
|
1253 // |
|
1254 // writes dir buffer to disk |
|
1255 // |
|
1256 { |
|
1257 test(aCluster != 1); |
|
1258 |
|
1259 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1260 test(r==KErrNone); |
|
1261 |
|
1262 if (aCluster == -1) |
|
1263 { |
|
1264 r=TheRawDisk.Write(gRootDirStart, aDirBuf); |
|
1265 } |
|
1266 else if (aCluster == 0) // root directory cluster |
|
1267 { |
|
1268 TPtr8 dirPtr = aDirBuf.MidTPtr(0, gBytesPerCluster); |
|
1269 r=TheRawDisk.Write(gRootDirStart, dirPtr); |
|
1270 } |
|
1271 else |
|
1272 { |
|
1273 // directory buffer starts at root directory, so |
|
1274 // calculate offset from there. |
|
1275 TInt pos = ((aCluster - 2) * gBytesPerCluster) + |
|
1276 (gRootDirSectors * BootSector.BytesPerSector()); |
|
1277 TPtr8 dirPtr = aDirBuf.MidTPtr(pos, gBytesPerCluster); |
|
1278 r=TheRawDisk.Write(gRootDirStart + pos, dirPtr); |
|
1279 } |
|
1280 |
|
1281 test(r==KErrNone); |
|
1282 if (ExtBufPtr) |
|
1283 { |
|
1284 TPtr8 des(ExtBufPtr->Des()); |
|
1285 r=TheRawDisk.Write(gRootDirStart + ExtBufAdd, des); |
|
1286 test(r==KErrNone); |
|
1287 } |
|
1288 TheRawDisk.Close(); |
|
1289 } |
|
1290 |
|
1291 LOCAL_C void WriteFatDisk(TDes8& aFatBuf, TInt aStart=0) |
|
1292 // |
|
1293 // writes fat buffer to disk |
|
1294 // |
|
1295 { |
|
1296 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1297 test(r==KErrNone); |
|
1298 TInt fatCount=BootSector.NumberOfFats() - aStart; |
|
1299 TInt pos = gFatStartBytes + aStart * gFatSizeSectors*BootSector.BytesPerSector(); |
|
1300 while(fatCount--) |
|
1301 { |
|
1302 r=TheRawDisk.Write(pos, aFatBuf); |
|
1303 test(r==KErrNone); |
|
1304 pos += gFatSizeSectors*BootSector.BytesPerSector(); |
|
1305 } |
|
1306 TheRawDisk.Close(); |
|
1307 } |
|
1308 |
|
1309 LOCAL_C void WriteReservedId(TInt aBytePos) |
|
1310 // |
|
1311 // write reserved id to byte 19 of entry starting at aBytePos |
|
1312 // |
|
1313 { |
|
1314 TUint8* pEntry=DirPtr(aBytePos); |
|
1315 pEntry[19]=1; |
|
1316 } |
|
1317 |
|
1318 LOCAL_C void WriteEndOfDir(TInt aBytePos) |
|
1319 // |
|
1320 // write end of directory marker to entry starting at aBytePos |
|
1321 // |
|
1322 { |
|
1323 TUint8* pEntry=DirPtr(aBytePos); |
|
1324 Mem::FillZ(pEntry,KFatDirNameSize); |
|
1325 } |
|
1326 |
|
1327 LOCAL_C void WriteDelete(TInt aBytePos,TInt aNum) |
|
1328 // |
|
1329 // writes 0xe5 to entries starting at aBytePos |
|
1330 // |
|
1331 { |
|
1332 TUint8* pEntry=DirPtr(aBytePos); |
|
1333 while(aNum--) |
|
1334 { |
|
1335 pEntry[0]=0xE5; |
|
1336 pEntry+=KSizeOfFatDirEntry; |
|
1337 } |
|
1338 } |
|
1339 |
|
1340 LOCAL_C void WriteCopyDir(TInt aSrc, TInt aDst) |
|
1341 // |
|
1342 // Copy one directory entry over another |
|
1343 // |
|
1344 { |
|
1345 TUint8* pSrc=DirPtr(aSrc); |
|
1346 TUint8* pDst=DirPtr(aDst); |
|
1347 Mem::Copy(pDst, pSrc, KSizeOfFatDirEntry); |
|
1348 } |
|
1349 |
|
1350 LOCAL_C void InitialiseBuffers() |
|
1351 // |
|
1352 // reads disk into buffers |
|
1353 // |
|
1354 { |
|
1355 gFatTestEntries = MaxClusters(); |
|
1356 if (gFatTestEntries > KMaxFatSize) |
|
1357 gFatTestEntries = KMaxFatSize; |
|
1358 gFatTestSize = PosInBytes(gFatTestEntries); |
|
1359 FatBufPtr=HBufC8::New(gFatTestSize); |
|
1360 test(FatBufPtr!=NULL); |
|
1361 DirBufPtr=HBufC8::New(DirBufferSize()); |
|
1362 test(DirBufPtr!=NULL); |
|
1363 |
|
1364 // Buffers for reading from disk |
|
1365 FatDiskPtr=HBufC8::New(gFatTestSize); |
|
1366 test(FatDiskPtr!=NULL); |
|
1367 DirDiskPtr=HBufC8::New(DirBufferSize()); |
|
1368 test(DirDiskPtr!=NULL); |
|
1369 } |
|
1370 |
|
1371 LOCAL_C TBool IsSameAsDrive(const TDes8& aFatBuf,const TDes8& aDirBuf) |
|
1372 // |
|
1373 // compares the two bufs passed in with those on disk |
|
1374 // |
|
1375 { |
|
1376 TPtr8 fatDisk=FatDiskPtr->Des(); |
|
1377 TPtr8 dirDisk=DirDiskPtr->Des(); |
|
1378 ReadDirDisk(dirDisk); |
|
1379 ReadFatDisk(fatDisk); |
|
1380 TBool fatOk = (aFatBuf.Compare(fatDisk)==0); |
|
1381 TBool dirOk = (aDirBuf.Compare(dirDisk)==0); |
|
1382 if (!fatOk) |
|
1383 { |
|
1384 TInt i = FindUnMatch(aFatBuf.Ptr(), fatDisk.Ptr(), fatDisk.Length()); |
|
1385 switch (gDiskType) |
|
1386 { |
|
1387 case EFat32: |
|
1388 i /= 4; |
|
1389 |
|
1390 if(i == 1) |
|
1391 {//-- mismatch in FAT[1] for FAT16/FAT32 it is OK because FAT[1] is used by volume finalisation |
|
1392 //-- to store Volume Clean Shutdown flag |
|
1393 fatOk = ETrue; |
|
1394 } |
|
1395 |
|
1396 break; |
|
1397 |
|
1398 case EFat16: |
|
1399 i /= 2; |
|
1400 |
|
1401 if(i == 1) |
|
1402 {//-- mismatch in FAT[1] for FAT16/FAT32 it is OK because FAT[1] is used by volume finalisation |
|
1403 //-- to store Volume Clean Shutdown flag |
|
1404 fatOk = ETrue; |
|
1405 } |
|
1406 |
|
1407 break; |
|
1408 |
|
1409 case EFat12: |
|
1410 i = i*2 / 3; |
|
1411 if (GetFatEntry(i, aFatBuf.Ptr()) == GetFatEntry(i, fatDisk.Ptr())) |
|
1412 ++i; |
|
1413 break; |
|
1414 default: |
|
1415 test(0); |
|
1416 } |
|
1417 |
|
1418 if(fatOk && i==1) |
|
1419 { |
|
1420 test.Printf(_L("Skipping FAT[1] entry for FAT16/32 \n"), i); |
|
1421 } |
|
1422 else |
|
1423 { |
|
1424 test.Printf(_L("FAT entry %d different from expected\n"), i); |
|
1425 |
|
1426 RDebug::Print(_L("Expected:\n")); |
|
1427 DumpFat(aFatBuf.Ptr()); |
|
1428 RDebug::Print(_L("Actual:\n")); |
|
1429 DumpFat(fatDisk.Ptr()); |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 if (!dirOk) |
|
1434 { |
|
1435 TInt i = FindUnMatch(aDirBuf.Ptr(), dirDisk.Ptr(), dirDisk.Length()); |
|
1436 TInt clust = ByteToCluster(i); |
|
1437 TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry; |
|
1438 test.Printf(_L("DIR different from expected\n")); |
|
1439 test.Printf(_L(" at pos %d sector %d cluster %d entry %d:\n"), i, i / BootSector.BytesPerSector(), clust, entry); |
|
1440 |
|
1441 RDebug::Print(_L("Expected:\n")); |
|
1442 DumpHex(aDirBuf.Ptr() + i, 32); |
|
1443 RDebug::Print(_L("-------------")); |
|
1444 RDebug::Print(_L("Actual:\n")); |
|
1445 DumpHex(dirDisk.Ptr() + i, 32); |
|
1446 |
|
1447 RDebug::Print(_L("Expected:\n")); |
|
1448 DumpData(aFatBuf.Ptr(), aDirBuf.Ptr()); |
|
1449 RDebug::Print(_L("Actual:\n")); |
|
1450 DumpData(fatDisk.Ptr(), dirDisk.Ptr()); |
|
1451 } |
|
1452 else if (ExtBufPtr) |
|
1453 { |
|
1454 HBufC8* extPtr = HBufC8::New(ExtBufLen); |
|
1455 test(extPtr != NULL); |
|
1456 TInt r=TheRawDisk.Open(TheFs,gSessionPath[0]-'A'); |
|
1457 test(r==KErrNone); |
|
1458 TPtr8 des(extPtr->Des()); |
|
1459 r=TheRawDisk.Read(ExtBufAdd+gRootDirStart, des); |
|
1460 test(r==KErrNone); |
|
1461 TheRawDisk.Close(); |
|
1462 TInt i = FindUnMatch(ExtBufPtr->Ptr(), extPtr->Ptr(), ExtBufLen); |
|
1463 if (i >= 0) |
|
1464 { |
|
1465 TInt extcl = (ExtBufAdd - (gDataStartBytes-gRootDirStart)) / gBytesPerCluster + 2; |
|
1466 TInt clust = i / gBytesPerCluster; |
|
1467 TInt entry = i % gBytesPerCluster / KSizeOfFatDirEntry; |
|
1468 test.Printf(_L("DIR different from expected\n")); |
|
1469 test.Printf(_L(" at cluster %d entry %d:\n"), extcl+clust, entry); |
|
1470 DumpHex(ExtBufPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32); |
|
1471 RDebug::Print(_L("-------------")); |
|
1472 DumpHex(extPtr->Ptr() + clust * gBytesPerCluster + entry * KSizeOfFatDirEntry, 32); |
|
1473 // RDebug::Print(_L("Expected:\n")); |
|
1474 // DumpData(aFatBuf.Ptr(), aDirBuf.Ptr()); |
|
1475 // RDebug::Print(_L("Actual:\n")); |
|
1476 // DumpData(fatDisk.Ptr(), dirDisk.Ptr()); |
|
1477 dirOk = EFalse; |
|
1478 } |
|
1479 delete extPtr; |
|
1480 } |
|
1481 |
|
1482 return(fatOk && dirOk); |
|
1483 } |
|
1484 |
|
1485 LOCAL_C void WriteErased(TEntryInfo aTrg,TInt aToDelete) |
|
1486 // |
|
1487 // writes erased marker, starting at dos entry and working backwards |
|
1488 // used to simulate a part entry40*BootSector.BytesPerSector() |
|
1489 // |
|
1490 { |
|
1491 TInt toStart=aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry; |
|
1492 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1493 while(aToDelete--) |
|
1494 { |
|
1495 dirBuf[toStart]=0xE5; |
|
1496 toStart-=KSizeOfFatDirEntry; |
|
1497 } |
|
1498 } |
|
1499 |
|
1500 LOCAL_C void CreatePartialEntry(TEntryInfo aTrg,TInt aToDelete,TBool aAddEOfDir) |
|
1501 // |
|
1502 // creates a partial entry |
|
1503 // |
|
1504 { |
|
1505 WriteErased(aTrg,aToDelete); |
|
1506 if(aAddEOfDir) |
|
1507 WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry); |
|
1508 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1509 WriteDirDisk(dirBuf); |
|
1510 } |
|
1511 |
|
1512 LOCAL_C TBool TestPartialEntry(TEntryInfo aEntry) |
|
1513 // |
|
1514 // tests that scandrive deals with a partial entry and returns the result |
|
1515 // |
|
1516 { |
|
1517 test.Next(_L("TestPartialEntry")); |
|
1518 TInt r=TheFs.ScanDrive(gSessionPath); |
|
1519 test(r==KErrNone); |
|
1520 WriteDelete(aEntry.iBytePos,aEntry.iLength); |
|
1521 |
|
1522 TPtr8 fatBuf=FatBufPtr->Des(); |
|
1523 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1524 |
|
1525 TBool res=IsSameAsDrive(fatBuf,dirBuf); |
|
1526 return(res); |
|
1527 } |
|
1528 |
|
1529 LOCAL_C void CreateMatchingEntry(TEntryInfo aTrg,TEntryInfo aSrc,TBool aAddEOfDir) |
|
1530 // |
|
1531 // creates matching entry |
|
1532 // |
|
1533 { |
|
1534 test.Next(_L("Create entry with start cluster already used")); |
|
1535 TUint8* src = DirPtr(aSrc.iBytePos); |
|
1536 TUint8* dst = DirPtr(aTrg.iBytePos); |
|
1537 Mem::Copy(dst, src, aSrc.iLength*KSizeOfFatDirEntry); |
|
1538 WriteReservedId(aTrg.iBytePos+(aTrg.iLength-1)*KSizeOfFatDirEntry); |
|
1539 if(aAddEOfDir) |
|
1540 WriteEndOfDir(aTrg.iBytePos+aTrg.iLength*KSizeOfFatDirEntry); |
|
1541 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1542 WriteDirDisk(dirBuf); |
|
1543 } |
|
1544 |
|
1545 LOCAL_C TBool TestMatchingEntry(TEntryInfo aToDelete) |
|
1546 // |
|
1547 // tests that scandrive deals with matching entries correctly |
|
1548 // |
|
1549 { |
|
1550 test.Next(_L("TestMatchingEntries")); |
|
1551 WriteDelete(aToDelete.iBytePos,aToDelete.iLength); |
|
1552 TInt r=TheFs.ScanDrive(gSessionPath); |
|
1553 test(r==KErrNone); |
|
1554 |
|
1555 TPtr8 fatBuf=FatBufPtr->Des(); |
|
1556 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1557 |
|
1558 TBool res=IsSameAsDrive(fatBuf,dirBuf); |
|
1559 DirPtrFree(); |
|
1560 return(res); |
|
1561 } |
|
1562 |
|
1563 |
|
1564 LOCAL_C void TestExtendedChars() |
|
1565 // |
|
1566 // tests that extended characters corresponding to ISO Latin 1 |
|
1567 // characters 128-255 are recognised as valid by scandrive |
|
1568 // |
|
1569 { |
|
1570 test.Next(_L("TestExtendedChars()")); |
|
1571 Format(); |
|
1572 |
|
1573 _LIT(KRoot,"\\"); |
|
1574 CDir* dirs; |
|
1575 // check no entries in the root directory |
|
1576 TInt r=TheFs.GetDir(KRoot,KEntryAttMaskSupported,ESortNone,dirs); |
|
1577 test(r==KErrNone); |
|
1578 test(dirs->Count()==0); |
|
1579 delete(dirs); |
|
1580 dirs=NULL; |
|
1581 |
|
1582 // create file |
|
1583 _LIT(KOrigShortName,"P_SSI.TXT"); |
|
1584 |
|
1585 //_LIT(KTestFile,"\\p\xE4ssi.txt"); //-- this causes problems for VC6 and default locale different from English |
|
1586 TBuf<64> TestFileName(_L("\\p$ssi.txt")); |
|
1587 TestFileName[2] = 0xe4; //-- replace '$' with this code |
|
1588 |
|
1589 //_LIT(KExtShortName,"P\xC4SSI.TXT"); //-- this causes problems for VC6 and default locale different from English |
|
1590 TBuf<64> ExtShortName(_L("P$SSI.TXT")); |
|
1591 ExtShortName[1] = 0xC4; //-- replace '$' with this code |
|
1592 |
|
1593 |
|
1594 RFile file; |
|
1595 r=file.Replace(TheFs,TestFileName,EFileShareExclusive); |
|
1596 test(r==KErrNone); |
|
1597 file.Close(); |
|
1598 |
|
1599 // get short name |
|
1600 TFileName shortName; |
|
1601 r=TheFs.GetShortName(TestFileName,shortName); |
|
1602 test(r==KErrNone); |
|
1603 test(shortName==KOrigShortName); |
|
1604 |
|
1605 // must be first entry in root, modify to read like |
|
1606 // a windows-generated short name (ie. contains extended character) |
|
1607 DumpData(NULL, 0, 20); |
|
1608 TInt bytePos=ClusterEntryToBytes(0,1); |
|
1609 RRawDisk raw; |
|
1610 r=raw.Open(TheFs,gSessionPath[0]-'A'); |
|
1611 test(r==KErrNone); |
|
1612 TBuf8<1> buf(1); |
|
1613 |
|
1614 //-- change 2nd character in the short name (Fat DOS entry) |
|
1615 buf[0]=(TUint8)'\xC4'; |
|
1616 r=raw.Write(gRootDirStart+bytePos+1,buf); |
|
1617 test(r==KErrNone); |
|
1618 |
|
1619 //-- fix the fiddled short name checksum in the corresponding VFat entry |
|
1620 bytePos=ClusterEntryToBytes(0,0); |
|
1621 buf[0]=(TUint8)0x2f; |
|
1622 r=raw.Write(gRootDirStart+bytePos+13,buf); |
|
1623 test(r==KErrNone); |
|
1624 |
|
1625 // retrieve short name from media. |
|
1626 // Note: do not use RFs::GetShortName() as its behaviours are code page dependent. |
|
1627 bytePos=ClusterEntryToBytes(0,1); |
|
1628 TBuf8<11> shortNameBuf8; |
|
1629 r=raw.Read(gRootDirStart+bytePos,shortNameBuf8); |
|
1630 test(r==KErrNone); |
|
1631 shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8); |
|
1632 shortName.Copy(shortNameBuf8); |
|
1633 raw.Close(); |
|
1634 |
|
1635 |
|
1636 test(shortName==ExtShortName); |
|
1637 DumpData(NULL, 0, 20); |
|
1638 //TheFs.SetDebugRegister(KFSYS); |
|
1639 r=TheFs.ScanDrive(gSessionPath); |
|
1640 TheFs.SetDebugRegister(0); |
|
1641 test(r==KErrNone); |
|
1642 DumpData(NULL, 0, 20); |
|
1643 |
|
1644 // retrieve short name from media. |
|
1645 r=raw.Open(TheFs,gSessionPath[0]-'A'); |
|
1646 test(r==KErrNone); |
|
1647 bytePos=ClusterEntryToBytes(0,1); |
|
1648 r=raw.Read(gRootDirStart+bytePos,shortNameBuf8); |
|
1649 test(r==KErrNone); |
|
1650 shortNameBuf8 = DosNameFromStdFormat(shortNameBuf8); |
|
1651 shortName.Copy(shortNameBuf8); |
|
1652 raw.Close(); |
|
1653 |
|
1654 test(shortName==ExtShortName); |
|
1655 |
|
1656 // delete file |
|
1657 r=TheFs.Delete(TestFileName); |
|
1658 test(r==KErrNone); |
|
1659 } |
|
1660 |
|
1661 LOCAL_C void TestMountAndScan() |
|
1662 // |
|
1663 // test MountFileSystemAndScan() |
|
1664 // |
|
1665 { |
|
1666 TFullName extName; |
|
1667 TBool primaryExtensionExists = EFalse; |
|
1668 |
|
1669 test.Next(_L("TestMountAndScan")); |
|
1670 HBufC8* newFat=HBufC8::New(gFatTestSize); |
|
1671 test(newFat!=NULL); |
|
1672 TPtr8 fat=newFat->Des(); |
|
1673 TPtr8 origFat=FatBufPtr->Des(); |
|
1674 TPtr8 origDir=DirBufPtr->Des(); |
|
1675 |
|
1676 // set cluster of \scndrv\dir1\ to a hanging cluster |
|
1677 ReadFatDisk(fat); |
|
1678 WriteFat(gClusterDir1ext,35,fat.Ptr()); |
|
1679 WriteFat(35,36,fat.Ptr()); |
|
1680 WriteFatDisk(fat); |
|
1681 // set the default path to something other than the current drive |
|
1682 TFileName fsName; |
|
1683 TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A'); |
|
1684 test(r==KErrNone); |
|
1685 TFileName origDefPath, newDefPath; |
|
1686 r=TheFs.SessionPath(origDefPath); |
|
1687 test(r==KErrNone); |
|
1688 newDefPath=origDefPath; |
|
1689 newDefPath[0]=(TText)'z'; |
|
1690 r=TheFs.SetSessionPath(newDefPath); |
|
1691 test(r==KErrNone); |
|
1692 r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0); |
|
1693 if (r == KErrNone) |
|
1694 { |
|
1695 primaryExtensionExists = ETrue; |
|
1696 } |
|
1697 r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A'); |
|
1698 test(r==KErrNone); |
|
1699 // mount file system and check scandrive corrects error |
|
1700 TBool isMount; |
|
1701 if (primaryExtensionExists) |
|
1702 r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); |
|
1703 else |
|
1704 r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); |
|
1705 test(isMount && r==KErrNone); |
|
1706 TBool res=IsSameAsDrive(origFat,origDir); |
|
1707 test(res); |
|
1708 |
|
1709 r=TheFs.SetSessionPath(origDefPath); |
|
1710 test(r==KErrNone); |
|
1711 delete newFat; |
|
1712 } |
|
1713 |
|
1714 |
|
1715 LOCAL_C void TestConsecutiveMountAndScans() |
|
1716 // |
|
1717 // test fix for DEF093072: [codebase]MountFileSystemAndScan returns err -21 but ok flag |
|
1718 // |
|
1719 { |
|
1720 TFullName extName; |
|
1721 TBool primaryExtensionExists = EFalse; |
|
1722 TFileName fsName; |
|
1723 TInt r=TheFs.FileSystemName(fsName,gSessionPath[0]-'A'); |
|
1724 test(r==KErrNone); |
|
1725 r = TheFs.ExtensionName(extName,gSessionPath[0]-'A',0); |
|
1726 if (r == KErrNone) |
|
1727 { |
|
1728 primaryExtensionExists = ETrue; |
|
1729 } |
|
1730 r=TheFs.DismountFileSystem(fsName,gSessionPath[0]-'A'); |
|
1731 test(r==KErrNone); |
|
1732 |
|
1733 // RFs::MountFileSystemAndScan twice consecutively |
|
1734 // first time |
|
1735 TBool isMount; |
|
1736 if (primaryExtensionExists) |
|
1737 r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); |
|
1738 else |
|
1739 r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); |
|
1740 test(isMount && r==KErrNone); |
|
1741 // and a second time |
|
1742 if (primaryExtensionExists) |
|
1743 r=TheFs.MountFileSystemAndScan(fsName,extName,gSessionPath[0]-'A',isMount); |
|
1744 else |
|
1745 r=TheFs.MountFileSystemAndScan(fsName,gSessionPath[0]-'A',isMount); |
|
1746 test(!isMount && r==KErrAccessDenied); |
|
1747 } |
|
1748 |
|
1749 LOCAL_C void DoHangingClusters() |
|
1750 // |
|
1751 // Tests that scandrive removes hanging clusters |
|
1752 // |
|
1753 { |
|
1754 test.Next(_L("Check Hanging clusters")); |
|
1755 HBufC8* newFat=HBufC8::New(gFatTestSize); |
|
1756 test(newFat!=NULL); |
|
1757 TPtr8 fat=newFat->Des(); |
|
1758 TPtr8 origFat=FatBufPtr->Des(); |
|
1759 TPtr8 origDir=DirBufPtr->Des(); |
|
1760 |
|
1761 // set cluster of \scndrv\dir1\ to a hanging cluster |
|
1762 test.Start(_L("Test hanging cluster in \\scndrv\\dir1\\")); |
|
1763 ReadFatDisk(fat); |
|
1764 WriteFat(gClusterDir1ext,35,fat.Ptr()); |
|
1765 WriteFat(35,36,fat.Ptr()); |
|
1766 WriteFatDisk(fat); |
|
1767 TInt r=TheFs.ScanDrive(gSessionPath); |
|
1768 test(r==KErrNone); |
|
1769 TBool res=IsSameAsDrive(origFat,origDir); |
|
1770 test(res); |
|
1771 |
|
1772 // set cluster chain of first entry of \scndrv\dir1\ to |
|
1773 // larger size than file size |
|
1774 test.Next(_L("Test hanging cluster in first entry")); |
|
1775 ReadFatDisk(fat); |
|
1776 WriteFat(gClusterDir1ext,39,fat.Ptr()); |
|
1777 WriteFat(39,500,fat.Ptr()); |
|
1778 WriteFat(500,gEndOfChain,fat.Ptr()); |
|
1779 WriteFatDisk(fat); |
|
1780 r=TheFs.ScanDrive(gSessionPath); |
|
1781 test(r==KErrNone); |
|
1782 res=IsSameAsDrive(origFat,origDir); |
|
1783 test(res); |
|
1784 |
|
1785 // set cluster of \scndrv\ to a hanging cluster |
|
1786 test.Next(_L("Test hanging cluster of \\scndrv\\")); |
|
1787 ReadFatDisk(fat); |
|
1788 WriteFat(gClusterScnDrv,511,fat.Ptr()); |
|
1789 WriteFatDisk(fat); |
|
1790 r=TheFs.ScanDrive(gSessionPath); |
|
1791 test(r==KErrNone); |
|
1792 res=IsSameAsDrive(origFat,origDir); |
|
1793 test(res); |
|
1794 |
|
1795 delete newFat; |
|
1796 test.End(); |
|
1797 } |
|
1798 |
|
1799 LOCAL_C void DoLostClusters() |
|
1800 // |
|
1801 // Tests that scandrive removes lost clusters |
|
1802 // |
|
1803 { |
|
1804 test.Next(_L("Check lost clusters")); |
|
1805 HBufC8* newFat=HBufC8::New(gFatTestSize); |
|
1806 test(newFat!=NULL); |
|
1807 TPtr8 fat=newFat->Des(); |
|
1808 TPtr8 origFat=FatBufPtr->Des(); |
|
1809 TPtr8 origDir=DirBufPtr->Des(); |
|
1810 ReadFatDisk(origFat); |
|
1811 ReadDirDisk(origDir); |
|
1812 |
|
1813 // write cluster chain |
|
1814 test.Start(_L("Test removal of lost cluster chain")); |
|
1815 ReadFatDisk(fat); |
|
1816 for(TInt i=25;i<35;++i) |
|
1817 WriteFat(i,i+1,fat.Ptr()); |
|
1818 WriteFat(35,gEndOfChain,fat.Ptr()); |
|
1819 WriteFatDisk(fat); |
|
1820 TInt r=TheFs.ScanDrive(gSessionPath); |
|
1821 test(r==KErrNone); |
|
1822 TBool res=IsSameAsDrive(origFat,origDir); |
|
1823 test(res); |
|
1824 |
|
1825 // write semi-random changes to first fat |
|
1826 test.Next(_L("Test semi-random changes to first fat")); |
|
1827 for(TInt j=1;j<gFatTestSize/BootSector.BytesPerSector();++j) |
|
1828 { |
|
1829 TInt off = j*BootSector.BytesPerSector()+j*7%512; |
|
1830 fat[off]=1; |
|
1831 } |
|
1832 WriteFatDisk(fat); |
|
1833 r=TheFs.ScanDrive(gSessionPath); |
|
1834 test(r==KErrNone); |
|
1835 res=IsSameAsDrive(origFat,origDir); |
|
1836 test(res); |
|
1837 |
|
1838 // write semi-random changes to second fat |
|
1839 test.Next(_L("Test semi-random changes to second fat")); |
|
1840 WriteFatDisk(fat, 1); |
|
1841 r=TheFs.ScanDrive(gSessionPath); |
|
1842 test(r==KErrNone); |
|
1843 res=IsSameAsDrive(origFat,origDir); |
|
1844 test(res); |
|
1845 |
|
1846 delete newFat; |
|
1847 test.End(); |
|
1848 } |
|
1849 |
|
1850 LOCAL_C void DoPartEntries() |
|
1851 // |
|
1852 // Tests that scandrive detects/corrects partial entries |
|
1853 // |
|
1854 { |
|
1855 RFile temp; |
|
1856 TInt last; |
|
1857 TBool res; |
|
1858 test.Start(_L("Check partial entries")); |
|
1859 TPtr8 fatBuf=FatBufPtr->Des(); |
|
1860 TPtr8 dirBuf=DirBufPtr->Des(); |
|
1861 |
|
1862 TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); |
|
1863 test(r==KErrNone || r==KErrNotFound || KErrPathNotFound); |
|
1864 r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); |
|
1865 test(r==KErrNone || r==KErrNotFound || KErrPathNotFound); |
|
1866 |
|
1867 if (BootSector.RootDirEntries() != 0) |
|
1868 { |
|
1869 // Can only do this on FAT12/16, FAT32 root directory is extensible |
|
1870 // partial entry that fills up the root dir |
|
1871 test.Next(_L("Partial entry at end of rootdir")); |
|
1872 FillUpRootDir(2); |
|
1873 r=temp.Create(TheFs,_L("\\temp"),EFileShareAny); |
|
1874 test(r==KErrNone); |
|
1875 temp.Close(); |
|
1876 ReadDirDisk(dirBuf); |
|
1877 ReadFatDisk(fatBuf); |
|
1878 TEntryInfo partial1(ClusterEntryToBytes(gClusterRootDir,BootSector.RootDirEntries()-2),2); |
|
1879 CreatePartialEntry(partial1,1,EFalse); |
|
1880 res=TestPartialEntry(partial1); |
|
1881 test(res); |
|
1882 UnFillUpRootDir(2); |
|
1883 ReadDirDisk(dirBuf); |
|
1884 ReadFatDisk(fatBuf); |
|
1885 } |
|
1886 |
|
1887 // use first entry \scndrv\dir2\almostfull\ |
|
1888 test.Next(_L("Partial entry in middle of subdir")); |
|
1889 last = GetStartCluster(gClusterDir2_AFull,7); |
|
1890 TEntryInfo partial2(ClusterEntryToBytes(gClusterDir2_AFull,2),6); |
|
1891 CreatePartialEntry(partial2,3,EFalse); |
|
1892 // entry has been allocated a cluster which scandrive should delete along with partial entry |
|
1893 if (last > 0) |
|
1894 WriteFat(last,0,fatBuf.Ptr()); |
|
1895 res=TestPartialEntry(partial2); |
|
1896 test(res); |
|
1897 |
|
1898 // reduce size of \scndrv\dir2\full\ |
|
1899 test.Next(_L("Test directory reclaim")); |
|
1900 last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-2); |
|
1901 WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2)); |
|
1902 WriteDirDisk(dirBuf); |
|
1903 TInt entry = GetFatEntry(gClusterDir2_Full, fatBuf.Ptr()); |
|
1904 WriteFat(gClusterDir2_Full,gEndOfChain,fatBuf.Ptr()); |
|
1905 while (entry && (entry & gEndOfChain) != gEndOfChain) |
|
1906 { |
|
1907 TInt next = GetFatEntry(entry, fatBuf.Ptr()); |
|
1908 WriteFat(entry,0,fatBuf.Ptr()); |
|
1909 entry = next; |
|
1910 } |
|
1911 if (last > 0) |
|
1912 WriteFat(last,0,fatBuf.Ptr()); |
|
1913 r=TheFs.ScanDrive(gSessionPath); |
|
1914 test(r==KErrNone); |
|
1915 res=IsSameAsDrive(fatBuf,dirBuf); |
|
1916 test(res); |
|
1917 |
|
1918 // use last entry of first cluster in \scndrv\dir2\full\ |
|
1919 test.Next(_L("Partial entry at end of subdir")); |
|
1920 r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny); |
|
1921 test(r==KErrNone); |
|
1922 temp.Close(); |
|
1923 ReadDirDisk(dirBuf); |
|
1924 ReadFatDisk(fatBuf); |
|
1925 TEntryInfo partial3(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),2); |
|
1926 CreatePartialEntry(partial3,1,EFalse); |
|
1927 res=TestPartialEntry(partial3); |
|
1928 test(res); |
|
1929 |
|
1930 // use entry in \scndrv\dir2\almostfull\ |
|
1931 test.Next(_L("Partial entry preceeding end-of-dir marker")); |
|
1932 last = GetStartCluster(gClusterDir2_AFull,14); |
|
1933 if (last > 0) |
|
1934 WriteFat(last,0,fatBuf.Ptr()); |
|
1935 last = GetStartCluster(gClusterDir2_AFull,8); |
|
1936 if (last > 0) |
|
1937 WriteFat(last,0,fatBuf.Ptr()); |
|
1938 WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_AFull,14)); |
|
1939 WriteDirDisk(dirBuf); |
|
1940 TEntryInfo partial4(ClusterEntryToBytes(gClusterDir2_AFull,8),6); |
|
1941 CreatePartialEntry(partial4,4,EFalse); |
|
1942 res=TestPartialEntry(partial4); |
|
1943 test(res); |
|
1944 |
|
1945 // NOTE: |
|
1946 // Following test case is not valid anymore after fixing of |
|
1947 // PDEF128576: Unicode name file deleted after Scandrive |
|
1948 // In the fixes, we decided to discard file name checking in ScanDrive, |
|
1949 // as it is impossible for ScanDrive to judge if the illegal byte is part of a legal |
|
1950 // DBCS charater. |
|
1951 |
|
1952 // create entry in \scndrv\dir2\almostfull\ |
|
1953 // test.Next(_L("Partial entry with invalid dos name")); |
|
1954 // r=temp.Create(TheFs,_L("\\scndrv\\dir2\\almostfull\\Dodgy file name"),EFileShareAny); |
|
1955 // test(r==KErrNone); |
|
1956 // temp.Close(); |
|
1957 // ReadDirDisk(dirBuf); |
|
1958 // TInt dosStart=ClusterEntryToBytes(gClusterDir2_AFull,4); |
|
1959 // dirBuf[dosStart+4]=0x1; |
|
1960 // WriteDirDisk(dirBuf); |
|
1961 // r=TheFs.ScanDrive(gSessionPath); |
|
1962 // test(r==KErrNone); |
|
1963 // WriteDelete(dosStart-2*32,3); |
|
1964 // res=IsSameAsDrive(fatBuf,dirBuf); |
|
1965 // test(res); |
|
1966 |
|
1967 if (BootSector.SectorsPerCluster() == 1) |
|
1968 { |
|
1969 // use entry created in \scndrv\dir2\ |
|
1970 test.Next(_L("Partial entry spanning more than two clusters")); |
|
1971 last = GetStartCluster(gClusterDir2_Full,gEntriesPerCluster-1); |
|
1972 WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2)); |
|
1973 WriteEndOfDir(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-1)); |
|
1974 WriteDirDisk(dirBuf); |
|
1975 TFileName longFile=_L("\\scndrv\\dir2\\full\\"); |
|
1976 MakeVeryLongName(longFile); |
|
1977 r=temp.Create(TheFs,longFile,EFileShareAny); |
|
1978 test(r==KErrNone); |
|
1979 temp.Close(); |
|
1980 ReadDirDisk(dirBuf); |
|
1981 WriteFat(gClusterDir2_Full,gClusterDir2_SD3E,fatBuf.Ptr()); |
|
1982 WriteFat(gClusterDir2_SD3E,gClusterDir2_SD23E,fatBuf.Ptr()); |
|
1983 WriteFat(gClusterDir2_SD23E,gEndOfChain,fatBuf.Ptr()); |
|
1984 if (last > 0) |
|
1985 WriteFat(last,0,fatBuf.Ptr()); |
|
1986 TEntryInfo partial5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19); |
|
1987 CreatePartialEntry(partial5,7,EFalse); |
|
1988 res=TestPartialEntry(partial5); |
|
1989 test(res); |
|
1990 r=TheFs.Delete(longFile); |
|
1991 test(r==KErrNone || r==KErrNotFound); |
|
1992 r=TheFs.Delete(_L("\\temp")); |
|
1993 test(r==KErrNone || r==KErrNotFound); |
|
1994 } |
|
1995 ReadDirDisk(dirBuf); |
|
1996 |
|
1997 test.End(); |
|
1998 } |
|
1999 |
|
2000 LOCAL_C void DoMatchingEntries() |
|
2001 // |
|
2002 // Tests that scandrive detects/corrects entries with the same start cluster |
|
2003 // Copies entry to new location - replicates start cluster |
|
2004 // |
|
2005 { |
|
2006 test.Next(_L("Check matching entries")); |
|
2007 TPtr8 fatBuf=FatBufPtr->Des(); |
|
2008 TPtr8 dirBuf=DirBufPtr->Des(); |
|
2009 ReadDirDisk(dirBuf); |
|
2010 ReadFatDisk(fatBuf); |
|
2011 |
|
2012 // first entry in \scndrv\almostfull\ + root dir |
|
2013 test.Start(_L("matching entries in subdir + root dir")); |
|
2014 TEntryInfo from1(ClusterEntryToBytes(gClusterDir2_AFull,2),6); |
|
2015 TEntryInfo to1(ClusterEntryToBytes(gClusterRootDir,2),6); |
|
2016 CreateMatchingEntry(to1,from1,EFalse); |
|
2017 TBool res=TestMatchingEntry(to1); |
|
2018 test(res); |
|
2019 |
|
2020 // matching entries between 2 subdirs, one which has a full cluster |
|
2021 // first entry in \scndrv\dir2\full\ + end of \scndrv\dir2\almostfull\ |
|
2022 test.Next(_L("matching entries between 2 subdirs")); |
|
2023 TEntryInfo from2(ClusterEntryToBytes(gClusterDir2_Full,2),2); |
|
2024 TEntryInfo to2(ClusterEntryToBytes(gClusterDir2_AFull,14),2); |
|
2025 CreateMatchingEntry(to2,from2,EFalse); |
|
2026 res=TestMatchingEntry(to2); |
|
2027 test(res); |
|
2028 |
|
2029 // matching entries between two subdirs - one with end of dir marker next |
|
2030 // \scndrv\dir2\somedirwith3entries to \scndrv\ |
|
2031 test.Next(_L("matching entries between two subdirs")); |
|
2032 TEntryInfo from3(ClusterEntryToBytes(gClusterDir2,4),3); |
|
2033 TEntryInfo to3(ClusterEntryToBytes(gClusterScnDrv,6),3); |
|
2034 CreateMatchingEntry(to3,from3,ETrue); |
|
2035 res=TestMatchingEntry(to3); |
|
2036 test(res); |
|
2037 |
|
2038 // matching entries in same subdir, one in new cluster - irrelevant if matching names |
|
2039 // 1st and last entries in \scndrv\dir2\full\ |
|
2040 test.Next(_L("matching entries in same subdir")); |
|
2041 // delete entries to allow contiguous clusters in \scndrv\dir2\full directory |
|
2042 TInt r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedirwith3entries\\")); |
|
2043 test(r==KErrNone); |
|
2044 r=TheFs.RmDir(_L("\\scndrv\\dir2\\somedir2with3entries\\")); |
|
2045 test(r==KErrNone); |
|
2046 // ensure directory is expanded |
|
2047 RFile temp; |
|
2048 r=temp.Create(TheFs,_L("\\scndrv\\dir2\\full\\temp"),EFileShareAny); |
|
2049 test(r==KErrNone); |
|
2050 temp.Close(); |
|
2051 r=TheFs.Delete(_L("\\scndrv\\dir2\\full\\temp")); |
|
2052 test(r==KErrNone); |
|
2053 ReadDirDisk(dirBuf); |
|
2054 ReadFatDisk(fatBuf); |
|
2055 TEntryInfo from4(ClusterEntryToBytes(gClusterDir2_Full,4),2); |
|
2056 TEntryInfo to4(ClusterEntryToBytes(gClusterDir2_Full+1,0),2); |
|
2057 CreateMatchingEntry(to4,from4,ETrue); |
|
2058 res=TestMatchingEntry(to4); |
|
2059 test(res); |
|
2060 |
|
2061 // \scndrv\dir1\very long name to \\scndrv\dir2\full\ |
|
2062 test.Next(_L("matching entries in diff dirs + new cluster")); |
|
2063 // delete last entry in directory |
|
2064 r=TheFs.Delete(LastInFull); |
|
2065 test(r==KErrNone); |
|
2066 TFileName veryLongName=_L("\\scndrv\\dir2\\full\\"); |
|
2067 MakeVeryLongName(veryLongName); |
|
2068 r=temp.Create(TheFs,veryLongName,EFileShareAny); |
|
2069 test(r==KErrNone); |
|
2070 temp.Close(); |
|
2071 r=TheFs.Delete(veryLongName); |
|
2072 test(r==KErrNone); |
|
2073 ReadDirDisk(dirBuf); |
|
2074 ReadFatDisk(fatBuf); |
|
2075 TEntryInfo from5(ClusterEntryToBytes(gClusterDir1,2),19); |
|
2076 TEntryInfo to5(ClusterEntryToBytes(gClusterDir2_Full,gEntriesPerCluster-2),19); |
|
2077 CreateMatchingEntry(to5,from5,EFalse); |
|
2078 res=TestMatchingEntry(to5); |
|
2079 test(res); |
|
2080 |
|
2081 test.End(); |
|
2082 } |
|
2083 |
|
2084 |
|
2085 LOCAL_C void DoMaxDepth() |
|
2086 // |
|
2087 // Test directory structure with max possible depth |
|
2088 // |
|
2089 { |
|
2090 test.Next(_L("Check max directory depth")); |
|
2091 test.Start(_L("Using single character names")); |
|
2092 TPtr8 fatBuf=FatBufPtr->Des(); |
|
2093 TPtr8 dirBuf=DirBufPtr->Des(); |
|
2094 // Create dir structure |
|
2095 TFileName dir1=_L("\\"); |
|
2096 TFileName dir2; |
|
2097 CreateMaxDepthDir(dir1,dir2); |
|
2098 ReadDirDisk(dirBuf); |
|
2099 ReadFatDisk(fatBuf); |
|
2100 // run scandisk and compare |
|
2101 TInt r=TheFs.ScanDrive(gSessionPath); |
|
2102 test(r==KErrNone); |
|
2103 TBool res=IsSameAsDrive(fatBuf,dirBuf); |
|
2104 test(res); |
|
2105 // Create a entry with matching start cluster and check fixed up |
|
2106 TEntryInfo from(ClusterEntryToBytes(gClusterDir2_AFull,2),6); |
|
2107 TEntryInfo to(ClusterEntryToBytes(gClusterEndMaxDepth,2),6); |
|
2108 CreateMatchingEntry(to,from,ETrue); |
|
2109 res=TestMatchingEntry(to); |
|
2110 test(res); |
|
2111 // DeleteMaxDepthStructure |
|
2112 DeleteMaxDepthDir(dir1,dir2); |
|
2113 test.End(); |
|
2114 } |
|
2115 |
|
2116 LOCAL_C void DoRootDir() |
|
2117 // |
|
2118 // Check that a full root directory is searched OK |
|
2119 // |
|
2120 { |
|
2121 test.Next(_L("Check a full root directory")); |
|
2122 FillUpRootDir(); |
|
2123 TPtr8 fatBuf=FatBufPtr->Des(); |
|
2124 TPtr8 dirBuf=DirBufPtr->Des(); |
|
2125 ReadDirDisk(dirBuf); |
|
2126 ReadFatDisk(fatBuf); |
|
2127 |
|
2128 TInt r=TheFs.ScanDrive(gSessionPath); |
|
2129 test(r==KErrNone); |
|
2130 |
|
2131 TBool res=IsSameAsDrive(fatBuf,dirBuf); |
|
2132 test(res); |
|
2133 UnFillUpRootDir(); |
|
2134 } |
|
2135 |
|
2136 LOCAL_C void TestNonVfatNames(const TPtrC& aDirName, TInt aDirCluster, TInt aEntry=2) |
|
2137 // |
|
2138 // Check that files without 'long' entries are kept intact. Creates files with |
|
2139 // a DOS type name, and for each one created except the last deletes the VFAT |
|
2140 // entry by copying the DOS entry over it and writing end of directory. This |
|
2141 // leaves a VFAT entry at the end of the directory, except when there is only |
|
2142 // room for one file. |
|
2143 // |
|
2144 // The layout, for 1 sector per cluster, is thus like: |
|
2145 // 0 . |
|
2146 // 1 .. |
|
2147 // 2 TEMPFILE.000 |
|
2148 // 3 TEMPFILE.001 |
|
2149 // ... |
|
2150 // 14 tempfile.012 VFAT |
|
2151 // 15 TEMPFILE.012 |
|
2152 // |
|
2153 // or for an almost full directory |
|
2154 // |
|
2155 // 0 . |
|
2156 // 1 .. |
|
2157 // whatever... |
|
2158 // 14 TEMPFILE.000 |
|
2159 // 15 end of directory |
|
2160 // |
|
2161 { |
|
2162 test.Printf(_L("Test cluster %2d, aEntry %d: %S\n"), aDirCluster, aEntry, &aDirName); |
|
2163 TPtr8 fatBuf=FatBufPtr->Des(); |
|
2164 TPtr8 dirBuf=DirBufPtr->Des(); |
|
2165 TInt cluster = aDirCluster; |
|
2166 |
|
2167 TInt maxEntry = gEntriesPerCluster; |
|
2168 if (aDirName.Compare(_L("\\")) == KErrNone) |
|
2169 maxEntry = Min(gRootDirEntries, gEntriesPerCluster); |
|
2170 |
|
2171 TInt entry = aEntry; |
|
2172 TInt r = KErrNone; |
|
2173 TInt i; |
|
2174 |
|
2175 while (entry > gEntriesPerCluster) |
|
2176 { |
|
2177 entry -= gEntriesPerCluster; |
|
2178 cluster++; |
|
2179 } |
|
2180 |
|
2181 TInt nFiles = maxEntry - entry - 1; |
|
2182 TInt startEntry = entry; |
|
2183 |
|
2184 test.Printf(_L("cluster %d, entry %d maxEntry %d, nFiles %d\n"), cluster, entry, maxEntry, nFiles); |
|
2185 |
|
2186 TBuf8<256> buf; |
|
2187 buf.Fill('*', 256); |
|
2188 |
|
2189 // Set up files, ignoring used slots |
|
2190 TInt filesThisTime = nFiles; |
|
2191 TInt totalFilesCreated = 0; |
|
2192 FOREVER |
|
2193 { |
|
2194 // |
|
2195 // Create a number of VFat entries |
|
2196 // |
|
2197 // - We create as many as we can fit in the cluster in one go. |
|
2198 // This is faster than creating a single entry then copying, as writing the |
|
2199 // entries one at a time using RRawDisk causes a remount of the file system, |
|
2200 // which can take a very long time on a large disk. |
|
2201 // |
|
2202 filesThisTime = (nFiles - totalFilesCreated) >> 1; |
|
2203 if(filesThisTime == 0) |
|
2204 { |
|
2205 if(nFiles == totalFilesCreated) |
|
2206 { |
|
2207 test.Printf(_L("Created all Non-VFAT entries\n")); |
|
2208 break; |
|
2209 } |
|
2210 |
|
2211 //...creating the final entry |
|
2212 filesThisTime = 1; |
|
2213 } |
|
2214 |
|
2215 for (i = 0; i < filesThisTime; i++) |
|
2216 { |
|
2217 TFileName name(aDirName); |
|
2218 name.Append(_L("tempfile.")); |
|
2219 name.AppendNumFixedWidth(i+totalFilesCreated, EHex, 3); |
|
2220 RFile f; |
|
2221 r = f.Create(TheFs, name, EFileShareAny); |
|
2222 test(r == KErrNone); |
|
2223 r = f.Write(buf); |
|
2224 test(r == KErrNone); |
|
2225 f.Close(); |
|
2226 } |
|
2227 |
|
2228 // |
|
2229 // Move DOS FAT entries up using RRawDisk, deleting the original VFAT entries |
|
2230 // |
|
2231 ReadDirDisk(dirBuf, cluster); |
|
2232 TInt dosEntry = entry + 1; |
|
2233 for (i = 0; i < filesThisTime; i++) |
|
2234 { |
|
2235 // Copy VFAT to Non-VFAT entries |
|
2236 if (entry+2 < maxEntry || nFiles < 2) |
|
2237 { |
|
2238 TInt posVFAT = ClusterEntryToBytes(cluster, entry); |
|
2239 TInt posEOD = ClusterEntryToBytes(cluster, entry+1); |
|
2240 TInt posDOS = ClusterEntryToBytes(cluster, dosEntry); |
|
2241 |
|
2242 WriteCopyDir(posDOS, posVFAT); // Copy the DOS entry |
|
2243 WriteDelete(posDOS,2); // Delete the original entry |
|
2244 WriteEndOfDir(posEOD); // Write End Of Directory |
|
2245 |
|
2246 entry += 1; |
|
2247 dosEntry += 2; |
|
2248 } |
|
2249 else |
|
2250 { |
|
2251 // last entry has VFAT intact, to fill cluster |
|
2252 entry += 2; |
|
2253 } |
|
2254 |
|
2255 } |
|
2256 |
|
2257 WriteDirDisk(dirBuf, cluster); |
|
2258 totalFilesCreated += filesThisTime; |
|
2259 test.Printf(_L(" created %d entries\n"), totalFilesCreated); |
|
2260 } |
|
2261 |
|
2262 ReadDirDisk(dirBuf); |
|
2263 ReadFatDisk(fatBuf); |
|
2264 |
|
2265 DumpData(NULL, aDirCluster, cluster+1); |
|
2266 |
|
2267 test.Printf(_L("Running ScanDrive\n"), filesThisTime); |
|
2268 r=TheFs.ScanDrive(gSessionPath); |
|
2269 test(r==KErrNone); |
|
2270 |
|
2271 TBool res=IsSameAsDrive(fatBuf,dirBuf); |
|
2272 test(res); |
|
2273 |
|
2274 test.Printf(_L("Deleting %d files\n"), nFiles); |
|
2275 for (i = 0; i < nFiles; i++) |
|
2276 { |
|
2277 TFileName name(aDirName); |
|
2278 name.Append(_L("tempfile.")); |
|
2279 name.AppendNumFixedWidth(i, EHex, 3); |
|
2280 r = TheFs.Delete(name); |
|
2281 test(r == KErrNone); |
|
2282 } |
|
2283 |
|
2284 ReadDirDisk(dirBuf); |
|
2285 ReadFatDisk(fatBuf); |
|
2286 WriteEndOfDir(ClusterEntryToBytes(cluster, startEntry)); |
|
2287 WriteDirDisk(dirBuf); |
|
2288 |
|
2289 test.Printf(_L("Running ScanDrive\n"), filesThisTime); |
|
2290 r=TheFs.ScanDrive(gSessionPath); |
|
2291 test(r==KErrNone); |
|
2292 res=IsSameAsDrive(fatBuf,dirBuf); |
|
2293 test(res); |
|
2294 } |
|
2295 |
|
2296 LOCAL_C void DoNonVfatNames() |
|
2297 // |
|
2298 // Check that files without 'long' entries are kept intact |
|
2299 // |
|
2300 { |
|
2301 test.Next(_L("Check non-VFAT file names")); |
|
2302 TestNonVfatNames(_L("\\"), gClusterRootDir, 2); |
|
2303 TestNonVfatNames(_L("\\scndrv\\dir1\\"), gClusterDir1, 2+19); |
|
2304 TestNonVfatNames(_L("\\scndrv\\dir2\\somedirwith3entries\\"), gClusterDir2_SD3E, 2); |
|
2305 TestNonVfatNames(_L("\\scndrv\\dir2\\almostfull\\"), gClusterDir2_AFull, 14); |
|
2306 } |
|
2307 |
|
2308 |
|
2309 LOCAL_C void DoTests() |
|
2310 { |
|
2311 |
|
2312 Format(); |
|
2313 DoReadBootSector(); |
|
2314 DumpBootSector(); |
|
2315 InitialiseBuffers(); |
|
2316 CreateRootDir(); |
|
2317 CreateDirectoryStructure(); |
|
2318 TPtr8 fatBuf=FatBufPtr->Des(); |
|
2319 TPtr8 dirBuf=DirBufPtr->Des(); |
|
2320 ReadDirDisk(dirBuf); |
|
2321 ReadFatDisk(fatBuf); |
|
2322 DumpFat(); |
|
2323 DumpData(NULL, DirBufPtr->Ptr()); |
|
2324 |
|
2325 DoNonVfatNames(); |
|
2326 DoRootDir(); |
|
2327 DoMaxDepth(); |
|
2328 DoMatchingEntries(); |
|
2329 DoPartEntries(); |
|
2330 DoLostClusters(); |
|
2331 DoHangingClusters(); |
|
2332 TestMountAndScan(); |
|
2333 TestConsecutiveMountAndScans(); |
|
2334 DeleteDirectoryStructure(); |
|
2335 DeleteRootDir(); |
|
2336 TestExtendedChars(); |
|
2337 |
|
2338 DumpBootSector(); |
|
2339 DumpFat(); |
|
2340 DumpData(NULL, 0, 200); |
|
2341 |
|
2342 delete FatDiskPtr; |
|
2343 delete DirDiskPtr; |
|
2344 delete FatBufPtr; |
|
2345 delete DirBufPtr; |
|
2346 } |
|
2347 |
|
2348 |
|
2349 void CallTestsL() |
|
2350 { |
|
2351 TInt r; |
|
2352 r = TheFs.CharToDrive(gSessionPath[0], gDriveNumber); |
|
2353 test( KErrNone == r ); |
|
2354 |
|
2355 |
|
2356 //-- set up console output |
|
2357 Fat_Test_Utils::SetConsole(test.Console()); |
|
2358 |
|
2359 //-- print drive information |
|
2360 PrintDrvInfo(TheFs, gDriveNumber); |
|
2361 |
|
2362 if (!Is_Fat(TheFs, gDriveNumber)) |
|
2363 { |
|
2364 test.Printf(_L("CallTestsL: Skipped: test requires FAT filesystem\n")); |
|
2365 return; |
|
2366 } |
|
2367 |
|
2368 // check this is not the internal ram drive |
|
2369 TVolumeInfo v; |
|
2370 r=TheFs.Volume(v); |
|
2371 test(r==KErrNone); |
|
2372 if(v.iDrive.iMediaAtt&KMediaAttVariableSize) |
|
2373 { |
|
2374 test.Printf(_L("Error: Internal ram drive not tested\n")); |
|
2375 return; |
|
2376 } |
|
2377 |
|
2378 r=TheFs.SetSessionPath(gSessionPath); |
|
2379 test(r==KErrNone); |
|
2380 |
|
2381 DoTests(); |
|
2382 |
|
2383 return; |
|
2384 } |
|
2385 |
|
2386 |
|
2387 |
|
2388 |
|
2389 |
|
2390 |