• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Routines dealing with disk spaces and FAT table entries.
3 
4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 
14 
15 **/
16 
17 #include "Fat.h"
18 
19 
20 /**
21 
22   Get the FAT entry of the volume, which is identified with the Index.
23 
24   @param  Volume                - FAT file system volume.
25   @param  Index                 - The index of the FAT entry of the volume.
26 
27   @return The buffer of the FAT entry
28 
29 **/
30 STATIC
31 VOID *
FatLoadFatEntry(IN FAT_VOLUME * Volume,IN UINTN Index)32 FatLoadFatEntry (
33   IN FAT_VOLUME       *Volume,
34   IN UINTN            Index
35   )
36 {
37   UINTN       Pos;
38   EFI_STATUS  Status;
39 
40   if (Index > (Volume->MaxCluster + 1)) {
41     Volume->FatEntryBuffer = (UINT32) -1;
42     return &Volume->FatEntryBuffer;
43   }
44   //
45   // Compute buffer position needed
46   //
47   switch (Volume->FatType) {
48   case Fat12:
49     Pos = FAT_POS_FAT12 (Index);
50     break;
51 
52   case Fat16:
53     Pos = FAT_POS_FAT16 (Index);
54     break;
55 
56   default:
57     Pos = FAT_POS_FAT32 (Index);
58   }
59   //
60   // Set the position and read the buffer
61   //
62   Volume->FatEntryPos = Volume->FatPos + Pos;
63   Status = FatDiskIo (
64              Volume,
65              ReadFat,
66              Volume->FatEntryPos,
67              Volume->FatEntrySize,
68              &Volume->FatEntryBuffer,
69              NULL
70              );
71   if (EFI_ERROR (Status)) {
72     Volume->FatEntryBuffer = (UINT32) -1;
73   }
74 
75   return &Volume->FatEntryBuffer;
76 }
77 
78 /**
79 
80   Get the FAT entry value of the volume, which is identified with the Index.
81 
82   @param  Volume                - FAT file system volume.
83   @param  Index                 - The index of the FAT entry of the volume.
84 
85   @return  The value of the FAT entry.
86 
87 **/
88 STATIC
89 UINTN
FatGetFatEntry(IN FAT_VOLUME * Volume,IN UINTN Index)90 FatGetFatEntry (
91   IN FAT_VOLUME       *Volume,
92   IN UINTN            Index
93   )
94 {
95   VOID    *Pos;
96   UINT8   *En12;
97   UINT16  *En16;
98   UINT32  *En32;
99   UINTN   Accum;
100 
101   Pos = FatLoadFatEntry (Volume, Index);
102 
103   if (Index > (Volume->MaxCluster + 1)) {
104     return (UINTN) -1;
105   }
106 
107   switch (Volume->FatType) {
108   case Fat12:
109     En12   = Pos;
110     Accum = En12[0] | (En12[1] << 8);
111     Accum = FAT_ODD_CLUSTER_FAT12 (Index) ? (Accum >> 4) : (Accum & FAT_CLUSTER_MASK_FAT12);
112     Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT12) ? FAT_CLUSTER_SPECIAL_EXT : 0);
113     break;
114 
115   case Fat16:
116     En16   = Pos;
117     Accum = *En16;
118     Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);
119     break;
120 
121   default:
122     En32   = Pos;
123     Accum = *En32 & FAT_CLUSTER_MASK_FAT32;
124     Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT32) ? FAT_CLUSTER_SPECIAL_EXT : 0);
125   }
126 
127   return Accum;
128 }
129 
130 /**
131 
132   Set the FAT entry value of the volume, which is identified with the Index.
133 
134   @param  Volume                - FAT file system volume.
135   @param  Index                 - The index of the FAT entry of the volume.
136   @param  Value                 - The new value of the FAT entry.
137 
138   @retval EFI_SUCCESS           - Set the new FAT entry value sucessfully.
139   @retval EFI_VOLUME_CORRUPTED  - The FAT type of the volume is error.
140   @return other                 - An error occurred when operation the FAT entries.
141 
142 **/
143 STATIC
144 EFI_STATUS
FatSetFatEntry(IN FAT_VOLUME * Volume,IN UINTN Index,IN UINTN Value)145 FatSetFatEntry (
146   IN FAT_VOLUME       *Volume,
147   IN UINTN            Index,
148   IN UINTN            Value
149   )
150 {
151   VOID        *Pos;
152   UINT8       *En12;
153   UINT16      *En16;
154   UINT32      *En32;
155   UINTN       Accum;
156   EFI_STATUS  Status;
157   UINTN       OriginalVal;
158 
159   if (Index < FAT_MIN_CLUSTER) {
160     return EFI_VOLUME_CORRUPTED;
161   }
162 
163   OriginalVal = FatGetFatEntry (Volume, Index);
164   if (Value == FAT_CLUSTER_FREE && OriginalVal != FAT_CLUSTER_FREE) {
165     Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
166     if (Index < Volume->FatInfoSector.FreeInfo.NextCluster) {
167       Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
168     }
169   } else if (Value != FAT_CLUSTER_FREE && OriginalVal == FAT_CLUSTER_FREE) {
170     if (Volume->FatInfoSector.FreeInfo.ClusterCount != 0) {
171       Volume->FatInfoSector.FreeInfo.ClusterCount -= 1;
172     }
173   }
174   //
175   // Make sure the entry is in memory
176   //
177   Pos = FatLoadFatEntry (Volume, Index);
178 
179   //
180   // Update the value
181   //
182   switch (Volume->FatType) {
183   case Fat12:
184     En12   = Pos;
185     Accum = En12[0] | (En12[1] << 8);
186     Value = Value & FAT_CLUSTER_MASK_FAT12;
187 
188     if (FAT_ODD_CLUSTER_FAT12 (Index)) {
189       Accum = (Value << 4) | (Accum & 0xF);
190     } else {
191       Accum = Value | (Accum & FAT_CLUSTER_UNMASK_FAT12);
192     }
193 
194     En12[0]  = (UINT8) (Accum & 0xFF);
195     En12[1]  = (UINT8) (Accum >> 8);
196     break;
197 
198   case Fat16:
199     En16   = Pos;
200     *En16  = (UINT16) Value;
201     break;
202 
203   default:
204     En32   = Pos;
205     *En32  = (*En32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);
206   }
207   //
208   // If the volume's dirty bit is not set, set it now
209   //
210   if (!Volume->FatDirty && Volume->FatType != Fat12) {
211     Volume->FatDirty = TRUE;
212     FatAccessVolumeDirty (Volume, WriteFat, &Volume->DirtyValue);
213   }
214   //
215   // Write the updated fat entry value to the volume
216   // The fat is the first fat, and other fat will be in sync
217   // when the FAT cache flush back.
218   //
219   Status = FatDiskIo (
220              Volume,
221              WriteFat,
222              Volume->FatEntryPos,
223              Volume->FatEntrySize,
224              &Volume->FatEntryBuffer,
225              NULL
226              );
227   return Status;
228 }
229 
230 /**
231 
232   Free the cluster clain.
233 
234   @param  Volume                - FAT file system volume.
235   @param  Cluster               - The first cluster of cluster chain.
236 
237   @retval EFI_SUCCESS           - The cluster chain is freed successfully.
238   @retval EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.
239 
240 **/
241 STATIC
242 EFI_STATUS
FatFreeClusters(IN FAT_VOLUME * Volume,IN UINTN Cluster)243 FatFreeClusters (
244   IN FAT_VOLUME           *Volume,
245   IN UINTN                Cluster
246   )
247 {
248   UINTN LastCluster;
249 
250   while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
251     if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
252 
253       DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
254       return EFI_VOLUME_CORRUPTED;
255     }
256 
257     LastCluster = Cluster;
258     Cluster     = FatGetFatEntry (Volume, Cluster);
259     FatSetFatEntry (Volume, LastCluster, FAT_CLUSTER_FREE);
260   }
261 
262   return EFI_SUCCESS;
263 }
264 
265 /**
266 
267   Allocate a free cluster and return the cluster index.
268 
269   @param  Volume                - FAT file system volume.
270 
271   @return The index of the free cluster
272 
273 **/
274 STATIC
275 UINTN
FatAllocateCluster(IN FAT_VOLUME * Volume)276 FatAllocateCluster (
277   IN FAT_VOLUME   *Volume
278   )
279 {
280   UINTN Cluster;
281 
282   //
283   // Start looking at FatFreePos for the next unallocated cluster
284   //
285   if (Volume->DiskError) {
286     return (UINTN) FAT_CLUSTER_LAST;
287   }
288 
289   for (;;) {
290     //
291     // If the end of the list, return no available cluster
292     //
293     if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
294       if (Volume->FreeInfoValid && 0 < (INT32) (Volume->FatInfoSector.FreeInfo.ClusterCount)) {
295         Volume->FreeInfoValid = FALSE;
296       }
297 
298       FatComputeFreeInfo (Volume);
299       if (Volume->FatInfoSector.FreeInfo.NextCluster > (Volume->MaxCluster + 1)) {
300         return (UINTN) FAT_CLUSTER_LAST;
301       }
302     }
303 
304     Cluster = FatGetFatEntry (Volume, Volume->FatInfoSector.FreeInfo.NextCluster);
305     if (Cluster == FAT_CLUSTER_FREE) {
306       break;
307     }
308     //
309     // Try the next cluster
310     //
311     Volume->FatInfoSector.FreeInfo.NextCluster += 1;
312   }
313 
314   Cluster = Volume->FatInfoSector.FreeInfo.NextCluster;
315   Volume->FatInfoSector.FreeInfo.NextCluster += 1;
316   return Cluster;
317 }
318 
319 /**
320 
321   Count the number of clusters given a size.
322 
323   @param  Volume                - The file system volume.
324   @param  Size                  - The size in bytes.
325 
326   @return The number of the clusters.
327 
328 **/
329 STATIC
330 UINTN
FatSizeToClusters(IN FAT_VOLUME * Volume,IN UINTN Size)331 FatSizeToClusters (
332   IN FAT_VOLUME       *Volume,
333   IN UINTN            Size
334   )
335 {
336   UINTN Clusters;
337 
338   Clusters = Size >> Volume->ClusterAlignment;
339   if ((Size & (Volume->ClusterSize - 1)) > 0) {
340     Clusters += 1;
341   }
342 
343   return Clusters;
344 }
345 
346 /**
347 
348   Shrink the end of the open file base on the file size.
349 
350   @param  OFile                 - The open file.
351 
352   @retval EFI_SUCCESS           - Shrinked sucessfully.
353   @retval EFI_VOLUME_CORRUPTED  - There are errors in the file's clusters.
354 
355 **/
356 EFI_STATUS
FatShrinkEof(IN FAT_OFILE * OFile)357 FatShrinkEof (
358   IN FAT_OFILE            *OFile
359   )
360 {
361   FAT_VOLUME  *Volume;
362   UINTN       NewSize;
363   UINTN       CurSize;
364   UINTN       Cluster;
365   UINTN       LastCluster;
366 
367   Volume  = OFile->Volume;
368   ASSERT_VOLUME_LOCKED (Volume);
369 
370   NewSize = FatSizeToClusters (Volume, OFile->FileSize);
371 
372   //
373   // Find the address of the last cluster
374   //
375   Cluster     = OFile->FileCluster;
376   LastCluster = FAT_CLUSTER_FREE;
377 
378   if (NewSize != 0) {
379 
380     for (CurSize = 0; CurSize < NewSize; CurSize++) {
381       if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
382 
383         DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatShrinkEof: cluster chain corrupt\n"));
384         return EFI_VOLUME_CORRUPTED;
385       }
386 
387       LastCluster = Cluster;
388       Cluster     = FatGetFatEntry (Volume, Cluster);
389     }
390 
391     FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
392 
393   } else {
394     //
395     // Check to see if the file is already completely truncated
396     //
397     if (Cluster == FAT_CLUSTER_FREE) {
398       return EFI_SUCCESS;
399     }
400     //
401     // The file is being completely truncated.
402     //
403     OFile->FileCluster      = FAT_CLUSTER_FREE;
404   }
405   //
406   // Set CurrentCluster == FileCluster
407   // to force a recalculation of Position related stuffs
408   //
409   OFile->FileCurrentCluster = OFile->FileCluster;
410   OFile->FileLastCluster    = LastCluster;
411   OFile->Dirty              = TRUE;
412   //
413   // Free the remaining cluster chain
414   //
415   return FatFreeClusters (Volume, Cluster);
416 }
417 
418 /**
419 
420   Grow the end of the open file base on the NewSizeInBytes.
421 
422   @param  OFile                 - The open file.
423   @param  NewSizeInBytes        - The new size in bytes of the open file.
424 
425   @retval EFI_SUCCESS           - The file is grown sucessfully.
426   @retval EFI_UNSUPPORTED       - The file size is larger than 4GB.
427   @retval EFI_VOLUME_CORRUPTED  - There are errors in the files' clusters.
428   @retval EFI_VOLUME_FULL       - The volume is full and can not grow the file.
429 
430 **/
431 EFI_STATUS
FatGrowEof(IN FAT_OFILE * OFile,IN UINT64 NewSizeInBytes)432 FatGrowEof (
433   IN FAT_OFILE            *OFile,
434   IN UINT64               NewSizeInBytes
435   )
436 {
437   FAT_VOLUME  *Volume;
438   EFI_STATUS  Status;
439   UINTN       Cluster;
440   UINTN       CurSize;
441   UINTN       NewSize;
442   UINTN       LastCluster;
443   UINTN       NewCluster;
444   UINTN       ClusterCount;
445 
446   //
447   // For FAT file system, the max file is 4GB.
448   //
449   if (NewSizeInBytes > 0x0FFFFFFFFL) {
450     return EFI_UNSUPPORTED;
451   }
452 
453   Volume = OFile->Volume;
454   ASSERT_VOLUME_LOCKED (Volume);
455   //
456   // If the file is already large enough, do nothing
457   //
458   CurSize = FatSizeToClusters (Volume, OFile->FileSize);
459   NewSize = FatSizeToClusters (Volume, (UINTN) NewSizeInBytes);
460 
461   if (CurSize < NewSize) {
462     //
463     // If we haven't found the files last cluster do it now
464     //
465     if ((OFile->FileCluster != 0) && (OFile->FileLastCluster == 0)) {
466       Cluster       = OFile->FileCluster;
467       ClusterCount  = 0;
468 
469       while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
470         if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
471 
472           DEBUG (
473             (EFI_D_INIT | EFI_D_ERROR,
474             "FatGrowEof: cluster chain corrupt\n")
475             );
476           Status = EFI_VOLUME_CORRUPTED;
477           goto Done;
478         }
479 
480         ClusterCount++;
481         OFile->FileLastCluster  = Cluster;
482         Cluster                 = FatGetFatEntry (Volume, Cluster);
483       }
484 
485       if (ClusterCount != CurSize) {
486         DEBUG (
487           (EFI_D_INIT | EFI_D_ERROR,
488           "FatGrowEof: cluster chain size does not match file size\n")
489           );
490         Status = EFI_VOLUME_CORRUPTED;
491         goto Done;
492       }
493 
494     }
495     //
496     // Loop until we've allocated enough space
497     //
498     LastCluster = OFile->FileLastCluster;
499 
500     while (CurSize < NewSize) {
501       NewCluster = FatAllocateCluster (Volume);
502       if (FAT_END_OF_FAT_CHAIN (NewCluster)) {
503         if (LastCluster != FAT_CLUSTER_FREE) {
504           FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
505           OFile->FileLastCluster = LastCluster;
506         }
507 
508         Status = EFI_VOLUME_FULL;
509         goto Done;
510       }
511 
512       if (LastCluster != 0) {
513         FatSetFatEntry (Volume, LastCluster, NewCluster);
514       } else {
515         OFile->FileCluster        = NewCluster;
516         OFile->FileCurrentCluster = NewCluster;
517       }
518 
519       LastCluster = NewCluster;
520       CurSize += 1;
521     }
522     //
523     // Terminate the cluster list
524     //
525     FatSetFatEntry (Volume, LastCluster, (UINTN) FAT_CLUSTER_LAST);
526     OFile->FileLastCluster = LastCluster;
527   }
528 
529   OFile->FileSize = (UINTN) NewSizeInBytes;
530   OFile->Dirty    = TRUE;
531   return EFI_SUCCESS;
532 
533 Done:
534   FatShrinkEof (OFile);
535   return Status;
536 }
537 
538 /**
539 
540   Seek OFile to requested position, and calculate the number of
541   consecutive clusters from the position in the file
542 
543   @param  OFile                 - The open file.
544   @param  Position              - The file's position which will be accessed.
545   @param  PosLimit              - The maximum length current reading/writing may access
546 
547   @retval EFI_SUCCESS           - Set the info successfully.
548   @retval EFI_VOLUME_CORRUPTED  - Cluster chain corrupt.
549 
550 **/
551 EFI_STATUS
FatOFilePosition(IN FAT_OFILE * OFile,IN UINTN Position,IN UINTN PosLimit)552 FatOFilePosition (
553   IN FAT_OFILE            *OFile,
554   IN UINTN                Position,
555   IN UINTN                PosLimit
556   )
557 {
558   FAT_VOLUME  *Volume;
559   UINTN       ClusterSize;
560   UINTN       Cluster;
561   UINTN       StartPos;
562   UINTN       Run;
563 
564   Volume      = OFile->Volume;
565   ClusterSize = Volume->ClusterSize;
566 
567   ASSERT_VOLUME_LOCKED (Volume);
568 
569   //
570   // If this is the fixed root dir, then compute it's position
571   // from it's fixed info in the fat bpb
572   //
573   if (OFile->IsFixedRootDir) {
574     OFile->PosDisk  = Volume->RootPos + Position;
575     Run             = OFile->FileSize - Position;
576   } else {
577     //
578     // Run the file's cluster chain to find the current position
579     // If possible, run from the current cluster rather than
580     // start from beginning
581     // Assumption: OFile->Position is always consistent with
582     // OFile->FileCurrentCluster.
583     // OFile->Position is not modified outside this function;
584     // OFile->FileCurrentCluster is modified outside this function
585     // to be the same as OFile->FileCluster
586     // when OFile->FileCluster is updated, so make a check of this
587     // and invalidate the original OFile->Position in this case
588     //
589     Cluster     = OFile->FileCurrentCluster;
590     StartPos    = OFile->Position;
591     if (Position < StartPos || OFile->FileCluster == Cluster) {
592       StartPos  = 0;
593       Cluster   = OFile->FileCluster;
594     }
595 
596     while (StartPos + ClusterSize <= Position) {
597       StartPos += ClusterSize;
598       if (Cluster == FAT_CLUSTER_FREE || (Cluster >= FAT_CLUSTER_SPECIAL)) {
599         DEBUG ((EFI_D_INIT | EFI_D_ERROR, "FatOFilePosition:"" cluster chain corrupt\n"));
600         return EFI_VOLUME_CORRUPTED;
601       }
602 
603       Cluster = FatGetFatEntry (Volume, Cluster);
604     }
605 
606     if (Cluster < FAT_MIN_CLUSTER) {
607       return EFI_VOLUME_CORRUPTED;
608     }
609 
610     OFile->PosDisk            = Volume->FirstClusterPos +
611                                 LShiftU64 (Cluster - FAT_MIN_CLUSTER, Volume->ClusterAlignment) +
612                                 Position - StartPos;
613     OFile->FileCurrentCluster = Cluster;
614     OFile->Position           = StartPos;
615 
616     //
617     // Compute the number of consecutive clusters in the file
618     //
619     Run = StartPos + ClusterSize - Position;
620     if (!FAT_END_OF_FAT_CHAIN (Cluster)) {
621       while ((FatGetFatEntry (Volume, Cluster) == Cluster + 1) && Run < PosLimit) {
622         Run     += ClusterSize;
623         Cluster += 1;
624       }
625     }
626   }
627 
628   OFile->PosRem = Run;
629   return EFI_SUCCESS;
630 }
631 
632 /**
633 
634   Get the size of directory of the open file.
635 
636   @param  Volume                - The File System Volume.
637   @param  Cluster               - The Starting cluster.
638 
639   @return The physical size of the file starting at the input cluster, if there is error in the
640   cluster chain, the return value is 0.
641 
642 **/
643 UINTN
FatPhysicalDirSize(IN FAT_VOLUME * Volume,IN UINTN Cluster)644 FatPhysicalDirSize (
645   IN FAT_VOLUME            *Volume,
646   IN UINTN                 Cluster
647   )
648 {
649   UINTN Size;
650   ASSERT_VOLUME_LOCKED (Volume);
651   //
652   // Run the cluster chain for the OFile
653   //
654   Size = 0;
655   //
656   // N.B. ".." directories on some media do not contain a starting
657   // cluster.  In the case of "." or ".." we don't need the size anyway.
658   //
659   if (Cluster != 0) {
660     while (!FAT_END_OF_FAT_CHAIN (Cluster)) {
661       if (Cluster == FAT_CLUSTER_FREE || Cluster >= FAT_CLUSTER_SPECIAL) {
662         DEBUG (
663           (EFI_D_INIT | EFI_D_ERROR,
664           "FATDirSize: cluster chain corrupt\n")
665           );
666         return 0;
667       }
668 
669       Size += Volume->ClusterSize;
670       Cluster = FatGetFatEntry (Volume, Cluster);
671     }
672   }
673 
674   return Size;
675 }
676 
677 /**
678 
679   Get the physical size of a file on the disk.
680 
681   @param  Volume                - The file system volume.
682   @param  RealSize              - The real size of a file.
683 
684   @return The physical size of a file on the disk.
685 
686 **/
687 UINT64
FatPhysicalFileSize(IN FAT_VOLUME * Volume,IN UINTN RealSize)688 FatPhysicalFileSize (
689   IN FAT_VOLUME            *Volume,
690   IN UINTN                 RealSize
691   )
692 {
693   UINTN   ClusterSizeMask;
694   UINT64  PhysicalSize;
695   ClusterSizeMask = Volume->ClusterSize - 1;
696   PhysicalSize    = (RealSize + ClusterSizeMask) & (~((UINT64) ClusterSizeMask));
697   return PhysicalSize;
698 }
699 
700 /**
701 
702   Update the free cluster info of FatInfoSector of the volume.
703 
704   @param  Volume                - FAT file system volume.
705 
706 **/
707 VOID
FatComputeFreeInfo(IN FAT_VOLUME * Volume)708 FatComputeFreeInfo (
709   IN FAT_VOLUME *Volume
710   )
711 {
712   UINTN Index;
713 
714   //
715   // If we don't have valid info, compute it now
716   //
717   if (!Volume->FreeInfoValid) {
718 
719     Volume->FreeInfoValid                        = TRUE;
720     Volume->FatInfoSector.FreeInfo.ClusterCount  = 0;
721     for (Index = Volume->MaxCluster + 1; Index >= FAT_MIN_CLUSTER; Index--) {
722       if (Volume->DiskError) {
723         break;
724       }
725 
726       if (FatGetFatEntry (Volume, Index) == FAT_CLUSTER_FREE) {
727         Volume->FatInfoSector.FreeInfo.ClusterCount += 1;
728         Volume->FatInfoSector.FreeInfo.NextCluster = (UINT32) Index;
729       }
730     }
731 
732     Volume->FatInfoSector.Signature          = FAT_INFO_SIGNATURE;
733     Volume->FatInfoSector.InfoBeginSignature = FAT_INFO_BEGIN_SIGNATURE;
734     Volume->FatInfoSector.InfoEndSignature   = FAT_INFO_END_SIGNATURE;
735   }
736 }
737