VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/FatPkg/EnhancedFatDxe/FileSpace.c@ 77662

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

  • Property svn:eol-style set to native
File size: 18.2 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>
5This program and the accompanying materials are licensed and made available
6under the terms and conditions of the BSD License which accompanies this
7distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
30STATIC
31VOID *
32FatLoadFatEntry (
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**/
88STATIC
89UINTN
90FatGetFatEntry (
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**/
143STATIC
144EFI_STATUS
145FatSetFatEntry (
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**/
241STATIC
242EFI_STATUS
243FatFreeClusters (
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**/
274STATIC
275UINTN
276FatAllocateCluster (
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**/
329STATIC
330UINTN
331FatSizeToClusters (
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**/
356EFI_STATUS
357FatShrinkEof (
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**/
431EFI_STATUS
432FatGrowEof (
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
533Done:
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**/
551EFI_STATUS
552FatOFilePosition (
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**/
643UINTN
644FatPhysicalDirSize (
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**/
687UINT64
688FatPhysicalFileSize (
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**/
707VOID
708FatComputeFreeInfo (
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}
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