]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/EnhancedFatDxe/DirectoryManage.c
116f87a4c2b1066a6be8ddcd8b3c46960011c74d
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DirectoryManage.c
1 /*++
2
3 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12
13 Module Name:
14
15 DirectoryManage.c
16
17 Abstract:
18
19 Functions for performing directory entry io
20
21 Revision History
22
23 --*/
24
25 #include "Fat.h"
26
27 STATIC
28 EFI_STATUS
29 FatAccessEntry (
30 IN FAT_OFILE *Parent,
31 IN IO_MODE IoMode,
32 IN UINTN EntryPos,
33 IN OUT VOID *Entry
34 )
35 /*++
36
37 Routine Description:
38
39 Get a directory entry from disk for the Ofile.
40
41 Arguments:
42
43 Parent - The parent of the OFile which need to update.
44 IoMode - Indicate whether to read directory entry or write directroy entry.
45 EntryPos - The position of the directory entry to be accessed.
46 Entry - The directory entry read or written.
47
48 Returns:
49
50 EFI_SUCCESS - Access the directory entry sucessfully.
51 other - An error occurred when reading the directory entry.
52
53 --*/
54 {
55 UINTN Position;
56 UINTN BufferSize;
57
58 Position = EntryPos * sizeof (FAT_DIRECTORY_ENTRY);
59 if (Position >= Parent->FileSize) {
60 //
61 // End of directory
62 //
63 ASSERT (IoMode == READ_DATA);
64 ((FAT_DIRECTORY_ENTRY *) Entry)->FileName[0] = EMPTY_ENTRY_MARK;
65 ((FAT_DIRECTORY_ENTRY *) Entry)->Attributes = 0;
66 return EFI_SUCCESS;
67 }
68
69 BufferSize = sizeof (FAT_DIRECTORY_ENTRY);
70 return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);
71 }
72
73 EFI_STATUS
74 FatStoreDirEnt (
75 IN FAT_OFILE *OFile,
76 IN FAT_DIRENT *DirEnt
77 )
78 /*++
79
80 Routine Description:
81
82 Save the directory entry to disk.
83
84 Arguments:
85
86 OFile - The parent OFile which needs to update.
87 DirEnt - The directory entry to be saved.
88
89 Returns:
90
91 EFI_SUCCESS - Store the directory entry successfully.
92 other - An error occurred when writing the directory entry.
93
94 --*/
95 {
96 EFI_STATUS Status;
97 FAT_DIRECTORY_LFN LfnEntry;
98 UINTN EntryPos;
99 CHAR16 *LfnBufferPointer;
100 CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
101 UINT8 EntryCount;
102 UINT8 LfnOrdinal;
103
104 EntryPos = DirEnt->EntryPos;
105 EntryCount = DirEnt->EntryCount;
106 //
107 // Write directory entry
108 //
109 Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &DirEnt->Entry);
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 if (--EntryCount > 0) {
115 //
116 // Write LFN directory entry
117 //
118 SetMem (LfnBuffer, sizeof (CHAR16) * LFN_CHAR_TOTAL * EntryCount, 0xff);
119 StrCpy (LfnBuffer, DirEnt->FileString);
120 LfnBufferPointer = LfnBuffer;
121 LfnEntry.Attributes = FAT_ATTRIBUTE_LFN;
122 LfnEntry.Type = 0;
123 LfnEntry.MustBeZero = 0;
124 LfnEntry.Checksum = FatCheckSum (DirEnt->Entry.FileName);
125 for (LfnOrdinal = 1; LfnOrdinal <= EntryCount; LfnOrdinal++) {
126 LfnEntry.Ordinal = LfnOrdinal;
127 if (LfnOrdinal == EntryCount) {
128 LfnEntry.Ordinal |= FAT_LFN_LAST;
129 }
130
131 CopyMem (LfnEntry.Name1, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR1_LEN);
132 LfnBufferPointer += LFN_CHAR1_LEN;
133 CopyMem (LfnEntry.Name2, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR2_LEN);
134 LfnBufferPointer += LFN_CHAR2_LEN;
135 CopyMem (LfnEntry.Name3, LfnBufferPointer, sizeof (CHAR16) * LFN_CHAR3_LEN);
136 LfnBufferPointer += LFN_CHAR3_LEN;
137 EntryPos--;
138 if (DirEnt->Invalid) {
139 LfnEntry.Ordinal = DELETE_ENTRY_MARK;
140 }
141
142 Status = FatAccessEntry (OFile, WRITE_DATA, EntryPos, &LfnEntry);
143 if (EFI_ERROR (Status)) {
144 return Status;
145 }
146 }
147 }
148
149 return EFI_SUCCESS;
150 }
151
152 BOOLEAN
153 FatIsDotDirEnt (
154 IN FAT_DIRENT *DirEnt
155 )
156 /*++
157
158 Routine Description:
159
160 Determine whether the directory entry is "." or ".." entry.
161
162 Arguments:
163
164 DirEnt - The corresponding directory entry.
165
166 Returns:
167
168 TRUE - The directory entry is "." or ".." directory entry
169 FALSE - The directory entry is not "." or ".." directory entry
170
171 --*/
172 {
173 CHAR16 *FileString;
174 FileString = DirEnt->FileString;
175 if (StrCmp (FileString, L".") == 0 || StrCmp (FileString, L"..") == 0) {
176 return TRUE;
177 }
178
179 return FALSE;
180 }
181
182 STATIC
183 VOID
184 FatSetDirEntCluster (
185 IN FAT_OFILE *OFile
186 )
187 /*++
188
189 Routine Description:
190
191 Set the OFile's cluster info in its directory entry.
192
193 Arguments:
194
195 OFile - The corresponding OFile.
196
197 Returns:
198
199 None.
200
201 --*/
202 {
203 UINTN Cluster;
204 FAT_DIRENT *DirEnt;
205
206 DirEnt = OFile->DirEnt;
207 Cluster = OFile->FileCluster;
208 DirEnt->Entry.FileClusterHigh = (UINT16) (Cluster >> 16);
209 DirEnt->Entry.FileCluster = (UINT16) Cluster;
210 }
211
212 VOID
213 FatUpdateDirEntClusterSizeInfo (
214 IN FAT_OFILE *OFile
215 )
216 /*++
217
218 Routine Description:
219
220 Set the OFile's cluster and size info in its directory entry.
221
222 Arguments:
223
224 OFile - The corresponding OFile.
225
226 Returns:
227
228 None.
229
230 --*/
231 {
232 ASSERT (OFile->ODir == NULL);
233 OFile->DirEnt->Entry.FileSize = (UINT32) OFile->FileSize;
234 FatSetDirEntCluster (OFile);
235 }
236
237 VOID
238 FatCloneDirEnt (
239 IN FAT_DIRENT *DirEnt1,
240 IN FAT_DIRENT *DirEnt2
241 )
242 /*++
243
244 Routine Description:
245
246 Copy all the information of DirEnt2 to DirEnt1 except for 8.3 name.
247
248 Arguments:
249
250 DirEnt1 - The destination directory entry.
251 DirEnt2 - The source directory entry.
252
253 Returns:
254
255 None.
256
257 --*/
258 {
259 UINT8 *Entry1;
260 UINT8 *Entry2;
261 Entry1 = (UINT8 *) &DirEnt1->Entry;
262 Entry2 = (UINT8 *) &DirEnt2->Entry;
263 CopyMem (
264 Entry1 + FAT_ENTRY_INFO_OFFSET,
265 Entry2 + FAT_ENTRY_INFO_OFFSET,
266 sizeof (FAT_DIRECTORY_ENTRY) - FAT_ENTRY_INFO_OFFSET
267 );
268 }
269
270 STATIC
271 VOID
272 FatLoadLongNameEntry (
273 IN FAT_OFILE *Parent,
274 IN FAT_DIRENT *DirEnt
275 )
276 /*++
277
278 Routine Description:
279
280 Get the LFN for the directory entry.
281
282 Arguments:
283
284 Parent - The parent directory.
285 DirEnt - The directory entry to get LFN.
286
287 Returns:
288
289 None.
290
291 --*/
292 {
293 CHAR16 LfnBuffer[MAX_LFN_ENTRIES * LFN_CHAR_TOTAL + 1];
294 CHAR16 *LfnBufferPointer;
295 CHAR8 *File8Dot3Name;
296 UINTN EntryPos;
297 UINT8 LfnOrdinal;
298 UINT8 LfnChecksum;
299 FAT_DIRECTORY_LFN LfnEntry;
300 EFI_STATUS Status;
301
302 EntryPos = DirEnt->EntryPos;
303 File8Dot3Name = DirEnt->Entry.FileName;
304 LfnBufferPointer = LfnBuffer;
305 //
306 // Computes checksum for LFN
307 //
308 LfnChecksum = FatCheckSum (File8Dot3Name);
309 LfnOrdinal = 1;
310 do {
311 if (EntryPos == 0) {
312 LfnBufferPointer = LfnBuffer;
313 break;
314 }
315
316 EntryPos--;
317 Status = FatAccessEntry (Parent, READ_DATA, EntryPos, &LfnEntry);
318 if (EFI_ERROR (Status) ||
319 LfnEntry.Attributes != FAT_ATTRIBUTE_LFN ||
320 LfnEntry.MustBeZero != 0 ||
321 LfnEntry.Checksum != LfnChecksum ||
322 (LfnEntry.Ordinal & (~FAT_LFN_LAST)) != LfnOrdinal ||
323 LfnOrdinal > MAX_LFN_ENTRIES
324 ) {
325 //
326 // The directory entry does not have a long file name or
327 // some error occurs when loading long file name for a directory entry,
328 // and then we load the long name from short name
329 //
330 LfnBufferPointer = LfnBuffer;
331 break;
332 }
333
334 CopyMem (LfnBufferPointer, LfnEntry.Name1, sizeof (CHAR16) * LFN_CHAR1_LEN);
335 LfnBufferPointer += LFN_CHAR1_LEN;
336 CopyMem (LfnBufferPointer, LfnEntry.Name2, sizeof (CHAR16) * LFN_CHAR2_LEN);
337 LfnBufferPointer += LFN_CHAR2_LEN;
338 CopyMem (LfnBufferPointer, LfnEntry.Name3, sizeof (CHAR16) * LFN_CHAR3_LEN);
339 LfnBufferPointer += LFN_CHAR3_LEN;
340 LfnOrdinal++;
341 } while ((LfnEntry.Ordinal & FAT_LFN_LAST) == 0);
342 DirEnt->EntryCount = LfnOrdinal;
343 //
344 // Terminate current Lfnbuffer
345 //
346 *LfnBufferPointer = 0;
347 if (LfnBufferPointer == LfnBuffer) {
348 //
349 // Fail to get the long file name from long file name entry,
350 // get the file name from short name
351 //
352 FatGetFileNameViaCaseFlag (DirEnt, LfnBuffer);
353 }
354
355 DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);
356 }
357
358 STATIC
359 VOID
360 FatAddDirEnt (
361 IN FAT_ODIR *ODir,
362 IN FAT_DIRENT *DirEnt
363 )
364 /*++
365
366 Routine Description:
367
368 Add this directory entry node to the list of directory entries and hash table.
369
370 Arguments:
371
372 ODir - The parent OFile which needs to be updated.
373 DirEnt - The directory entry to be added.
374
375 Returns:
376
377 None.
378
379 --*/
380 {
381 if (DirEnt->Link.BackLink == NULL) {
382 DirEnt->Link.BackLink = &ODir->ChildList;
383 }
384 InsertTailList (DirEnt->Link.BackLink, &DirEnt->Link);
385 FatInsertToHashTable (ODir, DirEnt);
386 }
387
388 STATIC
389 EFI_STATUS
390 FatLoadNextDirEnt (
391 IN FAT_OFILE *OFile,
392 OUT FAT_DIRENT **PtrDirEnt
393 )
394 /*++
395
396 Routine Description:
397
398 Load from disk the next directory entry at current end of directory position
399
400 Arguments:
401
402 OFile - The parent OFile.
403 PtrDirEnt - The directory entry that is loaded.
404
405 Returns:
406
407 EFI_SUCCESS - Load the directory entry successfully.
408 EFI_OUT_OF_RESOURCES - Out of resource.
409 other - An error occurred when reading the directory entries.
410
411 --*/
412 {
413 EFI_STATUS Status;
414 FAT_DIRENT *DirEnt;
415 FAT_ODIR *ODir;
416 FAT_DIRECTORY_ENTRY Entry;
417
418 ODir = OFile->ODir;
419 //
420 // Make sure the parent's directory has been opened
421 //
422 ASSERT (ODir != NULL);
423 //
424 // Assert we have not reached the end of directory
425 //
426 ASSERT (!ODir->EndOfDir);
427 DirEnt = NULL;
428
429 for (;;) {
430 //
431 // Read the next directory entry until we find a valid directory entry (excluding lfn entry)
432 //
433 Status = FatAccessEntry (OFile, READ_DATA, ODir->CurrentEndPos, &Entry);
434 if (EFI_ERROR (Status)) {
435 return Status;
436 }
437
438 if (((UINT8) Entry.FileName[0] != DELETE_ENTRY_MARK) && (Entry.Attributes & FAT_ATTRIBUTE_VOLUME_ID) == 0) {
439 //
440 // We get a valid directory entry, then handle it
441 //
442 break;
443 }
444
445 ODir->CurrentEndPos++;
446 }
447
448 if (Entry.FileName[0] != EMPTY_ENTRY_MARK) {
449 //
450 // Although FAT spec states this field is always 0 for FAT12 & FAT16, some applications
451 // might use it for some special usage, it is safer to zero it in memory for FAT12 & FAT16.
452 //
453 if (OFile->Volume->FatType != FAT32) {
454 Entry.FileClusterHigh = 0;
455 }
456
457 //
458 // This is a valid directory entry
459 //
460 DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
461 if (DirEnt == NULL) {
462 return EFI_OUT_OF_RESOURCES;
463 }
464
465 DirEnt->Signature = FAT_DIRENT_SIGNATURE;
466 //
467 // Remember the directory's entry position on disk
468 //
469 DirEnt->EntryPos = (UINT16) ODir->CurrentEndPos;
470 CopyMem (&DirEnt->Entry, &Entry, sizeof (FAT_DIRECTORY_ENTRY));
471 FatLoadLongNameEntry (OFile, DirEnt);
472 if (DirEnt->FileString == NULL) {
473 Status = EFI_OUT_OF_RESOURCES;
474 goto Done;
475 }
476 //
477 // Add this directory entry to directory
478 //
479 FatAddDirEnt (ODir, DirEnt);
480 //
481 // Point to next directory entry
482 //
483 ODir->CurrentEndPos++;
484 } else {
485 ODir->EndOfDir = TRUE;
486 }
487
488 *PtrDirEnt = DirEnt;
489 return EFI_SUCCESS;
490
491 Done:
492 FatFreeDirEnt (DirEnt);
493 return Status;
494 }
495
496 EFI_STATUS
497 FatGetDirEntInfo (
498 IN FAT_VOLUME *Volume,
499 IN FAT_DIRENT *DirEnt,
500 IN OUT UINTN *BufferSize,
501 OUT VOID *Buffer
502 )
503 /*++
504
505 Routine Description:
506
507 Get the directory entry's info into Buffer.
508
509 Arguments:
510
511 Volume - FAT file system volume.
512 DirEnt - The corresponding directory entry.
513 BufferSize - Size of Buffer.
514 Buffer - Buffer containing file info.
515
516 Returns:
517
518 EFI_SUCCESS - Get the file info successfully.
519 EFI_BUFFER_TOO_SMALL - The buffer is too small.
520
521 --*/
522 {
523 UINTN Size;
524 UINTN NameSize;
525 UINTN ResultSize;
526 UINTN Cluster;
527 EFI_STATUS Status;
528 EFI_FILE_INFO *Info;
529 FAT_DIRECTORY_ENTRY *Entry;
530 FAT_DATE_TIME FatLastAccess;
531
532 ASSERT_VOLUME_LOCKED (Volume);
533
534 Size = SIZE_OF_EFI_FILE_INFO;
535 NameSize = StrSize (DirEnt->FileString);
536 ResultSize = Size + NameSize;
537
538 Status = EFI_BUFFER_TOO_SMALL;
539 if (*BufferSize >= ResultSize) {
540 Status = EFI_SUCCESS;
541 Entry = &DirEnt->Entry;
542 Info = Buffer;
543 Info->Size = ResultSize;
544 if ((Entry->Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
545 Cluster = (Entry->FileClusterHigh << 16) | Entry->FileCluster;
546 Info->PhysicalSize = FatPhysicalDirSize (Volume, Cluster);
547 Info->FileSize = Info->PhysicalSize;
548 } else {
549 Info->FileSize = Entry->FileSize;
550 Info->PhysicalSize = FatPhysicalFileSize (Volume, Entry->FileSize);
551 }
552
553 ZeroMem (&FatLastAccess.Time, sizeof (FatLastAccess.Time));
554 CopyMem (&FatLastAccess.Date, &Entry->FileLastAccess, sizeof (FatLastAccess.Date));
555 FatFatTimeToEfiTime (&FatLastAccess, &Info->LastAccessTime);
556 FatFatTimeToEfiTime (&Entry->FileCreateTime, &Info->CreateTime);
557 FatFatTimeToEfiTime (&Entry->FileModificationTime, &Info->ModificationTime);
558 Info->Attribute = Entry->Attributes & EFI_FILE_VALID_ATTR;
559 CopyMem ((CHAR8 *) Buffer + Size, DirEnt->FileString, NameSize);
560 }
561
562 *BufferSize = ResultSize;
563 return Status;
564 }
565
566 STATIC
567 EFI_STATUS
568 FatSearchODir (
569 IN FAT_OFILE *OFile,
570 IN CHAR16 *FileNameString,
571 OUT FAT_DIRENT **PtrDirEnt
572 )
573 /*++
574
575 Routine Description:
576
577 Search the directory for the directory entry whose filename is FileNameString.
578
579 Arguments:
580
581 OFile - The parent OFile whose directory is to be searched.
582 FileNameString - The filename to be searched.
583 PtrDirEnt - pointer to the directory entry if found.
584
585 Returns:
586
587 EFI_SUCCESS - Find the directory entry or not found.
588 other - An error occurred when reading the directory entries.
589
590 --*/
591 {
592 BOOLEAN PossibleShortName;
593 CHAR8 File8Dot3Name[FAT_NAME_LEN];
594 FAT_ODIR *ODir;
595 FAT_DIRENT *DirEnt;
596 EFI_STATUS Status;
597
598 ODir = OFile->ODir;
599 ASSERT (ODir != NULL);
600 //
601 // Check if the file name is a valid short name
602 //
603 PossibleShortName = FatCheckIs8Dot3Name (FileNameString, File8Dot3Name);
604 //
605 // Search the hash table first
606 //
607 DirEnt = *FatLongNameHashSearch (ODir, FileNameString);
608 if (DirEnt == NULL && PossibleShortName) {
609 DirEnt = *FatShortNameHashSearch (ODir, File8Dot3Name);
610 }
611 if (DirEnt == NULL) {
612 //
613 // We fail to get the directory entry from hash table; we then
614 // search the rest directory
615 //
616 while (!ODir->EndOfDir) {
617 Status = FatLoadNextDirEnt (OFile, &DirEnt);
618 if (EFI_ERROR (Status)) {
619 return Status;
620 }
621
622 if (DirEnt != NULL) {
623 if (FatStriCmp (FileNameString, DirEnt->FileString) == 0) {
624 break;
625 }
626
627 if (PossibleShortName && CompareMem (File8Dot3Name, DirEnt->Entry.FileName, FAT_NAME_LEN) == 0) {
628 break;
629 }
630 }
631 }
632 }
633
634 *PtrDirEnt = DirEnt;
635 return EFI_SUCCESS;
636 }
637
638 VOID
639 FatResetODirCursor (
640 IN FAT_OFILE *OFile
641 )
642 /*++
643
644 Routine Description:
645
646 Set the OFile's current directory cursor to the list head.
647
648 Arguments:
649
650 OFile - The directory OFile whose directory cursor is reset.
651
652 Returns:
653
654 None.
655
656 --*/
657 {
658 FAT_ODIR *ODir;
659
660 ODir = OFile->ODir;
661 ASSERT (ODir != NULL);
662 ODir->CurrentCursor = &(ODir->ChildList);
663 ODir->CurrentPos = 0;
664 }
665
666 EFI_STATUS
667 FatGetNextDirEnt (
668 IN FAT_OFILE *OFile,
669 OUT FAT_DIRENT **PtrDirEnt
670 )
671 /*++
672
673 Routine Description:
674
675 Set the directory's cursor to the next and get the next directory entry.
676
677 Arguments:
678
679 OFile - The parent OFile.
680 PtrDirEnt - The next directory entry.
681
682 Returns:
683
684 EFI_SUCCESS - We get the next directory entry successfully.
685 other - An error occurred when get next directory entry.
686
687 --*/
688 {
689 EFI_STATUS Status;
690 FAT_DIRENT *DirEnt;
691 FAT_ODIR *ODir;
692
693 ODir = OFile->ODir;
694 ASSERT (ODir != NULL);
695 if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
696 //
697 // End of directory, we will try one more time
698 //
699 if (!ODir->EndOfDir) {
700 //
701 // Read directory from disk
702 //
703 Status = FatLoadNextDirEnt (OFile, &DirEnt);
704 if (EFI_ERROR (Status)) {
705 return Status;
706 }
707 }
708 }
709
710 if (ODir->CurrentCursor->ForwardLink == &ODir->ChildList) {
711 //
712 // End of directory, return NULL
713 //
714 DirEnt = NULL;
715 ODir->CurrentPos = ODir->CurrentEndPos;
716 } else {
717 ODir->CurrentCursor = ODir->CurrentCursor->ForwardLink;
718 DirEnt = DIRENT_FROM_LINK (ODir->CurrentCursor);
719 ODir->CurrentPos = DirEnt->EntryPos + 1;
720 }
721
722 *PtrDirEnt = DirEnt;
723 return EFI_SUCCESS;
724 }
725
726 STATIC
727 VOID
728 FatSetEntryCount (
729 IN FAT_OFILE *OFile,
730 IN FAT_DIRENT *DirEnt
731 )
732 /*++
733
734 Routine Description:
735
736 Set the directory entry count according to the filename.
737
738 Arguments:
739
740 OFile - The corresponding OFile.
741 DirEnt - The directory entry to be set.
742
743 Returns:
744
745 None.
746
747 --*/
748 {
749 CHAR16 *FileString;
750 CHAR8 *File8Dot3Name;
751
752 //
753 // Get new entry count and set the 8.3 name
754 //
755 DirEnt->EntryCount = 1;
756 FileString = DirEnt->FileString;
757 File8Dot3Name = DirEnt->Entry.FileName;
758 SetMem (File8Dot3Name, FAT_NAME_LEN, ' ');
759 if (StrCmp (FileString, L".") == 0) {
760 //
761 // "." entry
762 //
763 File8Dot3Name[0] = '.';
764 FatCloneDirEnt (DirEnt, OFile->DirEnt);
765 } else if (StrCmp (FileString, L"..") == 0) {
766 //
767 // ".." entry
768 //
769 File8Dot3Name[0] = '.';
770 File8Dot3Name[1] = '.';
771 FatCloneDirEnt (DirEnt, OFile->Parent->DirEnt);
772 } else {
773 //
774 // Normal name
775 //
776 if (FatCheckIs8Dot3Name (FileString, File8Dot3Name)) {
777 //
778 // This file name is a valid 8.3 file name, we need to further check its case flag
779 //
780 FatSetCaseFlag (DirEnt);
781 } else {
782 //
783 // The file name is not a valid 8.3 name we need to generate an 8.3 name for it
784 //
785 FatCreate8Dot3Name (OFile, DirEnt);
786 DirEnt->EntryCount = (UINT8)(LFN_ENTRY_NUMBER (StrLen (FileString)) + DirEnt->EntryCount);
787 }
788 }
789 }
790
791 STATIC
792 EFI_STATUS
793 FatExpandODir (
794 IN FAT_OFILE *OFile
795 )
796 /*++
797
798 Routine Description:
799
800 Append a zero cluster to the current OFile.
801
802 Arguments:
803
804 OFile - The directory OFile which needs to be updated.
805
806 Returns:
807
808 EFI_SUCCESS - Append a zero cluster to the OFile successfully.
809 other - An error occurred when appending the zero cluster.
810
811 --*/
812 {
813 return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);
814 }
815
816 STATIC
817 EFI_STATUS
818 FatSeekVolumeId (
819 IN FAT_OFILE *Root,
820 OUT FAT_DIRENT *DirEnt
821 )
822 /*++
823
824 Routine Description:
825
826 Search the Root OFile for the possible volume label.
827
828 Arguments:
829
830 Root - The Root OFile.
831 DirEnt - The returned directory entry of volume label.
832
833 Returns:
834
835 EFI_SUCCESS - The search process is completed successfully.
836 other - An error occurred when searching volume label.
837
838 --*/
839 {
840 EFI_STATUS Status;
841 UINTN EntryPos;
842 FAT_DIRECTORY_ENTRY *Entry;
843
844 EntryPos = 0;
845 Entry = &DirEnt->Entry;
846 DirEnt->Invalid = TRUE;
847 do {
848 Status = FatAccessEntry (Root, READ_DATA, EntryPos, Entry);
849 if (EFI_ERROR (Status)) {
850 return Status;
851 }
852
853 if (((UINT8) Entry->FileName[0] != DELETE_ENTRY_MARK) && (((Entry->Attributes) & (~FAT_ATTRIBUTE_ARCHIVE)) == FAT_ATTRIBUTE_VOLUME_ID)) {
854 DirEnt->EntryPos = (UINT16) EntryPos;
855 DirEnt->EntryCount = 1;
856 DirEnt->Invalid = FALSE;
857 break;
858 }
859
860 EntryPos++;
861 } while (Entry->FileName[0] != EMPTY_ENTRY_MARK);
862 return EFI_SUCCESS;
863 }
864
865 STATIC
866 EFI_STATUS
867 FatFirstFitInsertDirEnt (
868 IN FAT_OFILE *OFile,
869 IN FAT_DIRENT *DirEnt
870 )
871 /*++
872
873 Routine Description:
874
875 Use First Fit Algorithm to insert directory entry.
876 Only this function will erase "E5" entries in a directory.
877 In view of safest recovery, this function will only be triggered
878 when maximum directory entry number has reached.
879
880 Arguments:
881
882 OFile - The corresponding OFile.
883 DirEnt - The directory entry to be inserted.
884
885 Returns:
886
887 EFI_SUCCESS - The directory entry has been successfully inserted.
888 EFI_VOLUME_FULL - The directory can not hold more directory entries.
889 Others - Some error occurred when inserting new directory entries.
890
891 --*/
892 {
893 EFI_STATUS Status;
894 FAT_ODIR *ODir;
895 LIST_ENTRY *CurrentEntry;
896 FAT_DIRENT *CurrentDirEnt;
897 UINT32 CurrentPos;
898 UINT32 LabelPos;
899 UINT32 NewEntryPos;
900 UINT16 EntryCount;
901 FAT_DIRENT LabelDirEnt;
902
903 LabelPos = 0;
904 if (OFile->Parent == NULL) {
905 Status = FatSeekVolumeId (OFile, &LabelDirEnt);
906 if (EFI_ERROR (Status)) {
907 return Status;
908 }
909
910 if (!LabelDirEnt.Invalid) {
911 LabelPos = LabelDirEnt.EntryPos;
912 }
913 }
914
915 EntryCount = DirEnt->EntryCount;
916 NewEntryPos = EntryCount;
917 CurrentPos = 0;
918 ODir = OFile->ODir;
919 for (CurrentEntry = ODir->ChildList.ForwardLink;
920 CurrentEntry != &ODir->ChildList;
921 CurrentEntry = CurrentEntry->ForwardLink
922 ) {
923 CurrentDirEnt = DIRENT_FROM_LINK (CurrentEntry);
924 if (NewEntryPos + CurrentDirEnt->EntryCount <= CurrentDirEnt->EntryPos) {
925 if (LabelPos > NewEntryPos || LabelPos <= CurrentPos) {
926 //
927 // first fit succeeded
928 //
929 goto Done;
930 }
931 }
932
933 CurrentPos = CurrentDirEnt->EntryPos;
934 NewEntryPos = CurrentPos + EntryCount;
935 }
936
937 if (NewEntryPos >= ODir->CurrentEndPos) {
938 return EFI_VOLUME_FULL;
939 }
940
941 Done:
942 DirEnt->EntryPos = (UINT16) NewEntryPos;
943 DirEnt->Link.BackLink = CurrentEntry;
944 return EFI_SUCCESS;
945 }
946
947 STATIC
948 EFI_STATUS
949 FatNewEntryPos (
950 IN FAT_OFILE *OFile,
951 IN FAT_DIRENT *DirEnt
952 )
953 /*++
954
955 Routine Description:
956
957 Find the new directory entry position for the directory entry.
958
959 Arguments:
960
961 OFile - The corresponding OFile.
962 DirEnt - The directory entry whose new position is to be set.
963
964 Returns:
965
966 EFI_SUCCESS - The new directory entry position is successfully found.
967 EFI_VOLUME_FULL - The directory has reach its maximum capacity.
968 other - An error occurred when reading the directory entry.
969
970 --*/
971 {
972 EFI_STATUS Status;
973 FAT_ODIR *ODir;
974 FAT_DIRENT *TempDirEnt;
975 UINT32 NewEndPos;
976
977 ODir = OFile->ODir;
978 ASSERT (ODir != NULL);
979 //
980 // Make sure the whole directory has been loaded
981 //
982 while (!ODir->EndOfDir) {
983 Status = FatLoadNextDirEnt (OFile, &TempDirEnt);
984 if (EFI_ERROR (Status)) {
985 return Status;
986 }
987 }
988 //
989 // We will append this entry to the end of directory
990 //
991 FatGetCurrentFatTime (&DirEnt->Entry.FileCreateTime);
992 CopyMem (&DirEnt->Entry.FileModificationTime, &DirEnt->Entry.FileCreateTime, sizeof (FAT_DATE_TIME));
993 CopyMem (&DirEnt->Entry.FileLastAccess, &DirEnt->Entry.FileCreateTime.Date, sizeof (FAT_DATE));
994 NewEndPos = ODir->CurrentEndPos + DirEnt->EntryCount;
995 if (NewEndPos * sizeof (FAT_DIRECTORY_ENTRY) > OFile->FileSize) {
996 if (NewEndPos >= (OFile->IsFixedRootDir ? OFile->Volume->RootEntries : FAT_MAX_DIRENTRY_COUNT)) {
997 //
998 // We try to use fist fit algorithm to insert this directory entry
999 //
1000 return FatFirstFitInsertDirEnt (OFile, DirEnt);
1001 }
1002 //
1003 // We should allocate a new cluster for this directory
1004 //
1005 Status = FatExpandODir (OFile);
1006 if (EFI_ERROR (Status)) {
1007 return Status;
1008 }
1009 }
1010 //
1011 // We append our directory entry at the end of directory file
1012 //
1013 ODir->CurrentEndPos = NewEndPos;
1014 DirEnt->EntryPos = (UINT16) (ODir->CurrentEndPos - 1);
1015 return EFI_SUCCESS;
1016 }
1017
1018 EFI_STATUS
1019 FatGetVolumeEntry (
1020 IN FAT_VOLUME *Volume,
1021 IN CHAR16 *Name
1022 )
1023 /*++
1024
1025 Routine Description:
1026
1027 Get the directory entry for the volume.
1028
1029 Arguments:
1030
1031 Volume - FAT file system volume.
1032 Name - The file name of the volume.
1033
1034 Returns:
1035
1036 EFI_SUCCESS - Update the volume with the directory entry sucessfully.
1037 others - An error occurred when getting volume label.
1038
1039 --*/
1040 {
1041 EFI_STATUS Status;
1042 FAT_DIRENT LabelDirEnt;
1043
1044 *Name = 0;
1045 Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
1046 if (!EFI_ERROR (Status)) {
1047 if (!LabelDirEnt.Invalid) {
1048 FatNameToStr (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, FALSE, Name);
1049 }
1050 }
1051
1052 return Status;
1053 }
1054
1055 EFI_STATUS
1056 FatSetVolumeEntry (
1057 IN FAT_VOLUME *Volume,
1058 IN CHAR16 *Name
1059 )
1060 /*++
1061
1062 Routine Description:
1063
1064 Set the relevant directory entry into disk for the volume.
1065
1066 Arguments:
1067
1068 Volume - FAT file system volume.
1069 Name - The new file name of the volume.
1070
1071 Returns:
1072
1073 EFI_SUCCESS - Update the Volume sucessfully.
1074 EFI_UNSUPPORTED - The input label is not a valid volume label.
1075 other - An error occurred when setting volume label.
1076
1077 --*/
1078 {
1079 EFI_STATUS Status;
1080 FAT_DIRENT LabelDirEnt;
1081 FAT_OFILE *Root;
1082
1083 Root = Volume->Root;
1084 Status = FatSeekVolumeId (Volume->Root, &LabelDirEnt);
1085 if (EFI_ERROR (Status)) {
1086 return Status;
1087 }
1088
1089 if (LabelDirEnt.Invalid) {
1090 //
1091 // If there is not the relevant directory entry, create a new one
1092 //
1093 ZeroMem (&LabelDirEnt, sizeof (FAT_DIRENT));
1094 LabelDirEnt.EntryCount = 1;
1095 Status = FatNewEntryPos (Root, &LabelDirEnt);
1096 if (EFI_ERROR (Status)) {
1097 return Status;
1098 }
1099
1100 LabelDirEnt.Entry.Attributes = FAT_ATTRIBUTE_VOLUME_ID;
1101 }
1102
1103 SetMem (LabelDirEnt.Entry.FileName, FAT_NAME_LEN, ' ');
1104 if (FatStrToFat (Name, FAT_NAME_LEN, LabelDirEnt.Entry.FileName)) {
1105 return EFI_UNSUPPORTED;
1106 }
1107
1108 FatGetCurrentFatTime (&LabelDirEnt.Entry.FileModificationTime);
1109 return FatStoreDirEnt (Root, &LabelDirEnt);
1110 }
1111
1112 EFI_STATUS
1113 FatCreateDotDirEnts (
1114 IN FAT_OFILE *OFile
1115 )
1116 /*++
1117
1118 Routine Description:
1119
1120 Create "." and ".." directory entries in the newly-created parent OFile.
1121
1122 Arguments:
1123
1124 OFile - The parent OFile.
1125
1126 Returns:
1127
1128 EFI_SUCCESS - The dot directory entries are successfully created.
1129 other - An error occurred when creating the directory entry.
1130
1131 --*/
1132 {
1133 EFI_STATUS Status;
1134 FAT_DIRENT *DirEnt;
1135
1136 Status = FatExpandODir (OFile);
1137 if (EFI_ERROR (Status)) {
1138 return Status;
1139 }
1140
1141 FatSetDirEntCluster (OFile);
1142 //
1143 // Create "."
1144 //
1145 Status = FatCreateDirEnt (OFile, L".", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
1146 if (EFI_ERROR (Status)) {
1147 return Status;
1148 }
1149 //
1150 // Create ".."
1151 //
1152 Status = FatCreateDirEnt (OFile, L"..", FAT_ATTRIBUTE_DIRECTORY, &DirEnt);
1153 return Status;
1154 }
1155
1156 EFI_STATUS
1157 FatCreateDirEnt (
1158 IN FAT_OFILE *OFile,
1159 IN CHAR16 *FileName,
1160 IN UINT8 Attributes,
1161 OUT FAT_DIRENT **PtrDirEnt
1162 )
1163 /*++
1164
1165 Routine Description:
1166
1167 Create a directory entry in the parent OFile.
1168
1169 Arguments:
1170
1171 OFile - The parent OFile.
1172 FileName - The filename of the newly-created directory entry.
1173 Attributes - The attribute of the newly-created directory entry.
1174 PtrDirEnt - The pointer to the newly-created directory entry.
1175
1176 Returns:
1177
1178 EFI_SUCCESS - The directory entry is successfully created.
1179 EFI_OUT_OF_RESOURCES - Not enough memory to create the directory entry.
1180 other - An error occurred when creating the directory entry.
1181
1182 --*/
1183 {
1184 FAT_DIRENT *DirEnt;
1185 FAT_ODIR *ODir;
1186 EFI_STATUS Status;
1187
1188 ASSERT (OFile != NULL);
1189 ODir = OFile->ODir;
1190 ASSERT (ODir != NULL);
1191 DirEnt = AllocateZeroPool (sizeof (FAT_DIRENT));
1192 if (DirEnt == NULL) {
1193 return EFI_OUT_OF_RESOURCES;
1194 }
1195
1196 DirEnt->Signature = FAT_DIRENT_SIGNATURE;
1197 DirEnt->FileString = AllocateCopyPool (StrSize (FileName), FileName);
1198 if (DirEnt->FileString == NULL) {
1199 Status = EFI_OUT_OF_RESOURCES;
1200 goto Done;
1201 }
1202 //
1203 // Determine how many directory entries we need
1204 //
1205 FatSetEntryCount (OFile, DirEnt);
1206 //
1207 // Determine the file's directory entry position
1208 //
1209 Status = FatNewEntryPos (OFile, DirEnt);
1210 if (EFI_ERROR (Status)) {
1211 goto Done;
1212 }
1213
1214 FatAddDirEnt (ODir, DirEnt);
1215 DirEnt->Entry.Attributes = Attributes;
1216 *PtrDirEnt = DirEnt;
1217 DEBUG ((EFI_D_INFO, "FSOpen: Created new directory entry '%S'\n", DirEnt->FileString));
1218 return FatStoreDirEnt (OFile, DirEnt);
1219
1220 Done:
1221 FatFreeDirEnt (DirEnt);
1222 return Status;
1223 }
1224
1225 EFI_STATUS
1226 FatRemoveDirEnt (
1227 IN FAT_OFILE *OFile,
1228 IN FAT_DIRENT *DirEnt
1229 )
1230 /*++
1231
1232 Routine Description:
1233
1234 Remove this directory entry node from the list of directory entries and hash table.
1235
1236 Arguments:
1237
1238 OFile - The parent OFile.
1239 DirEnt - The directory entry to be removed.
1240
1241 Returns:
1242
1243 EFI_SUCCESS - The directory entry is successfully removed.
1244 other - An error occurred when removing the directory entry.
1245
1246 --*/
1247 {
1248 FAT_ODIR *ODir;
1249
1250 ODir = OFile->ODir;
1251 if (ODir->CurrentCursor == &DirEnt->Link) {
1252 //
1253 // Move the directory cursor to its previous directory entry
1254 //
1255 ODir->CurrentCursor = ODir->CurrentCursor->BackLink;
1256 }
1257 //
1258 // Remove from directory entry list
1259 //
1260 RemoveEntryList (&DirEnt->Link);
1261 //
1262 // Remove from hash table
1263 //
1264 FatDeleteFromHashTable (ODir, DirEnt);
1265 DirEnt->Entry.FileName[0] = DELETE_ENTRY_MARK;
1266 DirEnt->Invalid = TRUE;
1267 return FatStoreDirEnt (OFile, DirEnt);
1268 }
1269
1270 EFI_STATUS
1271 FatOpenDirEnt (
1272 IN FAT_OFILE *Parent,
1273 IN FAT_DIRENT *DirEnt
1274 )
1275 /*++
1276
1277 Routine Description:
1278
1279 Open the directory entry to get the OFile.
1280
1281 Arguments:
1282
1283 OFile - The parent OFile.
1284 DirEnt - The directory entry to be opened.
1285
1286 Returns:
1287
1288 EFI_SUCCESS - The directory entry is successfully opened.
1289 EFI_OUT_OF_RESOURCES - not enough memory to allocate a new OFile.
1290 other - An error occurred when opening the directory entry.
1291
1292 --*/
1293 {
1294 FAT_OFILE *OFile;
1295 FAT_VOLUME *Volume;
1296
1297 if (DirEnt->OFile == NULL) {
1298 //
1299 // Open the directory entry
1300 //
1301 OFile = AllocateZeroPool (sizeof (FAT_OFILE));
1302 if (OFile == NULL) {
1303 return EFI_OUT_OF_RESOURCES;
1304 }
1305
1306 OFile->Signature = FAT_OFILE_SIGNATURE;
1307 InitializeListHead (&OFile->Opens);
1308 InitializeListHead (&OFile->ChildHead);
1309 OFile->Parent = Parent;
1310 OFile->DirEnt = DirEnt;
1311 if (Parent != NULL) {
1312 //
1313 // The newly created OFile is not root
1314 //
1315 Volume = Parent->Volume;
1316 OFile->FullPathLen = Parent->FullPathLen + 1 + StrLen (DirEnt->FileString);
1317 OFile->FileCluster = ((DirEnt->Entry.FileClusterHigh) << 16) | (DirEnt->Entry.FileCluster);
1318 InsertTailList (&Parent->ChildHead, &OFile->ChildLink);
1319 } else {
1320 //
1321 // The newly created OFile is root
1322 //
1323 Volume = VOLUME_FROM_ROOT_DIRENT (DirEnt);
1324 Volume->Root = OFile;
1325 OFile->FileCluster = Volume->RootCluster;
1326 if (Volume->FatType != FAT32) {
1327 OFile->IsFixedRootDir = TRUE;
1328 }
1329 }
1330
1331 OFile->FileCurrentCluster = OFile->FileCluster;
1332 OFile->Volume = Volume;
1333 InsertHeadList (&Volume->CheckRef, &OFile->CheckLink);
1334
1335 OFile->FileSize = DirEnt->Entry.FileSize;
1336 if ((DirEnt->Entry.Attributes & FAT_ATTRIBUTE_DIRECTORY) != 0) {
1337 if (OFile->IsFixedRootDir) {
1338 OFile->FileSize = Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY);
1339 } else {
1340 OFile->FileSize = FatPhysicalDirSize (Volume, OFile->FileCluster);
1341 }
1342
1343 FatRequestODir (OFile);
1344 if (OFile->ODir == NULL) {
1345 return EFI_OUT_OF_RESOURCES;
1346 }
1347 }
1348
1349 DirEnt->OFile = OFile;
1350 }
1351
1352 return EFI_SUCCESS;
1353 }
1354
1355 VOID
1356 FatCloseDirEnt (
1357 IN FAT_DIRENT *DirEnt
1358 )
1359 /*++
1360
1361 Routine Description:
1362
1363 Close the directory entry and free the OFile.
1364
1365 Arguments:
1366
1367 DirEnt - The directory entry to be closed.
1368
1369 Returns:
1370
1371 EFI_SUCCESS - The directory entry is successfully opened.
1372 Other - An error occurred when opening the directory entry.
1373
1374 --*/
1375 {
1376 FAT_OFILE *OFile;
1377 FAT_VOLUME *Volume;
1378
1379 OFile = DirEnt->OFile;
1380 ASSERT (OFile != NULL);
1381 Volume = OFile->Volume;
1382
1383 if (OFile->ODir != NULL) {
1384 FatDiscardODir (OFile);
1385 }
1386
1387 if (OFile->Parent == NULL) {
1388 Volume->Root = NULL;
1389 } else {
1390 RemoveEntryList (&OFile->ChildLink);
1391 }
1392
1393 FreePool (OFile);
1394 DirEnt->OFile = NULL;
1395 if (DirEnt->Invalid == TRUE) {
1396 //
1397 // Free directory entry itself
1398 //
1399 FatFreeDirEnt (DirEnt);
1400 }
1401 }
1402
1403 EFI_STATUS
1404 FatLocateOFile (
1405 IN OUT FAT_OFILE **PtrOFile,
1406 IN CHAR16 *FileName,
1407 IN UINT8 Attributes,
1408 OUT CHAR16 *NewFileName
1409 )
1410 /*++
1411
1412 Routine Description:
1413
1414 Traverse filename and open all OFiles that can be opened.
1415 Update filename pointer to the component that can't be opened.
1416 If more than one name component remains, returns an error;
1417 otherwise, return the remaining name component so that the caller might choose to create it.
1418
1419 Arguments:
1420 PtrOFile - As input, the reference OFile; as output, the located OFile.
1421 FileName - The file name relevant to the OFile.
1422 Attributes - The attribute of the destination OFile.
1423 NewFileName - The remaining file name.
1424
1425 Returns:
1426
1427 EFI_NOT_FOUND - The file name can't be opened and there is more than one
1428 components within the name left (this means the name can
1429 not be created either).
1430 EFI_INVALID_PARAMETER - The parameter is not valid.
1431 EFI_SUCCESS - Open the file successfully.
1432 other - An error occured when locating the OFile.
1433
1434 --*/
1435 {
1436 EFI_STATUS Status;
1437 FAT_VOLUME *Volume;
1438 CHAR16 ComponentName[EFI_PATH_STRING_LENGTH];
1439 UINTN FileNameLen;
1440 BOOLEAN DirIntended;
1441 CHAR16 *Next;
1442 FAT_OFILE *OFile;
1443 FAT_DIRENT *DirEnt;
1444
1445 DirEnt = NULL;
1446
1447 FileNameLen = StrLen (FileName);
1448 if (FileNameLen == 0) {
1449 return EFI_INVALID_PARAMETER;
1450 }
1451
1452 OFile = *PtrOFile;
1453 Volume = OFile->Volume;
1454
1455 DirIntended = FALSE;
1456 if (FileName[FileNameLen - 1] == PATH_NAME_SEPARATOR) {
1457 DirIntended = TRUE;
1458 }
1459 //
1460 // If name starts with path name separator, then move to root OFile
1461 //
1462 if (*FileName == PATH_NAME_SEPARATOR) {
1463 OFile = Volume->Root;
1464 FileName++;
1465 FileNameLen--;
1466 }
1467 //
1468 // Per FAT Spec the file name should meet the following criteria:
1469 // C1. Length (FileLongName) <= 255
1470 // C2. Length (X:FileFullPath<NUL>) <= 260
1471 // Here we check C2 first.
1472 //
1473 if (2 + OFile->FullPathLen + 1 + FileNameLen + 1 > EFI_PATH_STRING_LENGTH) {
1474 //
1475 // Full path length can not surpass 256
1476 //
1477 return EFI_INVALID_PARAMETER;
1478 }
1479 //
1480 // Start at current location
1481 //
1482 Next = FileName;
1483 for (;;) {
1484 //
1485 // Get the next component name
1486 //
1487 FileName = Next;
1488 Next = FatGetNextNameComponent (FileName, ComponentName);
1489
1490 //
1491 // If end of the file name, we're done
1492 //
1493 if (ComponentName[0] == 0) {
1494 if (DirIntended && OFile->ODir == NULL) {
1495 return EFI_NOT_FOUND;
1496 }
1497
1498 NewFileName[0] = 0;
1499 break;
1500 }
1501 //
1502 // If "dot", then current
1503 //
1504 if (StrCmp (ComponentName, L".") == 0) {
1505 continue;
1506 }
1507 //
1508 // If "dot dot", then parent
1509 //
1510 if (StrCmp (ComponentName, L"..") == 0) {
1511 if (OFile->Parent == NULL) {
1512 return EFI_INVALID_PARAMETER;
1513 }
1514 OFile = OFile->Parent;
1515 continue;
1516 }
1517
1518 if (!FatFileNameIsValid (ComponentName, NewFileName)) {
1519 return EFI_INVALID_PARAMETER;
1520 }
1521 //
1522 // We have a component name, try to open it
1523 //
1524 if (OFile->ODir == NULL) {
1525 //
1526 // This file isn't a directory, can't open it
1527 //
1528 return EFI_NOT_FOUND;
1529 }
1530 //
1531 // Search the compName in the directory
1532 //
1533 Status = FatSearchODir (OFile, NewFileName, &DirEnt);
1534 if (EFI_ERROR (Status)) {
1535 return Status;
1536 }
1537
1538 if (DirEnt == NULL) {
1539 //
1540 // component name is not found in the directory
1541 //
1542 if (*Next != 0) {
1543 return EFI_NOT_FOUND;
1544 }
1545
1546 if (DirIntended && (Attributes & FAT_ATTRIBUTE_DIRECTORY) == 0) {
1547 return EFI_INVALID_PARAMETER;
1548 }
1549 //
1550 // It's the last component name - return with the open
1551 // path and the remaining name
1552 //
1553 break;
1554 }
1555
1556 Status = FatOpenDirEnt (OFile, DirEnt);
1557 if (EFI_ERROR (Status)) {
1558 return Status;
1559 }
1560
1561 OFile = DirEnt->OFile;
1562 }
1563
1564 *PtrOFile = OFile;
1565 return EFI_SUCCESS;
1566 }
1567