|
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_fat16.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 |
|
19 #include "sl_std.h" |
|
20 #include "sl_cache.h" |
|
21 |
|
22 const TUint KDefFatResvdSec = 1; ///< default number of FAT12/16 reserved sectors |
|
23 |
|
24 /** |
|
25 Initialize the format parameters for a normal fixed sized disk |
|
26 Setting set to adhere to Rules of Count of clusters for FAT type |
|
27 |
|
28 @param aDiskSizeInSectors Size of volume in sectors |
|
29 @return system-wide error code |
|
30 */ |
|
31 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskNormal(TInt aDiskSizeInSectors, const TLocalDriveCapsV6& aCaps) |
|
32 { |
|
33 if( Drive().IsRemovable() ) |
|
34 iNumberOfFats = KNumberOfFatsExternal; |
|
35 else |
|
36 iNumberOfFats = KNumberOfFatsInternal; |
|
37 |
|
38 iReservedSectors=KDefFatResvdSec; |
|
39 if (aDiskSizeInSectors<4084*1) // < 2MB |
|
40 { |
|
41 iRootDirEntries=128; |
|
42 iSectorsPerCluster=1; |
|
43 iFileSystemName=KFileSystemName12; |
|
44 iSectorsPerFat=MaxFat12Sectors(); |
|
45 } |
|
46 else if (aDiskSizeInSectors<4084*2) // < 4MB (8168 sectors) |
|
47 { |
|
48 iRootDirEntries=256; |
|
49 iSectorsPerCluster=2; |
|
50 iFileSystemName=KFileSystemName12; |
|
51 iSectorsPerFat=MaxFat12Sectors(); |
|
52 } |
|
53 else if (aDiskSizeInSectors<4084*4) // < 8MB (16336 sectors) |
|
54 { |
|
55 iRootDirEntries=512; |
|
56 iSectorsPerCluster=4; |
|
57 iFileSystemName=KFileSystemName12; |
|
58 iSectorsPerFat=MaxFat12Sectors(); |
|
59 } |
|
60 else if (aDiskSizeInSectors<4084*8) // < 16MB (32672 sectors) |
|
61 { |
|
62 iRootDirEntries=512; |
|
63 iSectorsPerCluster=8; |
|
64 iFileSystemName=KFileSystemName12; |
|
65 iSectorsPerFat=MaxFat12Sectors(); |
|
66 } |
|
67 else // >= 16Mb - FAT16 |
|
68 { |
|
69 iFileSystemName=KFileSystemName16; |
|
70 TInt minSectorsPerCluster=(aDiskSizeInSectors+KMaxFAT16Entries-1)/KMaxFAT16Entries; |
|
71 iRootDirEntries=512; |
|
72 iSectorsPerCluster=1; |
|
73 while (minSectorsPerCluster>iSectorsPerCluster) |
|
74 iSectorsPerCluster<<=1; |
|
75 iSectorsPerFat=MaxFat16Sectors(); |
|
76 } |
|
77 |
|
78 // Ensure cluster size is a multiple of the block size |
|
79 TInt blockSizeInSectors = aCaps.iBlockSize >> iSectorSizeLog2; |
|
80 __PRINT1(_L("blockSizeInSectors: %d"),blockSizeInSectors); |
|
81 ASSERT(blockSizeInSectors == 0 || IsPowerOf2(blockSizeInSectors)); |
|
82 if (blockSizeInSectors != 0 && IsPowerOf2(blockSizeInSectors)) |
|
83 { |
|
84 __PRINT1(_L("iSectorsPerCluster (old): %d"),iSectorsPerCluster); |
|
85 AdjustClusterSize(blockSizeInSectors); |
|
86 __PRINT1(_L("iSectorsPerCluster (new): %d"),iSectorsPerCluster); |
|
87 } |
|
88 |
|
89 // Align first data sector on an erase block boundary if |
|
90 // (1) the iEraseBlockSize is specified |
|
91 // (2) the start of the partition is already aligned to an erase block boundary, |
|
92 // i.e. iHiddenSectors is zero or a multiple of iEraseBlockSize |
|
93 __PRINT1(_L("iHiddenSectors: %d"),iHiddenSectors); |
|
94 TInt eraseblockSizeInSectors = aCaps.iEraseBlockSize >> iSectorSizeLog2; |
|
95 __PRINT1(_L("eraseblockSizeInSectors: %d"),eraseblockSizeInSectors); |
|
96 ASSERT(eraseblockSizeInSectors == 0 || IsPowerOf2(eraseblockSizeInSectors)); |
|
97 ASSERT(eraseblockSizeInSectors == 0 || eraseblockSizeInSectors >= blockSizeInSectors); |
|
98 if ((eraseblockSizeInSectors != 0) && |
|
99 (iHiddenSectors % eraseblockSizeInSectors == 0) && |
|
100 (IsPowerOf2(eraseblockSizeInSectors)) && |
|
101 (eraseblockSizeInSectors >= blockSizeInSectors)) |
|
102 { |
|
103 TInt r = AdjustFirstDataSectorAlignment(eraseblockSizeInSectors); |
|
104 ASSERT(r == KErrNone); |
|
105 (void) r; |
|
106 } |
|
107 __PRINT1(_L("iReservedSectors: %d"),iReservedSectors); |
|
108 __PRINT1(_L("FirstDataSector: %d"), FirstDataSector()); |
|
109 |
|
110 return KErrNone; |
|
111 } |
|
112 |
|
113 TInt CFatFormatCB::FirstDataSector() const |
|
114 { |
|
115 TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; |
|
116 return iHiddenSectors + iReservedSectors + iNumberOfFats*iSectorsPerFat + rootDirSectors; |
|
117 } |
|
118 |
|
119 void CFatFormatCB::AdjustClusterSize(TInt aRecommendedSectorsPerCluster) |
|
120 { |
|
121 const TInt KMaxSecPerCluster = 64; // 32K |
|
122 while (aRecommendedSectorsPerCluster > iSectorsPerCluster && iSectorsPerCluster <= (KMaxSecPerCluster/2)) |
|
123 iSectorsPerCluster<<= 1; |
|
124 } |
|
125 |
|
126 // AdjustFirstDataSectorAlignment() |
|
127 // Attempts to align the first data sector on an erase block boundary by modifying the |
|
128 // number of reserved sectors. |
|
129 TInt CFatFormatCB::AdjustFirstDataSectorAlignment(TInt aEraseBlockSizeInSectors) |
|
130 { |
|
131 const TBool bFat16 = Is16BitFat(); |
|
132 |
|
133 // Save these 2 values in the event of a convergence failure; this should |
|
134 // hopefully never happen, but we will cater for this in release mode to be safe, |
|
135 TInt reservedSectorsSaved = iReservedSectors; |
|
136 TInt sectorsPerFatSaved = iSectorsPerFat; |
|
137 |
|
138 TInt reservedSectorsOld = 0; |
|
139 |
|
140 // zero for FAT32 |
|
141 TInt rootDirSectors = (iRootDirEntries * KSizeOfFatDirEntry + (iBytesPerSector-1)) / iBytesPerSector; |
|
142 TInt fatSectors = 0; |
|
143 |
|
144 TInt KMaxIterations = 10; |
|
145 TInt n; |
|
146 for (n=0; n<KMaxIterations && reservedSectorsOld != iReservedSectors; n++) |
|
147 { |
|
148 reservedSectorsOld = iReservedSectors; |
|
149 |
|
150 iSectorsPerFat = bFat16 ? MaxFat16Sectors() : MaxFat12Sectors(); |
|
151 |
|
152 fatSectors = iSectorsPerFat * iNumberOfFats; |
|
153 |
|
154 // calculate number of blocks |
|
155 TInt nBlocks = (iReservedSectors + fatSectors + rootDirSectors + aEraseBlockSizeInSectors-1) / aEraseBlockSizeInSectors; |
|
156 |
|
157 iReservedSectors = (nBlocks * aEraseBlockSizeInSectors) - rootDirSectors - fatSectors; |
|
158 } |
|
159 |
|
160 ASSERT(iReservedSectors >= (TInt) KDefFatResvdSec); |
|
161 |
|
162 if ((FirstDataSector() & (aEraseBlockSizeInSectors-1)) == 0) |
|
163 { |
|
164 return KErrNone; |
|
165 } |
|
166 else |
|
167 { |
|
168 iReservedSectors = reservedSectorsSaved; |
|
169 iSectorsPerFat = sectorsPerFatSaved; |
|
170 return KErrGeneral; |
|
171 } |
|
172 } |
|
173 |
|
174 /** |
|
175 Initialize the user specific format parameters for fixed sized disk. |
|
176 |
|
177 @param aDiskSizeInSectors disk size in sectors |
|
178 @return system-wide error code |
|
179 */ |
|
180 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskUser(TInt aDiskSizeInSectors) |
|
181 { |
|
182 //-- KErrArgument will be returned if iSpecialInfo().iFATBits isn't one of EFB32, EFB16, EFB32 |
|
183 |
|
184 if(iSpecialInfo().iFlags & TLDFormatInfo::EOneFatTable) |
|
185 iNumberOfFats = 1; |
|
186 else if(iSpecialInfo().iFlags & TLDFormatInfo::ETwoFatTables) |
|
187 iNumberOfFats = 2; |
|
188 else if(Drive().IsRemovable()) |
|
189 iNumberOfFats = KNumberOfFatsExternal; |
|
190 else |
|
191 iNumberOfFats = KNumberOfFatsInternal; |
|
192 |
|
193 |
|
194 if(iSpecialInfo().iReservedSectors == 0) |
|
195 iReservedSectors = KDefFatResvdSec; //-- user hasn't specified reserved sectors count, use default (FAT12/16) |
|
196 else |
|
197 iReservedSectors = iSpecialInfo().iReservedSectors; |
|
198 |
|
199 |
|
200 const TInt KMaxSecPerCluster = 64; |
|
201 const TInt KDefaultSecPerCluster= 8; //-- default value, if the iSpecialInfo().iSectorsPerCluster isn't specified |
|
202 |
|
203 iSectorsPerCluster = iSpecialInfo().iSectorsPerCluster; |
|
204 if(iSectorsPerCluster <= 0) |
|
205 {//-- default value, user hasn't specified TLDFormatInfo::iSectorsPerCluster |
|
206 iSectorsPerCluster = KDefaultSecPerCluster; //-- will be adjusted later |
|
207 } |
|
208 else |
|
209 { |
|
210 iSectorsPerCluster = Min(1<<Log2(iSectorsPerCluster), KMaxSecPerCluster); |
|
211 } |
|
212 |
|
213 //----------------------------------------- |
|
214 |
|
215 if (aDiskSizeInSectors < 4096) // < 2MB |
|
216 { |
|
217 iSectorsPerCluster = 1; |
|
218 iRootDirEntries = 128; |
|
219 } |
|
220 else if (aDiskSizeInSectors < 8192) // < 4MB |
|
221 { |
|
222 iSectorsPerCluster = Min(iSectorsPerCluster, 2); |
|
223 iRootDirEntries = 256; |
|
224 } |
|
225 else if (aDiskSizeInSectors < 32768) // < 16MB |
|
226 { |
|
227 iSectorsPerCluster = Min(iSectorsPerCluster, 4); |
|
228 iRootDirEntries = 512; |
|
229 } |
|
230 else if (aDiskSizeInSectors < 131072) // < 64MB |
|
231 { |
|
232 iSectorsPerCluster = Min(iSectorsPerCluster, 8); |
|
233 iRootDirEntries = 512; |
|
234 } |
|
235 else // >= 64Mb |
|
236 iRootDirEntries = 512; |
|
237 |
|
238 //----------------------------------------- |
|
239 |
|
240 TLDFormatInfo::TFATBits fatBits = iSpecialInfo().iFATBits; |
|
241 if (fatBits == TLDFormatInfo::EFBDontCare) |
|
242 { |
|
243 const TFatType fatType = SuggestFatType(); |
|
244 switch(fatType) |
|
245 { |
|
246 case EFat12: |
|
247 fatBits = TLDFormatInfo::EFB12; |
|
248 break; |
|
249 case EFat16: |
|
250 fatBits = TLDFormatInfo::EFB16; |
|
251 break; |
|
252 case EFat32: |
|
253 fatBits = TLDFormatInfo::EFB32; |
|
254 break; |
|
255 case EInvalid: |
|
256 ASSERT(0); |
|
257 } |
|
258 } |
|
259 |
|
260 TFatType reqFatType(EInvalid); //-- requested FAT type |
|
261 |
|
262 switch (fatBits) |
|
263 { |
|
264 case TLDFormatInfo::EFB12: |
|
265 iFileSystemName=KFileSystemName12; |
|
266 iSectorsPerFat=MaxFat12Sectors(); |
|
267 reqFatType = EFat12; |
|
268 break; |
|
269 |
|
270 case TLDFormatInfo::EFB16: |
|
271 iFileSystemName=KFileSystemName16; |
|
272 iSectorsPerFat=MaxFat16Sectors(); |
|
273 reqFatType = EFat16; |
|
274 break; |
|
275 |
|
276 case TLDFormatInfo::EFB32: |
|
277 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT32 Not supported!")); |
|
278 return KErrNotSupported; |
|
279 |
|
280 default: |
|
281 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() Incorrect FAT type specifier!")); |
|
282 return KErrArgument; |
|
283 }; |
|
284 |
|
285 //-- check if we can format the volume with requested FAT type |
|
286 const TFatType fatType = SuggestFatType(); |
|
287 if(fatType != reqFatType) |
|
288 {//-- volume metrics don't correspond to the requested FAT type |
|
289 __PRINT(_L("CFatFormatCB::InitFormatDataForFixedSizeDiskUser() FAT type mismatch!")); |
|
290 return KErrArgument; |
|
291 } |
|
292 |
|
293 |
|
294 return KErrNone; |
|
295 } |
|
296 |
|
297 /** |
|
298 Initialize the format parameters for a custom fixed sized disk |
|
299 |
|
300 @param aFormatInfo The custom format parameters |
|
301 @return system-wide error code |
|
302 */ |
|
303 TInt CFatFormatCB::InitFormatDataForFixedSizeDiskCustom(const TLDFormatInfo& aFormatInfo) |
|
304 { |
|
305 if(aFormatInfo.iFlags & TLDFormatInfo::EOneFatTable) |
|
306 iNumberOfFats = 1; |
|
307 else if(aFormatInfo.iFlags & TLDFormatInfo::ETwoFatTables) |
|
308 iNumberOfFats = 2; |
|
309 else if(Drive().IsRemovable()) |
|
310 iNumberOfFats = KNumberOfFatsExternal; |
|
311 else |
|
312 iNumberOfFats = KNumberOfFatsInternal; |
|
313 |
|
314 iRootDirEntries=512; |
|
315 |
|
316 iSectorsPerCluster = aFormatInfo.iSectorsPerCluster; |
|
317 iSectorsPerTrack = aFormatInfo.iSectorsPerTrack; |
|
318 iNumberOfHeads = aFormatInfo.iNumberOfSides; |
|
319 iReservedSectors = aFormatInfo.iReservedSectors ? aFormatInfo.iReservedSectors : KDefFatResvdSec; |
|
320 |
|
321 switch (aFormatInfo.iFATBits) |
|
322 { |
|
323 case TLDFormatInfo::EFB12: |
|
324 iFileSystemName = KFileSystemName12; |
|
325 iSectorsPerFat = MaxFat12Sectors(); |
|
326 break; |
|
327 |
|
328 case TLDFormatInfo::EFB16: |
|
329 iFileSystemName = KFileSystemName16; |
|
330 iSectorsPerFat = MaxFat16Sectors(); |
|
331 break; |
|
332 |
|
333 default: |
|
334 { |
|
335 TInt64 clusters64 = (aFormatInfo.iCapacity / KDefaultSectorSize) / iSectorsPerCluster; |
|
336 TInt clusters = I64LOW(clusters64); |
|
337 if (clusters < 4085) |
|
338 { |
|
339 iFileSystemName = KFileSystemName12; |
|
340 iSectorsPerFat = MaxFat12Sectors(); |
|
341 } |
|
342 else |
|
343 { |
|
344 iFileSystemName = KFileSystemName16; |
|
345 iSectorsPerFat = MaxFat16Sectors(); |
|
346 } |
|
347 } |
|
348 } |
|
349 |
|
350 return KErrNone; |
|
351 } |
|
352 |
|
353 void CFatFormatCB::RecordOldInfoL() |
|
354 { |
|
355 __PRINT(_L("CFatFormatCB::RecordOldInfoL")); |
|
356 // Check if mount or disk is corrupt |
|
357 // This should be stored in member variable because FatMount is remounted |
|
358 // every time RFormat::Next() gets called thus FatMount().Initialised() |
|
359 // will be inconsistent with previous state. |
|
360 TLocalDriveCapsV3Buf caps; |
|
361 User::LeaveIfError(LocalDrive()->Caps(caps)); |
|
362 iVariableSize=((caps().iMediaAtt)&KMediaAttVariableSize) ? (TBool)ETrue : (TBool)EFalse; |
|
363 iDiskCorrupt = !FatMount().ConsistentState(); |
|
364 iBadClusters.Reset(); |
|
365 iBadSectors.Reset(); |
|
366 if (!iVariableSize && !iDiskCorrupt && (iMode & EQuickFormat)) |
|
367 { |
|
368 iOldFirstFreeSector = FatMount().iFirstFreeByte >> FatMount().SectorSizeLog2(); |
|
369 iOldSectorsPerCluster = FatMount().SectorsPerCluster(); |
|
370 |
|
371 FatMount().FAT().InvalidateCacheL(); //-- invalidate whole FAT cache |
|
372 |
|
373 const TInt maxClusterNum = FatMount().iUsableClusters + KFatFirstSearchCluster; |
|
374 |
|
375 // Collect bad cluster information from current FAT table |
|
376 const TUint32 mark = FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit; |
|
377 for (TInt i=KFatFirstSearchCluster; i<maxClusterNum; i++) |
|
378 if (FatMount().FAT().ReadL(i) == mark) |
|
379 iBadClusters.AppendL(i); |
|
380 } |
|
381 } |
|
382 |
|
383 /** |
|
384 Create the boot sector on media for the volume. |
|
385 |
|
386 @leave System wide error codes |
|
387 */ |
|
388 void CFatFormatCB::CreateBootSectorL() |
|
389 { |
|
390 __PRINT1(_L("CFatFormatCB::CreateBootSector() drive:%d"),DriveNumber()); |
|
391 |
|
392 TFatBootSector bootSector; |
|
393 |
|
394 bootSector.SetVendorID(KDefaultVendorID); |
|
395 bootSector.SetBytesPerSector(iBytesPerSector); |
|
396 bootSector.SetSectorsPerCluster(iSectorsPerCluster); |
|
397 bootSector.SetReservedSectors(iReservedSectors); |
|
398 bootSector.SetNumberOfFats(iNumberOfFats); |
|
399 bootSector.SetRootDirEntries(iRootDirEntries); |
|
400 if (iMaxDiskSectors<(TInt)KMaxTUint16) |
|
401 bootSector.SetTotalSectors(iMaxDiskSectors); |
|
402 else |
|
403 { |
|
404 bootSector.SetTotalSectors(0); |
|
405 bootSector.SetHugeSectors(iMaxDiskSectors); |
|
406 } |
|
407 TInt numberOfClusters=iMaxDiskSectors/iSectorsPerCluster; |
|
408 if (numberOfClusters>(TInt)KMaxTUint16) |
|
409 User::Leave(KErrTooBig); |
|
410 bootSector.SetFatSectors(iSectorsPerFat); |
|
411 bootSector.SetReservedByte(0); |
|
412 TTime timeID; |
|
413 timeID.HomeTime(); // System time in future? |
|
414 bootSector.SetUniqueID(I64LOW(timeID.Int64())); // Generate UniqueID from time |
|
415 bootSector.SetVolumeLabel(_L8("")); |
|
416 bootSector.SetFileSysType(iFileSystemName); |
|
417 // Floppy specific info: |
|
418 bootSector.SetJumpInstruction(); |
|
419 bootSector.SetMediaDescriptor(KBootSectorMediaDescriptor); |
|
420 bootSector.SetNumberOfHeads(iNumberOfHeads); |
|
421 bootSector.SetHiddenSectors(iHiddenSectors); |
|
422 bootSector.SetSectorsPerTrack(iSectorsPerTrack); |
|
423 bootSector.SetPhysicalDriveNumber(128); |
|
424 bootSector.SetExtendedBootSignature(0x29); |
|
425 |
|
426 |
|
427 User::LeaveIfError(FatMount().DoWriteBootSector(KBootSectorNum*bootSector.BytesPerSector(), bootSector)); |
|
428 } |
|
429 |
|
430 //------------------------------------------------------------------------------------------------------------------- |
|
431 |
|
432 /** |
|
433 Format a disk section, called iteratively to erase whole of media, on last iteration |
|
434 creates an empty volume. If called with quick formatonly erases the Fat leaving the |
|
435 rest of the volume intact. |
|
436 |
|
437 @leave System wide error code |
|
438 */ |
|
439 void CFatFormatCB::DoFormatStepL() |
|
440 { |
|
441 if (iFormatInfo.iFormatIsCurrent==EFalse) |
|
442 { |
|
443 if (iMode & EForceErase) |
|
444 { |
|
445 TInt r = FatMount().ErasePassword(); |
|
446 User::LeaveIfError(r); |
|
447 // CFatMountCB::ErasePassword() calls TBusLocalDrive::ForceRemount(), |
|
448 // so need to stop a remount from occurring in next call to : |
|
449 // TFsFormatNext::DoRequestL((), TDrive::CheckMount(). |
|
450 FatMount().Drive().SetChanged(EFalse); |
|
451 } |
|
452 |
|
453 RecordOldInfoL(); |
|
454 InitializeFormatDataL(); |
|
455 FatMount().DoDismount(); |
|
456 if (iVariableSize) |
|
457 FatMount().ReduceSizeL(0,I64LOW(FatMount().iSize)); |
|
458 } |
|
459 // |
|
460 // Blank disk if not EQuickFormat |
|
461 // |
|
462 if (!iVariableSize && !(iMode & EQuickFormat) && iCurrentStep) |
|
463 { |
|
464 if (iFormatInfo.iFormatIsCurrent == EFalse) |
|
465 {//-- firstly invalidate sectors 0-6 inclusive |
|
466 DoZeroFillMediaL(0, 7*iBytesPerSector); |
|
467 } |
|
468 |
|
469 TInt ret=FatMount().LocalDrive()->Format(iFormatInfo); |
|
470 if (ret!=KErrNone && ret!=KErrEof) // Handle format error |
|
471 ret = HandleCorrupt(ret); |
|
472 if (ret!=KErrNone && ret!=KErrEof) // KErrEof could be set by LocalDrive()->Format() |
|
473 User::Leave(ret); |
|
474 if (ret==KErrNone) |
|
475 { |
|
476 iCurrentStep=100-(100*iFormatInfo.i512ByteSectorsFormatted)/iMaxDiskSectors; |
|
477 if (iCurrentStep<=0) |
|
478 iCurrentStep=1; |
|
479 return; |
|
480 } |
|
481 } |
|
482 |
|
483 // ReMount since MBR may have been rewritten and partition may have moved / changed size |
|
484 TInt ret = LocalDrive()->ForceRemount(0); |
|
485 if (ret != KErrNone && ret != KErrNotSupported) |
|
486 User::Leave(ret); |
|
487 |
|
488 // MBR may have changed, so need to re-read iHiddenSectors etc.before BPB is written |
|
489 InitializeFormatDataL(); |
|
490 |
|
491 // Translate bad sector number to cluster number which contains that sector |
|
492 // This only happens in full format, in quick format they are already cluster numbers |
|
493 if (!iVariableSize && !(iMode & EQuickFormat)) |
|
494 User::LeaveIfError(BadSectorToCluster()); |
|
495 |
|
496 // |
|
497 // Do the rest of the disk in one lump |
|
498 // |
|
499 iCurrentStep=0; |
|
500 |
|
501 |
|
502 //-- zero-fill media from position 0 to the FAT end, i.e main & backup boot sector, FSInfo and its copy and all FATs |
|
503 const TUint32 posFatEnd = ((iSectorsPerFat*iNumberOfFats) + iReservedSectors) * iBytesPerSector; //-- last FAT end position |
|
504 |
|
505 if (iVariableSize) |
|
506 FatMount().EnlargeL(posFatEnd); |
|
507 |
|
508 DoZeroFillMediaL(0, posFatEnd); |
|
509 |
|
510 //-- Zero fill root directory |
|
511 const TInt rootDirSector = iReservedSectors + (iNumberOfFats * iSectorsPerFat); |
|
512 const TInt rootDirSize = iRootDirEntries * KSizeOfFatDirEntry; //-- size in bytes |
|
513 |
|
514 const TUint32 posRootDirStart = rootDirSector * iBytesPerSector; |
|
515 const TUint32 posRootDirEnd = posRootDirStart + rootDirSize; |
|
516 |
|
517 const TInt numOfRootSectors=(rootDirSize%iBytesPerSector) ? (rootDirSize/iBytesPerSector+1) : (rootDirSize/iBytesPerSector); |
|
518 if (iVariableSize) |
|
519 FatMount().EnlargeL(iBytesPerSector*numOfRootSectors); |
|
520 |
|
521 DoZeroFillMediaL(posRootDirStart, posRootDirEnd); |
|
522 |
|
523 // Enlarge ram drive to take into account rounding of |
|
524 // data start to cluster boundary |
|
525 if(iVariableSize && iSectorsPerCluster!=1) |
|
526 { |
|
527 const TInt firstFreeSector=rootDirSector+numOfRootSectors; |
|
528 const TInt firstFreeCluster=firstFreeSector%iSectorsPerCluster ? firstFreeSector/iSectorsPerCluster+1 : firstFreeSector/iSectorsPerCluster; |
|
529 const TInt alignedSector=firstFreeCluster*iSectorsPerCluster; |
|
530 if(alignedSector!=firstFreeSector) |
|
531 FatMount().EnlargeL((alignedSector-firstFreeSector)*iBytesPerSector); |
|
532 } |
|
533 |
|
534 //-- FAT[0] must contain media descriptor in the low byte, FAT[1] for fat16/32 may contain some flags |
|
535 TBuf8<4> startFat(4); |
|
536 startFat.Fill(0xFF); |
|
537 |
|
538 if(iVariableSize||Is16BitFat()) //-- FAT16 or RAM drive which is always FAT16 |
|
539 { |
|
540 startFat.SetLength(4); |
|
541 } |
|
542 else //-- FAT12 |
|
543 { |
|
544 startFat.SetLength(3); |
|
545 } |
|
546 |
|
547 startFat[0]=KBootSectorMediaDescriptor; |
|
548 |
|
549 //-- write FAT[0] and FAT[1] entries to all copies of FAT |
|
550 for(TInt i=0;i<iNumberOfFats;i++) |
|
551 { |
|
552 User::LeaveIfError(LocalDrive()->Write(iBytesPerSector*(iReservedSectors+(iSectorsPerFat*i)),startFat)); |
|
553 } |
|
554 |
|
555 //-- create boot sectors |
|
556 CreateBootSectorL(); |
|
557 |
|
558 //-- here we have bad clusters numbers saved by the quick format |
|
559 //-- Interpret old bad cluster number to new cluster number and mark new bad clusters |
|
560 if (!iVariableSize && iBadClusters.Count()>0) |
|
561 { |
|
562 //-- Here we need fully mounted volume, so mount it normally. |
|
563 FatMount().MountL(EFalse); |
|
564 |
|
565 iBadClusters.Sort(); |
|
566 TranslateL(); |
|
567 TInt mark = FatMount().Is16BitFat() ? KBad_16Bit : KBad_12Bit; |
|
568 TInt i; |
|
569 |
|
570 for (i=0; i<iBadClusters.Count(); ++i) |
|
571 FatMount().FAT().WriteL(iBadClusters[i], mark); |
|
572 |
|
573 FatMount().FAT().FlushL(); |
|
574 #if defined(_DEBUG) |
|
575 TInt r=FatMount().CheckDisk(); |
|
576 __PRINT1(_L("CFatFormatCB::DoFormatStepL() CheckDisk res: %d"),r); |
|
577 #endif |
|
578 } |
|
579 else |
|
580 { |
|
581 //-- We do not need to perform full mount in this case, the TDrive object will be marked as changed in ~CFormatCB and the |
|
582 //-- mount will be closed. Therefore on the first access to it it will be mounted normally. |
|
583 FatMount().MountL(ETrue); //-- force mount |
|
584 } |
|
585 |
|
586 __PRINT1(_L("CFatFormatCB::DoFormatStepL() Format complete drv:%d"), DriveNumber()); |
|
587 } |
|
588 |
|
589 TInt CFatFormatCB::BadSectorToCluster() |
|
590 { |
|
591 const TInt sizeofFatAndRootDir = iSectorsPerFat*iNumberOfFats + ((iRootDirEntries*KSizeOfFatDirEntry+(1<<iSectorSizeLog2)-1)>>iSectorSizeLog2); |
|
592 TInt firstFreeSector = iReservedSectors + sizeofFatAndRootDir; |
|
593 |
|
594 TInt i, r; |
|
595 for (i=0; i<iBadSectors.Count(); ++i) |
|
596 { |
|
597 TInt badSector = iBadSectors[i]; |
|
598 // Check in rare case that corrupt in critical area |
|
599 // which includes bootsector, FAT table, (and root dir if not FAT32) |
|
600 if (badSector < firstFreeSector) |
|
601 { |
|
602 if (badSector == 0) // Boot sector corrupt |
|
603 return KErrCorrupt; |
|
604 if (badSector < iReservedSectors) // Harmless in reserved area |
|
605 continue; |
|
606 // Extend reserved area to cover bad sector |
|
607 iReservedSectors = badSector + 1; |
|
608 firstFreeSector = iReservedSectors + sizeofFatAndRootDir; |
|
609 continue; |
|
610 } |
|
611 |
|
612 // Figure out bad cluster number and record it |
|
613 TInt cluster = (badSector-firstFreeSector)/iSectorsPerCluster + KFatFirstSearchCluster; |
|
614 if (iBadClusters.Find(cluster) == KErrNotFound) |
|
615 { |
|
616 if ((r=iBadClusters.Append(cluster)) != KErrNone) |
|
617 return r; |
|
618 } |
|
619 } |
|
620 return KErrNone; |
|
621 } |
|
622 |