2 File IO routines inspired by Streams with an EFI flavor
4 Copyright (c) 2007, Intel Corporation<BR>
5 Portions copyright (c) 2008-2009, Apple Inc. All rights reserved.
7 All rights reserved. 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
);
157 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiFirmwareVolume2ProtocolGuid
, NULL
, &mFvCount
, &mFv
);
159 if (mLoadFile
!= NULL
) {
160 FreePool (mLoadFile
);
162 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &mLoadFileCount
, &mLoadFile
);
168 if (&mFsInfo
[0] != NULL
) {
169 // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code
170 for (Index
= 0; Index
< mFsCount
; Index
++) {
171 if (mFsInfo
[Index
] != NULL
) {
172 FreePool (mFsInfo
[Index
]);
178 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &mFsCount
, &mFs
);
181 mFsInfo
= AllocateZeroPool (mFsCount
* sizeof (EFI_FILE_SYSTEM_INFO
*));
182 if (mFsInfo
== NULL
) {
183 // If we can't do this then we can't support file system entries
186 // Loop through all the file system structures and cache the file system info data
187 for (Index
=0; Index
< mFsCount
; Index
++) {
188 Status
= gBS
->HandleProtocol (mFs
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
189 if (!EFI_ERROR (Status
)) {
190 Status
= Fs
->OpenVolume (Fs
, &Root
);
191 if (!EFI_ERROR (Status
)) {
192 // Get information about the volume
194 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
195 if (Status
== EFI_BUFFER_TOO_SMALL
) {
196 mFsInfo
[Index
] = AllocatePool (Size
);
197 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
209 PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\.
210 Return TRUE if the <devce name> prefix of PathName matches a file system
211 Volume Name. MatchIndex is the array index in mFsInfo[] of the match,
212 and it can be used with mFs[] to find the handle that needs to be opened
214 @param PathName PathName to check
215 @param FileStart Index of the first character of the <path>
216 @param MatchIndex Index in mFsInfo[] that matches
218 @return TRUE PathName matches a Volume Label and MatchIndex is valid
219 @return FALSE PathName does not match a Volume Label MatchIndex undefined
226 OUT UINTN
*MatchIndex
234 for (Index
=0; Index
< mFsCount
; Index
++) {
235 if (mFsInfo
[Index
] == NULL
) {
236 // FsInfo is not valid so skip it
239 VolStrLen
= StrLen (mFsInfo
[Index
]->VolumeLabel
);
240 for (Compare
= 0, Match
= TRUE
; Compare
< (FileStart
- 1); Compare
++) {
241 if (Compare
> VolStrLen
) {
245 if (PathName
[Compare
] != (CHAR8
)mFsInfo
[Index
]->VolumeLabel
[Compare
]) {
246 // If the VolumeLabel has a space allow a _ to match with it in addition to ' '
247 if (!((PathName
[Compare
] == '_') && (mFsInfo
[Index
]->VolumeLabel
[Compare
] == L
' '))) {
264 Return the number of devices of the current type active in the system
266 @param Type Device type to check
268 @return 0 Invalid type
273 IN EFI_OPEN_FILE_TYPE DeviceType
276 switch (DeviceType
) {
277 case EfiOpenLoadFile
:
278 return mLoadFileCount
;
279 case EfiOpenFirmwareVolume
:
281 case EfiOpenFileSystem
:
291 ConvertIpStringToEfiIp (
293 OUT EFI_IP_ADDRESS
*ServerIp
299 ServerIp
->v4
.Addr
[0] = (UINT8
)AsciiStrDecimalToUintn (Str
);
301 Str
= AsciiStrStr (Str
, ".");
303 return EFI_DEVICE_ERROR
;
306 ServerIp
->v4
.Addr
[1] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
308 Str
= AsciiStrStr (Str
, ".");
310 return EFI_DEVICE_ERROR
;
313 ServerIp
->v4
.Addr
[2] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
315 Str
= AsciiStrStr (Str
, ".");
317 return EFI_DEVICE_ERROR
;
320 ServerIp
->v4
.Addr
[3] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
327 Internal work function to extract a device number from a string skipping
328 text. Easy way to extract numbers from strings like blk7:.
330 @param Str String to extract device number form
332 @return -1 Device string is not valid
337 EblConvertDevStringToNumber (
345 // Find the first digit
346 Max
= AsciiStrLen (Str
);
347 for (Index
= 0; !((*Str
>= '0') && (*Str
<= '9')) && (Index
< Max
); Index
++) {
354 return AsciiStrDecimalToUintn (Str
);
359 Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo
361 @param File Open file handle
362 @param FileName Name of file after device stripped off
368 IN OUT EFI_OPEN_FILE
*File
,
370 IN CONST UINT64 OpenMode
375 FILEPATH_DEVICE_PATH
*FilePath
;
376 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
377 CHAR16 UnicodeFileName
[MAX_PATHNAME
];
378 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
379 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
380 EFI_FILE_HANDLE Root
;
383 if ( *FileName
!= 0 ) {
384 AsciiStrToUnicodeStr (FileName
, UnicodeFileName
);
386 AsciiStrToUnicodeStr ("\\", UnicodeFileName
);
389 Size
= StrSize (UnicodeFileName
);
390 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ sizeof (EFI_DEVICE_PATH_PROTOCOL
));
391 if (FileDevicePath
!= NULL
) {
392 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
393 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
394 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
395 CopyMem (&FilePath
->PathName
, UnicodeFileName
, Size
);
396 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
397 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
399 if (File
->EfiHandle
!= NULL
) {
400 File
->DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
403 File
->DevicePath
= AppendDevicePath (File
->DevicePath
, FileDevicePath
);
404 FreePool (FileDevicePath
);
407 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
408 if (!EFI_ERROR (Status
)) {
409 CopyMem (&File
->FsBlockIoMedia
, BlkIo
->Media
, sizeof (EFI_BLOCK_IO_MEDIA
));
411 // If we are not opening the device this will get over written with file info
412 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
415 if (File
->Type
== EfiOpenFileSystem
) {
416 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
417 if (!EFI_ERROR (Status
)) {
418 Status
= Fs
->OpenVolume (Fs
, &Root
);
419 if (!EFI_ERROR (Status
)) {
420 // Get information about the volume
422 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
423 if (Status
== EFI_BUFFER_TOO_SMALL
) {
424 File
->FsInfo
= AllocatePool (Size
);
425 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
428 // Get information about the file
429 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
430 if (!EFI_ERROR (Status
)) {
432 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
433 if (Status
== EFI_BUFFER_TOO_SMALL
) {
434 File
->FsFileInfo
= AllocatePool (Size
);
435 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
436 if (!EFI_ERROR (Status
)) {
437 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
438 File
->MaxPosition
= (UINT64
)File
->Size
;
446 } else if (File
->Type
== EfiOpenBlockIo
) {
447 File
->Size
= (UINTN
)File
->MaxPosition
;
453 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
456 CompareGuidToString (
465 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
470 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
472 if (*StringPtr
== '-') {
477 if (*GuidPtr
== '-') {
482 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
483 return EFI_NOT_FOUND
;
495 Internal work function to fill in EFI_OPEN_FILE information for the FV
497 @param File Open file handle
498 @param FileName Name of file after device stripped off
503 EblFvFileDevicePath (
504 IN OUT EFI_OPEN_FILE
*File
,
506 IN CONST UINT64 OpenMode
510 EFI_STATUS GetNextFileStatus
;
511 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
512 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
514 UINT32 AuthenticationStatus
;
515 CHAR8 AsciiSection
[MAX_PATHNAME
];
518 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
521 UINTN NumberOfBlocks
;
524 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
525 if (EFI_ERROR (Status
)) {
529 // Get FVB Info about the handle
530 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
531 if (!EFI_ERROR (Status
)) {
532 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
533 if (!EFI_ERROR (Status
)) {
534 for (Lba
= 0, File
->FvSize
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
535 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
536 if (EFI_ERROR (Status
)) {
544 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
546 if (*FileName
== '\0') {
547 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
548 File
->Size
= File
->FvSize
;
549 File
->MaxPosition
= File
->Size
;
553 File
->FvType
= EFI_FV_FILETYPE_ALL
;
554 GetNextFileStatus
= File
->Fv
->GetNextFile (
562 if (!EFI_ERROR (GetNextFileStatus
)) {
563 // Compare GUID first
564 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
565 if (!EFI_ERROR(Status
)) {
570 Status
= File
->Fv
->ReadSection (
573 EFI_SECTION_USER_INTERFACE
,
577 &AuthenticationStatus
579 if (!EFI_ERROR (Status
)) {
580 UnicodeStrToAsciiStr (Section
, AsciiSection
);
581 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
588 } while (!EFI_ERROR (GetNextFileStatus
));
590 if (EFI_ERROR (GetNextFileStatus
)) {
591 return GetNextFileStatus
;
594 if (OpenMode
!= EFI_SECTION_ALL
) {
595 // Calculate the size of the section we are targeting
598 Status
= File
->Fv
->ReadSection (
605 &AuthenticationStatus
607 if (EFI_ERROR (Status
)) {
612 File
->MaxPosition
= File
->Size
;
613 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
614 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
618 // FVB not required if FV was soft loaded...
626 Open a device named by PathName. The PathName includes a device name and
627 path seperated by a :. See file header for more details on the PathName
628 syntax. There is no checking to prevent a file from being opened more than
631 SectionType is only used to open an FV. Each file in an FV contains multiple
632 secitons and only the SectionType section is opened.
634 For any file that is opened with EfiOpen() must be closed with EfiClose().
636 @param PathName Path to parse to open
637 @param OpenMode Same as EFI_FILE.Open()
638 @param SectionType Section in FV to open.
640 @return NULL Open failed
641 @return Valid EFI_OPEN_FILE handle
647 IN CONST UINT64 OpenMode
,
648 IN CONST EFI_SECTION_TYPE SectionType
653 EFI_OPEN_FILE FileData
;
657 EFI_OPEN_FILE_GUARD
*GuardFile
;
658 BOOLEAN VolumeNameMatch
;
659 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
662 CHAR8
*CwdPlusPathName
;
664 EFI_SECTION_TYPE ModifiedSectionType
;
666 EblUpdateDeviceLists ();
669 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
671 StrLen
= AsciiStrSize (PathName
);
673 // Smallest valid path is 1 char and a null
677 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
678 if (PathName
[FileStart
] == ':') {
685 // Matching volume name has precedence over handle based names
687 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
688 if (!VolumeNameMatch
) {
689 if (FileStart
== StrLen
) {
690 // No Volume name or device name, so try Current Working Directory
696 // We could add a current working diretory concept
697 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
698 if (CwdPlusPathName
== NULL
) {
702 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
703 // PathName starts in / so this means we go to the root of the device in the CWD.
704 CwdPlusPathName
[0] = '\0';
705 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
706 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
707 if (gCwd
[FileStart
] == ':') {
709 CwdPlusPathName
[FileStart
] = '\0';
714 AsciiStrCpy (CwdPlusPathName
, gCwd
);
715 StrLen
= AsciiStrLen (gCwd
);
716 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
717 AsciiStrCat (CwdPlusPathName
, "\\");
721 AsciiStrCat (CwdPlusPathName
, PathName
);
722 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
723 // Extra error check to make sure we don't recusre and blow stack
727 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
728 FreePool (CwdPlusPathName
);
732 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
735 File
->DeviceName
= AllocatePool (StrLen
);
736 AsciiStrCpy (File
->DeviceName
, PathName
);
737 File
->DeviceName
[FileStart
- 1] = '\0';
738 File
->FileName
= &File
->DeviceName
[FileStart
];
739 if (File
->FileName
[0] == '\0') {
740 // if it is just a file name use / as root
741 File
->FileName
= "\\";
745 // Use best match algorithm on the dev names so we only need to look at the
746 // first few charters to match the full device name. Short name forms are
747 // legal from the caller.
749 Status
= EFI_SUCCESS
;
750 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
751 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
752 if (DevNumber
>= mFsCount
) {
755 File
->Type
= EfiOpenFileSystem
;
756 File
->EfiHandle
= mFs
[DevNumber
];
757 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
759 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
760 if (DevNumber
>= mFvCount
) {
763 File
->Type
= EfiOpenFirmwareVolume
;
764 File
->EfiHandle
= mFv
[DevNumber
];
766 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
767 // Skip leading / as its not really needed for the FV since no directories are supported
772 ModifiedSectionType
= SectionType
;
773 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
774 if (PathName
[Index
] == ':') {
775 // Support fv0:\DxeCore:0x10
776 // This means open the PE32 Section of the file
777 ModifiedSectionType
= AsciiStrHexToUintn (&PathName
[Index
+ 1]);
778 PathName
[Index
] = '\0';
781 File
->FvSectionType
= ModifiedSectionType
;
782 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
784 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
785 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
786 File
->Type
= EfiOpenMemoryBuffer
;
787 // 1st colon is at PathName[FileStart - 1]
788 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
791 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
795 // If we ran out of string, there's no extra data
796 if (PathName
[FileStart
] == '\0') {
799 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
802 // if there's no number after the second colon, default
804 if (File
->Size
== 0) {
805 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
808 File
->MaxPosition
= File
->Size
;
809 File
->BaseOffset
= (UINTN
)File
->Buffer
;
811 } else if (*PathName
== 'l' || *PathName
== 'L') {
812 if (DevNumber
>= mLoadFileCount
) {
815 File
->Type
= EfiOpenLoadFile
;
816 File
->EfiHandle
= mLoadFile
[DevNumber
];
818 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
819 if (EFI_ERROR (Status
)) {
823 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
824 if (EFI_ERROR (Status
)) {
827 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
829 } else if (*PathName
== 'b' || *PathName
== 'B') {
830 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
831 if (DevNumber
>= mBlkIoCount
) {
834 File
->Type
= EfiOpenBlockIo
;
835 File
->EfiHandle
= mBlkIo
[DevNumber
];
836 EblFileDevicePath (File
, "", OpenMode
);
838 // 1st colon is at PathName[FileStart - 1]
839 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
842 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
846 // If we ran out of string, there's no extra data
847 if (PathName
[FileStart
] == '\0') {
850 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
853 // if a zero size is passed in (or the size is left out entirely),
854 // go to the end of the device.
856 File
->Size
= File
->Size
- File
->DiskOffset
;
861 File
->MaxPosition
= File
->Size
;
862 File
->BaseOffset
= File
->DiskOffset
;
863 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
865 // Get current IP address
866 Status
= EblGetCurrentIpAddress (&Ip
);
867 if (EFI_ERROR(Status
)) {
868 AsciiPrint("Device IP Address is not configured.\n");
873 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
874 File
->Type
= EfiOpenTftp
;
875 File
->IsDirty
= FALSE
;
876 File
->IsBufferValid
= FALSE
;
878 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
881 if (EFI_ERROR (Status
)) {
885 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
886 if (GuardFile
== NULL
) {
890 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
891 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
892 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
894 return &(GuardFile
->File
);
897 FreePool (File
->DeviceName
);
901 #define FILE_COPY_CHUNK 0x01000000
905 IN CHAR8
*DestinationFile
,
909 EFI_OPEN_FILE
*Source
= NULL
;
910 EFI_OPEN_FILE
*Destination
= NULL
;
911 EFI_STATUS Status
= EFI_SUCCESS
;
915 UINTN Chunk
= FILE_COPY_CHUNK
;
917 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
918 if (Source
== NULL
) {
919 AsciiPrint("Source file open error.\n");
920 Status
= EFI_NOT_FOUND
;
924 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
925 if (Destination
== NULL
) {
926 AsciiPrint("Destination file open error.\n");
927 Status
= EFI_NOT_FOUND
;
931 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
932 if (Buffer
== NULL
) {
933 Status
= EFI_OUT_OF_RESOURCES
;
937 Size
= EfiTell(Source
, NULL
);
939 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
940 Chunk
= FILE_COPY_CHUNK
;
942 Status
= EfiRead(Source
, Buffer
, &Chunk
);
943 if (EFI_ERROR(Status
)) {
944 AsciiPrint("Read file error\n");
948 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
949 if (EFI_ERROR(Status
)) {
950 AsciiPrint("Write file error\n");
957 Chunk
= Size
- Offset
;
959 Status
= EfiRead(Source
, Buffer
, &Chunk
);
960 if (EFI_ERROR(Status
)) {
961 AsciiPrint("Read file error\n");
965 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
966 if (EFI_ERROR(Status
)) {
967 AsciiPrint("Write file error\n");
973 if (Source
!= NULL
) {
974 Status
= EfiClose(Source
);
975 if (EFI_ERROR(Status
)) {
976 AsciiPrint("Source close error");
980 if (Destination
!= NULL
) {
981 Status
= EfiClose(Destination
);
982 if (EFI_ERROR(Status
)) {
983 AsciiPrint("Destination close error");
987 if (Buffer
!= NULL
) {
995 Use DeviceType and Index to form a valid PathName and try and open it.
997 @param DeviceType Device type to open
998 @param Index Device Index to use. Zero relative.
1000 @return NULL Open failed
1001 @return Valid EFI_OPEN_FILE handle
1005 EfiDeviceOpenByType (
1006 IN EFI_OPEN_FILE_TYPE DeviceType
,
1011 CHAR8 Path
[MAX_CMD_LINE
];
1013 switch (DeviceType
) {
1014 case EfiOpenLoadFile
:
1015 DevStr
= "loadfile%d:";
1017 case EfiOpenFirmwareVolume
:
1020 case EfiOpenFileSystem
:
1023 case EfiOpenBlockIo
:
1026 case EfiOpenMemoryBuffer
:
1033 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1035 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1040 Close a file handle opened by EfiOpen() and free all resources allocated by
1043 @param Stream Open File Handle
1045 @return EFI_INVALID_PARAMETER Stream is not an Open File
1046 @return EFI_SUCCESS Steam closed
1051 IN EFI_OPEN_FILE
*File
1055 UINT64 TftpBufferSize
;
1057 if (!FileHandleValid (File
)) {
1058 return EFI_INVALID_PARAMETER
;
1061 //Write the buffer contents to TFTP file.
1062 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1064 TftpBufferSize
= File
->Size
;
1066 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1072 (UINT8
*)File
->FileName
,
1076 if (EFI_ERROR(Status
)) {
1077 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1082 if ((File
->Type
== EfiOpenLoadFile
) ||
1083 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1084 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1085 EblFreePool(File
->Buffer
);
1088 EblFreePool (File
->DevicePath
);
1089 EblFreePool (File
->DeviceName
);
1090 EblFreePool (File
->FsFileInfo
);
1091 EblFreePool (File
->FsInfo
);
1093 if (File
->FsFileHandle
!= NULL
) {
1094 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1097 // Need to free File and it's Guard structures
1098 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1104 Return the size of the file represented by Stream. Also return the current
1105 Seek position. Opening a file will enable a valid file size to be returned.
1106 LoadFile is an exception as a load file size is set to zero.
1108 @param Stream Open File Handle
1110 @return 0 Stream is not an Open File or a valid LoadFile handle
1115 IN EFI_OPEN_FILE
*File
,
1116 OUT EFI_LBA
*CurrentPosition OPTIONAL
1120 UINT64 BufferSize
= 0;
1122 if (!FileHandleValid (File
)) {
1126 if (CurrentPosition
!= NULL
) {
1127 *CurrentPosition
= File
->CurrentPosition
;
1130 if (File
->Type
== EfiOpenLoadFile
) {
1131 // Figure out the File->Size
1132 File
->Buffer
= NULL
;
1134 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1135 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1139 File
->MaxPosition
= (UINT64
)File
->Size
;
1140 } else if (File
->Type
== EfiOpenTftp
) {
1143 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1149 (UINT8
*)File
->FileName
,
1153 if (EFI_ERROR(Status
)) {
1154 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1158 File
->Size
= (UINTN
)BufferSize
;
1159 File
->MaxPosition
= File
->Size
;
1167 Seek to the Offset locaiton in the file. LoadFile and FV device types do
1168 not support EfiSeek(). It is not possible to grow the file size using
1171 SeekType defines how use Offset to calculate the new file position:
1172 EfiSeekStart : Position = Offset
1173 EfiSeekCurrent: Position is Offset bytes from the current position
1174 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1176 @param Stream Open File Handle
1177 @param Offset Offset to seek too.
1178 @param SeekType Type of seek to perform
1181 @return EFI_INVALID_PARAMETER Stream is not an Open File
1182 @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek
1183 @return EFI_NOT_FOUND Seek past the end of the file.
1184 @return EFI_SUCCESS Steam closed
1189 IN EFI_OPEN_FILE
*File
,
1191 IN EFI_SEEK_TYPE SeekType
1195 UINT64 CurrentPosition
;
1197 if (!FileHandleValid (File
)) {
1198 return EFI_INVALID_PARAMETER
;
1201 if (File
->Type
== EfiOpenLoadFile
) {
1202 // LoadFile does not support Seek
1203 return EFI_UNSUPPORTED
;
1206 CurrentPosition
= File
->CurrentPosition
;
1209 if (Offset
> File
->MaxPosition
) {
1210 return EFI_NOT_FOUND
;
1212 CurrentPosition
= Offset
;
1215 case EfiSeekCurrent
:
1216 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1217 return EFI_NOT_FOUND
;
1219 CurrentPosition
+= Offset
;
1224 // We don't support growing file size via seeking past end of file
1225 return EFI_UNSUPPORTED
;
1227 CurrentPosition
= File
->MaxPosition
;
1231 return EFI_NOT_FOUND
;
1234 Status
= EFI_SUCCESS
;
1235 if (File
->FsFileHandle
!= NULL
) {
1236 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1239 if (!EFI_ERROR (Status
)) {
1240 File
->CurrentPosition
= CurrentPosition
;
1248 IN OUT EFI_OPEN_FILE
*File
1252 UINT64 TftpBufferSize
;
1254 if (File
->IsBufferValid
) {
1258 // Make sure the file size is set.
1259 EfiTell (File
, NULL
);
1261 //Allocate a buffer to hold the whole file.
1262 File
->Buffer
= AllocatePool(File
->Size
);
1263 if (File
->Buffer
== NULL
) {
1264 return EFI_OUT_OF_RESOURCES
;
1267 TftpBufferSize
= File
->Size
;
1270 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1276 (UINT8
*)File
->FileName
,
1279 if (EFI_ERROR(Status
)) {
1280 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1281 FreePool(File
->Buffer
);
1285 // Set the buffer valid flag.
1286 File
->IsBufferValid
= TRUE
;
1292 Read BufferSize bytes from the current locaiton in the file. For load file,
1293 FV, and TFTP case you must read the entire file.
1295 @param Stream Open File Handle
1296 @param Buffer Caller allocated buffer.
1297 @param BufferSize Size of buffer in bytes.
1300 @return EFI_SUCCESS Stream is not an Open File
1301 @return EFI_END_OF_FILE Tried to read past the end of the file
1302 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1303 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1304 @return "other" Error returned from device read
1309 IN EFI_OPEN_FILE
*File
,
1311 OUT UINTN
*BufferSize
1315 UINT32 AuthenticationStatus
;
1316 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1318 if (!FileHandleValid (File
)) {
1319 return EFI_INVALID_PARAMETER
;
1322 // Don't read past the end of the file.
1323 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1324 return EFI_END_OF_FILE
;
1327 switch (File
->Type
) {
1328 case EfiOpenLoadFile
:
1329 // Figure out the File->Size
1330 EfiTell (File
, NULL
);
1332 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1335 case EfiOpenFirmwareVolume
:
1336 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1337 // This is the entire FV device, so treat like a memory buffer
1338 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1339 File
->CurrentPosition
+= *BufferSize
;
1340 Status
= EFI_SUCCESS
;
1342 if (File
->Buffer
== NULL
) {
1343 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1344 Status
= File
->Fv
->ReadFile (
1347 (VOID
**)&File
->Buffer
,
1350 &File
->FvAttributes
,
1351 &AuthenticationStatus
1354 Status
= File
->Fv
->ReadSection (
1357 File
->FvSectionType
,
1359 (VOID
**)&File
->Buffer
,
1361 &AuthenticationStatus
1364 if (EFI_ERROR (Status
)) {
1367 File
->IsBufferValid
= TRUE
;
1369 // Operate on the cached buffer so Seek will work
1370 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1371 File
->CurrentPosition
+= *BufferSize
;
1372 Status
= EFI_SUCCESS
;
1376 case EfiOpenMemoryBuffer
:
1377 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1378 File
->CurrentPosition
+= *BufferSize
;
1379 Status
= EFI_SUCCESS
;
1382 case EfiOpenFileSystem
:
1383 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1384 File
->CurrentPosition
+= *BufferSize
;
1387 case EfiOpenBlockIo
:
1388 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1389 if (!EFI_ERROR(Status
)) {
1390 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
.MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1392 File
->CurrentPosition
+= *BufferSize
;
1396 // Cache the file if it hasn't been cached yet.
1397 if (File
->IsBufferValid
== FALSE
) {
1398 Status
= CacheTftpFile (File
);
1399 if (EFI_ERROR (Status
)) {
1404 // Copy out the requested data
1405 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1406 File
->CurrentPosition
+= *BufferSize
;
1408 Status
= EFI_SUCCESS
;
1412 return EFI_INVALID_PARAMETER
;
1420 Read the entire file into a buffer. This routine allocates the buffer and
1421 returns it to the user full of the read data.
1423 This is very useful for load flie where it's hard to know how big the buffer
1426 @param Stream Open File Handle
1427 @param Buffer Pointer to buffer to return.
1428 @param BufferSize Pointer to Size of buffer return..
1431 @return EFI_SUCCESS Stream is not an Open File
1432 @return EFI_END_OF_FILE Tried to read past the end of the file
1433 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1434 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1435 @return "other" Error returned from device read
1439 EfiReadAllocatePool (
1440 IN EFI_OPEN_FILE
*File
,
1442 OUT UINTN
*BufferSize
1445 if (!FileHandleValid (File
)) {
1446 return EFI_INVALID_PARAMETER
;
1449 // Loadfile defers file size determination on Open so use tell to find it
1450 EfiTell (File
, NULL
);
1452 *BufferSize
= File
->Size
;
1453 *Buffer
= AllocatePool (*BufferSize
);
1454 if (*Buffer
== NULL
) {
1455 return EFI_NOT_FOUND
;
1458 return EfiRead (File
, *Buffer
, BufferSize
);
1463 Write data back to the file. For TFTP case you must write the entire file.
1465 @param Stream Open File Handle
1466 @param Buffer Pointer to buffer to return.
1467 @param BufferSize Pointer to Size of buffer return..
1470 @return EFI_SUCCESS Stream is not an Open File
1471 @return EFI_END_OF_FILE Tried to read past the end of the file
1472 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1473 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1474 @return "other" Error returned from device write
1479 IN EFI_OPEN_FILE
*File
,
1481 OUT UINTN
*BufferSize
1485 EFI_FV_WRITE_FILE_DATA FileData
;
1486 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1488 if (!FileHandleValid (File
)) {
1489 return EFI_INVALID_PARAMETER
;
1492 switch (File
->Type
) {
1493 case EfiOpenMemoryBuffer
:
1494 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1495 return EFI_END_OF_FILE
;
1498 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1499 File
->CurrentPosition
+= *BufferSize
;
1500 Status
= EFI_SUCCESS
;
1502 case EfiOpenLoadFile
:
1503 // LoadFile device is read only be definition
1504 Status
= EFI_UNSUPPORTED
;
1506 case EfiOpenFirmwareVolume
:
1507 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1508 // Writes not support to a specific section. You have to update entire file
1509 return EFI_UNSUPPORTED
;
1512 FileData
.NameGuid
= &(File
->FvNameGuid
);
1513 FileData
.Type
= File
->FvType
;
1514 FileData
.FileAttributes
= File
->FvAttributes
;
1515 FileData
.Buffer
= Buffer
;
1516 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1517 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1520 case EfiOpenFileSystem
:
1521 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1522 File
->CurrentPosition
+= *BufferSize
;
1525 case EfiOpenBlockIo
:
1526 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1527 return EFI_END_OF_FILE
;
1530 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1531 if (!EFI_ERROR(Status
)) {
1532 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
.MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1534 File
->CurrentPosition
+= *BufferSize
;
1538 // Cache the file if it hasn't been cached yet.
1539 if (File
->IsBufferValid
== FALSE
) {
1540 Status
= CacheTftpFile(File
);
1541 if (EFI_ERROR(Status
)) {
1546 // Don't overwrite the buffer
1547 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1550 TempBuffer
= File
->Buffer
;
1552 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1553 if (File
->Buffer
== NULL
) {
1554 return EFI_OUT_OF_RESOURCES
;
1557 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1559 FreePool (TempBuffer
);
1561 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1562 File
->MaxPosition
= (UINT64
)File
->Size
;
1565 // Copy in the requested data
1566 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1567 File
->CurrentPosition
+= *BufferSize
;
1569 // Mark the file dirty
1570 File
->IsDirty
= TRUE
;
1572 Status
= EFI_SUCCESS
;
1576 Status
= EFI_INVALID_PARAMETER
;
1584 Given Cwd expand Path to remove .. and replace them with real
1587 @param Cwd Current Working Directory
1588 @param Path Path to expand
1590 @return NULL Cwd or Path are not valid
1591 @return 'other' Path with .. expanded
1601 CHAR8
*Work
, *Start
, *End
;
1605 if (Cwd
== NULL
|| Path
== NULL
) {
1609 StrLen
= AsciiStrSize (Cwd
);
1611 // Smallest valid path is 1 char and a null
1615 StrLen
= AsciiStrSize (Path
);
1616 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1617 if (NewPath
== NULL
) {
1620 AsciiStrCpy (NewPath
, Cwd
);
1622 End
= Path
+ StrLen
;
1623 for (Start
= Path
;;) {
1624 Work
= AsciiStrStr (Start
, "..") ;
1626 // Remaining part of Path contains no more ..
1630 // append path prior to ..
1631 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1632 StrLen
= AsciiStrLen (NewPath
);
1633 for (i
= StrLen
; i
>= 0; i
--) {
1634 if (NewPath
[i
] == ':') {
1638 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1639 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1640 // leave the / before a :
1641 NewPath
[i
+1] = '\0';
1643 // replace / will Null to remove trailing file/dir reference
1653 // Handle the path that remains after the ..
1654 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1661 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1662 the path does not contain a device name, The CWD is prepended to the path.
1664 @param Cwd Current Working Directory to set
1667 @return EFI_SUCCESS CWD is set
1668 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1676 EFI_OPEN_FILE
*File
;
1681 return EFI_INVALID_PARAMETER
;
1684 if (AsciiStrCmp (Cwd
, ".") == 0) {
1690 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1696 Len
= AsciiStrLen (gCwd
);
1697 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1698 // parent is device so nothing to do
1702 // Expand .. in Cwd, given we know current working directory
1703 Path
= ExpandPath (gCwd
, Cwd
);
1705 return EFI_NOT_FOUND
;
1709 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1711 return EFI_INVALID_PARAMETER
;
1718 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1719 // relative to the current gCwd or not.
1720 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1722 return EFI_INVALID_PARAMETER
;
1724 AsciiStrCpy (gCwd
, File
->DeviceName
);
1725 if (File
->FileName
== NULL
) {
1726 AsciiStrCat (gCwd
, ":\\");
1728 AsciiStrCat (gCwd
, ":");
1729 AsciiStrCat (gCwd
, File
->FileName
);
1741 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1742 the path does not contain a device name, The CWD is prepended to the path.
1743 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1744 a call to EfiSetCwd() it is not legal to use the pointer returned by
1747 @param Cwd Current Working Directory
1750 @return "" No CWD set
1751 @return 'other' Returns buffer that contains CWD.