]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/FileSpace.c
BaseTools: Library hashing fix and optimization for --hash feature
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / FileSpace.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Routines dealing with disk spaces and FAT table entries.\r
b9ec9330 3\r
149d6335 4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
eb6cb4ce 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b9ec9330
QH
6\r
7\r
b9ec9330 8\r
cae7420b 9**/\r
b9ec9330 10\r
cae7420b 11#include "Fat.h"\r
b9ec9330 12\r
b9ec9330 13\r
cae7420b 14/**\r
b9ec9330 15\r
cae7420b 16 Get the FAT entry of the volume, which is identified with the Index.\r
b9ec9330 17\r
cae7420b
DB
18 @param Volume - FAT file system volume.\r
19 @param Index - The index of the FAT entry of the volume.\r
b9ec9330 20\r
cae7420b 21 @return The buffer of the FAT entry\r
b9ec9330 22\r
cae7420b 23**/\r
b9ec9330
QH
24STATIC\r
25VOID *\r
26FatLoadFatEntry (\r
27 IN FAT_VOLUME *Volume,\r
28 IN UINTN Index\r
29 )\r
b9ec9330
QH
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
c1680e88 42 case Fat12:\r
b9ec9330
QH
43 Pos = FAT_POS_FAT12 (Index);\r
44 break;\r
45\r
c1680e88 46 case Fat16:\r
b9ec9330
QH
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
c1680e88 59 ReadFat,\r
b9ec9330
QH
60 Volume->FatEntryPos,\r
61 Volume->FatEntrySize,\r
149d6335
RN
62 &Volume->FatEntryBuffer,\r
63 NULL\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
82STATIC\r
83UINTN\r
84FatGetFatEntry (\r
85 IN FAT_VOLUME *Volume,\r
86 IN UINTN Index\r
87 )\r
b9ec9330
QH
88{\r
89 VOID *Pos;\r
c1680e88
DB
90 UINT8 *En12;\r
91 UINT16 *En16;\r
92 UINT32 *En32;\r
b9ec9330
QH
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
c1680e88
DB
102 case Fat12:\r
103 En12 = Pos;\r
104 Accum = En12[0] | (En12[1] << 8);\r
b9ec9330
QH
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
c1680e88
DB
109 case Fat16:\r
110 En16 = Pos;\r
111 Accum = *En16;\r
b9ec9330
QH
112 Accum = Accum | ((Accum >= FAT_CLUSTER_SPECIAL_FAT16) ? FAT_CLUSTER_SPECIAL_EXT : 0);\r
113 break;\r
114\r
115 default:\r
c1680e88
DB
116 En32 = Pos;\r
117 Accum = *En32 & FAT_CLUSTER_MASK_FAT32;\r
b9ec9330
QH
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
cae7420b
DB
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 sucessfully.\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
b9ec9330
QH
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
b9ec9330
QH
144{\r
145 VOID *Pos;\r
c1680e88
DB
146 UINT8 *En12;\r
147 UINT16 *En16;\r
148 UINT32 *En32;\r
b9ec9330
QH
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
c1680e88
DB
177 case Fat12:\r
178 En12 = Pos;\r
179 Accum = En12[0] | (En12[1] << 8);\r
b9ec9330
QH
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
c1680e88
DB
188 En12[0] = (UINT8) (Accum & 0xFF);\r
189 En12[1] = (UINT8) (Accum >> 8);\r
b9ec9330
QH
190 break;\r
191\r
c1680e88
DB
192 case Fat16:\r
193 En16 = Pos;\r
194 *En16 = (UINT16) Value;\r
b9ec9330
QH
195 break;\r
196\r
197 default:\r
c1680e88
DB
198 En32 = Pos;\r
199 *En32 = (*En32 & FAT_CLUSTER_UNMASK_FAT32) | (UINT32) (Value & FAT_CLUSTER_MASK_FAT32);\r
b9ec9330
QH
200 }\r
201 //\r
202 // If the volume's dirty bit is not set, set it now\r
203 //\r
c1680e88 204 if (!Volume->FatDirty && Volume->FatType != Fat12) {\r
b9ec9330 205 Volume->FatDirty = TRUE;\r
c1680e88 206 FatAccessVolumeDirty (Volume, WriteFat, &Volume->DirtyValue);\r
b9ec9330
QH
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
c1680e88 215 WriteFat,\r
b9ec9330
QH
216 Volume->FatEntryPos,\r
217 Volume->FatEntrySize,\r
149d6335
RN
218 &Volume->FatEntryBuffer,\r
219 NULL\r
b9ec9330
QH
220 );\r
221 return Status;\r
222}\r
223\r
cae7420b
DB
224/**\r
225\r
226 Free the cluster clain.\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
b9ec9330
QH
235STATIC\r
236EFI_STATUS\r
237FatFreeClusters (\r
238 IN FAT_VOLUME *Volume,\r
239 IN UINTN Cluster\r
240 )\r
b9ec9330
QH
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
cae7420b 259/**\r
b9ec9330
QH
260\r
261 Allocate a free cluster and return the cluster index.\r
262\r
cae7420b 263 @param Volume - FAT file system volume.\r
b9ec9330 264\r
cae7420b 265 @return The index of the free cluster\r
b9ec9330 266\r
cae7420b
DB
267**/\r
268STATIC\r
269UINTN\r
270FatAllocateCluster (\r
271 IN FAT_VOLUME *Volume\r
272 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
323STATIC\r
324UINTN\r
325FatSizeToClusters (\r
326 IN FAT_VOLUME *Volume,\r
327 IN UINTN Size\r
328 )\r
b9ec9330
QH
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
cae7420b 340/**\r
b9ec9330
QH
341\r
342 Shrink the end of the open file base on the file size.\r
343\r
cae7420b 344 @param OFile - The open file.\r
b9ec9330 345\r
cae7420b
DB
346 @retval EFI_SUCCESS - Shrinked sucessfully.\r
347 @retval EFI_VOLUME_CORRUPTED - There are errors in the file's clusters.\r
b9ec9330 348\r
cae7420b
DB
349**/\r
350EFI_STATUS\r
351FatShrinkEof (\r
352 IN FAT_OFILE *OFile\r
353 )\r
b9ec9330
QH
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
cae7420b 412/**\r
b9ec9330
QH
413\r
414 Grow the end of the open file base on the NewSizeInBytes.\r
415\r
cae7420b
DB
416 @param OFile - The open file.\r
417 @param NewSizeInBytes - The new size in bytes of the open file.\r
b9ec9330 418\r
cae7420b
DB
419 @retval EFI_SUCCESS - The file is grown sucessfully.\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
b9ec9330 423\r
cae7420b
DB
424**/\r
425EFI_STATUS\r
426FatGrowEof (\r
427 IN FAT_OFILE *OFile,\r
428 IN UINT64 NewSizeInBytes\r
429 )\r
b9ec9330
QH
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
add1310d 464 if (Cluster < FAT_MIN_CLUSTER || Cluster > Volume->MaxCluster + 1) {\r
b9ec9330
QH
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
ea1486c2
RN
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
b9ec9330
QH
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
add1310d
RH
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
b9ec9330 534 }\r
b9ec9330
QH
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
cae7420b 546/**\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330 554\r
cae7420b
DB
555 @retval EFI_SUCCESS - Set the info successfully.\r
556 @retval EFI_VOLUME_CORRUPTED - Cluster chain corrupt.\r
b9ec9330 557\r
cae7420b
DB
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
b9ec9330
QH
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 it's position\r
579 // from it's 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
add1310d 614 if (Cluster < FAT_MIN_CLUSTER || Cluster > Volume->MaxCluster + 1) {\r
b9ec9330
QH
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
cae7420b 640/**\r
b9ec9330 641\r
cae7420b 642 Get the size of directory of the open file.\r
b9ec9330 643\r
cae7420b
DB
644 @param Volume - The File System Volume.\r
645 @param Cluster - The Starting cluster.\r
b9ec9330 646\r
cae7420b 647 @return The physical size of the file starting at the input cluster, if there is error in the\r
b9ec9330
QH
648 cluster chain, the return value is 0.\r
649\r
cae7420b
DB
650**/\r
651UINTN\r
652FatPhysicalDirSize (\r
653 IN FAT_VOLUME *Volume,\r
654 IN UINTN Cluster\r
655 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
695UINT64\r
696FatPhysicalFileSize (\r
697 IN FAT_VOLUME *Volume,\r
698 IN UINTN RealSize\r
699 )\r
b9ec9330
QH
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
cae7420b 708/**\r
b9ec9330
QH
709\r
710 Update the free cluster info of FatInfoSector of the volume.\r
711\r
cae7420b 712 @param Volume - FAT file system volume.\r
b9ec9330 713\r
cae7420b
DB
714**/\r
715VOID\r
716FatComputeFreeInfo (\r
717 IN FAT_VOLUME *Volume\r
718 )\r
b9ec9330
QH
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