3 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Routines dealing with disk spaces and FAT table entries
31 IN FAT_VOLUME
*Volume
,
38 Get the FAT entry of the volume, which is identified with the Index.
42 Volume - FAT file system volume.
43 Index - The index of the FAT entry of the volume.
47 The buffer of the FAT entry
54 if (Index
> (Volume
->MaxCluster
+ 1)) {
55 Volume
->FatEntryBuffer
= (UINT32
) -1;
56 return &Volume
->FatEntryBuffer
;
59 // Compute buffer position needed
61 switch (Volume
->FatType
) {
63 Pos
= FAT_POS_FAT12 (Index
);
67 Pos
= FAT_POS_FAT16 (Index
);
71 Pos
= FAT_POS_FAT32 (Index
);
74 // Set the position and read the buffer
76 Volume
->FatEntryPos
= Volume
->FatPos
+ Pos
;
82 &Volume
->FatEntryBuffer
,
85 if (EFI_ERROR (Status
)) {
86 Volume
->FatEntryBuffer
= (UINT32
) -1;
89 return &Volume
->FatEntryBuffer
;
95 IN FAT_VOLUME
*Volume
,
102 Get the FAT entry value of the volume, which is identified with the Index.
106 Volume - FAT file system volume.
107 Index - The index of the FAT entry of the volume.
111 The value of the FAT entry.
121 Pos
= FatLoadFatEntry (Volume
, Index
);
123 if (Index
> (Volume
->MaxCluster
+ 1)) {
127 switch (Volume
->FatType
) {
130 Accum
= E12
[0] | (E12
[1] << 8);
131 Accum
= FAT_ODD_CLUSTER_FAT12 (Index
) ? (Accum
>> 4) : (Accum
& FAT_CLUSTER_MASK_FAT12
);
132 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT12
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
138 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT16
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
143 Accum
= *E32
& FAT_CLUSTER_MASK_FAT32
;
144 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT32
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
153 IN FAT_VOLUME
*Volume
,
161 Set the FAT entry value of the volume, which is identified with the Index.
165 Volume - FAT file system volume.
166 Index - The index of the FAT entry of the volume.
167 Value - The new value of the FAT entry.
171 EFI_SUCCESS - Set the new FAT entry value sucessfully.
172 EFI_VOLUME_CORRUPTED - The FAT type of the volume is error.
173 other - An error occurred when operation the FAT entries.
185 if (Index
< FAT_MIN_CLUSTER
) {
186 return EFI_VOLUME_CORRUPTED
;
189 OriginalVal
= FatGetFatEntry (Volume
, Index
);
190 if (Value
== FAT_CLUSTER_FREE
&& OriginalVal
!= FAT_CLUSTER_FREE
) {
191 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
+= 1;
192 if (Index
< Volume
->FatInfoSector
.FreeInfo
.NextCluster
) {
193 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= (UINT32
) Index
;
195 } else if (Value
!= FAT_CLUSTER_FREE
&& OriginalVal
== FAT_CLUSTER_FREE
) {
196 if (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
!= 0) {
197 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
-= 1;
201 // Make sure the entry is in memory
203 Pos
= FatLoadFatEntry (Volume
, Index
);
208 switch (Volume
->FatType
) {
211 Accum
= E12
[0] | (E12
[1] << 8);
212 Value
= Value
& FAT_CLUSTER_MASK_FAT12
;
214 if (FAT_ODD_CLUSTER_FAT12 (Index
)) {
215 Accum
= (Value
<< 4) | (Accum
& 0xF);
217 Accum
= Value
| (Accum
& FAT_CLUSTER_UNMASK_FAT12
);
220 E12
[0] = (UINT8
) (Accum
& 0xFF);
221 E12
[1] = (UINT8
) (Accum
>> 8);
226 *E16
= (UINT16
) Value
;
231 *E32
= (*E32
& FAT_CLUSTER_UNMASK_FAT32
) | (UINT32
) (Value
& FAT_CLUSTER_MASK_FAT32
);
234 // If the volume's dirty bit is not set, set it now
236 if (!Volume
->FatDirty
&& Volume
->FatType
!= FAT12
) {
237 Volume
->FatDirty
= TRUE
;
238 FatAccessVolumeDirty (Volume
, WRITE_FAT
, &Volume
->DirtyValue
);
241 // Write the updated fat entry value to the volume
242 // The fat is the first fat, and other fat will be in sync
243 // when the FAT cache flush back.
249 Volume
->FatEntrySize
,
250 &Volume
->FatEntryBuffer
,
259 IN FAT_VOLUME
*Volume
,
266 Free the cluster clain.
270 Volume - FAT file system volume.
271 Cluster - The first cluster of cluster chain.
275 EFI_SUCCESS - The cluster chain is freed successfully.
276 EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
282 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
283 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
285 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
286 return EFI_VOLUME_CORRUPTED
;
289 LastCluster
= Cluster
;
290 Cluster
= FatGetFatEntry (Volume
, Cluster
);
291 FatSetFatEntry (Volume
, LastCluster
, FAT_CLUSTER_FREE
);
300 IN FAT_VOLUME
*Volume
306 Allocate a free cluster and return the cluster index.
310 Volume - FAT file system volume.
314 The index of the free cluster
321 // Start looking at FatFreePos for the next unallocated cluster
323 if (Volume
->DiskError
) {
324 return (UINTN
) FAT_CLUSTER_LAST
;
329 // If the end of the list, return no available cluster
331 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
332 if (Volume
->FreeInfoValid
&& 0 < (INT32
) (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
)) {
333 Volume
->FreeInfoValid
= FALSE
;
336 FatComputeFreeInfo (Volume
);
337 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
338 return (UINTN
) FAT_CLUSTER_LAST
;
342 Cluster
= FatGetFatEntry (Volume
, Volume
->FatInfoSector
.FreeInfo
.NextCluster
);
343 if (Cluster
== FAT_CLUSTER_FREE
) {
347 // Try the next cluster
349 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
352 Cluster
= Volume
->FatInfoSector
.FreeInfo
.NextCluster
;
353 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
360 IN FAT_VOLUME
*Volume
,
367 Count the number of clusters given a size
371 Volume - The file system volume.
372 Size - The size in bytes.
376 The number of the clusters.
382 Clusters
= Size
>> Volume
->ClusterAlignment
;
383 if ((Size
& (Volume
->ClusterSize
- 1)) > 0) {
398 Shrink the end of the open file base on the file size.
402 OFile - The open file.
406 EFI_SUCCESS - Shrinked sucessfully.
407 EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
417 Volume
= OFile
->Volume
;
418 ASSERT_VOLUME_LOCKED (Volume
);
420 NewSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
423 // Find the address of the last cluster
425 Cluster
= OFile
->FileCluster
;
426 LastCluster
= FAT_CLUSTER_FREE
;
430 for (CurSize
= 0; CurSize
< NewSize
; CurSize
++) {
431 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
433 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
434 return EFI_VOLUME_CORRUPTED
;
437 LastCluster
= Cluster
;
438 Cluster
= FatGetFatEntry (Volume
, Cluster
);
441 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
445 // Check to see if the file is already completely truncated
447 if (Cluster
== FAT_CLUSTER_FREE
) {
451 // The file is being completely truncated.
453 OFile
->FileCluster
= FAT_CLUSTER_FREE
;
456 // Set CurrentCluster == FileCluster
457 // to force a recalculation of Position related stuffs
459 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
460 OFile
->FileLastCluster
= LastCluster
;
463 // Free the remaining cluster chain
465 return FatFreeClusters (Volume
, Cluster
);
471 IN UINT64 NewSizeInBytes
477 Grow the end of the open file base on the NewSizeInBytes.
481 OFile - The open file.
482 NewSizeInBytes - The new size in bytes of the open file.
486 EFI_SUCCESS - The file is grown sucessfully.
487 EFI_UNSUPPORTED - The file size is larger than 4GB.
488 EFI_VOLUME_CORRUPTED - There are errors in the files' clusters.
489 EFI_VOLUME_FULL - The volume is full and can not grow the file.
503 // For FAT file system, the max file is 4GB.
505 if (NewSizeInBytes
> 0x0FFFFFFFFL
) {
506 return EFI_UNSUPPORTED
;
509 Volume
= OFile
->Volume
;
510 ASSERT_VOLUME_LOCKED (Volume
);
512 // If the file is already large enough, do nothing
514 CurSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
515 NewSize
= FatSizeToClusters (Volume
, (UINTN
) NewSizeInBytes
);
517 if (CurSize
< NewSize
) {
519 // If we haven't found the files last cluster do it now
521 if ((OFile
->FileCluster
!= 0) && (OFile
->FileLastCluster
== 0)) {
522 Cluster
= OFile
->FileCluster
;
525 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
526 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
529 (EFI_D_INIT
| EFI_D_ERROR
,
530 "FatGrowEof: cluster chain corrupt\n")
532 Status
= EFI_VOLUME_CORRUPTED
;
537 OFile
->FileLastCluster
= Cluster
;
538 Cluster
= FatGetFatEntry (Volume
, Cluster
);
541 if (ClusterCount
!= CurSize
) {
543 (EFI_D_INIT
| EFI_D_ERROR
,
544 "FatGrowEof: cluster chain size does not match file size\n")
546 Status
= EFI_VOLUME_CORRUPTED
;
552 // Loop until we've allocated enough space
554 LastCluster
= OFile
->FileLastCluster
;
556 while (CurSize
< NewSize
) {
557 NewCluster
= FatAllocateCluster (Volume
);
558 if (FAT_END_OF_FAT_CHAIN (NewCluster
)) {
559 if (LastCluster
!= FAT_CLUSTER_FREE
) {
560 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
561 OFile
->FileLastCluster
= LastCluster
;
564 Status
= EFI_VOLUME_FULL
;
568 if (LastCluster
!= 0) {
569 FatSetFatEntry (Volume
, LastCluster
, NewCluster
);
571 OFile
->FileCluster
= NewCluster
;
572 OFile
->FileCurrentCluster
= NewCluster
;
575 LastCluster
= NewCluster
;
579 // Terminate the cluster list
581 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
582 OFile
->FileLastCluster
= LastCluster
;
585 OFile
->FileSize
= (UINTN
) NewSizeInBytes
;
590 FatShrinkEof (OFile
);
604 Seek OFile to requested position, and calculate the number of
605 consecutive clusters from the position in the file
609 OFile - The open file.
610 Position - The file's position which will be accessed.
611 PosLimit - The maximum length current reading/writing may access
615 EFI_SUCCESS - Set the info successfully.
616 EFI_VOLUME_CORRUPTED - Cluster chain corrupt.
626 Volume
= OFile
->Volume
;
627 ClusterSize
= Volume
->ClusterSize
;
629 ASSERT_VOLUME_LOCKED (Volume
);
632 // If this is the fixed root dir, then compute it's position
633 // from it's fixed info in the fat bpb
635 if (OFile
->IsFixedRootDir
) {
636 OFile
->PosDisk
= Volume
->RootPos
+ Position
;
637 Run
= OFile
->FileSize
- Position
;
640 // Run the file's cluster chain to find the current position
641 // If possible, run from the current cluster rather than
642 // start from beginning
643 // Assumption: OFile->Position is always consistent with
644 // OFile->FileCurrentCluster.
645 // OFile->Position is not modified outside this function;
646 // OFile->FileCurrentCluster is modified outside this function
647 // to be the same as OFile->FileCluster
648 // when OFile->FileCluster is updated, so make a check of this
649 // and invalidate the original OFile->Position in this case
651 Cluster
= OFile
->FileCurrentCluster
;
652 StartPos
= OFile
->Position
;
653 if (Position
< StartPos
|| OFile
->FileCluster
== Cluster
) {
655 Cluster
= OFile
->FileCluster
;
658 while (StartPos
+ ClusterSize
<= Position
) {
659 StartPos
+= ClusterSize
;
660 if (Cluster
== FAT_CLUSTER_FREE
|| (Cluster
>= FAT_CLUSTER_SPECIAL
)) {
661 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatOFilePosition:"" cluster chain corrupt\n"));
662 return EFI_VOLUME_CORRUPTED
;
665 Cluster
= FatGetFatEntry (Volume
, Cluster
);
668 if (Cluster
< FAT_MIN_CLUSTER
) {
669 return EFI_VOLUME_CORRUPTED
;
672 OFile
->PosDisk
= Volume
->FirstClusterPos
+
673 LShiftU64 (Cluster
- FAT_MIN_CLUSTER
, Volume
->ClusterAlignment
) +
675 OFile
->FileCurrentCluster
= Cluster
;
676 OFile
->Position
= StartPos
;
679 // Compute the number of consecutive clusters in the file
681 Run
= StartPos
+ ClusterSize
- Position
;
682 if (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
683 while ((FatGetFatEntry (Volume
, Cluster
) == Cluster
+ 1) && Run
< PosLimit
) {
696 IN FAT_VOLUME
*Volume
,
703 Get the size of directory of the open file
707 Volume - The File System Volume.
708 Cluster - The Starting cluster.
712 The physical size of the file starting at the input cluster, if there is error in the
713 cluster chain, the return value is 0.
718 ASSERT_VOLUME_LOCKED (Volume
);
720 // Run the cluster chain for the OFile
724 // N.B. ".." directories on some media do not contain a starting
725 // cluster. In the case of "." or ".." we don't need the size anyway.
728 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
729 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
731 (EFI_D_INIT
| EFI_D_ERROR
,
732 "FATDirSize: cluster chain corrupt\n")
737 Size
+= Volume
->ClusterSize
;
738 Cluster
= FatGetFatEntry (Volume
, Cluster
);
746 FatPhysicalFileSize (
747 IN FAT_VOLUME
*Volume
,
754 Get the physical size of a file on the disk.
758 Volume - The file system volume.
759 RealSize - The real size of a file.
763 The physical size of a file on the disk.
767 UINTN ClusterSizeMask
;
769 ClusterSizeMask
= Volume
->ClusterSize
- 1;
770 PhysicalSize
= (RealSize
+ ClusterSizeMask
) & (~((UINT64
) ClusterSizeMask
));
776 IN FAT_VOLUME
*Volume
782 Update the free cluster info of FatInfoSector of the volume.
786 Volume - FAT file system volume.
797 // If we don't have valid info, compute it now
799 if (!Volume
->FreeInfoValid
) {
801 Volume
->FreeInfoValid
= TRUE
;
802 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
= 0;
803 for (Index
= Volume
->MaxCluster
+ 1; Index
>= FAT_MIN_CLUSTER
; Index
--) {
804 if (Volume
->DiskError
) {
808 if (FatGetFatEntry (Volume
, Index
) == FAT_CLUSTER_FREE
) {
809 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
+= 1;
810 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= (UINT32
) Index
;
814 Volume
->FatInfoSector
.Signature
= FAT_INFO_SIGNATURE
;
815 Volume
->FatInfoSector
.InfoBeginSignature
= FAT_INFO_BEGIN_SIGNATURE
;
816 Volume
->FatInfoSector
.InfoEndSignature
= FAT_INFO_END_SIGNATURE
;