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 insensitive 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 recalculating 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
;
412 File
->FsBlockIo
= BlkIo
;
414 // If we are not opening the device this will get over written with file info
415 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
418 if (File
->Type
== EfiOpenFileSystem
) {
419 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
420 if (!EFI_ERROR (Status
)) {
421 Status
= Fs
->OpenVolume (Fs
, &Root
);
422 if (!EFI_ERROR (Status
)) {
423 // Get information about the volume
425 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
426 if (Status
== EFI_BUFFER_TOO_SMALL
) {
427 File
->FsInfo
= AllocatePool (Size
);
428 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
431 // Get information about the file
432 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
433 if (!EFI_ERROR (Status
)) {
435 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
436 if (Status
== EFI_BUFFER_TOO_SMALL
) {
437 File
->FsFileInfo
= AllocatePool (Size
);
438 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
439 if (!EFI_ERROR (Status
)) {
440 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
441 File
->MaxPosition
= (UINT64
)File
->Size
;
449 } else if (File
->Type
== EfiOpenBlockIo
) {
450 File
->Size
= (UINTN
)File
->MaxPosition
;
456 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
459 CompareGuidToString (
468 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
473 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
475 if (*StringPtr
== '-') {
480 if (*GuidPtr
== '-') {
485 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
486 return EFI_NOT_FOUND
;
498 Internal work function to fill in EFI_OPEN_FILE information for the FV
500 @param File Open file handle
501 @param FileName Name of file after device stripped off
506 EblFvFileDevicePath (
507 IN OUT EFI_OPEN_FILE
*File
,
509 IN CONST UINT64 OpenMode
513 EFI_STATUS GetNextFileStatus
;
514 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
515 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
517 UINT32 AuthenticationStatus
;
518 CHAR8 AsciiSection
[MAX_PATHNAME
];
521 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
524 UINTN NumberOfBlocks
;
525 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
529 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
530 if (EFI_ERROR (Status
)) {
534 // Get FVB Info about the handle
535 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
536 if (!EFI_ERROR (Status
)) {
537 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
538 if (!EFI_ERROR (Status
)) {
539 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
540 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
541 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
542 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
545 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
546 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
547 if (EFI_ERROR (Status
)) {
555 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
557 if (*FileName
== '\0') {
558 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
559 File
->Size
= File
->FvSize
;
560 File
->MaxPosition
= File
->Size
;
564 File
->FvType
= EFI_FV_FILETYPE_ALL
;
565 GetNextFileStatus
= File
->Fv
->GetNextFile (
573 if (!EFI_ERROR (GetNextFileStatus
)) {
574 // Compare GUID first
575 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
576 if (!EFI_ERROR(Status
)) {
581 Status
= File
->Fv
->ReadSection (
584 EFI_SECTION_USER_INTERFACE
,
588 &AuthenticationStatus
590 if (!EFI_ERROR (Status
)) {
591 UnicodeStrToAsciiStr (Section
, AsciiSection
);
592 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
599 } while (!EFI_ERROR (GetNextFileStatus
));
601 if (EFI_ERROR (GetNextFileStatus
)) {
602 return GetNextFileStatus
;
605 if (OpenMode
!= EFI_SECTION_ALL
) {
606 // Calculate the size of the section we are targeting
609 Status
= File
->Fv
->ReadSection (
612 (EFI_SECTION_TYPE
)OpenMode
,
616 &AuthenticationStatus
618 if (EFI_ERROR (Status
)) {
623 File
->MaxPosition
= File
->Size
;
624 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
625 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
629 // FVB not required if FV was soft loaded...
637 Open a device named by PathName. The PathName includes a device name and
638 path separated by a :. See file header for more details on the PathName
639 syntax. There is no checking to prevent a file from being opened more than
642 SectionType is only used to open an FV. Each file in an FV contains multiple
643 sections and only the SectionType section is opened.
645 For any file that is opened with EfiOpen() must be closed with EfiClose().
647 @param PathName Path to parse to open
648 @param OpenMode Same as EFI_FILE.Open()
649 @param SectionType Section in FV to open.
651 @return NULL Open failed
652 @return Valid EFI_OPEN_FILE handle
658 IN CONST UINT64 OpenMode
,
659 IN CONST EFI_SECTION_TYPE SectionType
664 EFI_OPEN_FILE FileData
;
668 EFI_OPEN_FILE_GUARD
*GuardFile
;
669 BOOLEAN VolumeNameMatch
;
670 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
673 CHAR8
*CwdPlusPathName
;
675 EFI_SECTION_TYPE ModifiedSectionType
;
677 EblUpdateDeviceLists ();
680 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
682 StrLen
= AsciiStrSize (PathName
);
684 // Smallest valid path is 1 char and a null
688 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
689 if (PathName
[FileStart
] == ':') {
696 // Matching volume name has precedence over handle based names
698 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
699 if (!VolumeNameMatch
) {
700 if (FileStart
== StrLen
) {
701 // No Volume name or device name, so try Current Working Directory
707 // We could add a current working directory concept
708 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
709 if (CwdPlusPathName
== NULL
) {
713 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
714 // PathName starts in / so this means we go to the root of the device in the CWD.
715 CwdPlusPathName
[0] = '\0';
716 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
717 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
718 if (gCwd
[FileStart
] == ':') {
720 CwdPlusPathName
[FileStart
] = '\0';
725 AsciiStrCpy (CwdPlusPathName
, gCwd
);
726 StrLen
= AsciiStrLen (gCwd
);
727 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
728 AsciiStrCat (CwdPlusPathName
, "\\");
732 AsciiStrCat (CwdPlusPathName
, PathName
);
733 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
734 // Extra error check to make sure we don't recurse and blow stack
738 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
739 FreePool (CwdPlusPathName
);
743 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
746 File
->DeviceName
= AllocatePool (StrLen
);
747 AsciiStrCpy (File
->DeviceName
, PathName
);
748 File
->DeviceName
[FileStart
- 1] = '\0';
749 File
->FileName
= &File
->DeviceName
[FileStart
];
750 if (File
->FileName
[0] == '\0') {
751 // if it is just a file name use / as root
752 File
->FileName
= "\\";
756 // Use best match algorithm on the dev names so we only need to look at the
757 // first few charters to match the full device name. Short name forms are
758 // legal from the caller.
760 Status
= EFI_SUCCESS
;
761 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
762 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
763 if (DevNumber
>= mFsCount
) {
766 File
->Type
= EfiOpenFileSystem
;
767 File
->EfiHandle
= mFs
[DevNumber
];
768 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
770 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
771 if (DevNumber
>= mFvCount
) {
774 File
->Type
= EfiOpenFirmwareVolume
;
775 File
->EfiHandle
= mFv
[DevNumber
];
777 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
778 // Skip leading / as its not really needed for the FV since no directories are supported
783 ModifiedSectionType
= SectionType
;
784 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
785 if (PathName
[Index
] == ':') {
786 // Support fv0:\DxeCore:0x10
787 // This means open the PE32 Section of the file
788 ModifiedSectionType
= (EFI_SECTION_TYPE
)AsciiStrHexToUintn (&PathName
[Index
+ 1]);
789 PathName
[Index
] = '\0';
792 File
->FvSectionType
= ModifiedSectionType
;
793 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
795 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
796 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
797 File
->Type
= EfiOpenMemoryBuffer
;
798 // 1st colon is at PathName[FileStart - 1]
799 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
802 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
806 // If we ran out of string, there's no extra data
807 if (PathName
[FileStart
] == '\0') {
810 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
813 // if there's no number after the second colon, default
815 if (File
->Size
== 0) {
816 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
819 File
->MaxPosition
= File
->Size
;
820 File
->BaseOffset
= (UINTN
)File
->Buffer
;
822 } else if (*PathName
== 'l' || *PathName
== 'L') {
823 if (DevNumber
>= mLoadFileCount
) {
826 File
->Type
= EfiOpenLoadFile
;
827 File
->EfiHandle
= mLoadFile
[DevNumber
];
829 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
830 if (EFI_ERROR (Status
)) {
834 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
835 if (EFI_ERROR (Status
)) {
838 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
840 } else if (*PathName
== 'b' || *PathName
== 'B') {
841 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
842 if (DevNumber
>= mBlkIoCount
) {
845 File
->Type
= EfiOpenBlockIo
;
846 File
->EfiHandle
= mBlkIo
[DevNumber
];
847 EblFileDevicePath (File
, "", OpenMode
);
849 // 1st colon is at PathName[FileStart - 1]
850 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
853 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
857 // If we ran out of string, there's no extra data
858 if (PathName
[FileStart
] == '\0') {
861 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
864 // if a zero size is passed in (or the size is left out entirely),
865 // go to the end of the device.
867 File
->Size
= File
->Size
- File
->DiskOffset
;
872 File
->MaxPosition
= File
->Size
;
873 File
->BaseOffset
= File
->DiskOffset
;
874 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
876 // Get current IP address
877 Status
= EblGetCurrentIpAddress (&Ip
);
878 if (EFI_ERROR(Status
)) {
879 AsciiPrint("Device IP Address is not configured.\n");
884 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
885 File
->Type
= EfiOpenTftp
;
886 File
->IsDirty
= FALSE
;
887 File
->IsBufferValid
= FALSE
;
889 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
892 if (EFI_ERROR (Status
)) {
896 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
897 if (GuardFile
== NULL
) {
901 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
902 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
903 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
905 return &(GuardFile
->File
);
908 FreePool (File
->DeviceName
);
912 #define FILE_COPY_CHUNK 0x01000000
916 IN CHAR8
*DestinationFile
,
920 EFI_OPEN_FILE
*Source
= NULL
;
921 EFI_OPEN_FILE
*Destination
= NULL
;
922 EFI_STATUS Status
= EFI_SUCCESS
;
926 UINTN Chunk
= FILE_COPY_CHUNK
;
928 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
929 if (Source
== NULL
) {
930 AsciiPrint("Source file open error.\n");
931 Status
= EFI_NOT_FOUND
;
935 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
936 if (Destination
== NULL
) {
937 AsciiPrint("Destination file open error.\n");
938 Status
= EFI_NOT_FOUND
;
942 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
943 if (Buffer
== NULL
) {
944 Status
= EFI_OUT_OF_RESOURCES
;
948 Size
= EfiTell(Source
, NULL
);
950 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
951 Chunk
= FILE_COPY_CHUNK
;
953 Status
= EfiRead(Source
, Buffer
, &Chunk
);
954 if (EFI_ERROR(Status
)) {
955 AsciiPrint("Read file error %r\n", Status
);
959 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
960 if (EFI_ERROR(Status
)) {
961 AsciiPrint("Write file error %r\n", Status
);
968 Chunk
= Size
- Offset
;
970 Status
= EfiRead(Source
, Buffer
, &Chunk
);
971 if (EFI_ERROR(Status
)) {
972 AsciiPrint("Read file error\n");
976 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
977 if (EFI_ERROR(Status
)) {
978 AsciiPrint("Write file error\n");
984 if (Source
!= NULL
) {
985 Status
= EfiClose(Source
);
986 if (EFI_ERROR(Status
)) {
987 AsciiPrint("Source close error");
991 if (Destination
!= NULL
) {
992 Status
= EfiClose(Destination
);
993 if (EFI_ERROR(Status
)) {
994 AsciiPrint("Destination close error");
998 if (Buffer
!= NULL
) {
1006 Use DeviceType and Index to form a valid PathName and try and open it.
1008 @param DeviceType Device type to open
1009 @param Index Device Index to use. Zero relative.
1011 @return NULL Open failed
1012 @return Valid EFI_OPEN_FILE handle
1016 EfiDeviceOpenByType (
1017 IN EFI_OPEN_FILE_TYPE DeviceType
,
1022 CHAR8 Path
[MAX_CMD_LINE
];
1024 switch (DeviceType
) {
1025 case EfiOpenLoadFile
:
1026 DevStr
= "loadfile%d:";
1028 case EfiOpenFirmwareVolume
:
1031 case EfiOpenFileSystem
:
1034 case EfiOpenBlockIo
:
1037 case EfiOpenMemoryBuffer
:
1044 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1046 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1051 Close a file handle opened by EfiOpen() and free all resources allocated by
1054 @param Stream Open File Handle
1056 @return EFI_INVALID_PARAMETER Stream is not an Open File
1057 @return EFI_SUCCESS Steam closed
1062 IN EFI_OPEN_FILE
*File
1066 UINT64 TftpBufferSize
;
1068 if (!FileHandleValid (File
)) {
1069 return EFI_INVALID_PARAMETER
;
1072 //Write the buffer contents to TFTP file.
1073 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1075 TftpBufferSize
= File
->Size
;
1077 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1083 (UINT8
*)File
->FileName
,
1087 if (EFI_ERROR(Status
)) {
1088 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1093 if ((File
->Type
== EfiOpenLoadFile
) ||
1094 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1095 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1096 EblFreePool(File
->Buffer
);
1099 EblFreePool (File
->DevicePath
);
1100 EblFreePool (File
->DeviceName
);
1101 EblFreePool (File
->FsFileInfo
);
1102 EblFreePool (File
->FsInfo
);
1104 if (File
->FsFileHandle
!= NULL
) {
1105 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1108 // Need to free File and it's Guard structures
1109 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1115 Return the size of the file represented by Stream. Also return the current
1116 Seek position. Opening a file will enable a valid file size to be returned.
1117 LoadFile is an exception as a load file size is set to zero.
1119 @param Stream Open File Handle
1121 @return 0 Stream is not an Open File or a valid LoadFile handle
1126 IN EFI_OPEN_FILE
*File
,
1127 OUT EFI_LBA
*CurrentPosition OPTIONAL
1131 UINT64 BufferSize
= 0;
1133 if (!FileHandleValid (File
)) {
1137 if (CurrentPosition
!= NULL
) {
1138 *CurrentPosition
= File
->CurrentPosition
;
1141 if (File
->Type
== EfiOpenLoadFile
) {
1142 // Figure out the File->Size
1143 File
->Buffer
= NULL
;
1145 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1146 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1150 File
->MaxPosition
= (UINT64
)File
->Size
;
1151 } else if (File
->Type
== EfiOpenTftp
) {
1154 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1160 (UINT8
*)File
->FileName
,
1164 if (EFI_ERROR(Status
)) {
1165 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1169 File
->Size
= (UINTN
)BufferSize
;
1170 File
->MaxPosition
= File
->Size
;
1178 Seek to the Offset location in the file. LoadFile and FV device types do
1179 not support EfiSeek(). It is not possible to grow the file size using
1182 SeekType defines how use Offset to calculate the new file position:
1183 EfiSeekStart : Position = Offset
1184 EfiSeekCurrent: Position is Offset bytes from the current position
1185 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1187 @param Stream Open File Handle
1188 @param Offset Offset to seek too.
1189 @param SeekType Type of seek to perform
1192 @return EFI_INVALID_PARAMETER Stream is not an Open File
1193 @return EFI_UNSUPPORTED LoadFile and FV do not support Seek
1194 @return EFI_NOT_FOUND Seek past the end of the file.
1195 @return EFI_SUCCESS Steam closed
1200 IN EFI_OPEN_FILE
*File
,
1202 IN EFI_SEEK_TYPE SeekType
1206 UINT64 CurrentPosition
;
1208 if (!FileHandleValid (File
)) {
1209 return EFI_INVALID_PARAMETER
;
1212 if (File
->Type
== EfiOpenLoadFile
) {
1213 // LoadFile does not support Seek
1214 return EFI_UNSUPPORTED
;
1217 CurrentPosition
= File
->CurrentPosition
;
1220 if (Offset
> File
->MaxPosition
) {
1221 return EFI_NOT_FOUND
;
1223 CurrentPosition
= Offset
;
1226 case EfiSeekCurrent
:
1227 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1228 return EFI_NOT_FOUND
;
1230 CurrentPosition
+= Offset
;
1235 // We don't support growing file size via seeking past end of file
1236 return EFI_UNSUPPORTED
;
1238 CurrentPosition
= File
->MaxPosition
;
1242 return EFI_NOT_FOUND
;
1245 Status
= EFI_SUCCESS
;
1246 if (File
->FsFileHandle
!= NULL
) {
1247 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1250 if (!EFI_ERROR (Status
)) {
1251 File
->CurrentPosition
= CurrentPosition
;
1259 IN OUT EFI_OPEN_FILE
*File
1263 UINT64 TftpBufferSize
;
1265 if (File
->IsBufferValid
) {
1269 // Make sure the file size is set.
1270 EfiTell (File
, NULL
);
1272 //Allocate a buffer to hold the whole file.
1273 File
->Buffer
= AllocatePool(File
->Size
);
1274 if (File
->Buffer
== NULL
) {
1275 return EFI_OUT_OF_RESOURCES
;
1278 TftpBufferSize
= File
->Size
;
1281 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1287 (UINT8
*)File
->FileName
,
1290 if (EFI_ERROR(Status
)) {
1291 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1292 FreePool(File
->Buffer
);
1296 // Set the buffer valid flag.
1297 File
->IsBufferValid
= TRUE
;
1303 Read BufferSize bytes from the current location in the file. For load file,
1304 FV, and TFTP case you must read the entire file.
1306 @param Stream Open File Handle
1307 @param Buffer Caller allocated buffer.
1308 @param BufferSize Size of buffer in bytes.
1311 @return EFI_SUCCESS Stream is not an Open File
1312 @return EFI_END_OF_FILE Tried to read past the end of the file
1313 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1314 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1315 @return "other" Error returned from device read
1320 IN EFI_OPEN_FILE
*File
,
1322 OUT UINTN
*BufferSize
1326 UINT32 AuthenticationStatus
;
1327 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1329 if (!FileHandleValid (File
)) {
1330 return EFI_INVALID_PARAMETER
;
1333 // Don't read past the end of the file.
1334 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1335 return EFI_END_OF_FILE
;
1338 switch (File
->Type
) {
1339 case EfiOpenLoadFile
:
1340 // Figure out the File->Size
1341 EfiTell (File
, NULL
);
1343 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1346 case EfiOpenFirmwareVolume
:
1347 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1348 // This is the entire FV device, so treat like a memory buffer
1349 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1350 File
->CurrentPosition
+= *BufferSize
;
1351 Status
= EFI_SUCCESS
;
1353 if (File
->Buffer
== NULL
) {
1354 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1355 Status
= File
->Fv
->ReadFile (
1358 (VOID
**)&File
->Buffer
,
1361 &File
->FvAttributes
,
1362 &AuthenticationStatus
1365 Status
= File
->Fv
->ReadSection (
1368 File
->FvSectionType
,
1370 (VOID
**)&File
->Buffer
,
1372 &AuthenticationStatus
1375 if (EFI_ERROR (Status
)) {
1378 File
->IsBufferValid
= TRUE
;
1380 // Operate on the cached buffer so Seek will work
1381 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1382 File
->CurrentPosition
+= *BufferSize
;
1383 Status
= EFI_SUCCESS
;
1387 case EfiOpenMemoryBuffer
:
1388 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1389 File
->CurrentPosition
+= *BufferSize
;
1390 Status
= EFI_SUCCESS
;
1393 case EfiOpenFileSystem
:
1394 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1395 File
->CurrentPosition
+= *BufferSize
;
1398 case EfiOpenBlockIo
:
1399 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1400 if (!EFI_ERROR(Status
)) {
1401 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1403 File
->CurrentPosition
+= *BufferSize
;
1407 // Cache the file if it hasn't been cached yet.
1408 if (File
->IsBufferValid
== FALSE
) {
1409 Status
= CacheTftpFile (File
);
1410 if (EFI_ERROR (Status
)) {
1415 // Copy out the requested data
1416 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1417 File
->CurrentPosition
+= *BufferSize
;
1419 Status
= EFI_SUCCESS
;
1423 return EFI_INVALID_PARAMETER
;
1431 Read the entire file into a buffer. This routine allocates the buffer and
1432 returns it to the user full of the read data.
1434 This is very useful for load file where it's hard to know how big the buffer
1437 @param Stream Open File Handle
1438 @param Buffer Pointer to buffer to return.
1439 @param BufferSize Pointer to Size of buffer return..
1442 @return EFI_SUCCESS Stream is not an Open File
1443 @return EFI_END_OF_FILE Tried to read past the end of the file
1444 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1445 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1446 @return "other" Error returned from device read
1450 EfiReadAllocatePool (
1451 IN EFI_OPEN_FILE
*File
,
1453 OUT UINTN
*BufferSize
1456 if (!FileHandleValid (File
)) {
1457 return EFI_INVALID_PARAMETER
;
1460 // Loadfile defers file size determination on Open so use tell to find it
1461 EfiTell (File
, NULL
);
1463 *BufferSize
= File
->Size
;
1464 *Buffer
= AllocatePool (*BufferSize
);
1465 if (*Buffer
== NULL
) {
1466 return EFI_NOT_FOUND
;
1469 return EfiRead (File
, *Buffer
, BufferSize
);
1474 Write data back to the file. For TFTP case you must write the entire file.
1476 @param Stream Open File Handle
1477 @param Buffer Pointer to buffer to return.
1478 @param BufferSize Pointer to Size of buffer return..
1481 @return EFI_SUCCESS Stream is not an Open File
1482 @return EFI_END_OF_FILE Tried to read past the end of the file
1483 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1484 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1485 @return "other" Error returned from device write
1490 IN EFI_OPEN_FILE
*File
,
1492 OUT UINTN
*BufferSize
1496 EFI_FV_WRITE_FILE_DATA FileData
;
1497 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1499 if (!FileHandleValid (File
)) {
1500 return EFI_INVALID_PARAMETER
;
1503 switch (File
->Type
) {
1504 case EfiOpenMemoryBuffer
:
1505 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1506 return EFI_END_OF_FILE
;
1509 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1510 File
->CurrentPosition
+= *BufferSize
;
1511 Status
= EFI_SUCCESS
;
1513 case EfiOpenLoadFile
:
1514 // LoadFile device is read only be definition
1515 Status
= EFI_UNSUPPORTED
;
1517 case EfiOpenFirmwareVolume
:
1518 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1519 // Writes not support to a specific section. You have to update entire file
1520 return EFI_UNSUPPORTED
;
1523 FileData
.NameGuid
= &(File
->FvNameGuid
);
1524 FileData
.Type
= File
->FvType
;
1525 FileData
.FileAttributes
= File
->FvAttributes
;
1526 FileData
.Buffer
= Buffer
;
1527 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1528 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1531 case EfiOpenFileSystem
:
1532 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1533 File
->CurrentPosition
+= *BufferSize
;
1536 case EfiOpenBlockIo
:
1537 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1538 return EFI_END_OF_FILE
;
1541 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1542 if (!EFI_ERROR(Status
)) {
1543 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1545 File
->CurrentPosition
+= *BufferSize
;
1549 // Cache the file if it hasn't been cached yet.
1550 if (File
->IsBufferValid
== FALSE
) {
1551 Status
= CacheTftpFile(File
);
1552 if (EFI_ERROR(Status
)) {
1557 // Don't overwrite the buffer
1558 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1561 TempBuffer
= File
->Buffer
;
1563 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1564 if (File
->Buffer
== NULL
) {
1565 return EFI_OUT_OF_RESOURCES
;
1568 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1570 FreePool (TempBuffer
);
1572 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1573 File
->MaxPosition
= (UINT64
)File
->Size
;
1576 // Copy in the requested data
1577 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1578 File
->CurrentPosition
+= *BufferSize
;
1580 // Mark the file dirty
1581 File
->IsDirty
= TRUE
;
1583 Status
= EFI_SUCCESS
;
1587 Status
= EFI_INVALID_PARAMETER
;
1595 Given Cwd expand Path to remove .. and replace them with real
1598 @param Cwd Current Working Directory
1599 @param Path Path to expand
1601 @return NULL Cwd or Path are not valid
1602 @return 'other' Path with .. expanded
1612 CHAR8
*Work
, *Start
, *End
;
1616 if (Cwd
== NULL
|| Path
== NULL
) {
1620 StrLen
= AsciiStrSize (Cwd
);
1622 // Smallest valid path is 1 char and a null
1626 StrLen
= AsciiStrSize (Path
);
1627 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1628 if (NewPath
== NULL
) {
1631 AsciiStrCpy (NewPath
, Cwd
);
1633 End
= Path
+ StrLen
;
1634 for (Start
= Path
;;) {
1635 Work
= AsciiStrStr (Start
, "..") ;
1637 // Remaining part of Path contains no more ..
1641 // append path prior to ..
1642 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1643 StrLen
= AsciiStrLen (NewPath
);
1644 for (i
= StrLen
; i
>= 0; i
--) {
1645 if (NewPath
[i
] == ':') {
1649 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1650 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1651 // leave the / before a :
1652 NewPath
[i
+1] = '\0';
1654 // replace / will Null to remove trailing file/dir reference
1664 // Handle the path that remains after the ..
1665 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1672 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1673 the path does not contain a device name, The CWD is prepended to the path.
1675 @param Cwd Current Working Directory to set
1678 @return EFI_SUCCESS CWD is set
1679 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1687 EFI_OPEN_FILE
*File
;
1692 return EFI_INVALID_PARAMETER
;
1695 if (AsciiStrCmp (Cwd
, ".") == 0) {
1701 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1707 Len
= AsciiStrLen (gCwd
);
1708 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1709 // parent is device so nothing to do
1713 // Expand .. in Cwd, given we know current working directory
1714 Path
= ExpandPath (gCwd
, Cwd
);
1716 return EFI_NOT_FOUND
;
1720 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1722 return EFI_INVALID_PARAMETER
;
1729 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1730 // relative to the current gCwd or not.
1731 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1733 return EFI_INVALID_PARAMETER
;
1736 AsciiStrCpy (gCwd
, File
->DeviceName
);
1737 if (File
->FileName
== NULL
) {
1738 AsciiStrCat (gCwd
, ":\\");
1740 AsciiStrCat (gCwd
, ":");
1741 AsciiStrCat (gCwd
, File
->FileName
);
1754 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1755 the path does not contain a device name, The CWD is prepended to the path.
1756 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1757 a call to EfiSetCwd() it is not legal to use the pointer returned by
1760 @param Cwd Current Working Directory
1763 @return "" No CWD set
1764 @return 'other' Returns buffer that contains CWD.