2 Routines dealing with disk spaces and FAT table entries.
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
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.
22 Get the FAT entry of the volume, which is identified with the Index.
24 @param Volume - FAT file system volume.
25 @param Index - The index of the FAT entry of the volume.
27 @return The buffer of the FAT entry
33 IN FAT_VOLUME
*Volume
,
40 if (Index
> (Volume
->MaxCluster
+ 1)) {
41 Volume
->FatEntryBuffer
= (UINT32
) -1;
42 return &Volume
->FatEntryBuffer
;
45 // Compute buffer position needed
47 switch (Volume
->FatType
) {
49 Pos
= FAT_POS_FAT12 (Index
);
53 Pos
= FAT_POS_FAT16 (Index
);
57 Pos
= FAT_POS_FAT32 (Index
);
60 // Set the position and read the buffer
62 Volume
->FatEntryPos
= Volume
->FatPos
+ Pos
;
68 &Volume
->FatEntryBuffer
,
71 if (EFI_ERROR (Status
)) {
72 Volume
->FatEntryBuffer
= (UINT32
) -1;
75 return &Volume
->FatEntryBuffer
;
80 Get the FAT entry value of the volume, which is identified with the Index.
82 @param Volume - FAT file system volume.
83 @param Index - The index of the FAT entry of the volume.
85 @return The value of the FAT entry.
91 IN FAT_VOLUME
*Volume
,
101 Pos
= FatLoadFatEntry (Volume
, Index
);
103 if (Index
> (Volume
->MaxCluster
+ 1)) {
107 switch (Volume
->FatType
) {
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);
118 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT16
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
123 Accum
= *En32
& FAT_CLUSTER_MASK_FAT32
;
124 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT32
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
132 Set the FAT entry value of the volume, which is identified with the Index.
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.
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.
146 IN FAT_VOLUME
*Volume
,
159 if (Index
< FAT_MIN_CLUSTER
) {
160 return EFI_VOLUME_CORRUPTED
;
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
;
169 } else if (Value
!= FAT_CLUSTER_FREE
&& OriginalVal
== FAT_CLUSTER_FREE
) {
170 if (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
!= 0) {
171 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
-= 1;
175 // Make sure the entry is in memory
177 Pos
= FatLoadFatEntry (Volume
, Index
);
182 switch (Volume
->FatType
) {
185 Accum
= En12
[0] | (En12
[1] << 8);
186 Value
= Value
& FAT_CLUSTER_MASK_FAT12
;
188 if (FAT_ODD_CLUSTER_FAT12 (Index
)) {
189 Accum
= (Value
<< 4) | (Accum
& 0xF);
191 Accum
= Value
| (Accum
& FAT_CLUSTER_UNMASK_FAT12
);
194 En12
[0] = (UINT8
) (Accum
& 0xFF);
195 En12
[1] = (UINT8
) (Accum
>> 8);
200 *En16
= (UINT16
) Value
;
205 *En32
= (*En32
& FAT_CLUSTER_UNMASK_FAT32
) | (UINT32
) (Value
& FAT_CLUSTER_MASK_FAT32
);
208 // If the volume's dirty bit is not set, set it now
210 if (!Volume
->FatDirty
&& Volume
->FatType
!= Fat12
) {
211 Volume
->FatDirty
= TRUE
;
212 FatAccessVolumeDirty (Volume
, WriteFat
, &Volume
->DirtyValue
);
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.
223 Volume
->FatEntrySize
,
224 &Volume
->FatEntryBuffer
,
232 Free the cluster clain.
234 @param Volume - FAT file system volume.
235 @param Cluster - The first cluster of cluster chain.
237 @retval EFI_SUCCESS - The cluster chain is freed successfully.
238 @retval EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
244 IN FAT_VOLUME
*Volume
,
250 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
251 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
253 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
254 return EFI_VOLUME_CORRUPTED
;
257 LastCluster
= Cluster
;
258 Cluster
= FatGetFatEntry (Volume
, Cluster
);
259 FatSetFatEntry (Volume
, LastCluster
, FAT_CLUSTER_FREE
);
267 Allocate a free cluster and return the cluster index.
269 @param Volume - FAT file system volume.
271 @return The index of the free cluster
277 IN FAT_VOLUME
*Volume
283 // Start looking at FatFreePos for the next unallocated cluster
285 if (Volume
->DiskError
) {
286 return (UINTN
) FAT_CLUSTER_LAST
;
291 // If the end of the list, return no available cluster
293 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
294 if (Volume
->FreeInfoValid
&& 0 < (INT32
) (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
)) {
295 Volume
->FreeInfoValid
= FALSE
;
298 FatComputeFreeInfo (Volume
);
299 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
300 return (UINTN
) FAT_CLUSTER_LAST
;
304 Cluster
= FatGetFatEntry (Volume
, Volume
->FatInfoSector
.FreeInfo
.NextCluster
);
305 if (Cluster
== FAT_CLUSTER_FREE
) {
309 // Try the next cluster
311 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
314 Cluster
= Volume
->FatInfoSector
.FreeInfo
.NextCluster
;
315 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
321 Count the number of clusters given a size.
323 @param Volume - The file system volume.
324 @param Size - The size in bytes.
326 @return The number of the clusters.
332 IN FAT_VOLUME
*Volume
,
338 Clusters
= Size
>> Volume
->ClusterAlignment
;
339 if ((Size
& (Volume
->ClusterSize
- 1)) > 0) {
348 Shrink the end of the open file base on the file size.
350 @param OFile - The open file.
352 @retval EFI_SUCCESS - Shrinked sucessfully.
353 @retval EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
367 Volume
= OFile
->Volume
;
368 ASSERT_VOLUME_LOCKED (Volume
);
370 NewSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
373 // Find the address of the last cluster
375 Cluster
= OFile
->FileCluster
;
376 LastCluster
= FAT_CLUSTER_FREE
;
380 for (CurSize
= 0; CurSize
< NewSize
; CurSize
++) {
381 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
383 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
384 return EFI_VOLUME_CORRUPTED
;
387 LastCluster
= Cluster
;
388 Cluster
= FatGetFatEntry (Volume
, Cluster
);
391 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
395 // Check to see if the file is already completely truncated
397 if (Cluster
== FAT_CLUSTER_FREE
) {
401 // The file is being completely truncated.
403 OFile
->FileCluster
= FAT_CLUSTER_FREE
;
406 // Set CurrentCluster == FileCluster
407 // to force a recalculation of Position related stuffs
409 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
410 OFile
->FileLastCluster
= LastCluster
;
413 // Free the remaining cluster chain
415 return FatFreeClusters (Volume
, Cluster
);
420 Grow the end of the open file base on the NewSizeInBytes.
422 @param OFile - The open file.
423 @param NewSizeInBytes - The new size in bytes of the open file.
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.
434 IN UINT64 NewSizeInBytes
447 // For FAT file system, the max file is 4GB.
449 if (NewSizeInBytes
> 0x0FFFFFFFFL
) {
450 return EFI_UNSUPPORTED
;
453 Volume
= OFile
->Volume
;
454 ASSERT_VOLUME_LOCKED (Volume
);
456 // If the file is already large enough, do nothing
458 CurSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
459 NewSize
= FatSizeToClusters (Volume
, (UINTN
) NewSizeInBytes
);
461 if (CurSize
< NewSize
) {
463 // If we haven't found the files last cluster do it now
465 if ((OFile
->FileCluster
!= 0) && (OFile
->FileLastCluster
== 0)) {
466 Cluster
= OFile
->FileCluster
;
469 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
470 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
473 (EFI_D_INIT
| EFI_D_ERROR
,
474 "FatGrowEof: cluster chain corrupt\n")
476 Status
= EFI_VOLUME_CORRUPTED
;
481 OFile
->FileLastCluster
= Cluster
;
482 Cluster
= FatGetFatEntry (Volume
, Cluster
);
485 if (ClusterCount
!= CurSize
) {
487 (EFI_D_INIT
| EFI_D_ERROR
,
488 "FatGrowEof: cluster chain size does not match file size\n")
490 Status
= EFI_VOLUME_CORRUPTED
;
496 // Loop until we've allocated enough space
498 LastCluster
= OFile
->FileLastCluster
;
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
;
508 Status
= EFI_VOLUME_FULL
;
512 if (LastCluster
!= 0) {
513 FatSetFatEntry (Volume
, LastCluster
, NewCluster
);
515 OFile
->FileCluster
= NewCluster
;
516 OFile
->FileCurrentCluster
= NewCluster
;
519 LastCluster
= NewCluster
;
523 // Terminate the cluster list
525 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
526 OFile
->FileLastCluster
= LastCluster
;
529 OFile
->FileSize
= (UINTN
) NewSizeInBytes
;
534 FatShrinkEof (OFile
);
540 Seek OFile to requested position, and calculate the number of
541 consecutive clusters from the position in the file
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
547 @retval EFI_SUCCESS - Set the info successfully.
548 @retval EFI_VOLUME_CORRUPTED - Cluster chain corrupt.
564 Volume
= OFile
->Volume
;
565 ClusterSize
= Volume
->ClusterSize
;
567 ASSERT_VOLUME_LOCKED (Volume
);
570 // If this is the fixed root dir, then compute it's position
571 // from it's fixed info in the fat bpb
573 if (OFile
->IsFixedRootDir
) {
574 OFile
->PosDisk
= Volume
->RootPos
+ Position
;
575 Run
= OFile
->FileSize
- Position
;
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
589 Cluster
= OFile
->FileCurrentCluster
;
590 StartPos
= OFile
->Position
;
591 if (Position
< StartPos
|| OFile
->FileCluster
== Cluster
) {
593 Cluster
= OFile
->FileCluster
;
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
;
603 Cluster
= FatGetFatEntry (Volume
, Cluster
);
606 if (Cluster
< FAT_MIN_CLUSTER
) {
607 return EFI_VOLUME_CORRUPTED
;
610 OFile
->PosDisk
= Volume
->FirstClusterPos
+
611 LShiftU64 (Cluster
- FAT_MIN_CLUSTER
, Volume
->ClusterAlignment
) +
613 OFile
->FileCurrentCluster
= Cluster
;
614 OFile
->Position
= StartPos
;
617 // Compute the number of consecutive clusters in the file
619 Run
= StartPos
+ ClusterSize
- Position
;
620 if (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
621 while ((FatGetFatEntry (Volume
, Cluster
) == Cluster
+ 1) && Run
< PosLimit
) {
634 Get the size of directory of the open file.
636 @param Volume - The File System Volume.
637 @param Cluster - The Starting cluster.
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.
645 IN FAT_VOLUME
*Volume
,
650 ASSERT_VOLUME_LOCKED (Volume
);
652 // Run the cluster chain for the OFile
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.
660 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
661 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
663 (EFI_D_INIT
| EFI_D_ERROR
,
664 "FATDirSize: cluster chain corrupt\n")
669 Size
+= Volume
->ClusterSize
;
670 Cluster
= FatGetFatEntry (Volume
, Cluster
);
679 Get the physical size of a file on the disk.
681 @param Volume - The file system volume.
682 @param RealSize - The real size of a file.
684 @return The physical size of a file on the disk.
688 FatPhysicalFileSize (
689 IN FAT_VOLUME
*Volume
,
693 UINTN ClusterSizeMask
;
695 ClusterSizeMask
= Volume
->ClusterSize
- 1;
696 PhysicalSize
= (RealSize
+ ClusterSizeMask
) & (~((UINT64
) ClusterSizeMask
));
702 Update the free cluster info of FatInfoSector of the volume.
704 @param Volume - FAT file system volume.
709 IN FAT_VOLUME
*Volume
715 // If we don't have valid info, compute it now
717 if (!Volume
->FreeInfoValid
) {
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
) {
726 if (FatGetFatEntry (Volume
, Index
) == FAT_CLUSTER_FREE
) {
727 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
+= 1;
728 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= (UINT32
) Index
;
732 Volume
->FatInfoSector
.Signature
= FAT_INFO_SIGNATURE
;
733 Volume
->FatInfoSector
.InfoBeginSignature
= FAT_INFO_BEGIN_SIGNATURE
;
734 Volume
->FatInfoSector
.InfoEndSignature
= FAT_INFO_END_SIGNATURE
;