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