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