VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/FatPkg/EnhancedFatDxe/FileSpace.c@ 105681

Last change on this file since 105681 was 99404, checked in by vboxsync, 23 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette