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