3 Copyright (c) 2005, Intel Corporation
4 All rights reserved. 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
84 if (EFI_ERROR (Status
)) {
85 Volume
->FatEntryBuffer
= (UINT32
) -1;
88 return &Volume
->FatEntryBuffer
;
94 IN FAT_VOLUME
*Volume
,
101 Get the FAT entry value of the volume, which is identified with the Index.
105 Volume - FAT file system volume.
106 Index - The index of the FAT entry of the volume.
110 The value of the FAT entry.
120 Pos
= FatLoadFatEntry (Volume
, Index
);
122 if (Index
> (Volume
->MaxCluster
+ 1)) {
126 switch (Volume
->FatType
) {
129 Accum
= E12
[0] | (E12
[1] << 8);
130 Accum
= FAT_ODD_CLUSTER_FAT12 (Index
) ? (Accum
>> 4) : (Accum
& FAT_CLUSTER_MASK_FAT12
);
131 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT12
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
137 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT16
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
142 Accum
= *E32
& FAT_CLUSTER_MASK_FAT32
;
143 Accum
= Accum
| ((Accum
>= FAT_CLUSTER_SPECIAL_FAT32
) ? FAT_CLUSTER_SPECIAL_EXT
: 0);
152 IN FAT_VOLUME
*Volume
,
160 Set the FAT entry value of the volume, which is identified with the Index.
164 Volume - FAT file system volume.
165 Index - The index of the FAT entry of the volume.
166 Value - The new value of the FAT entry.
170 EFI_SUCCESS - Set the new FAT entry value sucessfully.
171 EFI_VOLUME_CORRUPTED - The FAT type of the volume is error.
172 other - An error occurred when operation the FAT entries.
184 if (Index
< FAT_MIN_CLUSTER
) {
185 return EFI_VOLUME_CORRUPTED
;
188 OriginalVal
= FatGetFatEntry (Volume
, Index
);
189 if (Value
== FAT_CLUSTER_FREE
&& OriginalVal
!= FAT_CLUSTER_FREE
) {
190 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
+= 1;
191 if (Index
< Volume
->FatInfoSector
.FreeInfo
.NextCluster
) {
192 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= (UINT32
) Index
;
194 } else if (Value
!= FAT_CLUSTER_FREE
&& OriginalVal
== FAT_CLUSTER_FREE
) {
195 if (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
!= 0) {
196 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
-= 1;
200 // Make sure the entry is in memory
202 Pos
= FatLoadFatEntry (Volume
, Index
);
207 switch (Volume
->FatType
) {
210 Accum
= E12
[0] | (E12
[1] << 8);
211 Value
= Value
& FAT_CLUSTER_MASK_FAT12
;
213 if (FAT_ODD_CLUSTER_FAT12 (Index
)) {
214 Accum
= (Value
<< 4) | (Accum
& 0xF);
216 Accum
= Value
| (Accum
& FAT_CLUSTER_UNMASK_FAT12
);
219 E12
[0] = (UINT8
) (Accum
& 0xFF);
220 E12
[1] = (UINT8
) (Accum
>> 8);
225 *E16
= (UINT16
) Value
;
230 *E32
= (*E32
& FAT_CLUSTER_UNMASK_FAT32
) | (UINT32
) (Value
& FAT_CLUSTER_MASK_FAT32
);
233 // If the volume's dirty bit is not set, set it now
235 if (!Volume
->FatDirty
&& Volume
->FatType
!= FAT12
) {
236 Volume
->FatDirty
= TRUE
;
237 FatAccessVolumeDirty (Volume
, WRITE_FAT
, &Volume
->DirtyValue
);
240 // Write the updated fat entry value to the volume
241 // The fat is the first fat, and other fat will be in sync
242 // when the FAT cache flush back.
248 Volume
->FatEntrySize
,
249 &Volume
->FatEntryBuffer
257 IN FAT_VOLUME
*Volume
,
264 Free the cluster clain.
268 Volume - FAT file system volume.
269 Cluster - The first cluster of cluster chain.
273 EFI_SUCCESS - The cluster chain is freed successfully.
274 EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
280 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
281 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
283 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
284 return EFI_VOLUME_CORRUPTED
;
287 LastCluster
= Cluster
;
288 Cluster
= FatGetFatEntry (Volume
, Cluster
);
289 FatSetFatEntry (Volume
, LastCluster
, FAT_CLUSTER_FREE
);
298 IN FAT_VOLUME
*Volume
304 Allocate a free cluster and return the cluster index.
308 Volume - FAT file system volume.
312 The index of the free cluster
319 // Start looking at FatFreePos for the next unallocated cluster
321 if (Volume
->DiskError
) {
322 return (UINTN
) FAT_CLUSTER_LAST
;
327 // If the end of the list, return no available cluster
329 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
330 if (Volume
->FreeInfoValid
&& 0 < (INT32
) (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
)) {
331 Volume
->FreeInfoValid
= FALSE
;
334 FatComputeFreeInfo (Volume
);
335 if (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> (Volume
->MaxCluster
+ 1)) {
336 return (UINTN
) FAT_CLUSTER_LAST
;
340 Cluster
= FatGetFatEntry (Volume
, Volume
->FatInfoSector
.FreeInfo
.NextCluster
);
341 if (Cluster
== FAT_CLUSTER_FREE
) {
345 // Try the next cluster
347 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
350 Cluster
= Volume
->FatInfoSector
.FreeInfo
.NextCluster
;
351 Volume
->FatInfoSector
.FreeInfo
.NextCluster
+= 1;
358 IN FAT_VOLUME
*Volume
,
365 Count the number of clusters given a size
369 Volume - The file system volume.
370 Size - The size in bytes.
374 The number of the clusters.
380 Clusters
= Size
>> Volume
->ClusterAlignment
;
381 if ((Size
& (Volume
->ClusterSize
- 1)) > 0) {
396 Shrink the end of the open file base on the file size.
400 OFile - The open file.
404 EFI_SUCCESS - Shrinked sucessfully.
405 EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.
415 Volume
= OFile
->Volume
;
416 ASSERT_VOLUME_LOCKED (Volume
);
418 NewSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
421 // Find the address of the last cluster
423 Cluster
= OFile
->FileCluster
;
424 LastCluster
= FAT_CLUSTER_FREE
;
428 for (CurSize
= 0; CurSize
< NewSize
; CurSize
++) {
429 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
431 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatShrinkEof: cluster chain corrupt\n"));
432 return EFI_VOLUME_CORRUPTED
;
435 LastCluster
= Cluster
;
436 Cluster
= FatGetFatEntry (Volume
, Cluster
);
439 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
443 // Check to see if the file is already completely truncated
445 if (Cluster
== FAT_CLUSTER_FREE
) {
449 // The file is being completely truncated.
451 OFile
->FileCluster
= FAT_CLUSTER_FREE
;
454 // Set CurrentCluster == FileCluster
455 // to force a recalculation of Position related stuffs
457 OFile
->FileCurrentCluster
= OFile
->FileCluster
;
458 OFile
->FileLastCluster
= LastCluster
;
461 // Free the remaining cluster chain
463 return FatFreeClusters (Volume
, Cluster
);
469 IN UINT64 NewSizeInBytes
475 Grow the end of the open file base on the NewSizeInBytes.
479 OFile - The open file.
480 NewSizeInBytes - The new size in bytes of the open file.
484 EFI_SUCCESS - The file is grown sucessfully.
485 EFI_UNSUPPORTED - The file size is larger than 4GB.
486 EFI_VOLUME_CORRUPTED - There are errors in the files' clusters.
487 EFI_VOLUME_FULL - The volume is full and can not grow the file.
501 // For FAT file system, the max file is 4GB.
503 if (NewSizeInBytes
> 0x0FFFFFFFFL
) {
504 return EFI_UNSUPPORTED
;
507 Volume
= OFile
->Volume
;
508 ASSERT_VOLUME_LOCKED (Volume
);
510 // If the file is already large enough, do nothing
512 CurSize
= FatSizeToClusters (Volume
, OFile
->FileSize
);
513 NewSize
= FatSizeToClusters (Volume
, (UINTN
) NewSizeInBytes
);
515 if (CurSize
< NewSize
) {
517 // If we haven't found the files last cluster do it now
519 if ((OFile
->FileCluster
!= 0) && (OFile
->FileLastCluster
== 0)) {
520 Cluster
= OFile
->FileCluster
;
523 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
524 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
527 (EFI_D_INIT
| EFI_D_ERROR
,
528 "FatGrowEof: cluster chain corrupt\n")
530 Status
= EFI_VOLUME_CORRUPTED
;
535 OFile
->FileLastCluster
= Cluster
;
536 Cluster
= FatGetFatEntry (Volume
, Cluster
);
539 if (ClusterCount
!= CurSize
) {
541 (EFI_D_INIT
| EFI_D_ERROR
,
542 "FatGrowEof: cluster chain size does not match file size\n")
544 Status
= EFI_VOLUME_CORRUPTED
;
550 // Loop until we've allocated enough space
552 LastCluster
= OFile
->FileLastCluster
;
554 while (CurSize
< NewSize
) {
555 NewCluster
= FatAllocateCluster (Volume
);
556 if (FAT_END_OF_FAT_CHAIN (NewCluster
)) {
557 if (LastCluster
!= FAT_CLUSTER_FREE
) {
558 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
559 OFile
->FileLastCluster
= LastCluster
;
562 Status
= EFI_VOLUME_FULL
;
566 if (LastCluster
!= 0) {
567 FatSetFatEntry (Volume
, LastCluster
, NewCluster
);
569 OFile
->FileCluster
= NewCluster
;
570 OFile
->FileCurrentCluster
= NewCluster
;
573 LastCluster
= NewCluster
;
577 // Terminate the cluster list
579 FatSetFatEntry (Volume
, LastCluster
, (UINTN
) FAT_CLUSTER_LAST
);
580 OFile
->FileLastCluster
= LastCluster
;
583 OFile
->FileSize
= (UINTN
) NewSizeInBytes
;
588 FatShrinkEof (OFile
);
602 Seek OFile to requested position, and calculate the number of
603 consecutive clusters from the position in the file
607 OFile - The open file.
608 Position - The file's position which will be accessed.
609 PosLimit - The maximum length current reading/writing may access
613 EFI_SUCCESS - Set the info successfully.
614 EFI_VOLUME_CORRUPTED - Cluster chain corrupt.
624 Volume
= OFile
->Volume
;
625 ClusterSize
= Volume
->ClusterSize
;
627 ASSERT_VOLUME_LOCKED (Volume
);
630 // If this is the fixed root dir, then compute it's position
631 // from it's fixed info in the fat bpb
633 if (OFile
->IsFixedRootDir
) {
634 OFile
->PosDisk
= Volume
->RootPos
+ Position
;
635 Run
= OFile
->FileSize
- Position
;
638 // Run the file's cluster chain to find the current position
639 // If possible, run from the current cluster rather than
640 // start from beginning
641 // Assumption: OFile->Position is always consistent with
642 // OFile->FileCurrentCluster.
643 // OFile->Position is not modified outside this function;
644 // OFile->FileCurrentCluster is modified outside this function
645 // to be the same as OFile->FileCluster
646 // when OFile->FileCluster is updated, so make a check of this
647 // and invalidate the original OFile->Position in this case
649 Cluster
= OFile
->FileCurrentCluster
;
650 StartPos
= OFile
->Position
;
651 if (Position
< StartPos
|| OFile
->FileCluster
== Cluster
) {
653 Cluster
= OFile
->FileCluster
;
656 while (StartPos
+ ClusterSize
<= Position
) {
657 StartPos
+= ClusterSize
;
658 if (Cluster
== FAT_CLUSTER_FREE
|| (Cluster
>= FAT_CLUSTER_SPECIAL
)) {
659 DEBUG ((EFI_D_INIT
| EFI_D_ERROR
, "FatOFilePosition:"" cluster chain corrupt\n"));
660 return EFI_VOLUME_CORRUPTED
;
663 Cluster
= FatGetFatEntry (Volume
, Cluster
);
666 if (Cluster
< FAT_MIN_CLUSTER
) {
667 return EFI_VOLUME_CORRUPTED
;
670 OFile
->PosDisk
= Volume
->FirstClusterPos
+
671 LShiftU64 (Cluster
- FAT_MIN_CLUSTER
, Volume
->ClusterAlignment
) +
673 OFile
->FileCurrentCluster
= Cluster
;
674 OFile
->Position
= StartPos
;
677 // Compute the number of consecutive clusters in the file
679 Run
= StartPos
+ ClusterSize
- Position
;
680 if (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
681 while ((FatGetFatEntry (Volume
, Cluster
) == Cluster
+ 1) && Run
< PosLimit
) {
694 IN FAT_VOLUME
*Volume
,
701 Get the size of directory of the open file
705 Volume - The File System Volume.
706 Cluster - The Starting cluster.
710 The physical size of the file starting at the input cluster, if there is error in the
711 cluster chain, the return value is 0.
716 ASSERT_VOLUME_LOCKED (Volume
);
718 // Run the cluster chain for the OFile
722 // N.B. ".." directories on some media do not contain a starting
723 // cluster. In the case of "." or ".." we don't need the size anyway.
726 while (!FAT_END_OF_FAT_CHAIN (Cluster
)) {
727 if (Cluster
== FAT_CLUSTER_FREE
|| Cluster
>= FAT_CLUSTER_SPECIAL
) {
729 (EFI_D_INIT
| EFI_D_ERROR
,
730 "FATDirSize: cluster chain corrupt\n")
735 Size
+= Volume
->ClusterSize
;
736 Cluster
= FatGetFatEntry (Volume
, Cluster
);
744 FatPhysicalFileSize (
745 IN FAT_VOLUME
*Volume
,
752 Get the physical size of a file on the disk.
756 Volume - The file system volume.
757 RealSize - The real size of a file.
761 The physical size of a file on the disk.
765 UINTN ClusterSizeMask
;
767 ClusterSizeMask
= Volume
->ClusterSize
- 1;
768 PhysicalSize
= (RealSize
+ ClusterSizeMask
) & (~((UINT64
) ClusterSizeMask
));
774 IN FAT_VOLUME
*Volume
780 Update the free cluster info of FatInfoSector of the volume.
784 Volume - FAT file system volume.
795 // If we don't have valid info, compute it now
797 if (!Volume
->FreeInfoValid
) {
799 Volume
->FreeInfoValid
= TRUE
;
800 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
= 0;
801 for (Index
= Volume
->MaxCluster
+ 1; Index
>= FAT_MIN_CLUSTER
; Index
--) {
802 if (Volume
->DiskError
) {
806 if (FatGetFatEntry (Volume
, Index
) == FAT_CLUSTER_FREE
) {
807 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
+= 1;
808 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= (UINT32
) Index
;
812 Volume
->FatInfoSector
.Signature
= FAT_INFO_SIGNATURE
;
813 Volume
->FatInfoSector
.InfoBeginSignature
= FAT_INFO_BEGIN_SIGNATURE
;
814 Volume
->FatInfoSector
.InfoEndSignature
= FAT_INFO_END_SIGNATURE
;