]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/DirectoryManage.c
BaseTools: Library hashing fix and optimization for --hash feature
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DirectoryManage.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Functions for performing directory entry io.\r
b9ec9330 3\r
e76bc43e 4Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>\r
eb6cb4ce 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b9ec9330 6\r
cae7420b 7**/\r
b9ec9330 8\r
cae7420b 9#include "Fat.h"\r
b9ec9330 10\r
cae7420b 11/**\r
b9ec9330 12\r
cae7420b 13 Get a directory entry from disk for the Ofile.\r
b9ec9330 14\r
cae7420b
DB
15 @param Parent - The parent of the OFile which need to update.\r
16 @param IoMode - Indicate whether to read directory entry or write directroy 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
b9ec9330 19\r
cae7420b
DB
20 @retval EFI_SUCCESS - Access the directory entry sucessfully.\r
21 @return other - An error occurred when reading the directory entry.\r
b9ec9330 22\r
cae7420b 23**/\r
b9ec9330
QH
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
b9ec9330
QH
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
c1680e88 41 ASSERT (IoMode == ReadData);\r
b9ec9330
QH
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
149d6335 48 return FatAccessOFile (Parent, IoMode, Position, &BufferSize, Entry, NULL);\r
b9ec9330
QH
49}\r
50\r
cae7420b 51/**\r
b9ec9330
QH
52\r
53 Save the directory entry to disk.\r
54\r
cae7420b
DB
55 @param OFile - The parent OFile which needs to update.\r
56 @param DirEnt - The directory entry to be saved.\r
b9ec9330 57\r
cae7420b
DB
58 @retval EFI_SUCCESS - Store the directory entry successfully.\r
59 @return other - An error occurred when writing the directory entry.\r
b9ec9330 60\r
cae7420b
DB
61**/\r
62EFI_STATUS\r
63FatStoreDirEnt (\r
64 IN FAT_OFILE *OFile,\r
65 IN FAT_DIRENT *DirEnt\r
66 )\r
b9ec9330
QH
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
c1680e88 81 Status = FatAccessEntry (OFile, WriteData, EntryPos, &DirEnt->Entry);\r
b9ec9330
QH
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
e76bc43e
HW
91 Status = StrCpyS (\r
92 LfnBuffer,\r
0cdc10bd 93 ARRAY_SIZE (LfnBuffer),\r
e76bc43e
HW
94 DirEnt->FileString\r
95 );\r
96 if (EFI_ERROR (Status)) {\r
97 return Status;\r
98 }\r
99\r
b9ec9330
QH
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
c1680e88 122 Status = FatAccessEntry (OFile, WriteData, EntryPos, &LfnEntry);\r
b9ec9330
QH
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
cae7420b 132/**\r
b9ec9330
QH
133\r
134 Determine whether the directory entry is "." or ".." entry.\r
135\r
cae7420b 136 @param DirEnt - The corresponding directory entry.\r
b9ec9330 137\r
cae7420b
DB
138 @retval TRUE - The directory entry is "." or ".." directory entry\r
139 @retval FALSE - The directory entry is not "." or ".." directory entry\r
b9ec9330 140\r
cae7420b
DB
141**/\r
142BOOLEAN\r
143FatIsDotDirEnt (\r
144 IN FAT_DIRENT *DirEnt\r
145 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
163STATIC\r
164VOID\r
165FatSetDirEntCluster (\r
166 IN FAT_OFILE *OFile\r
167 )\r
b9ec9330
QH
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
cae7420b 178/**\r
b9ec9330
QH
179\r
180 Set the OFile's cluster and size info in its directory entry.\r
181\r
cae7420b 182 @param OFile - The corresponding OFile.\r
b9ec9330 183\r
cae7420b
DB
184**/\r
185VOID\r
186FatUpdateDirEntClusterSizeInfo (\r
187 IN FAT_OFILE *OFile\r
188 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
203VOID\r
204FatCloneDirEnt (\r
205 IN FAT_DIRENT *DirEnt1,\r
206 IN FAT_DIRENT *DirEnt2\r
207 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
228STATIC\r
229VOID\r
230FatLoadLongNameEntry (\r
231 IN FAT_OFILE *Parent,\r
232 IN FAT_DIRENT *DirEnt\r
233 )\r
b9ec9330
QH
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
c1680e88 259 Status = FatAccessEntry (Parent, ReadData, EntryPos, &LfnEntry);\r
b9ec9330
QH
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
e76bc43e
HW
294 FatGetFileNameViaCaseFlag (\r
295 DirEnt,\r
296 LfnBuffer,\r
0cdc10bd 297 ARRAY_SIZE (LfnBuffer)\r
e76bc43e 298 );\r
b9ec9330
QH
299 }\r
300\r
301 DirEnt->FileString = AllocateCopyPool (StrSize (LfnBuffer), LfnBuffer);\r
302}\r
303\r
cae7420b
DB
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
b9ec9330
QH
312STATIC\r
313VOID\r
314FatAddDirEnt (\r
315 IN FAT_ODIR *ODir,\r
316 IN FAT_DIRENT *DirEnt\r
317 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
338STATIC\r
339EFI_STATUS\r
340FatLoadNextDirEnt (\r
341 IN FAT_OFILE *OFile,\r
342 OUT FAT_DIRENT **PtrDirEnt\r
343 )\r
b9ec9330
QH
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
c1680e88 365 Status = FatAccessEntry (OFile, ReadData, ODir->CurrentEndPos, &Entry);\r
b9ec9330
QH
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
c1680e88 385 if (OFile->Volume->FatType != Fat32) {\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
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
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
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
b9ec9330
QH
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
cae7420b 558/**\r
b9ec9330
QH
559\r
560 Set the OFile's current directory cursor to the list head.\r
561\r
cae7420b 562 @param OFile - The directory OFile whose directory cursor is reset.\r
b9ec9330 563\r
cae7420b
DB
564**/\r
565VOID\r
566FatResetODirCursor (\r
567 IN FAT_OFILE *OFile\r
568 )\r
b9ec9330
QH
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
cae7420b 578/**\r
b9ec9330 579\r
c3b8ec43 580 Set the directory's cursor to the next and get the next directory entry.\r
b9ec9330 581\r
cae7420b
DB
582 @param OFile - The parent OFile.\r
583 @param PtrDirEnt - The next directory entry.\r
b9ec9330 584\r
cae7420b
DB
585 @retval EFI_SUCCESS - We get the next directory entry successfully.\r
586 @return other - An error occurred when get next directory entry.\r
b9ec9330 587\r
cae7420b
DB
588**/\r
589EFI_STATUS\r
590FatGetNextDirEnt (\r
591 IN FAT_OFILE *OFile,\r
592 OUT FAT_DIRENT **PtrDirEnt\r
593 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
640STATIC\r
641VOID\r
642FatSetEntryCount (\r
643 IN FAT_OFILE *OFile,\r
644 IN FAT_DIRENT *DirEnt\r
645 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
699STATIC\r
700EFI_STATUS\r
701FatExpandODir (\r
702 IN FAT_OFILE *OFile\r
703 )\r
cae7420b
DB
704{\r
705 return FatExpandOFile (OFile, OFile->FileSize + OFile->Volume->ClusterSize);\r
706}\r
b9ec9330 707\r
cae7420b 708/**\r
b9ec9330 709\r
cae7420b 710 Search the Root OFile for the possible volume label.\r
b9ec9330 711\r
cae7420b
DB
712 @param Root - The Root OFile.\r
713 @param DirEnt - The returned directory entry of volume label.\r
b9ec9330 714\r
cae7420b
DB
715 @retval EFI_SUCCESS - The search process is completed successfully.\r
716 @return other - An error occurred when searching volume label.\r
b9ec9330 717\r
cae7420b 718**/\r
b9ec9330
QH
719STATIC\r
720EFI_STATUS\r
721FatSeekVolumeId (\r
722 IN FAT_OFILE *Root,\r
723 OUT FAT_DIRENT *DirEnt\r
724 )\r
b9ec9330
QH
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
c1680e88 734 Status = FatAccessEntry (Root, ReadData, EntryPos, Entry);\r
b9ec9330
QH
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
cae7420b 751/**\r
b9ec9330
QH
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
cae7420b
DB
758 @param OFile - The corresponding OFile.\r
759 @param DirEnt - The directory entry to be inserted.\r
b9ec9330 760\r
cae7420b
DB
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
b9ec9330 764\r
cae7420b
DB
765**/\r
766STATIC\r
767EFI_STATUS\r
768FatFirstFitInsertDirEnt (\r
769 IN FAT_OFILE *OFile,\r
770 IN FAT_DIRENT *DirEnt\r
771 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
839STATIC\r
840EFI_STATUS\r
841FatNewEntryPos (\r
842 IN FAT_OFILE *OFile,\r
843 IN FAT_DIRENT *DirEnt\r
844 )\r
b9ec9330
QH
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
a13db369
KG
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
b9ec9330
QH
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
cae7420b 892/**\r
b9ec9330
QH
893\r
894 Get the directory entry for the volume.\r
895\r
cae7420b
DB
896 @param Volume - FAT file system volume.\r
897 @param Name - The file name of the volume.\r
b9ec9330 898\r
cae7420b
DB
899 @retval EFI_SUCCESS - Update the volume with the directory entry sucessfully.\r
900 @return others - An error occurred when getting volume label.\r
b9ec9330 901\r
cae7420b
DB
902**/\r
903EFI_STATUS\r
904FatGetVolumeEntry (\r
905 IN FAT_VOLUME *Volume,\r
906 IN CHAR16 *Name\r
907 )\r
b9ec9330
QH
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
cae7420b 923/**\r
b9ec9330
QH
924\r
925 Set the relevant directory entry into disk for the volume.\r
926\r
cae7420b
DB
927 @param Volume - FAT file system volume.\r
928 @param Name - The new file name of the volume.\r
b9ec9330 929\r
cae7420b
DB
930 @retval EFI_SUCCESS - Update the Volume sucessfully.\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
b9ec9330 933\r
cae7420b
DB
934**/\r
935EFI_STATUS\r
936FatSetVolumeEntry (\r
937 IN FAT_VOLUME *Volume,\r
938 IN CHAR16 *Name\r
939 )\r
b9ec9330
QH
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
cae7420b 974/**\r
b9ec9330
QH
975\r
976 Create "." and ".." directory entries in the newly-created parent OFile.\r
977\r
cae7420b 978 @param OFile - The parent OFile.\r
b9ec9330 979\r
cae7420b
DB
980 @retval EFI_SUCCESS - The dot directory entries are successfully created.\r
981 @return other - An error occurred when creating the directory entry.\r
b9ec9330 982\r
cae7420b
DB
983**/\r
984EFI_STATUS\r
985FatCreateDotDirEnts (\r
986 IN FAT_OFILE *OFile\r
987 )\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330
QH
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
b9ec9330
QH
1033{\r
1034 FAT_DIRENT *DirEnt;\r
1035 FAT_ODIR *ODir;\r
1036 EFI_STATUS Status;\r
1037\r
35053df3 1038 ASSERT (OFile != NULL);\r
b9ec9330
QH
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
cae7420b 1075/**\r
b9ec9330
QH
1076\r
1077 Remove this directory entry node from the list of directory entries and hash table.\r
1078\r
cae7420b
DB
1079 @param OFile - The parent OFile.\r
1080 @param DirEnt - The directory entry to be removed.\r
b9ec9330 1081\r
cae7420b
DB
1082 @retval EFI_SUCCESS - The directory entry is successfully removed.\r
1083 @return other - An error occurred when removing the directory entry.\r
b9ec9330 1084\r
cae7420b
DB
1085**/\r
1086EFI_STATUS\r
1087FatRemoveDirEnt (\r
1088 IN FAT_OFILE *OFile,\r
1089 IN FAT_DIRENT *DirEnt\r
1090 )\r
b9ec9330
QH
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
cae7420b 1114/**\r
b9ec9330
QH
1115\r
1116 Open the directory entry to get the OFile.\r
1117\r
cae7420b
DB
1118 @param Parent - The parent OFile.\r
1119 @param DirEnt - The directory entry to be opened.\r
b9ec9330 1120\r
cae7420b
DB
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
b9ec9330 1124\r
cae7420b
DB
1125**/\r
1126EFI_STATUS\r
1127FatOpenDirEnt (\r
1128 IN FAT_OFILE *Parent,\r
1129 IN FAT_DIRENT *DirEnt\r
1130 )\r
b9ec9330
QH
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
c1680e88 1164 if (Volume->FatType != Fat32) {\r
b9ec9330
QH
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
cae7420b 1193/**\r
b9ec9330
QH
1194\r
1195 Close the directory entry and free the OFile.\r
1196\r
cae7420b 1197 @param DirEnt - The directory entry to be closed.\r
b9ec9330 1198\r
cae7420b
DB
1199**/\r
1200VOID\r
1201FatCloseDirEnt (\r
1202 IN FAT_DIRENT *DirEnt\r
1203 )\r
b9ec9330
QH
1204{\r
1205 FAT_OFILE *OFile;\r
1206 FAT_VOLUME *Volume;\r
1207\r
1208 OFile = DirEnt->OFile;\r
b9ec9330 1209 ASSERT (OFile != NULL);\r
35053df3 1210 Volume = OFile->Volume;\r
b9ec9330
QH
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
cae7420b 1232/**\r
b9ec9330
QH
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
cae7420b
DB
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
b9ec9330 1243\r
cae7420b 1244 @retval EFI_NOT_FOUND - The file name can't be opened and there is more than one\r
b9ec9330
QH
1245 components within the name left (this means the name can\r
1246 not be created either).\r
cae7420b
DB
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 occured when locating the OFile.\r
b9ec9330 1250\r
cae7420b
DB
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
b9ec9330
QH
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
05bcb9e8
JJ
1269 DirEnt = NULL;\r
1270\r
b9ec9330
QH
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