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>
44 #include <Guid/FileInfo.h>
45 #include <Guid/ZeroGuid.h>
47 #include <Library/BaseLib.h>
48 #include <Library/MemoryAllocationLib.h>
49 #include <Library/DevicePathLib.h>
50 #include <Library/PrintLib.h>
51 #include <Library/BaseMemoryLib.h>
52 #include <Library/UefiLib.h>
53 #include <Library/UefiBootServicesTableLib.h>
54 #include <Library/UefiRuntimeServicesTableLib.h>
55 #include <Library/DebugLib.h>
56 #include <Library/EfiFileLib.h>
57 #include <Library/PcdLib.h>
58 #include <Library/EblNetworkLib.h>
63 #define EFI_OPEN_FILE_GUARD_HEADER 0x4B4D4641
64 #define EFI_OPEN_FILE_GUARD_FOOTER 0x444D5A56
66 // Need to defend against this overflowing
67 #define MAX_CMD_LINE 0x200
73 } EFI_OPEN_FILE_GUARD
;
76 // globals to store current open device info
77 EFI_HANDLE
*mBlkIo
= NULL
;
78 UINTN mBlkIoCount
= 0;
80 EFI_HANDLE
*mFs
= NULL
;
82 // mFsInfo[] array entries must match mFs[] handles
83 EFI_FILE_SYSTEM_INFO
**mFsInfo
= NULL
;
85 EFI_HANDLE
*mFv
= NULL
;
87 EFI_HANDLE
*mLoadFile
= NULL
;
88 UINTN mLoadFileCount
= 0;
93 Internal worker function to validate a File handle.
95 @param File Open File Handle
97 @return TRUE File is valid
98 @return FALSE File is not valid
104 IN EFI_OPEN_FILE
*File
107 EFI_OPEN_FILE_GUARD
*GuardFile
;
109 // Look right before and after file structure for the correct signatures
110 GuardFile
= BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
);
111 if ((GuardFile
->Header
!= EFI_OPEN_FILE_GUARD_HEADER
) ||
112 (GuardFile
->Footer
!= EFI_OPEN_FILE_GUARD_FOOTER
) ) {
120 Internal worker function. If Buffer is not NULL free it.
122 @param Buffer Buffer to FreePool()
130 if (Buffer
!= NULL
) {
136 Update Device List Global Variables
140 EblUpdateDeviceLists (
146 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
147 EFI_FILE_HANDLE Root
;
150 if (mBlkIo
!= NULL
) {
153 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &mBlkIoCount
, &mBlkIo
);
160 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiFirmwareVolume2ProtocolGuid
, NULL
, &mFvCount
, &mFv
);
162 if (mLoadFile
!= NULL
) {
163 FreePool (mLoadFile
);
165 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &mLoadFileCount
, &mLoadFile
);
171 if (&mFsInfo
[0] != NULL
) {
172 // Need to Free the mFsInfo prior to recalculating mFsCount so don't move this code
173 for (Index
= 0; Index
< mFsCount
; Index
++) {
174 if (mFsInfo
[Index
] != NULL
) {
175 FreePool (mFsInfo
[Index
]);
181 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &mFsCount
, &mFs
);
184 mFsInfo
= AllocateZeroPool (mFsCount
* sizeof (EFI_FILE_SYSTEM_INFO
*));
185 if (mFsInfo
== NULL
) {
186 // If we can't do this then we can't support file system entries
189 // Loop through all the file system structures and cache the file system info data
190 for (Index
=0; Index
< mFsCount
; Index
++) {
191 Status
= gBS
->HandleProtocol (mFs
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
192 if (!EFI_ERROR (Status
)) {
193 Status
= Fs
->OpenVolume (Fs
, &Root
);
194 if (!EFI_ERROR (Status
)) {
195 // Get information about the volume
197 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
198 if (Status
== EFI_BUFFER_TOO_SMALL
) {
199 mFsInfo
[Index
] = AllocatePool (Size
);
200 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
212 PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\.
213 Return TRUE if the <devce name> prefix of PathName matches a file system
214 Volume Name. MatchIndex is the array index in mFsInfo[] of the match,
215 and it can be used with mFs[] to find the handle that needs to be opened
217 @param PathName PathName to check
218 @param FileStart Index of the first character of the <path>
219 @param MatchIndex Index in mFsInfo[] that matches
221 @return TRUE PathName matches a Volume Label and MatchIndex is valid
222 @return FALSE PathName does not match a Volume Label MatchIndex undefined
229 OUT UINTN
*MatchIndex
237 for (Index
=0; Index
< mFsCount
; Index
++) {
238 if (mFsInfo
[Index
] == NULL
) {
239 // FsInfo is not valid so skip it
242 VolStrLen
= StrLen (mFsInfo
[Index
]->VolumeLabel
);
243 for (Compare
= 0, Match
= TRUE
; Compare
< (FileStart
- 1); Compare
++) {
244 if (Compare
> VolStrLen
) {
248 if (PathName
[Compare
] != (CHAR8
)mFsInfo
[Index
]->VolumeLabel
[Compare
]) {
249 // If the VolumeLabel has a space allow a _ to match with it in addition to ' '
250 if (!((PathName
[Compare
] == '_') && (mFsInfo
[Index
]->VolumeLabel
[Compare
] == L
' '))) {
267 Return the number of devices of the current type active in the system
269 @param Type Device type to check
271 @return 0 Invalid type
276 IN EFI_OPEN_FILE_TYPE DeviceType
279 switch (DeviceType
) {
280 case EfiOpenLoadFile
:
281 return mLoadFileCount
;
282 case EfiOpenFirmwareVolume
:
284 case EfiOpenFileSystem
:
294 ConvertIpStringToEfiIp (
296 OUT EFI_IP_ADDRESS
*ServerIp
302 ServerIp
->v4
.Addr
[0] = (UINT8
)AsciiStrDecimalToUintn (Str
);
304 Str
= AsciiStrStr (Str
, ".");
306 return EFI_DEVICE_ERROR
;
309 ServerIp
->v4
.Addr
[1] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
311 Str
= AsciiStrStr (Str
, ".");
313 return EFI_DEVICE_ERROR
;
316 ServerIp
->v4
.Addr
[2] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
318 Str
= AsciiStrStr (Str
, ".");
320 return EFI_DEVICE_ERROR
;
323 ServerIp
->v4
.Addr
[3] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
330 Internal work function to extract a device number from a string skipping
331 text. Easy way to extract numbers from strings like blk7:.
333 @param Str String to extract device number form
335 @return -1 Device string is not valid
340 EblConvertDevStringToNumber (
348 // Find the first digit
349 Max
= AsciiStrLen (Str
);
350 for (Index
= 0; !((*Str
>= '0') && (*Str
<= '9')) && (Index
< Max
); Index
++) {
357 return AsciiStrDecimalToUintn (Str
);
362 Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo
364 @param File Open file handle
365 @param FileName Name of file after device stripped off
371 IN OUT EFI_OPEN_FILE
*File
,
373 IN CONST UINT64 OpenMode
378 FILEPATH_DEVICE_PATH
*FilePath
;
379 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
380 CHAR16 UnicodeFileName
[MAX_PATHNAME
];
381 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
382 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
383 EFI_FILE_HANDLE Root
;
386 if ( *FileName
!= 0 ) {
387 AsciiStrToUnicodeStr (FileName
, UnicodeFileName
);
389 AsciiStrToUnicodeStr ("\\", UnicodeFileName
);
392 Size
= StrSize (UnicodeFileName
);
393 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ sizeof (EFI_DEVICE_PATH_PROTOCOL
));
394 if (FileDevicePath
!= NULL
) {
395 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
396 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
397 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
398 CopyMem (&FilePath
->PathName
, UnicodeFileName
, Size
);
399 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
400 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
402 if (File
->EfiHandle
!= NULL
) {
403 File
->DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
406 File
->DevicePath
= AppendDevicePath (File
->DevicePath
, FileDevicePath
);
407 FreePool (FileDevicePath
);
410 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
411 if (!EFI_ERROR (Status
)) {
412 File
->FsBlockIoMedia
= BlkIo
->Media
;
413 File
->FsBlockIo
= BlkIo
;
415 // If we are not opening the device this will get over written with file info
416 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
419 if (File
->Type
== EfiOpenFileSystem
) {
420 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
421 if (!EFI_ERROR (Status
)) {
422 Status
= Fs
->OpenVolume (Fs
, &Root
);
423 if (!EFI_ERROR (Status
)) {
424 // Get information about the volume
426 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
427 if (Status
== EFI_BUFFER_TOO_SMALL
) {
428 File
->FsInfo
= AllocatePool (Size
);
429 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
432 // Get information about the file
433 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
434 if (!EFI_ERROR (Status
)) {
436 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
437 if (Status
== EFI_BUFFER_TOO_SMALL
) {
438 File
->FsFileInfo
= AllocatePool (Size
);
439 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
440 if (!EFI_ERROR (Status
)) {
441 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
442 File
->MaxPosition
= (UINT64
)File
->Size
;
450 } else if (File
->Type
== EfiOpenBlockIo
) {
451 File
->Size
= (UINTN
)File
->MaxPosition
;
457 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
460 CompareGuidToString (
469 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
474 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
476 if (*StringPtr
== '-') {
481 if (*GuidPtr
== '-') {
486 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
487 return EFI_NOT_FOUND
;
499 Internal work function to fill in EFI_OPEN_FILE information for the FV
501 @param File Open file handle
502 @param FileName Name of file after device stripped off
507 EblFvFileDevicePath (
508 IN OUT EFI_OPEN_FILE
*File
,
510 IN CONST UINT64 OpenMode
514 EFI_STATUS GetNextFileStatus
;
515 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
516 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
518 UINT32 AuthenticationStatus
;
519 CHAR8 AsciiSection
[MAX_PATHNAME
];
522 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
525 UINTN NumberOfBlocks
;
526 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
530 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
531 if (EFI_ERROR (Status
)) {
535 // Get FVB Info about the handle
536 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
537 if (!EFI_ERROR (Status
)) {
538 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
539 if (!EFI_ERROR (Status
)) {
540 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
541 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
542 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
543 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
546 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
547 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
548 if (EFI_ERROR (Status
)) {
556 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
558 if (*FileName
== '\0') {
559 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
560 File
->Size
= File
->FvSize
;
561 File
->MaxPosition
= File
->Size
;
565 File
->FvType
= EFI_FV_FILETYPE_ALL
;
566 GetNextFileStatus
= File
->Fv
->GetNextFile (
574 if (!EFI_ERROR (GetNextFileStatus
)) {
575 // Compare GUID first
576 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
577 if (!EFI_ERROR(Status
)) {
582 Status
= File
->Fv
->ReadSection (
585 EFI_SECTION_USER_INTERFACE
,
589 &AuthenticationStatus
591 if (!EFI_ERROR (Status
)) {
592 UnicodeStrToAsciiStr (Section
, AsciiSection
);
593 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
600 } while (!EFI_ERROR (GetNextFileStatus
));
602 if (EFI_ERROR (GetNextFileStatus
)) {
603 return GetNextFileStatus
;
606 if (OpenMode
!= EFI_SECTION_ALL
) {
607 // Calculate the size of the section we are targeting
610 Status
= File
->Fv
->ReadSection (
613 (EFI_SECTION_TYPE
)OpenMode
,
617 &AuthenticationStatus
619 if (EFI_ERROR (Status
)) {
624 File
->MaxPosition
= File
->Size
;
625 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
626 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
630 // FVB not required if FV was soft loaded...
638 Open a device named by PathName. The PathName includes a device name and
639 path separated by a :. See file header for more details on the PathName
640 syntax. There is no checking to prevent a file from being opened more than
643 SectionType is only used to open an FV. Each file in an FV contains multiple
644 sections and only the SectionType section is opened.
646 For any file that is opened with EfiOpen() must be closed with EfiClose().
648 @param PathName Path to parse to open
649 @param OpenMode Same as EFI_FILE.Open()
650 @param SectionType Section in FV to open.
652 @return NULL Open failed
653 @return Valid EFI_OPEN_FILE handle
659 IN CONST UINT64 OpenMode
,
660 IN CONST EFI_SECTION_TYPE SectionType
665 EFI_OPEN_FILE FileData
;
669 EFI_OPEN_FILE_GUARD
*GuardFile
;
670 BOOLEAN VolumeNameMatch
;
671 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
674 CHAR8
*CwdPlusPathName
;
676 EFI_SECTION_TYPE ModifiedSectionType
;
678 EblUpdateDeviceLists ();
681 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
683 StrLen
= AsciiStrSize (PathName
);
685 // Smallest valid path is 1 char and a null
689 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
690 if (PathName
[FileStart
] == ':') {
697 // Matching volume name has precedence over handle based names
699 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
700 if (!VolumeNameMatch
) {
701 if (FileStart
== StrLen
) {
702 // No Volume name or device name, so try Current Working Directory
708 // We could add a current working directory concept
709 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
710 if (CwdPlusPathName
== NULL
) {
714 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
715 // PathName starts in / so this means we go to the root of the device in the CWD.
716 CwdPlusPathName
[0] = '\0';
717 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
718 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
719 if (gCwd
[FileStart
] == ':') {
721 CwdPlusPathName
[FileStart
] = '\0';
726 AsciiStrCpy (CwdPlusPathName
, gCwd
);
727 StrLen
= AsciiStrLen (gCwd
);
728 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
729 AsciiStrCat (CwdPlusPathName
, "\\");
733 AsciiStrCat (CwdPlusPathName
, PathName
);
734 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
735 // Extra error check to make sure we don't recurse and blow stack
739 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
740 FreePool (CwdPlusPathName
);
744 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
747 File
->DeviceName
= AllocatePool (StrLen
);
748 AsciiStrCpy (File
->DeviceName
, PathName
);
749 File
->DeviceName
[FileStart
- 1] = '\0';
750 File
->FileName
= &File
->DeviceName
[FileStart
];
751 if (File
->FileName
[0] == '\0') {
752 // if it is just a file name use / as root
753 File
->FileName
= "\\";
757 // Use best match algorithm on the dev names so we only need to look at the
758 // first few charters to match the full device name. Short name forms are
759 // legal from the caller.
761 Status
= EFI_SUCCESS
;
762 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
763 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
764 if (DevNumber
>= mFsCount
) {
767 File
->Type
= EfiOpenFileSystem
;
768 File
->EfiHandle
= mFs
[DevNumber
];
769 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
771 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
772 if (DevNumber
>= mFvCount
) {
775 File
->Type
= EfiOpenFirmwareVolume
;
776 File
->EfiHandle
= mFv
[DevNumber
];
778 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
779 // Skip leading / as its not really needed for the FV since no directories are supported
784 ModifiedSectionType
= SectionType
;
785 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
786 if (PathName
[Index
] == ':') {
787 // Support fv0:\DxeCore:0x10
788 // This means open the PE32 Section of the file
789 ModifiedSectionType
= (EFI_SECTION_TYPE
)AsciiStrHexToUintn (&PathName
[Index
+ 1]);
790 PathName
[Index
] = '\0';
793 File
->FvSectionType
= ModifiedSectionType
;
794 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
796 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
797 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
798 File
->Type
= EfiOpenMemoryBuffer
;
799 // 1st colon is at PathName[FileStart - 1]
800 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
803 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
807 // If we ran out of string, there's no extra data
808 if (PathName
[FileStart
] == '\0') {
811 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
814 // if there's no number after the second colon, default
816 if (File
->Size
== 0) {
817 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
820 File
->MaxPosition
= File
->Size
;
821 File
->BaseOffset
= (UINTN
)File
->Buffer
;
823 } else if (*PathName
== 'l' || *PathName
== 'L') {
824 if (DevNumber
>= mLoadFileCount
) {
827 File
->Type
= EfiOpenLoadFile
;
828 File
->EfiHandle
= mLoadFile
[DevNumber
];
830 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
831 if (EFI_ERROR (Status
)) {
835 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
836 if (EFI_ERROR (Status
)) {
839 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
841 } else if (*PathName
== 'b' || *PathName
== 'B') {
842 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
843 if (DevNumber
>= mBlkIoCount
) {
846 File
->Type
= EfiOpenBlockIo
;
847 File
->EfiHandle
= mBlkIo
[DevNumber
];
848 EblFileDevicePath (File
, "", OpenMode
);
850 // 1st colon is at PathName[FileStart - 1]
851 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
854 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
858 // If we ran out of string, there's no extra data
859 if (PathName
[FileStart
] == '\0') {
862 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
865 // if a zero size is passed in (or the size is left out entirely),
866 // go to the end of the device.
868 File
->Size
= File
->Size
- File
->DiskOffset
;
873 File
->MaxPosition
= File
->Size
;
874 File
->BaseOffset
= File
->DiskOffset
;
875 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
877 // Get current IP address
878 Status
= EblGetCurrentIpAddress (&Ip
);
879 if (EFI_ERROR(Status
)) {
880 AsciiPrint("Device IP Address is not configured.\n");
885 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
886 File
->Type
= EfiOpenTftp
;
887 File
->IsDirty
= FALSE
;
888 File
->IsBufferValid
= FALSE
;
890 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
893 if (EFI_ERROR (Status
)) {
897 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
898 if (GuardFile
== NULL
) {
902 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
903 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
904 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
906 return &(GuardFile
->File
);
909 FreePool (File
->DeviceName
);
913 #define FILE_COPY_CHUNK 0x01000000
917 IN CHAR8
*DestinationFile
,
921 EFI_OPEN_FILE
*Source
= NULL
;
922 EFI_OPEN_FILE
*Destination
= NULL
;
923 EFI_STATUS Status
= EFI_SUCCESS
;
927 UINTN Chunk
= FILE_COPY_CHUNK
;
929 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
930 if (Source
== NULL
) {
931 AsciiPrint("Source file open error.\n");
932 Status
= EFI_NOT_FOUND
;
936 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
937 if (Destination
== NULL
) {
938 AsciiPrint("Destination file open error.\n");
939 Status
= EFI_NOT_FOUND
;
943 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
944 if (Buffer
== NULL
) {
945 Status
= EFI_OUT_OF_RESOURCES
;
949 Size
= EfiTell(Source
, NULL
);
951 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
952 Chunk
= FILE_COPY_CHUNK
;
954 Status
= EfiRead(Source
, Buffer
, &Chunk
);
955 if (EFI_ERROR(Status
)) {
956 AsciiPrint("Read file error %r\n", Status
);
960 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
961 if (EFI_ERROR(Status
)) {
962 AsciiPrint("Write file error %r\n", Status
);
969 Chunk
= Size
- Offset
;
971 Status
= EfiRead(Source
, Buffer
, &Chunk
);
972 if (EFI_ERROR(Status
)) {
973 AsciiPrint("Read file error\n");
977 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
978 if (EFI_ERROR(Status
)) {
979 AsciiPrint("Write file error\n");
985 if (Source
!= NULL
) {
986 Status
= EfiClose(Source
);
987 if (EFI_ERROR(Status
)) {
988 AsciiPrint("Source close error");
992 if (Destination
!= NULL
) {
993 Status
= EfiClose(Destination
);
994 if (EFI_ERROR(Status
)) {
995 AsciiPrint("Destination close error");
999 if (Buffer
!= NULL
) {
1007 Use DeviceType and Index to form a valid PathName and try and open it.
1009 @param DeviceType Device type to open
1010 @param Index Device Index to use. Zero relative.
1012 @return NULL Open failed
1013 @return Valid EFI_OPEN_FILE handle
1017 EfiDeviceOpenByType (
1018 IN EFI_OPEN_FILE_TYPE DeviceType
,
1023 CHAR8 Path
[MAX_CMD_LINE
];
1025 switch (DeviceType
) {
1026 case EfiOpenLoadFile
:
1027 DevStr
= "loadfile%d:";
1029 case EfiOpenFirmwareVolume
:
1032 case EfiOpenFileSystem
:
1035 case EfiOpenBlockIo
:
1038 case EfiOpenMemoryBuffer
:
1045 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1047 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1052 Close a file handle opened by EfiOpen() and free all resources allocated by
1055 @param Stream Open File Handle
1057 @return EFI_INVALID_PARAMETER Stream is not an Open File
1058 @return EFI_SUCCESS Steam closed
1063 IN EFI_OPEN_FILE
*File
1067 UINT64 TftpBufferSize
;
1069 if (!FileHandleValid (File
)) {
1070 return EFI_INVALID_PARAMETER
;
1073 //Write the buffer contents to TFTP file.
1074 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1076 TftpBufferSize
= File
->Size
;
1078 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1084 (UINT8
*)File
->FileName
,
1088 if (EFI_ERROR(Status
)) {
1089 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1094 if ((File
->Type
== EfiOpenLoadFile
) ||
1095 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1096 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1097 EblFreePool(File
->Buffer
);
1100 EblFreePool (File
->DevicePath
);
1101 EblFreePool (File
->DeviceName
);
1102 EblFreePool (File
->FsFileInfo
);
1103 EblFreePool (File
->FsInfo
);
1105 if (File
->FsFileHandle
!= NULL
) {
1106 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1109 // Need to free File and it's Guard structures
1110 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1116 Return the size of the file represented by Stream. Also return the current
1117 Seek position. Opening a file will enable a valid file size to be returned.
1118 LoadFile is an exception as a load file size is set to zero.
1120 @param Stream Open File Handle
1122 @return 0 Stream is not an Open File or a valid LoadFile handle
1127 IN EFI_OPEN_FILE
*File
,
1128 OUT EFI_LBA
*CurrentPosition OPTIONAL
1132 UINT64 BufferSize
= 0;
1134 if (!FileHandleValid (File
)) {
1138 if (CurrentPosition
!= NULL
) {
1139 *CurrentPosition
= File
->CurrentPosition
;
1142 if (File
->Type
== EfiOpenLoadFile
) {
1143 // Figure out the File->Size
1144 File
->Buffer
= NULL
;
1146 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1147 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1151 File
->MaxPosition
= (UINT64
)File
->Size
;
1152 } else if (File
->Type
== EfiOpenTftp
) {
1155 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1161 (UINT8
*)File
->FileName
,
1165 if (EFI_ERROR(Status
)) {
1166 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1170 File
->Size
= (UINTN
)BufferSize
;
1171 File
->MaxPosition
= File
->Size
;
1179 Seek to the Offset location in the file. LoadFile and FV device types do
1180 not support EfiSeek(). It is not possible to grow the file size using
1183 SeekType defines how use Offset to calculate the new file position:
1184 EfiSeekStart : Position = Offset
1185 EfiSeekCurrent: Position is Offset bytes from the current position
1186 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1188 @param Stream Open File Handle
1189 @param Offset Offset to seek too.
1190 @param SeekType Type of seek to perform
1193 @return EFI_INVALID_PARAMETER Stream is not an Open File
1194 @return EFI_UNSUPPORTED LoadFile and FV do not support Seek
1195 @return EFI_NOT_FOUND Seek past the end of the file.
1196 @return EFI_SUCCESS Steam closed
1201 IN EFI_OPEN_FILE
*File
,
1203 IN EFI_SEEK_TYPE SeekType
1207 UINT64 CurrentPosition
;
1209 if (!FileHandleValid (File
)) {
1210 return EFI_INVALID_PARAMETER
;
1213 if (File
->Type
== EfiOpenLoadFile
) {
1214 // LoadFile does not support Seek
1215 return EFI_UNSUPPORTED
;
1218 CurrentPosition
= File
->CurrentPosition
;
1221 if (Offset
> File
->MaxPosition
) {
1222 return EFI_NOT_FOUND
;
1224 CurrentPosition
= Offset
;
1227 case EfiSeekCurrent
:
1228 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1229 return EFI_NOT_FOUND
;
1231 CurrentPosition
+= Offset
;
1236 // We don't support growing file size via seeking past end of file
1237 return EFI_UNSUPPORTED
;
1239 CurrentPosition
= File
->MaxPosition
;
1243 return EFI_NOT_FOUND
;
1246 Status
= EFI_SUCCESS
;
1247 if (File
->FsFileHandle
!= NULL
) {
1248 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1251 if (!EFI_ERROR (Status
)) {
1252 File
->CurrentPosition
= CurrentPosition
;
1260 IN OUT EFI_OPEN_FILE
*File
1264 UINT64 TftpBufferSize
;
1266 if (File
->IsBufferValid
) {
1270 // Make sure the file size is set.
1271 EfiTell (File
, NULL
);
1273 //Allocate a buffer to hold the whole file.
1274 File
->Buffer
= AllocatePool(File
->Size
);
1275 if (File
->Buffer
== NULL
) {
1276 return EFI_OUT_OF_RESOURCES
;
1279 TftpBufferSize
= File
->Size
;
1282 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1288 (UINT8
*)File
->FileName
,
1291 if (EFI_ERROR(Status
)) {
1292 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1293 FreePool(File
->Buffer
);
1297 // Set the buffer valid flag.
1298 File
->IsBufferValid
= TRUE
;
1304 Read BufferSize bytes from the current location in the file. For load file,
1305 FV, and TFTP case you must read the entire file.
1307 @param Stream Open File Handle
1308 @param Buffer Caller allocated buffer.
1309 @param BufferSize Size of buffer in bytes.
1312 @return EFI_SUCCESS Stream is not an Open File
1313 @return EFI_END_OF_FILE Tried to read past the end of the file
1314 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1315 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1316 @return "other" Error returned from device read
1321 IN EFI_OPEN_FILE
*File
,
1323 OUT UINTN
*BufferSize
1327 UINT32 AuthenticationStatus
;
1328 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1330 if (!FileHandleValid (File
)) {
1331 return EFI_INVALID_PARAMETER
;
1334 // Don't read past the end of the file.
1335 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1336 return EFI_END_OF_FILE
;
1339 switch (File
->Type
) {
1340 case EfiOpenLoadFile
:
1341 // Figure out the File->Size
1342 EfiTell (File
, NULL
);
1344 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1347 case EfiOpenFirmwareVolume
:
1348 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1349 // This is the entire FV device, so treat like a memory buffer
1350 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1351 File
->CurrentPosition
+= *BufferSize
;
1352 Status
= EFI_SUCCESS
;
1354 if (File
->Buffer
== NULL
) {
1355 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1356 Status
= File
->Fv
->ReadFile (
1359 (VOID
**)&File
->Buffer
,
1362 &File
->FvAttributes
,
1363 &AuthenticationStatus
1366 Status
= File
->Fv
->ReadSection (
1369 File
->FvSectionType
,
1371 (VOID
**)&File
->Buffer
,
1373 &AuthenticationStatus
1376 if (EFI_ERROR (Status
)) {
1379 File
->IsBufferValid
= TRUE
;
1381 // Operate on the cached buffer so Seek will work
1382 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1383 File
->CurrentPosition
+= *BufferSize
;
1384 Status
= EFI_SUCCESS
;
1388 case EfiOpenMemoryBuffer
:
1389 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1390 File
->CurrentPosition
+= *BufferSize
;
1391 Status
= EFI_SUCCESS
;
1394 case EfiOpenFileSystem
:
1395 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1396 File
->CurrentPosition
+= *BufferSize
;
1399 case EfiOpenBlockIo
:
1400 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1401 if (!EFI_ERROR(Status
)) {
1402 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1404 File
->CurrentPosition
+= *BufferSize
;
1408 // Cache the file if it hasn't been cached yet.
1409 if (File
->IsBufferValid
== FALSE
) {
1410 Status
= CacheTftpFile (File
);
1411 if (EFI_ERROR (Status
)) {
1416 // Copy out the requested data
1417 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1418 File
->CurrentPosition
+= *BufferSize
;
1420 Status
= EFI_SUCCESS
;
1424 return EFI_INVALID_PARAMETER
;
1432 Read the entire file into a buffer. This routine allocates the buffer and
1433 returns it to the user full of the read data.
1435 This is very useful for load file where it's hard to know how big the buffer
1438 @param Stream Open File Handle
1439 @param Buffer Pointer to buffer to return.
1440 @param BufferSize Pointer to Size of buffer return..
1443 @return EFI_SUCCESS Stream is not an Open File
1444 @return EFI_END_OF_FILE Tried to read past the end of the file
1445 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1446 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1447 @return "other" Error returned from device read
1451 EfiReadAllocatePool (
1452 IN EFI_OPEN_FILE
*File
,
1454 OUT UINTN
*BufferSize
1457 if (!FileHandleValid (File
)) {
1458 return EFI_INVALID_PARAMETER
;
1461 // Loadfile defers file size determination on Open so use tell to find it
1462 EfiTell (File
, NULL
);
1464 *BufferSize
= File
->Size
;
1465 *Buffer
= AllocatePool (*BufferSize
);
1466 if (*Buffer
== NULL
) {
1467 return EFI_NOT_FOUND
;
1470 return EfiRead (File
, *Buffer
, BufferSize
);
1475 Write data back to the file. For TFTP case you must write the entire file.
1477 @param Stream Open File Handle
1478 @param Buffer Pointer to buffer to return.
1479 @param BufferSize Pointer to Size of buffer return..
1482 @return EFI_SUCCESS Stream is not an Open File
1483 @return EFI_END_OF_FILE Tried to read past the end of the file
1484 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1485 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1486 @return "other" Error returned from device write
1491 IN EFI_OPEN_FILE
*File
,
1493 OUT UINTN
*BufferSize
1497 EFI_FV_WRITE_FILE_DATA FileData
;
1498 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1500 if (!FileHandleValid (File
)) {
1501 return EFI_INVALID_PARAMETER
;
1504 switch (File
->Type
) {
1505 case EfiOpenMemoryBuffer
:
1506 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1507 return EFI_END_OF_FILE
;
1510 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1511 File
->CurrentPosition
+= *BufferSize
;
1512 Status
= EFI_SUCCESS
;
1514 case EfiOpenLoadFile
:
1515 // LoadFile device is read only be definition
1516 Status
= EFI_UNSUPPORTED
;
1518 case EfiOpenFirmwareVolume
:
1519 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1520 // Writes not support to a specific section. You have to update entire file
1521 return EFI_UNSUPPORTED
;
1524 FileData
.NameGuid
= &(File
->FvNameGuid
);
1525 FileData
.Type
= File
->FvType
;
1526 FileData
.FileAttributes
= File
->FvAttributes
;
1527 FileData
.Buffer
= Buffer
;
1528 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1529 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1532 case EfiOpenFileSystem
:
1533 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1534 File
->CurrentPosition
+= *BufferSize
;
1537 case EfiOpenBlockIo
:
1538 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1539 return EFI_END_OF_FILE
;
1542 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1543 if (!EFI_ERROR(Status
)) {
1544 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1546 File
->CurrentPosition
+= *BufferSize
;
1550 // Cache the file if it hasn't been cached yet.
1551 if (File
->IsBufferValid
== FALSE
) {
1552 Status
= CacheTftpFile(File
);
1553 if (EFI_ERROR(Status
)) {
1558 // Don't overwrite the buffer
1559 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1562 TempBuffer
= File
->Buffer
;
1564 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1565 if (File
->Buffer
== NULL
) {
1566 return EFI_OUT_OF_RESOURCES
;
1569 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1571 FreePool (TempBuffer
);
1573 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1574 File
->MaxPosition
= (UINT64
)File
->Size
;
1577 // Copy in the requested data
1578 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1579 File
->CurrentPosition
+= *BufferSize
;
1581 // Mark the file dirty
1582 File
->IsDirty
= TRUE
;
1584 Status
= EFI_SUCCESS
;
1588 Status
= EFI_INVALID_PARAMETER
;
1596 Given Cwd expand Path to remove .. and replace them with real
1599 @param Cwd Current Working Directory
1600 @param Path Path to expand
1602 @return NULL Cwd or Path are not valid
1603 @return 'other' Path with .. expanded
1613 CHAR8
*Work
, *Start
, *End
;
1617 if (Cwd
== NULL
|| Path
== NULL
) {
1621 StrLen
= AsciiStrSize (Cwd
);
1623 // Smallest valid path is 1 char and a null
1627 StrLen
= AsciiStrSize (Path
);
1628 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1629 if (NewPath
== NULL
) {
1632 AsciiStrCpy (NewPath
, Cwd
);
1634 End
= Path
+ StrLen
;
1635 for (Start
= Path
;;) {
1636 Work
= AsciiStrStr (Start
, "..") ;
1638 // Remaining part of Path contains no more ..
1642 // append path prior to ..
1643 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1644 StrLen
= AsciiStrLen (NewPath
);
1645 for (i
= StrLen
; i
>= 0; i
--) {
1646 if (NewPath
[i
] == ':') {
1650 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1651 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1652 // leave the / before a :
1653 NewPath
[i
+1] = '\0';
1655 // replace / will Null to remove trailing file/dir reference
1665 // Handle the path that remains after the ..
1666 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1673 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1674 the path does not contain a device name, The CWD is prepended to the path.
1676 @param Cwd Current Working Directory to set
1679 @return EFI_SUCCESS CWD is set
1680 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1688 EFI_OPEN_FILE
*File
;
1693 return EFI_INVALID_PARAMETER
;
1696 if (AsciiStrCmp (Cwd
, ".") == 0) {
1702 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1708 Len
= AsciiStrLen (gCwd
);
1709 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1710 // parent is device so nothing to do
1714 // Expand .. in Cwd, given we know current working directory
1715 Path
= ExpandPath (gCwd
, Cwd
);
1717 return EFI_NOT_FOUND
;
1721 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1723 return EFI_INVALID_PARAMETER
;
1730 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1731 // relative to the current gCwd or not.
1732 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1734 return EFI_INVALID_PARAMETER
;
1737 AsciiStrCpy (gCwd
, File
->DeviceName
);
1738 if (File
->FileName
== NULL
) {
1739 AsciiStrCat (gCwd
, ":\\");
1741 AsciiStrCat (gCwd
, ":");
1742 AsciiStrCat (gCwd
, File
->FileName
);
1755 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1756 the path does not contain a device name, The CWD is prepended to the path.
1757 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1758 a call to EfiSetCwd() it is not legal to use the pointer returned by
1761 @param Cwd Current Working Directory
1764 @return "" No CWD set
1765 @return 'other' Returns buffer that contains CWD.