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