TianoCore EDK2 master
Loading...
Searching...
No Matches
FileSpace.c
Go to the documentation of this file.
1
11#include "Fat.h"
12
24VOID *
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
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
138STATIC
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
239STATIC
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
271STATIC
272UINTN
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
327STATIC
328UINTN
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
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
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
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
653UINTN
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
698UINT64
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
719VOID
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}
UINT64 UINTN
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
EFI_STATUS FatDiskIo(IN FAT_VOLUME *Volume, IN IO_MODE IoMode, IN UINT64 Offset, IN UINTN BufferSize, IN OUT VOID *Buffer, IN FAT_TASK *Task)
Definition: Misc.c:315
EFI_STATUS FatAccessVolumeDirty(IN FAT_VOLUME *Volume, IN IO_MODE IoMode, IN VOID *DirtyValue)
Definition: Misc.c:230
STATIC UINTN FatAllocateCluster(IN FAT_VOLUME *Volume)
Definition: FileSpace.c:273
UINTN FatPhysicalDirSize(IN FAT_VOLUME *Volume, IN UINTN Cluster)
Definition: FileSpace.c:654
EFI_STATUS FatGrowEof(IN FAT_OFILE *OFile, IN UINT64 NewSizeInBytes)
Definition: FileSpace.c:429
EFI_STATUS FatOFilePosition(IN FAT_OFILE *OFile, IN UINTN Position, IN UINTN PosLimit)
Definition: FileSpace.c:562
STATIC UINTN FatGetFatEntry(IN FAT_VOLUME *Volume, IN UINTN Index)
Definition: FileSpace.c:85
VOID FatComputeFreeInfo(IN FAT_VOLUME *Volume)
Definition: FileSpace.c:720
UINT64 FatPhysicalFileSize(IN FAT_VOLUME *Volume, IN UINTN RealSize)
Definition: FileSpace.c:699
EFI_STATUS FatShrinkEof(IN FAT_OFILE *OFile)
Definition: FileSpace.c:355
STATIC VOID * FatLoadFatEntry(IN FAT_VOLUME *Volume, IN UINTN Index)
Definition: FileSpace.c:25
STATIC EFI_STATUS FatSetFatEntry(IN FAT_VOLUME *Volume, IN UINTN Index, IN UINTN Value)
Definition: FileSpace.c:140
STATIC EFI_STATUS FatFreeClusters(IN FAT_VOLUME *Volume, IN UINTN Cluster)
Definition: FileSpace.c:241
STATIC UINTN FatSizeToClusters(IN FAT_VOLUME *Volume, IN UINTN Size)
Definition: FileSpace.c:329
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112