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