|
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 // f32\sfat\sl_fatmisc32.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "sl_std.h" |
|
19 #include "sl_cache.h" |
|
20 |
|
21 /** |
|
22 @return ETrue if it is Fat32 |
|
23 */ |
|
24 TBool CFatFormatCB::Is32BitFat() const |
|
25 { |
|
26 return(iFileSystemName==KFileSystemName32); |
|
27 } |
|
28 |
|
29 /** |
|
30 @return ETrue if it is Fat16 |
|
31 */ |
|
32 TBool CFatFormatCB::Is16BitFat() const |
|
33 { |
|
34 return(iFileSystemName==KFileSystemName16); |
|
35 } |
|
36 |
|
37 /** |
|
38 Calculate the FAT size in sectors for a Fat32 volume |
|
39 |
|
40 @return The number of sectors |
|
41 */ |
|
42 TUint32 CFatFormatCB::MaxFat32Sectors() const |
|
43 { |
|
44 TUint32 calc1 = iMaxDiskSectors - iReservedSectors; |
|
45 TUint32 calc2 = (256 * iSectorsPerCluster) + iNumberOfFats; |
|
46 calc2 = calc2 >> 1; |
|
47 return (calc1 + (calc2 - 1))/calc2; |
|
48 } |
|
49 |
|
50 |
|
51 const TUint KDefFatResvdSec = 1; ///< default number of FAT12/16 reserved sectors |
|
52 const TUint KDefFat32ResvdSec = 32; ///< default number of FAT32 reserved sectors |
|
53 |
|
54 //------------------------------------------------------------------------------------------------------------------- |
|
55 void Dump_TLDFormatInfo(const TLDFormatInfo& aInfo) |
|
56 { |
|
57 (void)aInfo; |
|
58 #ifdef _DEBUG |
|
59 __PRINT(_L("----- TLDFormatInfo dump:")); |
|
60 __PRINT1(_L("iCapacity:%d"), aInfo.iCapacity); |
|
61 __PRINT1(_L("iSectorsPerCluster:%d"), aInfo.iSectorsPerCluster); |
|
62 __PRINT1(_L("iSectorsPerTrack:%d"), aInfo.iSectorsPerTrack); |
|
63 __PRINT1(_L("iFATBits:%d"), aInfo.iFATBits); |
|
64 __PRINT1(_L("iReservedSectors:%d"), aInfo.iReservedSectors); |
|
65 __PRINT1(_L("iFlags:%d"), aInfo.iFlags); |
|
66 __PRINT(_L("-----")); |
|
67 #endif |
|
68 } |
|
69 |
|
70 //------------------------------------------------------------------------------------------------------------------- |
|
71 |
|
72 /** |
|
73 Initialize the format parameters for a normal fixed sized disk |
|
74 Setting set to adhere to Rules of Count of clusters for FAT type |
|
75 |
|
76 @param aDiskSizeInSectors Size of volume in sectors |
|
77 @return system-wide error code |
|
78 */ |
|
79 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskNormal(TInt aDiskSizeInSectors, const TLocalDriveCapsV6& aCaps) |
|
80 { |
|
81 __PRINT1(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskNormal() sectors:%d"), aDiskSizeInSectors); |
|
82 |
|
83 if( Drive().IsRemovable() ) |
|
84 iNumberOfFats = KNumberOfFatsExternal; |
|
85 else |
|
86 iNumberOfFats = KNumberOfFatsInternal; |
|
87 |
|
88 iReservedSectors=KDefFatResvdSec; |
|
89 if (aDiskSizeInSectors <=4084*1) // 2MB |
|
90 { |
|
91 iRootDirEntries=128; |
|
92 iSectorsPerCluster=1; |
|
93 iFileSystemName=KFileSystemName12; |
|
94 iSectorsPerFat=MaxFat12Sectors(); |
|
95 } |
|
96 else if (aDiskSizeInSectors<4084*2) // < 4MB (8168 sectors) |
|
97 { |
|
98 iRootDirEntries=256; |
|
99 iSectorsPerCluster=2; |
|
100 iFileSystemName=KFileSystemName12; |
|
101 iSectorsPerFat=MaxFat12Sectors(); |
|
102 } |
|
103 else if (aDiskSizeInSectors<4084*4) // < 8MB (16336 sectors) |
|
104 { |
|
105 iRootDirEntries=512; |
|
106 iSectorsPerCluster=4; |
|
107 iFileSystemName=KFileSystemName12; |
|
108 iSectorsPerFat=MaxFat12Sectors(); |
|
109 } |
|
110 else if (aDiskSizeInSectors<4084*8) // < 16MB (32672 sectors) |
|
111 { |
|
112 iRootDirEntries=512; |
|
113 iSectorsPerCluster=8; |
|
114 iFileSystemName=KFileSystemName12; |
|
115 iSectorsPerFat=MaxFat12Sectors(); |
|
116 } |
|
117 else if(aDiskSizeInSectors<1048576) // >= 16Mb - FAT16 < (1048576) 512MB |
|
118 { |
|
119 iFileSystemName=KFileSystemName16; |
|
120 TInt minSectorsPerCluster=(aDiskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries; |
|
121 iRootDirEntries=512; |
|
122 iSectorsPerCluster=1; |
|
123 while (minSectorsPerCluster>iSectorsPerCluster) |
|
124 iSectorsPerCluster<<=1; |
|
125 iSectorsPerFat=MaxFat16Sectors(); |
|
126 } |
|
127 else //use FAT32 |
|
128 { |
|
129 iFileSystemName=KFileSystemName32; |
|
130 iRootDirEntries=0; //this is always the case for fat32 |
|
131 if(aDiskSizeInSectors < 16777216) //8GB in 512byte sectors |
|
132 iSectorsPerCluster=8; |
|
133 else if(aDiskSizeInSectors < 33554432) //16GB in 512byte sectors |
|
134 iSectorsPerCluster=16; |
|
135 else if(aDiskSizeInSectors < 67108864) //32GB in 512byte sectors |
|
136 iSectorsPerCluster=32; |
|
137 else |
|
138 iSectorsPerCluster=64; //Anything >= 32GB uses a 32K cluster size |
|
139 iReservedSectors=KDefFat32ResvdSec; |
|
140 iRootClusterNum=2; //As recomended in the document |
|
141 iSectorsPerFat=MaxFat32Sectors(); |
|
142 |
|
143 } |
|
144 |
|
145 // Ensure cluster size is a multiple of the block size |
|
146 TInt blockSizeInSectors = aCaps.iBlockSize >> iSectorSizeLog2; |
|
147 __PRINT1(_L("blockSizeInSectors: %d"),blockSizeInSectors); |
|
148 ASSERT(blockSizeInSectors == 0 || IsPowerOf2(blockSizeInSectors)); |
|
149 if (blockSizeInSectors != 0 && IsPowerOf2(blockSizeInSectors)) |
|
150 { |
|
151 __PRINT1(_L("iSectorsPerCluster (old): %d"),iSectorsPerCluster); |
|
152 AdjustClusterSize(blockSizeInSectors); |
|
153 __PRINT1(_L("iSectorsPerCluster (new): %d"),iSectorsPerCluster); |
|
154 } |
|
155 |
|
156 // Align first data sector on an erase block boundary if |
|
157 // (1) the iEraseBlockSize is specified |
|
158 // (2) the start of the partition is already aligned to an erase block boundary, |
|
159 // i.e. iHiddenSectors is zero or a multiple of iEraseBlockSize |
|
160 __PRINT1(_L("iHiddenSectors: %d"),iHiddenSectors); |
|
161 TInt eraseblockSizeInSectors = aCaps.iEraseBlockSize >> iSectorSizeLog2; |
|
162 __PRINT1(_L("eraseblockSizeInSectors: %d"),eraseblockSizeInSectors); |
|
163 ASSERT(eraseblockSizeInSectors == 0 || IsPowerOf2(eraseblockSizeInSectors)); |
|
164 ASSERT(eraseblockSizeInSectors == 0 || eraseblockSizeInSectors >= blockSizeInSectors); |
|
165 if ((eraseblockSizeInSectors != 0) && |
|
166 (iHiddenSectors % eraseblockSizeInSectors == 0) && |
|
167 (IsPowerOf2(eraseblockSizeInSectors)) && |
|
168 (eraseblockSizeInSectors >= blockSizeInSectors)) |
|
169 { |
|
170 TInt r = AdjustFirstDataSectorAlignment(eraseblockSizeInSectors); |
|
171 ASSERT(r == KErrNone); |
|
172 (void) r; |
|
173 } |
|
174 __PRINT1(_L("iReservedSectors: %d"),iReservedSectors); |
|
175 __PRINT1(_L("FirstDataSector: %d"), FirstDataSector()); |
|
176 |
|
177 return KErrNone; |
|
178 } |
|
179 |
|
180 TInt CFatFormatCB::FirstDataSector() const |
|
181 { |
|
182 TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; |
|
183 return iHiddenSectors + iReservedSectors + iNumberOfFats*iSectorsPerFat + rootDirSectors; |
|
184 } |
|
185 |
|
186 void CFatFormatCB::AdjustClusterSize(TInt aRecommendedSectorsPerCluster) |
|
187 { |
|
188 const TInt KMaxSecPerCluster = 64; // 32K |
|
189 while (aRecommendedSectorsPerCluster > iSectorsPerCluster && iSectorsPerCluster <= (KMaxSecPerCluster/2)) |
|
190 iSectorsPerCluster<<= 1; |
|
191 } |
|
192 |
|
193 // AdjustFirstDataSectorAlignment() |
|
194 // Attempts to align the first data sector on an erase block boundary by modifying the |
|
195 // number of reserved sectors. |
|
196 TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors) |
|
197 { |
|
198 const TBool bFat16 = Is16BitFat(); |
|
199 const TBool bFat32 = Is32BitFat(); |
|
200 |
|
201 // Save these 2 values in the event of a convergence failure; this should |
|
202 // hopefully never happen, but we will cater for this in release mode to be safe, |
|
203 TInt reservedSectorsSaved = iReservedSectors; |
|
204 TInt sectorsPerFatSaved = iSectorsPerFat; |
|
205 |
|
206 TInt reservedSectorsOld = 0; |
|
207 |
|
208 // zero for FAT32 |
|
209 TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; |
|
210 TInt fatSectors = 0; |
|
211 |
|
212 TInt KMaxIterations = 10; |
|
213 TInt n; |
|
214 for (n=0; n<KMaxIterations && reservedSectorsOld != iReservedSectors; n++) |
|
215 { |
|
216 reservedSectorsOld = iReservedSectors; |
|
217 |
|
218 iSectorsPerFat = bFat32 ? MaxFat32Sectors() : bFat16 ? MaxFat16Sectors() : MaxFat12Sectors(); |
|
219 |
|
220 fatSectors = iSectorsPerFat * iNumberOfFats; |
|
221 |
|
222 // calculate number of blocks |
|
223 TInt nBlocks = (iReservedSectors + fatSectors + rootDirSectors + aEraseBlockSizeInSectors-1) / aEraseBlockSizeInSectors; |
|
224 |
|
225 iReservedSectors = (nBlocks * aEraseBlockSizeInSectors) - rootDirSectors - fatSectors; |
|
226 } |
|
227 |
|
228 ASSERT(iReservedSectors >= (TInt) (bFat32 ? KDefFat32ResvdSec : KDefFatResvdSec)); |
|
229 |
|
230 if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0) |
|
231 { |
|
232 return KErrNone; |
|
233 } |
|
234 else |
|
235 { |
|
236 iReservedSectors = reservedSectorsSaved; |
|
237 iSectorsPerFat = sectorsPerFatSaved; |
|
238 return KErrGeneral; |
|
239 } |
|
240 } |
|
241 |
|
242 |
|
243 //------------------------------------------------------------------------------------------------------------------- |
|
244 |
|
245 /** |
|
246 Create the boot sector on media for the volume. For FAT32 also creates a backup copy of the boot sector. |
|
247 |
|
248 @leave System wide error codes |
|
249 */ |
|
250 void CFatFormatCB::CreateBootSectorL() |
|
251 { |
|
252 __PRINT1(_L("CFatFormatCB::CreateBootSector() drive:%d"),DriveNumber()); |
|
253 |
|
254 |
|
255 const TBool bFat32 = Is32BitFat(); |
|
256 |
|
257 TFatBootSector bootSector; |
|
258 |
|
259 bootSector.SetVendorID(KDefaultVendorID); |
|
260 bootSector.SetBytesPerSector(iBytesPerSector); |
|
261 bootSector.SetSectorsPerCluster(iSectorsPerCluster); |
|
262 bootSector.SetReservedSectors(iReservedSectors); |
|
263 bootSector.SetNumberOfFats(iNumberOfFats); |
|
264 iCountOfClusters=iMaxDiskSectors/iSectorsPerCluster; |
|
265 if (!bFat32) |
|
266 { |
|
267 if (iCountOfClusters>(TInt)KMaxTUint16) |
|
268 User::Leave(KErrTooBig); |
|
269 } |
|
270 |
|
271 bootSector.SetReservedByte(0); |
|
272 TTime timeID; |
|
273 timeID.HomeTime(); // System time in future? |
|
274 bootSector.SetUniqueID(I64LOW(timeID.Int64())); // Generate UniqueID from time |
|
275 bootSector.SetVolumeLabel(_L8("")); |
|
276 bootSector.SetFileSysType(iFileSystemName); |
|
277 // Floppy specific info: |
|
278 bootSector.SetJumpInstruction(); |
|
279 bootSector.SetMediaDescriptor(KBootSectorMediaDescriptor); |
|
280 bootSector.SetNumberOfHeads(iNumberOfHeads); |
|
281 bootSector.SetHiddenSectors(iHiddenSectors); |
|
282 bootSector.SetSectorsPerTrack(iSectorsPerTrack); |
|
283 bootSector.SetPhysicalDriveNumber(128); |
|
284 bootSector.SetExtendedBootSignature(0x29); |
|
285 |
|
286 if(bFat32) |
|
287 { |
|
288 bootSector.SetFatSectors(0); |
|
289 bootSector.SetFatSectors32(iSectorsPerFat); |
|
290 bootSector.SetRootDirEntries(0); |
|
291 bootSector.SetTotalSectors(0); |
|
292 bootSector.SetHugeSectors(iMaxDiskSectors); |
|
293 bootSector.SetFATFlags(0); |
|
294 bootSector.SetVersionNumber(0x00); |
|
295 bootSector.SetRootClusterNum(iRootClusterNum); |
|
296 bootSector.SetFSInfoSectorNum(KFSInfoSectorNum); |
|
297 bootSector.SetBkBootRecSector(KBkBootSectorNum); |
|
298 } |
|
299 else//fat12 and 16 |
|
300 { |
|
301 bootSector.SetFatSectors32(0); |
|
302 bootSector.SetFatSectors(iSectorsPerFat); |
|
303 bootSector.SetRootDirEntries(iRootDirEntries); |
|
304 |
|
305 if (iMaxDiskSectors<=(TInt)KMaxTUint16) |
|
306 { |
|
307 bootSector.SetTotalSectors(iMaxDiskSectors); |
|
308 bootSector.SetHugeSectors(0); |
|
309 } |
|
310 else |
|
311 { |
|
312 bootSector.SetTotalSectors(0); |
|
313 bootSector.SetHugeSectors(iMaxDiskSectors); |
|
314 } |
|
315 } |
|
316 |
|
317 //-- write main boot sector to the first sector on media |
|
318 User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*bootSector.BytesPerSector(), bootSector)); |
|
319 |
|
320 //-- for FAT32 write backup copy of the boot sector |
|
321 if(bFat32) |
|
322 { |
|
323 User::LeaveIfError(FatMount().DoWriteBootSector(KBkBootSectorNum*bootSector.BytesPerSector(), bootSector)); |
|
324 } |
|
325 |
|
326 } |
|
327 |
|
328 //------------------------------------------------------------------------------------------------------------------- |
|
329 |
|
330 /** |
|
331 Format a disk section, called iteratively to erase whole of media, on last iteration |
|
332 creates an empty volume. If called with quick formatonly erases the Fat leaving the |
|
333 rest of the volume intact. |
|
334 |
|
335 @leave System wide error code |
|
336 */ |
|
337 void CFatFormatCB::DoFormatStepL() |
|
338 { |
|
339 if (iFormatInfo.iFormatIsCurrent==EFalse) |
|
340 { // Only done first time through |
|
341 if (iMode & EForceErase) |
|
342 { |
|
343 TInt r = FatMount().ErasePassword(); |
|
344 User::LeaveIfError(r); |
|
345 // CFatMountCB::ErasePassword() calls TBusLocalDrive::ForceRemount(), |
|
346 // so need to stop a remount from occurring in next call to : |
|
347 // TFsFormatNext::DoRequestL((), TDrive::CheckMount(). |
|
348 FatMount().Drive().SetChanged(EFalse); |
|
349 } |
|
350 |
|
351 RecordOldInfoL(); |
|
352 InitializeFormatDataL(); |
|
353 FatMount().DoDismount(); |
|
354 if (iVariableSize) |
|
355 FatMount().ReduceSizeL(0,I64LOW(FatMount().iSize)); |
|
356 } |
|
357 // |
|
358 // Blank disk if not EQuickFormat |
|
359 // |
|
360 if (!iVariableSize && !(iMode & EQuickFormat) && iCurrentStep) |
|
361 { |
|
362 if (iFormatInfo.iFormatIsCurrent == EFalse) |
|
363 {//-- firstly invalidate sectors 0-6 inclusive, they may contain main boot sector, backup boot sector and FSInfo sector. |
|
364 DoZeroFillMediaL(0, (KBkBootSectorNum+1)*iBytesPerSector); |
|
365 } |
|
366 TInt ret=FatMount().LocalDrive()->Format(iFormatInfo); |
|
367 if (ret!=KErrNone && ret!=KErrEof) // Handle format error |
|
368 ret = HandleCorrupt(ret); |
|
369 |
|
370 if (ret!=KErrNone && ret!=KErrEof) // KErrEof could be set by LocalDrive()->Format() |
|
371 User::Leave(ret); |
|
372 |
|
373 if (ret==KErrNone) |
|
374 { |
|
375 iCurrentStep = I64LOW( 100 - (100 * TInt64(iFormatInfo.i512ByteSectorsFormatted)) / iMaxDiskSectors ); |
|
376 if (iCurrentStep<=0) |
|
377 iCurrentStep=1; |
|
378 return; |
|
379 } |
|
380 } |
|
381 |
|
382 // ReMount since MBR may have been rewritten and partition may have moved / changed size |
|
383 TInt ret = LocalDrive()->ForceRemount(0); |
|
384 if (ret != KErrNone && ret != KErrNotSupported) |
|
385 User::Leave(ret); |
|
386 |
|
387 // MBR may have changed, so need to re-read iHiddenSectors etc.before BPB is written |
|
388 InitializeFormatDataL(); |
|
389 |
|
390 // Translate bad sector number to cluster number which contains that sector |
|
391 // This only happens in full format, in quick format they are already cluster numbers |
|
392 if (!iVariableSize && !(iMode & EQuickFormat)) |
|
393 User::LeaveIfError(BadSectorToCluster()); |
|
394 |
|
395 //Check if root cluster is bad and update as required |
|
396 if(Is32BitFat() && !iVariableSize && (iMode & EQuickFormat)) |
|
397 { |
|
398 if(iBadClusters.Find(iRootClusterNum) != KErrNotFound) |
|
399 { |
|
400 iRootClusterNum++; |
|
401 while(iBadClusters.Find(iRootClusterNum) != KErrNotFound) |
|
402 { |
|
403 iRootClusterNum++; |
|
404 } |
|
405 } |
|
406 } |
|
407 |
|
408 // |
|
409 // Do the rest of the disk in one lump |
|
410 // |
|
411 iCurrentStep=0; |
|
412 |
|
413 //-- zero-fill media from position 0 to the FAT end, i.e main & backup boot sector, FSInfo and its copy and all FATs |
|
414 const TUint32 posFatEnd = ((iSectorsPerFat*iNumberOfFats) + iReservedSectors) * iBytesPerSector; //-- last FAT end position |
|
415 |
|
416 if (iVariableSize) |
|
417 FatMount().EnlargeL(posFatEnd); |
|
418 |
|
419 DoZeroFillMediaL(0, posFatEnd); |
|
420 |
|
421 if(Is32BitFat()) |
|
422 {//create an empty root directory entry here |
|
423 |
|
424 const TUint KFat32EntrySz = 4; //-- FAT32 entry size, bytes |
|
425 const TInt startFAT1 = iReservedSectors; //-- FAT1 start sector |
|
426 const TInt entryOffset = iRootClusterNum*KFat32EntrySz; //-- Root dir entry offset in the FAT, bytes |
|
427 |
|
428 TBuf8<KFat32EntrySz> EOF(KFat32EntrySz); |
|
429 EOF[0]=0xFF; |
|
430 EOF[1]=0xFF; |
|
431 EOF[2]=0xFF; |
|
432 EOF[3]=0x0F; |
|
433 |
|
434 //-- write EOF mark to the every FAT copy |
|
435 for(TInt i=0; i<iNumberOfFats; i++) |
|
436 { |
|
437 const TInt rootDirEntryPos = iBytesPerSector*(startFAT1 + i*iSectorsPerFat) + entryOffset; |
|
438 User::LeaveIfError(LocalDrive()->Write(rootDirEntryPos, EOF)); |
|
439 } |
|
440 |
|
441 //-- zero-fill FAT32 root directory (just 1 cluster) |
|
442 const TInt firstDataSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); //+RootDirSectors (not required for fat32) |
|
443 const TInt firstSectorOfCluster = ((iRootClusterNum - KFatFirstSearchCluster) * iSectorsPerCluster) + firstDataSector; |
|
444 |
|
445 const TUint32 posRootDirStart = firstSectorOfCluster * iBytesPerSector; |
|
446 const TUint32 posRootDirEnd = posRootDirStart + iSectorsPerCluster*iBytesPerSector; |
|
447 |
|
448 DoZeroFillMediaL(posRootDirStart, posRootDirEnd); |
|
449 } |
|
450 else |
|
451 {//-- FAT12/16 |
|
452 //-- Zero fill root directory |
|
453 const TInt rootDirSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); |
|
454 const TInt rootDirSize = iRootDirEntries * KSizeOfFatDirEntry; //-- size in bytes |
|
455 |
|
456 const TUint32 posRootDirStart = rootDirSector * iBytesPerSector; |
|
457 const TUint32 posRootDirEnd = posRootDirStart + rootDirSize; |
|
458 |
|
459 const TInt numOfRootSectors=(rootDirSize%iBytesPerSector) ? (rootDirSize/iBytesPerSector+1) : (rootDirSize/iBytesPerSector); |
|
460 if (iVariableSize) |
|
461 FatMount().EnlargeL(iBytesPerSector*numOfRootSectors); |
|
462 |
|
463 DoZeroFillMediaL(posRootDirStart, posRootDirEnd); |
|
464 |
|
465 // Enlarge ram drive to take into account rounding of |
|
466 // data start to cluster boundary |
|
467 if(iVariableSize && iSectorsPerCluster!=1) |
|
468 { |
|
469 const TInt firstFreeSector=rootDirSector+numOfRootSectors; |
|
470 const TInt firstFreeCluster=firstFreeSector%iSectorsPerCluster ? firstFreeSector/iSectorsPerCluster+1 : firstFreeSector/iSectorsPerCluster; |
|
471 const TInt alignedSector=firstFreeCluster*iSectorsPerCluster; |
|
472 if(alignedSector!=firstFreeSector) |
|
473 FatMount().EnlargeL((alignedSector-firstFreeSector)*iBytesPerSector); |
|
474 } |
|
475 } |
|
476 |
|
477 //-- FAT[0] must contain media descriptor in the low byte, FAT[1] for fat16/32 may contain some flags |
|
478 TBuf8<8> startFat(8); |
|
479 startFat.Fill(0xFF); |
|
480 |
|
481 if(Is32BitFat()) //-- FAT32 |
|
482 {//-- FAT32 uses only low 28 bits in FAT entry. |
|
483 startFat[3] = 0x0F; |
|
484 startFat[7] = 0x0F; |
|
485 } |
|
486 else if(iVariableSize||Is16BitFat()) //-- FAT16 or RAM drive which is always FAT16 |
|
487 { |
|
488 startFat.SetLength(4); |
|
489 } |
|
490 else //-- FAT12 |
|
491 { |
|
492 startFat.SetLength(3); |
|
493 } |
|
494 |
|
495 startFat[0]=KBootSectorMediaDescriptor; |
|
496 |
|
497 //-- write FAT[0] and FAT[1] entries to all copies of FAT |
|
498 for(TInt i=0;i<iNumberOfFats;i++) |
|
499 { |
|
500 User::LeaveIfError(LocalDrive()->Write(iBytesPerSector*(iReservedSectors+(iSectorsPerFat*i)),startFat)); |
|
501 } |
|
502 |
|
503 //-- create boot sectors |
|
504 CreateBootSectorL(); |
|
505 |
|
506 //-- create FSInfo sectors |
|
507 if (Is32BitFat()) |
|
508 { |
|
509 CreateReservedBootSectorL(); |
|
510 CreateFSInfoSectorL(); |
|
511 } |
|
512 |
|
513 //-- here we have bad clusters numbers saved by the quick format |
|
514 //-- Interpret old bad cluster number to new cluster number and mark new bad clusters |
|
515 if (!iVariableSize && iBadClusters.Count()>0) |
|
516 { |
|
517 |
|
518 //-- Here we need fully mounted volume, so mount it normally. |
|
519 FatMount().MountL(EFalse); |
|
520 |
|
521 iBadClusters.Sort(); |
|
522 TranslateL(); |
|
523 const TInt mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit); |
|
524 |
|
525 for (TInt i=0; i<iBadClusters.Count(); ++i) |
|
526 FatMount().FAT().WriteL(iBadClusters[i], mark); |
|
527 |
|
528 FatMount().FAT().FlushL(); |
|
529 |
|
530 //-- indicate that the volume is "dirty" in order to the next Mount evend not to use FSInfo, which |
|
531 //-- contains incorrect value of free clusters because we already have bad ones saved. |
|
532 //-- This is a very rare condition. |
|
533 FatMount().SetVolumeCleanL(EFalse); |
|
534 |
|
535 #if defined(_DEBUG) |
|
536 TInt r=FatMount().CheckDisk(); |
|
537 __PRINT1(_L("CFatFormatCB::DoFormatStepL() CheckDisk res: %d"),r); |
|
538 #endif |
|
539 } |
|
540 else |
|
541 { |
|
542 //-- We do not need to perform full mount in this case, the TDrive object will be marked as changed in ~CFormatCB and the |
|
543 //-- mount will be closed. Therefore on the first access to it it will be mounted normally. |
|
544 FatMount().MountL(ETrue); //-- force mount |
|
545 } |
|
546 |
|
547 __PRINT1(_L("CFatFormatCB::DoFormatStepL() Format complete drv:%d"), DriveNumber()); |
|
548 } |
|
549 |
|
550 |
|
551 //------------------------------------------------------------------------------------------------------------------- |
|
552 |
|
553 /** |
|
554 Initialize the user specific format parameters for fixed sized disk. |
|
555 |
|
556 @param aDiskSizeInSectors disk size in sectors |
|
557 @return system-wide error code |
|
558 */ |
|
559 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors) |
|
560 { |
|
561 __PRINT1(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() sectors:%d"), aDiskSizeInSectors); |
|
562 Dump_TLDFormatInfo(iSpecialInfo()); |
|
563 |
|
564 //-- KErrArgument will be returned if iSpecialInfo().iFATBits isn't one of EFB32, EFB16, EFB32 |
|
565 |
|
566 if(iSpecialInfo().iFlags & TLDFormatInfo::EOneFatTable) |
|
567 iNumberOfFats = 1; |
|
568 else if(iSpecialInfo().iFlags & TLDFormatInfo::ETwoFatTables) |
|
569 iNumberOfFats = 2; |
|
570 else if(Drive().IsRemovable()) |
|
571 iNumberOfFats = KNumberOfFatsExternal; |
|
572 else |
|
573 iNumberOfFats = KNumberOfFatsInternal; |
|
574 |
|
575 |
|
576 if(iSpecialInfo().iReservedSectors == 0) |
|
577 iReservedSectors = KDefFatResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT12/16) |
|
578 else |
|
579 iReservedSectors = iSpecialInfo().iReservedSectors; |
|
580 |
|
581 |
|
582 const TInt KMaxSecPerCluster = 64; |
|
583 const TInt KDefaultSecPerCluster= 8; //-- default value, if the iSpecialInfo().iSectorsPerCluster isn't specified |
|
584 |
|
585 iSectorsPerCluster = iSpecialInfo().iSectorsPerCluster; |
|
586 if(iSectorsPerCluster <= 0) |
|
587 {//-- default value, user hasn't specified TLDFormatInfo::iSectorsPerCluster |
|
588 iSectorsPerCluster = KDefaultSecPerCluster; //-- will be adjusted later |
|
589 } |
|
590 else |
|
591 { |
|
592 iSectorsPerCluster = Min(1<<Log2(iSectorsPerCluster), KMaxSecPerCluster); |
|
593 } |
|
594 |
|
595 //----------------------------------------- |
|
596 |
|
597 if (aDiskSizeInSectors < 4096) // < 2MB |
|
598 { |
|
599 iSectorsPerCluster = 1; |
|
600 iRootDirEntries = 128; |
|
601 } |
|
602 else if (aDiskSizeInSectors < 8192) // < 4MB |
|
603 { |
|
604 iSectorsPerCluster = Min(iSectorsPerCluster, 2); |
|
605 iRootDirEntries = 256; |
|
606 } |
|
607 else if (aDiskSizeInSectors < 32768) // < 16MB |
|
608 { |
|
609 iSectorsPerCluster = Min(iSectorsPerCluster, 4); |
|
610 iRootDirEntries = 512; |
|
611 } |
|
612 else if (aDiskSizeInSectors < 1048576) // < 512MB |
|
613 { |
|
614 iSectorsPerCluster = Min(iSectorsPerCluster, 8); |
|
615 iRootDirEntries = 512; |
|
616 } |
|
617 else // FAT32 |
|
618 { |
|
619 iRootDirEntries = 512; |
|
620 iSectorsPerCluster = Min(iSectorsPerCluster, KMaxSecPerCluster); |
|
621 } |
|
622 |
|
623 |
|
624 //----------------------------------------- |
|
625 |
|
626 TLDFormatInfo::TFATBits fatBits = iSpecialInfo().iFATBits; |
|
627 if (fatBits == TLDFormatInfo::EFBDontCare) |
|
628 { |
|
629 const TFatType fatType = SuggestFatType(); |
|
630 switch(fatType) |
|
631 { |
|
632 case EFat12: |
|
633 fatBits = TLDFormatInfo::EFB12; |
|
634 break; |
|
635 case EFat16: |
|
636 fatBits = TLDFormatInfo::EFB16; |
|
637 break; |
|
638 case EFat32: |
|
639 fatBits = TLDFormatInfo::EFB32; |
|
640 break; |
|
641 case EInvalid: |
|
642 ASSERT(0); |
|
643 } |
|
644 } |
|
645 |
|
646 TFatType reqFatType(EInvalid); //-- requested FAT type |
|
647 |
|
648 switch (fatBits) |
|
649 { |
|
650 case TLDFormatInfo::EFB12: |
|
651 iFileSystemName=KFileSystemName12; |
|
652 iSectorsPerFat=MaxFat12Sectors(); |
|
653 reqFatType = EFat12; |
|
654 break; |
|
655 |
|
656 case TLDFormatInfo::EFB16: |
|
657 iFileSystemName=KFileSystemName16; |
|
658 iSectorsPerFat=MaxFat16Sectors(); |
|
659 reqFatType = EFat16; |
|
660 break; |
|
661 |
|
662 case TLDFormatInfo::EFB32: |
|
663 iFileSystemName=KFileSystemName32; |
|
664 iSectorsPerFat=MaxFat32Sectors(); |
|
665 |
|
666 iRootDirEntries = 0; |
|
667 iRootClusterNum = 2; |
|
668 |
|
669 if(iSpecialInfo().iReservedSectors == 0) |
|
670 iReservedSectors = KDefFat32ResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT32) |
|
671 else |
|
672 iReservedSectors = iSpecialInfo().iReservedSectors; |
|
673 |
|
674 reqFatType = EFat32; |
|
675 break; |
|
676 |
|
677 default: |
|
678 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() Incorrect FAT type specifier!")); |
|
679 return KErrArgument; |
|
680 } |
|
681 |
|
682 //-- check if we can format the volume with requested FAT type |
|
683 const TFatType fatType = SuggestFatType(); |
|
684 if(fatType != reqFatType) |
|
685 { |
|
686 //-- volume metrics don't correspond to the requested FAT type |
|
687 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT type mismatch!")); |
|
688 return KErrArgument; |
|
689 } |
|
690 |
|
691 return KErrNone; |
|
692 } |
|
693 |
|
694 /** |
|
695 Initialize the format parameters for a custom fixed sized disk |
|
696 |
|
697 @param aFormatInfo The custom format parameters |
|
698 @return system-wide error code |
|
699 */ |
|
700 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskCustom(const TLDFormatInfo& aFormatInfo) |
|
701 { |
|
702 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskCustom()")); |
|
703 Dump_TLDFormatInfo(aFormatInfo); |
|
704 |
|
705 if(aFormatInfo.iFlags & TLDFormatInfo::EOneFatTable) |
|
706 iNumberOfFats = 1; |
|
707 else if(aFormatInfo.iFlags & TLDFormatInfo::ETwoFatTables) |
|
708 iNumberOfFats = 2; |
|
709 else if(Drive().IsRemovable()) |
|
710 iNumberOfFats = KNumberOfFatsExternal; |
|
711 else |
|
712 iNumberOfFats = KNumberOfFatsInternal; |
|
713 |
|
714 iRootDirEntries=512; |
|
715 |
|
716 iSectorsPerCluster = aFormatInfo.iSectorsPerCluster; |
|
717 iSectorsPerTrack = aFormatInfo.iSectorsPerTrack; |
|
718 iNumberOfHeads = aFormatInfo.iNumberOfSides; |
|
719 iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFatResvdSec; |
|
720 |
|
721 switch (aFormatInfo.iFATBits) |
|
722 { |
|
723 case TLDFormatInfo::EFB12: |
|
724 iFileSystemName = KFileSystemName12; |
|
725 iSectorsPerFat = MaxFat12Sectors(); |
|
726 break; |
|
727 |
|
728 case TLDFormatInfo::EFB16: |
|
729 iFileSystemName = KFileSystemName16; |
|
730 iSectorsPerFat = MaxFat16Sectors(); |
|
731 break; |
|
732 |
|
733 case TLDFormatInfo::EFB32: |
|
734 iFileSystemName = KFileSystemName32; |
|
735 iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFat32ResvdSec; |
|
736 iSectorsPerFat = MaxFat32Sectors(); |
|
737 iRootDirEntries = 0; |
|
738 iRootClusterNum = 2; |
|
739 break; |
|
740 |
|
741 default: |
|
742 { |
|
743 TInt64 clusters64 = (aFormatInfo.iCapacity / KDefaultSectorSize) / iSectorsPerCluster; |
|
744 TInt clusters = I64LOW(clusters64); |
|
745 if (clusters < 4085) |
|
746 { |
|
747 iFileSystemName = KFileSystemName12; |
|
748 iSectorsPerFat = MaxFat12Sectors(); |
|
749 } |
|
750 else if(clusters < 65525) |
|
751 { |
|
752 iFileSystemName = KFileSystemName16; |
|
753 iSectorsPerFat = MaxFat16Sectors(); |
|
754 } |
|
755 else |
|
756 { |
|
757 iFileSystemName = KFileSystemName32; |
|
758 iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFat32ResvdSec; |
|
759 iSectorsPerFat = MaxFat32Sectors(); |
|
760 iRootDirEntries = 0; |
|
761 iRootClusterNum = 2; |
|
762 } |
|
763 } |
|
764 } |
|
765 |
|
766 return KErrNone; |
|
767 } |
|
768 |
|
769 void CFatFormatCB::RecordOldInfoL() |
|
770 { |
|
771 // Check if mount or disk is corrupt |
|
772 // This should be stored in member variable because FatMount is remounted |
|
773 // every time RFormat::Next() gets called thus FatMount().Initialised() |
|
774 // will be inconsistent with previous state. |
|
775 TLocalDriveCapsV3Buf caps; |
|
776 User::LeaveIfError(LocalDrive()->Caps(caps)); |
|
777 iVariableSize=((caps().iMediaAtt)&KMediaAttVariableSize) ? (TBool)ETrue : (TBool)EFalse; |
|
778 iDiskCorrupt = !FatMount().ConsistentState(); |
|
779 iBadClusters.Reset(); |
|
780 iBadSectors.Reset(); |
|
781 if (!iVariableSize && !iDiskCorrupt && (iMode&EQuickFormat)) |
|
782 { |
|
783 iOldFirstFreeSector = FatMount().iFirstFreeByte>>FatMount().SectorSizeLog2(); |
|
784 iOldSectorsPerCluster = FatMount().SectorsPerCluster(); |
|
785 |
|
786 FatMount().FAT().InvalidateCacheL(); //-- invalidate whole FAT cache |
|
787 |
|
788 // Collect bad cluster information from current FAT table |
|
789 const TInt maxClusterNum = FatMount().UsableClusters() + KFatFirstSearchCluster; |
|
790 const TUint32 mark = FatMount().Is32BitFat() ? KBad_32Bit : (FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit); |
|
791 |
|
792 for (TInt i=KFatFirstSearchCluster; i<maxClusterNum; ++i) |
|
793 { |
|
794 if (FatMount().FAT().ReadL(i) == mark) |
|
795 iBadClusters.AppendL(i); |
|
796 } |
|
797 } |
|
798 } |
|
799 |
|
800 |
|
801 |
|
802 |
|
803 TInt CFatFormatCB::BadSectorToCluster() |
|
804 { |
|
805 TInt sizeofFatAndRootDir; |
|
806 if (iFileSystemName != KFileSystemName32) |
|
807 sizeofFatAndRootDir = iSectorsPerFat*iNumberOfFats + ((iRootDirEntries*KSizeOfFatDirEntry+(1<<iSectorSizeLog2)-1)>>iSectorSizeLog2); |
|
808 else |
|
809 sizeofFatAndRootDir = (iRootClusterNum-2) * iSectorsPerCluster; |
|
810 TInt firstFreeSector = iReservedSectors + sizeofFatAndRootDir; |
|
811 |
|
812 // Check in rare case that corrupt in critical area |
|
813 // which includes bootsector, FAT table, (and root dir if not FAT32) |
|
814 TInt i, r; |
|
815 for (i=0; i<iBadSectors.Count(); ++i) |
|
816 { |
|
817 TInt badSector = iBadSectors[i]; |
|
818 // Check in rare case that corrupt in critical area |
|
819 // which includes bootsector, FAT table, (and root dir if not FAT32) |
|
820 if (firstFreeSector > badSector) |
|
821 { |
|
822 if (badSector == 0) // Boot sector corrupt |
|
823 return KErrCorrupt; |
|
824 if (iFileSystemName==KFileSystemName32 && badSector==1) // FSInfo corrupt |
|
825 return KErrCorrupt; |
|
826 if (badSector < iReservedSectors) // Harmless in reserved area |
|
827 continue; |
|
828 // Extend reserved area to cover bad sector |
|
829 iReservedSectors = badSector + 1; |
|
830 firstFreeSector = iReservedSectors + sizeofFatAndRootDir; |
|
831 continue; |
|
832 } |
|
833 |
|
834 // Figure out bad cluster number and record it |
|
835 TUint cluster = (badSector-firstFreeSector)/iSectorsPerCluster+2; |
|
836 if (iBadClusters.Find(cluster) == KErrNotFound) |
|
837 { |
|
838 if ((r=iBadClusters.Append(cluster)) != KErrNone) |
|
839 return r; |
|
840 if (iFileSystemName==KFileSystemName32 && iRootClusterNum==cluster) |
|
841 iRootClusterNum++; |
|
842 } |
|
843 } |
|
844 return KErrNone; |
|
845 } |
|
846 |
|
847 /** |
|
848 Create the File system information sector and its backup copy on a disk. |
|
849 Note that CFatMountCB is still not in mounted state, so we can not rely on it. |
|
850 |
|
851 @leave System wide error codes |
|
852 */ |
|
853 void CFatFormatCB::CreateFSInfoSectorL() |
|
854 { |
|
855 __PRINT1(_L("CFatFormatCB::CreateFSInfoSectorL() drv:%d"), DriveNumber()); |
|
856 |
|
857 ASSERT(Is32BitFat()); //-- Actually, CFatMount shall be in a consistent state. |
|
858 |
|
859 TFSInfo fsInfo; |
|
860 TBuf8<KSizeOfFSInfo> fsInfoSecBuf; |
|
861 |
|
862 const TUint32 freeSectors = iMaxDiskSectors - (iReservedSectors + (iNumberOfFats * iSectorsPerFat)); |
|
863 const TUint32 freeClusters = (freeSectors / iSectorsPerCluster) - 1; //-- 1st cluster is taken by empty Root Dir on FAT32 |
|
864 const TUint32 nextFreeClust = iRootClusterNum+1; |
|
865 |
|
866 fsInfo.SetFreeClusterCount(freeClusters); |
|
867 fsInfo.SetNextFreeCluster(nextFreeClust); |
|
868 |
|
869 fsInfo.Externalize(fsInfoSecBuf); //-- put data to the sector buffer |
|
870 |
|
871 User::LeaveIfError(LocalDrive()->Write(KFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- main FSInfo Sector |
|
872 User::LeaveIfError(LocalDrive()->Write(KBkFSInfoSectorNum*iBytesPerSector, fsInfoSecBuf)); //-- Backup FSInfo Sector |
|
873 |
|
874 } |
|
875 |
|
876 /** |
|
877 Create the reserved boot sector and its backup copy on a disk. |
|
878 These are located at sectors 2 & 8 |
|
879 |
|
880 @leave System wide error codes |
|
881 */ |
|
882 void CFatFormatCB::CreateReservedBootSectorL() |
|
883 { |
|
884 __PRINT1(_L("CFatFormatCB::CreateReserveBootSectorL() drv:%d"), DriveNumber()); |
|
885 |
|
886 ASSERT(Is32BitFat()); |
|
887 |
|
888 TFatBootSector bootSector; |
|
889 |
|
890 User::LeaveIfError(FatMount().DoWriteBootSector(KReservedBootSectorNum*KDefaultSectorSize, bootSector)); |
|
891 User::LeaveIfError(FatMount().DoWriteBootSector(KBkReservedBootSectorNum*KDefaultSectorSize, bootSector)); |
|
892 } |
|
893 |
|
894 |
|
895 |
|
896 |