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