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