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