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