2 File IO routines inspired by Streams with an EFI flavor
4 Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 Basic support for opening files on different device types. The device string
16 is in the form of DevType:Path. Current DevType is required as there is no
17 current mounted device concept of current working directory concept implement
20 Device names are case insensative and only check the leading characters for
21 unique matches. Thus the following are all the same:
27 Supported Device Names:
28 A0x1234:0x12 - A memory buffer starting at address 0x1234 for 0x12 bytes
29 l1: - EFI LoadFile device one.
30 B0: - EFI BlockIo zero.
31 fs3: - EFI Simple File System device 3
32 Fv2: - EFI Firmware VOlume device 2
33 10.0.1.102: - TFTP service IP followed by the file name
37 #include <Protocol/BlockIo.h>
38 #include <Protocol/DiskIo.h>
39 #include <Protocol/SimpleFileSystem.h>
40 #include <Protocol/FirmwareVolume2.h>
41 #include <Protocol/LoadFile.h>
42 #include <Protocol/FirmwareVolumeBlock.h>
43 #include <Guid/FileInfo.h>
44 #include <Library/BaseLib.h>
45 #include <Library/MemoryAllocationLib.h>
46 #include <Library/DevicePathLib.h>
47 #include <Library/PrintLib.h>
48 #include <Library/BaseMemoryLib.h>
49 #include <Library/UefiLib.h>
50 #include <Library/UefiBootServicesTableLib.h>
51 #include <Library/UefiRuntimeServicesTableLib.h>
52 #include <Library/DebugLib.h>
53 #include <Library/EfiFileLib.h>
54 #include <Library/PcdLib.h>
55 #include <Library/EblNetworkLib.h>
60 CONST EFI_GUID gZeroGuid
= { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } };
62 #define EFI_OPEN_FILE_GUARD_HEADER 0x4B4D4641
63 #define EFI_OPEN_FILE_GUARD_FOOTER 0x444D5A56
65 // Need to defend against this overflowing
66 #define MAX_CMD_LINE 0x200
72 } EFI_OPEN_FILE_GUARD
;
75 // globals to store current open device info
76 EFI_HANDLE
*mBlkIo
= NULL
;
77 UINTN mBlkIoCount
= 0;
79 EFI_HANDLE
*mFs
= NULL
;
81 // mFsInfo[] array entries must match mFs[] handles
82 EFI_FILE_SYSTEM_INFO
**mFsInfo
= NULL
;
84 EFI_HANDLE
*mFv
= NULL
;
86 EFI_HANDLE
*mLoadFile
= NULL
;
87 UINTN mLoadFileCount
= 0;
92 Internal worker function to validate a File handle.
94 @param File Open File Handle
96 @return TRUE File is valid
97 @return FALSE File is not valid
103 IN EFI_OPEN_FILE
*File
106 EFI_OPEN_FILE_GUARD
*GuardFile
;
108 // Look right before and after file structure for the correct signatures
109 GuardFile
= BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
);
110 if ((GuardFile
->Header
!= EFI_OPEN_FILE_GUARD_HEADER
) ||
111 (GuardFile
->Footer
!= EFI_OPEN_FILE_GUARD_FOOTER
) ) {
119 Internal worker function. If Buffer is not NULL free it.
121 @param Buffer Buffer to FreePool()
129 if (Buffer
!= NULL
) {
135 Update Device List Global Variables
139 EblUpdateDeviceLists (
145 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
146 EFI_FILE_HANDLE Root
;
149 if (mBlkIo
!= NULL
) {
152 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &mBlkIoCount
, &mBlkIo
);
159 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiFirmwareVolume2ProtocolGuid
, NULL
, &mFvCount
, &mFv
);
161 if (mLoadFile
!= NULL
) {
162 FreePool (mLoadFile
);
164 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &mLoadFileCount
, &mLoadFile
);
170 if (&mFsInfo
[0] != NULL
) {
171 // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code
172 for (Index
= 0; Index
< mFsCount
; Index
++) {
173 if (mFsInfo
[Index
] != NULL
) {
174 FreePool (mFsInfo
[Index
]);
180 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &mFsCount
, &mFs
);
183 mFsInfo
= AllocateZeroPool (mFsCount
* sizeof (EFI_FILE_SYSTEM_INFO
*));
184 if (mFsInfo
== NULL
) {
185 // If we can't do this then we can't support file system entries
188 // Loop through all the file system structures and cache the file system info data
189 for (Index
=0; Index
< mFsCount
; Index
++) {
190 Status
= gBS
->HandleProtocol (mFs
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
191 if (!EFI_ERROR (Status
)) {
192 Status
= Fs
->OpenVolume (Fs
, &Root
);
193 if (!EFI_ERROR (Status
)) {
194 // Get information about the volume
196 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
197 if (Status
== EFI_BUFFER_TOO_SMALL
) {
198 mFsInfo
[Index
] = AllocatePool (Size
);
199 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
211 PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\.
212 Return TRUE if the <devce name> prefix of PathName matches a file system
213 Volume Name. MatchIndex is the array index in mFsInfo[] of the match,
214 and it can be used with mFs[] to find the handle that needs to be opened
216 @param PathName PathName to check
217 @param FileStart Index of the first character of the <path>
218 @param MatchIndex Index in mFsInfo[] that matches
220 @return TRUE PathName matches a Volume Label and MatchIndex is valid
221 @return FALSE PathName does not match a Volume Label MatchIndex undefined
228 OUT UINTN
*MatchIndex
236 for (Index
=0; Index
< mFsCount
; Index
++) {
237 if (mFsInfo
[Index
] == NULL
) {
238 // FsInfo is not valid so skip it
241 VolStrLen
= StrLen (mFsInfo
[Index
]->VolumeLabel
);
242 for (Compare
= 0, Match
= TRUE
; Compare
< (FileStart
- 1); Compare
++) {
243 if (Compare
> VolStrLen
) {
247 if (PathName
[Compare
] != (CHAR8
)mFsInfo
[Index
]->VolumeLabel
[Compare
]) {
248 // If the VolumeLabel has a space allow a _ to match with it in addition to ' '
249 if (!((PathName
[Compare
] == '_') && (mFsInfo
[Index
]->VolumeLabel
[Compare
] == L
' '))) {
266 Return the number of devices of the current type active in the system
268 @param Type Device type to check
270 @return 0 Invalid type
275 IN EFI_OPEN_FILE_TYPE DeviceType
278 switch (DeviceType
) {
279 case EfiOpenLoadFile
:
280 return mLoadFileCount
;
281 case EfiOpenFirmwareVolume
:
283 case EfiOpenFileSystem
:
293 ConvertIpStringToEfiIp (
295 OUT EFI_IP_ADDRESS
*ServerIp
301 ServerIp
->v4
.Addr
[0] = (UINT8
)AsciiStrDecimalToUintn (Str
);
303 Str
= AsciiStrStr (Str
, ".");
305 return EFI_DEVICE_ERROR
;
308 ServerIp
->v4
.Addr
[1] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
310 Str
= AsciiStrStr (Str
, ".");
312 return EFI_DEVICE_ERROR
;
315 ServerIp
->v4
.Addr
[2] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
317 Str
= AsciiStrStr (Str
, ".");
319 return EFI_DEVICE_ERROR
;
322 ServerIp
->v4
.Addr
[3] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
329 Internal work function to extract a device number from a string skipping
330 text. Easy way to extract numbers from strings like blk7:.
332 @param Str String to extract device number form
334 @return -1 Device string is not valid
339 EblConvertDevStringToNumber (
347 // Find the first digit
348 Max
= AsciiStrLen (Str
);
349 for (Index
= 0; !((*Str
>= '0') && (*Str
<= '9')) && (Index
< Max
); Index
++) {
356 return AsciiStrDecimalToUintn (Str
);
361 Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo
363 @param File Open file handle
364 @param FileName Name of file after device stripped off
370 IN OUT EFI_OPEN_FILE
*File
,
372 IN CONST UINT64 OpenMode
377 FILEPATH_DEVICE_PATH
*FilePath
;
378 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
379 CHAR16 UnicodeFileName
[MAX_PATHNAME
];
380 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
381 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
382 EFI_FILE_HANDLE Root
;
385 if ( *FileName
!= 0 ) {
386 AsciiStrToUnicodeStr (FileName
, UnicodeFileName
);
388 AsciiStrToUnicodeStr ("\\", UnicodeFileName
);
391 Size
= StrSize (UnicodeFileName
);
392 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ sizeof (EFI_DEVICE_PATH_PROTOCOL
));
393 if (FileDevicePath
!= NULL
) {
394 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
395 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
396 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
397 CopyMem (&FilePath
->PathName
, UnicodeFileName
, Size
);
398 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
399 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
401 if (File
->EfiHandle
!= NULL
) {
402 File
->DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
405 File
->DevicePath
= AppendDevicePath (File
->DevicePath
, FileDevicePath
);
406 FreePool (FileDevicePath
);
409 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
410 if (!EFI_ERROR (Status
)) {
411 File
->FsBlockIoMedia
= BlkIo
->Media
;
413 // If we are not opening the device this will get over written with file info
414 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
417 if (File
->Type
== EfiOpenFileSystem
) {
418 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
419 if (!EFI_ERROR (Status
)) {
420 Status
= Fs
->OpenVolume (Fs
, &Root
);
421 if (!EFI_ERROR (Status
)) {
422 // Get information about the volume
424 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
425 if (Status
== EFI_BUFFER_TOO_SMALL
) {
426 File
->FsInfo
= AllocatePool (Size
);
427 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
430 // Get information about the file
431 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
432 if (!EFI_ERROR (Status
)) {
434 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
435 if (Status
== EFI_BUFFER_TOO_SMALL
) {
436 File
->FsFileInfo
= AllocatePool (Size
);
437 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
438 if (!EFI_ERROR (Status
)) {
439 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
440 File
->MaxPosition
= (UINT64
)File
->Size
;
448 } else if (File
->Type
== EfiOpenBlockIo
) {
449 File
->Size
= (UINTN
)File
->MaxPosition
;
455 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
458 CompareGuidToString (
467 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
472 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
474 if (*StringPtr
== '-') {
479 if (*GuidPtr
== '-') {
484 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
485 return EFI_NOT_FOUND
;
497 Internal work function to fill in EFI_OPEN_FILE information for the FV
499 @param File Open file handle
500 @param FileName Name of file after device stripped off
505 EblFvFileDevicePath (
506 IN OUT EFI_OPEN_FILE
*File
,
508 IN CONST UINT64 OpenMode
512 EFI_STATUS GetNextFileStatus
;
513 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
514 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
516 UINT32 AuthenticationStatus
;
517 CHAR8 AsciiSection
[MAX_PATHNAME
];
520 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
523 UINTN NumberOfBlocks
;
524 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
528 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
529 if (EFI_ERROR (Status
)) {
533 // Get FVB Info about the handle
534 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
535 if (!EFI_ERROR (Status
)) {
536 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
537 if (!EFI_ERROR (Status
)) {
538 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
539 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
540 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
541 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
544 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
545 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
546 if (EFI_ERROR (Status
)) {
554 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
556 if (*FileName
== '\0') {
557 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
558 File
->Size
= File
->FvSize
;
559 File
->MaxPosition
= File
->Size
;
563 File
->FvType
= EFI_FV_FILETYPE_ALL
;
564 GetNextFileStatus
= File
->Fv
->GetNextFile (
572 if (!EFI_ERROR (GetNextFileStatus
)) {
573 // Compare GUID first
574 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
575 if (!EFI_ERROR(Status
)) {
580 Status
= File
->Fv
->ReadSection (
583 EFI_SECTION_USER_INTERFACE
,
587 &AuthenticationStatus
589 if (!EFI_ERROR (Status
)) {
590 UnicodeStrToAsciiStr (Section
, AsciiSection
);
591 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
598 } while (!EFI_ERROR (GetNextFileStatus
));
600 if (EFI_ERROR (GetNextFileStatus
)) {
601 return GetNextFileStatus
;
604 if (OpenMode
!= EFI_SECTION_ALL
) {
605 // Calculate the size of the section we are targeting
608 Status
= File
->Fv
->ReadSection (
611 (EFI_SECTION_TYPE
)OpenMode
,
615 &AuthenticationStatus
617 if (EFI_ERROR (Status
)) {
622 File
->MaxPosition
= File
->Size
;
623 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
624 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
628 // FVB not required if FV was soft loaded...
636 Open a device named by PathName. The PathName includes a device name and
637 path seperated by a :. See file header for more details on the PathName
638 syntax. There is no checking to prevent a file from being opened more than
641 SectionType is only used to open an FV. Each file in an FV contains multiple
642 secitons and only the SectionType section is opened.
644 For any file that is opened with EfiOpen() must be closed with EfiClose().
646 @param PathName Path to parse to open
647 @param OpenMode Same as EFI_FILE.Open()
648 @param SectionType Section in FV to open.
650 @return NULL Open failed
651 @return Valid EFI_OPEN_FILE handle
657 IN CONST UINT64 OpenMode
,
658 IN CONST EFI_SECTION_TYPE SectionType
663 EFI_OPEN_FILE FileData
;
667 EFI_OPEN_FILE_GUARD
*GuardFile
;
668 BOOLEAN VolumeNameMatch
;
669 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
672 CHAR8
*CwdPlusPathName
;
674 EFI_SECTION_TYPE ModifiedSectionType
;
676 EblUpdateDeviceLists ();
679 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
681 StrLen
= AsciiStrSize (PathName
);
683 // Smallest valid path is 1 char and a null
687 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
688 if (PathName
[FileStart
] == ':') {
695 // Matching volume name has precedence over handle based names
697 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
698 if (!VolumeNameMatch
) {
699 if (FileStart
== StrLen
) {
700 // No Volume name or device name, so try Current Working Directory
706 // We could add a current working diretory concept
707 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
708 if (CwdPlusPathName
== NULL
) {
712 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
713 // PathName starts in / so this means we go to the root of the device in the CWD.
714 CwdPlusPathName
[0] = '\0';
715 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
716 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
717 if (gCwd
[FileStart
] == ':') {
719 CwdPlusPathName
[FileStart
] = '\0';
724 AsciiStrCpy (CwdPlusPathName
, gCwd
);
725 StrLen
= AsciiStrLen (gCwd
);
726 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
727 AsciiStrCat (CwdPlusPathName
, "\\");
731 AsciiStrCat (CwdPlusPathName
, PathName
);
732 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
733 // Extra error check to make sure we don't recusre and blow stack
737 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
738 FreePool (CwdPlusPathName
);
742 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
745 File
->DeviceName
= AllocatePool (StrLen
);
746 AsciiStrCpy (File
->DeviceName
, PathName
);
747 File
->DeviceName
[FileStart
- 1] = '\0';
748 File
->FileName
= &File
->DeviceName
[FileStart
];
749 if (File
->FileName
[0] == '\0') {
750 // if it is just a file name use / as root
751 File
->FileName
= "\\";
755 // Use best match algorithm on the dev names so we only need to look at the
756 // first few charters to match the full device name. Short name forms are
757 // legal from the caller.
759 Status
= EFI_SUCCESS
;
760 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
761 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
762 if (DevNumber
>= mFsCount
) {
765 File
->Type
= EfiOpenFileSystem
;
766 File
->EfiHandle
= mFs
[DevNumber
];
767 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
769 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
770 if (DevNumber
>= mFvCount
) {
773 File
->Type
= EfiOpenFirmwareVolume
;
774 File
->EfiHandle
= mFv
[DevNumber
];
776 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
777 // Skip leading / as its not really needed for the FV since no directories are supported
782 ModifiedSectionType
= SectionType
;
783 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
784 if (PathName
[Index
] == ':') {
785 // Support fv0:\DxeCore:0x10
786 // This means open the PE32 Section of the file
787 ModifiedSectionType
= (EFI_SECTION_TYPE
)AsciiStrHexToUintn (&PathName
[Index
+ 1]);
788 PathName
[Index
] = '\0';
791 File
->FvSectionType
= ModifiedSectionType
;
792 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
794 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
795 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
796 File
->Type
= EfiOpenMemoryBuffer
;
797 // 1st colon is at PathName[FileStart - 1]
798 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
801 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
805 // If we ran out of string, there's no extra data
806 if (PathName
[FileStart
] == '\0') {
809 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
812 // if there's no number after the second colon, default
814 if (File
->Size
== 0) {
815 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
818 File
->MaxPosition
= File
->Size
;
819 File
->BaseOffset
= (UINTN
)File
->Buffer
;
821 } else if (*PathName
== 'l' || *PathName
== 'L') {
822 if (DevNumber
>= mLoadFileCount
) {
825 File
->Type
= EfiOpenLoadFile
;
826 File
->EfiHandle
= mLoadFile
[DevNumber
];
828 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
829 if (EFI_ERROR (Status
)) {
833 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
834 if (EFI_ERROR (Status
)) {
837 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
839 } else if (*PathName
== 'b' || *PathName
== 'B') {
840 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
841 if (DevNumber
>= mBlkIoCount
) {
844 File
->Type
= EfiOpenBlockIo
;
845 File
->EfiHandle
= mBlkIo
[DevNumber
];
846 EblFileDevicePath (File
, "", OpenMode
);
848 // 1st colon is at PathName[FileStart - 1]
849 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
852 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
856 // If we ran out of string, there's no extra data
857 if (PathName
[FileStart
] == '\0') {
860 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
863 // if a zero size is passed in (or the size is left out entirely),
864 // go to the end of the device.
866 File
->Size
= File
->Size
- File
->DiskOffset
;
871 File
->MaxPosition
= File
->Size
;
872 File
->BaseOffset
= File
->DiskOffset
;
873 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
875 // Get current IP address
876 Status
= EblGetCurrentIpAddress (&Ip
);
877 if (EFI_ERROR(Status
)) {
878 AsciiPrint("Device IP Address is not configured.\n");
883 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
884 File
->Type
= EfiOpenTftp
;
885 File
->IsDirty
= FALSE
;
886 File
->IsBufferValid
= FALSE
;
888 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
891 if (EFI_ERROR (Status
)) {
895 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
896 if (GuardFile
== NULL
) {
900 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
901 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
902 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
904 return &(GuardFile
->File
);
907 FreePool (File
->DeviceName
);
911 #define FILE_COPY_CHUNK 0x01000000
915 IN CHAR8
*DestinationFile
,
919 EFI_OPEN_FILE
*Source
= NULL
;
920 EFI_OPEN_FILE
*Destination
= NULL
;
921 EFI_STATUS Status
= EFI_SUCCESS
;
925 UINTN Chunk
= FILE_COPY_CHUNK
;
927 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
928 if (Source
== NULL
) {
929 AsciiPrint("Source file open error.\n");
930 Status
= EFI_NOT_FOUND
;
934 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
935 if (Destination
== NULL
) {
936 AsciiPrint("Destination file open error.\n");
937 Status
= EFI_NOT_FOUND
;
941 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
942 if (Buffer
== NULL
) {
943 Status
= EFI_OUT_OF_RESOURCES
;
947 Size
= EfiTell(Source
, NULL
);
949 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
950 Chunk
= FILE_COPY_CHUNK
;
952 Status
= EfiRead(Source
, Buffer
, &Chunk
);
953 if (EFI_ERROR(Status
)) {
954 AsciiPrint("Read file error %r\n", Status
);
958 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
959 if (EFI_ERROR(Status
)) {
960 AsciiPrint("Write file error %r\n", Status
);
967 Chunk
= Size
- Offset
;
969 Status
= EfiRead(Source
, Buffer
, &Chunk
);
970 if (EFI_ERROR(Status
)) {
971 AsciiPrint("Read file error\n");
975 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
976 if (EFI_ERROR(Status
)) {
977 AsciiPrint("Write file error\n");
983 if (Source
!= NULL
) {
984 Status
= EfiClose(Source
);
985 if (EFI_ERROR(Status
)) {
986 AsciiPrint("Source close error");
990 if (Destination
!= NULL
) {
991 Status
= EfiClose(Destination
);
992 if (EFI_ERROR(Status
)) {
993 AsciiPrint("Destination close error");
997 if (Buffer
!= NULL
) {
1005 Use DeviceType and Index to form a valid PathName and try and open it.
1007 @param DeviceType Device type to open
1008 @param Index Device Index to use. Zero relative.
1010 @return NULL Open failed
1011 @return Valid EFI_OPEN_FILE handle
1015 EfiDeviceOpenByType (
1016 IN EFI_OPEN_FILE_TYPE DeviceType
,
1021 CHAR8 Path
[MAX_CMD_LINE
];
1023 switch (DeviceType
) {
1024 case EfiOpenLoadFile
:
1025 DevStr
= "loadfile%d:";
1027 case EfiOpenFirmwareVolume
:
1030 case EfiOpenFileSystem
:
1033 case EfiOpenBlockIo
:
1036 case EfiOpenMemoryBuffer
:
1043 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1045 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1050 Close a file handle opened by EfiOpen() and free all resources allocated by
1053 @param Stream Open File Handle
1055 @return EFI_INVALID_PARAMETER Stream is not an Open File
1056 @return EFI_SUCCESS Steam closed
1061 IN EFI_OPEN_FILE
*File
1065 UINT64 TftpBufferSize
;
1067 if (!FileHandleValid (File
)) {
1068 return EFI_INVALID_PARAMETER
;
1071 //Write the buffer contents to TFTP file.
1072 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1074 TftpBufferSize
= File
->Size
;
1076 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1082 (UINT8
*)File
->FileName
,
1086 if (EFI_ERROR(Status
)) {
1087 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1092 if ((File
->Type
== EfiOpenLoadFile
) ||
1093 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1094 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1095 EblFreePool(File
->Buffer
);
1098 EblFreePool (File
->DevicePath
);
1099 EblFreePool (File
->DeviceName
);
1100 EblFreePool (File
->FsFileInfo
);
1101 EblFreePool (File
->FsInfo
);
1103 if (File
->FsFileHandle
!= NULL
) {
1104 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1107 // Need to free File and it's Guard structures
1108 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1114 Return the size of the file represented by Stream. Also return the current
1115 Seek position. Opening a file will enable a valid file size to be returned.
1116 LoadFile is an exception as a load file size is set to zero.
1118 @param Stream Open File Handle
1120 @return 0 Stream is not an Open File or a valid LoadFile handle
1125 IN EFI_OPEN_FILE
*File
,
1126 OUT EFI_LBA
*CurrentPosition OPTIONAL
1130 UINT64 BufferSize
= 0;
1132 if (!FileHandleValid (File
)) {
1136 if (CurrentPosition
!= NULL
) {
1137 *CurrentPosition
= File
->CurrentPosition
;
1140 if (File
->Type
== EfiOpenLoadFile
) {
1141 // Figure out the File->Size
1142 File
->Buffer
= NULL
;
1144 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1145 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1149 File
->MaxPosition
= (UINT64
)File
->Size
;
1150 } else if (File
->Type
== EfiOpenTftp
) {
1153 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1159 (UINT8
*)File
->FileName
,
1163 if (EFI_ERROR(Status
)) {
1164 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1168 File
->Size
= (UINTN
)BufferSize
;
1169 File
->MaxPosition
= File
->Size
;
1177 Seek to the Offset locaiton in the file. LoadFile and FV device types do
1178 not support EfiSeek(). It is not possible to grow the file size using
1181 SeekType defines how use Offset to calculate the new file position:
1182 EfiSeekStart : Position = Offset
1183 EfiSeekCurrent: Position is Offset bytes from the current position
1184 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1186 @param Stream Open File Handle
1187 @param Offset Offset to seek too.
1188 @param SeekType Type of seek to perform
1191 @return EFI_INVALID_PARAMETER Stream is not an Open File
1192 @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek
1193 @return EFI_NOT_FOUND Seek past the end of the file.
1194 @return EFI_SUCCESS Steam closed
1199 IN EFI_OPEN_FILE
*File
,
1201 IN EFI_SEEK_TYPE SeekType
1205 UINT64 CurrentPosition
;
1207 if (!FileHandleValid (File
)) {
1208 return EFI_INVALID_PARAMETER
;
1211 if (File
->Type
== EfiOpenLoadFile
) {
1212 // LoadFile does not support Seek
1213 return EFI_UNSUPPORTED
;
1216 CurrentPosition
= File
->CurrentPosition
;
1219 if (Offset
> File
->MaxPosition
) {
1220 return EFI_NOT_FOUND
;
1222 CurrentPosition
= Offset
;
1225 case EfiSeekCurrent
:
1226 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1227 return EFI_NOT_FOUND
;
1229 CurrentPosition
+= Offset
;
1234 // We don't support growing file size via seeking past end of file
1235 return EFI_UNSUPPORTED
;
1237 CurrentPosition
= File
->MaxPosition
;
1241 return EFI_NOT_FOUND
;
1244 Status
= EFI_SUCCESS
;
1245 if (File
->FsFileHandle
!= NULL
) {
1246 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1249 if (!EFI_ERROR (Status
)) {
1250 File
->CurrentPosition
= CurrentPosition
;
1258 IN OUT EFI_OPEN_FILE
*File
1262 UINT64 TftpBufferSize
;
1264 if (File
->IsBufferValid
) {
1268 // Make sure the file size is set.
1269 EfiTell (File
, NULL
);
1271 //Allocate a buffer to hold the whole file.
1272 File
->Buffer
= AllocatePool(File
->Size
);
1273 if (File
->Buffer
== NULL
) {
1274 return EFI_OUT_OF_RESOURCES
;
1277 TftpBufferSize
= File
->Size
;
1280 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1286 (UINT8
*)File
->FileName
,
1289 if (EFI_ERROR(Status
)) {
1290 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1291 FreePool(File
->Buffer
);
1295 // Set the buffer valid flag.
1296 File
->IsBufferValid
= TRUE
;
1302 Read BufferSize bytes from the current locaiton in the file. For load file,
1303 FV, and TFTP case you must read the entire file.
1305 @param Stream Open File Handle
1306 @param Buffer Caller allocated buffer.
1307 @param BufferSize Size of buffer in bytes.
1310 @return EFI_SUCCESS Stream is not an Open File
1311 @return EFI_END_OF_FILE Tried to read past the end of the file
1312 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1313 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1314 @return "other" Error returned from device read
1319 IN EFI_OPEN_FILE
*File
,
1321 OUT UINTN
*BufferSize
1325 UINT32 AuthenticationStatus
;
1326 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1328 if (!FileHandleValid (File
)) {
1329 return EFI_INVALID_PARAMETER
;
1332 // Don't read past the end of the file.
1333 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1334 return EFI_END_OF_FILE
;
1337 switch (File
->Type
) {
1338 case EfiOpenLoadFile
:
1339 // Figure out the File->Size
1340 EfiTell (File
, NULL
);
1342 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1345 case EfiOpenFirmwareVolume
:
1346 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1347 // This is the entire FV device, so treat like a memory buffer
1348 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1349 File
->CurrentPosition
+= *BufferSize
;
1350 Status
= EFI_SUCCESS
;
1352 if (File
->Buffer
== NULL
) {
1353 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1354 Status
= File
->Fv
->ReadFile (
1357 (VOID
**)&File
->Buffer
,
1360 &File
->FvAttributes
,
1361 &AuthenticationStatus
1364 Status
= File
->Fv
->ReadSection (
1367 File
->FvSectionType
,
1369 (VOID
**)&File
->Buffer
,
1371 &AuthenticationStatus
1374 if (EFI_ERROR (Status
)) {
1377 File
->IsBufferValid
= TRUE
;
1379 // Operate on the cached buffer so Seek will work
1380 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1381 File
->CurrentPosition
+= *BufferSize
;
1382 Status
= EFI_SUCCESS
;
1386 case EfiOpenMemoryBuffer
:
1387 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1388 File
->CurrentPosition
+= *BufferSize
;
1389 Status
= EFI_SUCCESS
;
1392 case EfiOpenFileSystem
:
1393 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1394 File
->CurrentPosition
+= *BufferSize
;
1397 case EfiOpenBlockIo
:
1398 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1399 if (!EFI_ERROR(Status
)) {
1400 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1402 File
->CurrentPosition
+= *BufferSize
;
1406 // Cache the file if it hasn't been cached yet.
1407 if (File
->IsBufferValid
== FALSE
) {
1408 Status
= CacheTftpFile (File
);
1409 if (EFI_ERROR (Status
)) {
1414 // Copy out the requested data
1415 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1416 File
->CurrentPosition
+= *BufferSize
;
1418 Status
= EFI_SUCCESS
;
1422 return EFI_INVALID_PARAMETER
;
1430 Read the entire file into a buffer. This routine allocates the buffer and
1431 returns it to the user full of the read data.
1433 This is very useful for load flie where it's hard to know how big the buffer
1436 @param Stream Open File Handle
1437 @param Buffer Pointer to buffer to return.
1438 @param BufferSize Pointer to Size of buffer return..
1441 @return EFI_SUCCESS Stream is not an Open File
1442 @return EFI_END_OF_FILE Tried to read past the end of the file
1443 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1444 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1445 @return "other" Error returned from device read
1449 EfiReadAllocatePool (
1450 IN EFI_OPEN_FILE
*File
,
1452 OUT UINTN
*BufferSize
1455 if (!FileHandleValid (File
)) {
1456 return EFI_INVALID_PARAMETER
;
1459 // Loadfile defers file size determination on Open so use tell to find it
1460 EfiTell (File
, NULL
);
1462 *BufferSize
= File
->Size
;
1463 *Buffer
= AllocatePool (*BufferSize
);
1464 if (*Buffer
== NULL
) {
1465 return EFI_NOT_FOUND
;
1468 return EfiRead (File
, *Buffer
, BufferSize
);
1473 Write data back to the file. For TFTP case you must write the entire file.
1475 @param Stream Open File Handle
1476 @param Buffer Pointer to buffer to return.
1477 @param BufferSize Pointer to Size of buffer return..
1480 @return EFI_SUCCESS Stream is not an Open File
1481 @return EFI_END_OF_FILE Tried to read past the end of the file
1482 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1483 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1484 @return "other" Error returned from device write
1489 IN EFI_OPEN_FILE
*File
,
1491 OUT UINTN
*BufferSize
1495 EFI_FV_WRITE_FILE_DATA FileData
;
1496 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1498 if (!FileHandleValid (File
)) {
1499 return EFI_INVALID_PARAMETER
;
1502 switch (File
->Type
) {
1503 case EfiOpenMemoryBuffer
:
1504 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1505 return EFI_END_OF_FILE
;
1508 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1509 File
->CurrentPosition
+= *BufferSize
;
1510 Status
= EFI_SUCCESS
;
1512 case EfiOpenLoadFile
:
1513 // LoadFile device is read only be definition
1514 Status
= EFI_UNSUPPORTED
;
1516 case EfiOpenFirmwareVolume
:
1517 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1518 // Writes not support to a specific section. You have to update entire file
1519 return EFI_UNSUPPORTED
;
1522 FileData
.NameGuid
= &(File
->FvNameGuid
);
1523 FileData
.Type
= File
->FvType
;
1524 FileData
.FileAttributes
= File
->FvAttributes
;
1525 FileData
.Buffer
= Buffer
;
1526 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1527 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1530 case EfiOpenFileSystem
:
1531 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1532 File
->CurrentPosition
+= *BufferSize
;
1535 case EfiOpenBlockIo
:
1536 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1537 return EFI_END_OF_FILE
;
1540 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1541 if (!EFI_ERROR(Status
)) {
1542 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1544 File
->CurrentPosition
+= *BufferSize
;
1548 // Cache the file if it hasn't been cached yet.
1549 if (File
->IsBufferValid
== FALSE
) {
1550 Status
= CacheTftpFile(File
);
1551 if (EFI_ERROR(Status
)) {
1556 // Don't overwrite the buffer
1557 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1560 TempBuffer
= File
->Buffer
;
1562 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1563 if (File
->Buffer
== NULL
) {
1564 return EFI_OUT_OF_RESOURCES
;
1567 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1569 FreePool (TempBuffer
);
1571 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1572 File
->MaxPosition
= (UINT64
)File
->Size
;
1575 // Copy in the requested data
1576 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1577 File
->CurrentPosition
+= *BufferSize
;
1579 // Mark the file dirty
1580 File
->IsDirty
= TRUE
;
1582 Status
= EFI_SUCCESS
;
1586 Status
= EFI_INVALID_PARAMETER
;
1594 Given Cwd expand Path to remove .. and replace them with real
1597 @param Cwd Current Working Directory
1598 @param Path Path to expand
1600 @return NULL Cwd or Path are not valid
1601 @return 'other' Path with .. expanded
1611 CHAR8
*Work
, *Start
, *End
;
1615 if (Cwd
== NULL
|| Path
== NULL
) {
1619 StrLen
= AsciiStrSize (Cwd
);
1621 // Smallest valid path is 1 char and a null
1625 StrLen
= AsciiStrSize (Path
);
1626 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1627 if (NewPath
== NULL
) {
1630 AsciiStrCpy (NewPath
, Cwd
);
1632 End
= Path
+ StrLen
;
1633 for (Start
= Path
;;) {
1634 Work
= AsciiStrStr (Start
, "..") ;
1636 // Remaining part of Path contains no more ..
1640 // append path prior to ..
1641 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1642 StrLen
= AsciiStrLen (NewPath
);
1643 for (i
= StrLen
; i
>= 0; i
--) {
1644 if (NewPath
[i
] == ':') {
1648 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1649 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1650 // leave the / before a :
1651 NewPath
[i
+1] = '\0';
1653 // replace / will Null to remove trailing file/dir reference
1663 // Handle the path that remains after the ..
1664 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1671 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1672 the path does not contain a device name, The CWD is prepended to the path.
1674 @param Cwd Current Working Directory to set
1677 @return EFI_SUCCESS CWD is set
1678 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1686 EFI_OPEN_FILE
*File
;
1691 return EFI_INVALID_PARAMETER
;
1694 if (AsciiStrCmp (Cwd
, ".") == 0) {
1700 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1706 Len
= AsciiStrLen (gCwd
);
1707 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1708 // parent is device so nothing to do
1712 // Expand .. in Cwd, given we know current working directory
1713 Path
= ExpandPath (gCwd
, Cwd
);
1715 return EFI_NOT_FOUND
;
1719 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1721 return EFI_INVALID_PARAMETER
;
1728 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1729 // relative to the current gCwd or not.
1730 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1732 return EFI_INVALID_PARAMETER
;
1744 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1745 the path does not contain a device name, The CWD is prepended to the path.
1746 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1747 a call to EfiSetCwd() it is not legal to use the pointer returned by
1750 @param Cwd Current Working Directory
1753 @return "" No CWD set
1754 @return 'other' Returns buffer that contains CWD.