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
;
522 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
526 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
527 if (EFI_ERROR (Status
)) {
531 // Get FVB Info about the handle
532 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
533 if (!EFI_ERROR (Status
)) {
534 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
535 if (!EFI_ERROR (Status
)) {
536 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
537 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
538 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
539 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
542 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
543 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
544 if (EFI_ERROR (Status
)) {
552 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
554 if (*FileName
== '\0') {
555 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
556 File
->Size
= File
->FvSize
;
557 File
->MaxPosition
= File
->Size
;
561 File
->FvType
= EFI_FV_FILETYPE_ALL
;
562 GetNextFileStatus
= File
->Fv
->GetNextFile (
570 if (!EFI_ERROR (GetNextFileStatus
)) {
571 // Compare GUID first
572 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
573 if (!EFI_ERROR(Status
)) {
578 Status
= File
->Fv
->ReadSection (
581 EFI_SECTION_USER_INTERFACE
,
585 &AuthenticationStatus
587 if (!EFI_ERROR (Status
)) {
588 UnicodeStrToAsciiStr (Section
, AsciiSection
);
589 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
596 } while (!EFI_ERROR (GetNextFileStatus
));
598 if (EFI_ERROR (GetNextFileStatus
)) {
599 return GetNextFileStatus
;
602 if (OpenMode
!= EFI_SECTION_ALL
) {
603 // Calculate the size of the section we are targeting
606 Status
= File
->Fv
->ReadSection (
613 &AuthenticationStatus
615 if (EFI_ERROR (Status
)) {
620 File
->MaxPosition
= File
->Size
;
621 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
622 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
626 // FVB not required if FV was soft loaded...
634 Open a device named by PathName. The PathName includes a device name and
635 path seperated by a :. See file header for more details on the PathName
636 syntax. There is no checking to prevent a file from being opened more than
639 SectionType is only used to open an FV. Each file in an FV contains multiple
640 secitons and only the SectionType section is opened.
642 For any file that is opened with EfiOpen() must be closed with EfiClose().
644 @param PathName Path to parse to open
645 @param OpenMode Same as EFI_FILE.Open()
646 @param SectionType Section in FV to open.
648 @return NULL Open failed
649 @return Valid EFI_OPEN_FILE handle
655 IN CONST UINT64 OpenMode
,
656 IN CONST EFI_SECTION_TYPE SectionType
661 EFI_OPEN_FILE FileData
;
665 EFI_OPEN_FILE_GUARD
*GuardFile
;
666 BOOLEAN VolumeNameMatch
;
667 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
670 CHAR8
*CwdPlusPathName
;
672 EFI_SECTION_TYPE ModifiedSectionType
;
674 EblUpdateDeviceLists ();
677 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
679 StrLen
= AsciiStrSize (PathName
);
681 // Smallest valid path is 1 char and a null
685 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
686 if (PathName
[FileStart
] == ':') {
693 // Matching volume name has precedence over handle based names
695 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
696 if (!VolumeNameMatch
) {
697 if (FileStart
== StrLen
) {
698 // No Volume name or device name, so try Current Working Directory
704 // We could add a current working diretory concept
705 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
706 if (CwdPlusPathName
== NULL
) {
710 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
711 // PathName starts in / so this means we go to the root of the device in the CWD.
712 CwdPlusPathName
[0] = '\0';
713 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
714 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
715 if (gCwd
[FileStart
] == ':') {
717 CwdPlusPathName
[FileStart
] = '\0';
722 AsciiStrCpy (CwdPlusPathName
, gCwd
);
723 StrLen
= AsciiStrLen (gCwd
);
724 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
725 AsciiStrCat (CwdPlusPathName
, "\\");
729 AsciiStrCat (CwdPlusPathName
, PathName
);
730 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
731 // Extra error check to make sure we don't recusre and blow stack
735 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
736 FreePool (CwdPlusPathName
);
740 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
743 File
->DeviceName
= AllocatePool (StrLen
);
744 AsciiStrCpy (File
->DeviceName
, PathName
);
745 File
->DeviceName
[FileStart
- 1] = '\0';
746 File
->FileName
= &File
->DeviceName
[FileStart
];
747 if (File
->FileName
[0] == '\0') {
748 // if it is just a file name use / as root
749 File
->FileName
= "\\";
753 // Use best match algorithm on the dev names so we only need to look at the
754 // first few charters to match the full device name. Short name forms are
755 // legal from the caller.
757 Status
= EFI_SUCCESS
;
758 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
759 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
760 if (DevNumber
>= mFsCount
) {
763 File
->Type
= EfiOpenFileSystem
;
764 File
->EfiHandle
= mFs
[DevNumber
];
765 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
767 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
768 if (DevNumber
>= mFvCount
) {
771 File
->Type
= EfiOpenFirmwareVolume
;
772 File
->EfiHandle
= mFv
[DevNumber
];
774 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
775 // Skip leading / as its not really needed for the FV since no directories are supported
780 ModifiedSectionType
= SectionType
;
781 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
782 if (PathName
[Index
] == ':') {
783 // Support fv0:\DxeCore:0x10
784 // This means open the PE32 Section of the file
785 ModifiedSectionType
= AsciiStrHexToUintn (&PathName
[Index
+ 1]);
786 PathName
[Index
] = '\0';
789 File
->FvSectionType
= ModifiedSectionType
;
790 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
792 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
793 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
794 File
->Type
= EfiOpenMemoryBuffer
;
795 // 1st colon is at PathName[FileStart - 1]
796 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
799 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
803 // If we ran out of string, there's no extra data
804 if (PathName
[FileStart
] == '\0') {
807 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
810 // if there's no number after the second colon, default
812 if (File
->Size
== 0) {
813 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
816 File
->MaxPosition
= File
->Size
;
817 File
->BaseOffset
= (UINTN
)File
->Buffer
;
819 } else if (*PathName
== 'l' || *PathName
== 'L') {
820 if (DevNumber
>= mLoadFileCount
) {
823 File
->Type
= EfiOpenLoadFile
;
824 File
->EfiHandle
= mLoadFile
[DevNumber
];
826 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
827 if (EFI_ERROR (Status
)) {
831 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
832 if (EFI_ERROR (Status
)) {
835 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
837 } else if (*PathName
== 'b' || *PathName
== 'B') {
838 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
839 if (DevNumber
>= mBlkIoCount
) {
842 File
->Type
= EfiOpenBlockIo
;
843 File
->EfiHandle
= mBlkIo
[DevNumber
];
844 EblFileDevicePath (File
, "", OpenMode
);
846 // 1st colon is at PathName[FileStart - 1]
847 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
850 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
854 // If we ran out of string, there's no extra data
855 if (PathName
[FileStart
] == '\0') {
858 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
861 // if a zero size is passed in (or the size is left out entirely),
862 // go to the end of the device.
864 File
->Size
= File
->Size
- File
->DiskOffset
;
869 File
->MaxPosition
= File
->Size
;
870 File
->BaseOffset
= File
->DiskOffset
;
871 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
873 // Get current IP address
874 Status
= EblGetCurrentIpAddress (&Ip
);
875 if (EFI_ERROR(Status
)) {
876 AsciiPrint("Device IP Address is not configured.\n");
881 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
882 File
->Type
= EfiOpenTftp
;
883 File
->IsDirty
= FALSE
;
884 File
->IsBufferValid
= FALSE
;
886 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
889 if (EFI_ERROR (Status
)) {
893 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
894 if (GuardFile
== NULL
) {
898 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
899 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
900 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
902 return &(GuardFile
->File
);
905 FreePool (File
->DeviceName
);
909 #define FILE_COPY_CHUNK 0x01000000
913 IN CHAR8
*DestinationFile
,
917 EFI_OPEN_FILE
*Source
= NULL
;
918 EFI_OPEN_FILE
*Destination
= NULL
;
919 EFI_STATUS Status
= EFI_SUCCESS
;
923 UINTN Chunk
= FILE_COPY_CHUNK
;
925 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
926 if (Source
== NULL
) {
927 AsciiPrint("Source file open error.\n");
928 Status
= EFI_NOT_FOUND
;
932 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
933 if (Destination
== NULL
) {
934 AsciiPrint("Destination file open error.\n");
935 Status
= EFI_NOT_FOUND
;
939 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
940 if (Buffer
== NULL
) {
941 Status
= EFI_OUT_OF_RESOURCES
;
945 Size
= EfiTell(Source
, NULL
);
947 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
948 Chunk
= FILE_COPY_CHUNK
;
950 Status
= EfiRead(Source
, Buffer
, &Chunk
);
951 if (EFI_ERROR(Status
)) {
952 AsciiPrint("Read file error\n");
956 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
957 if (EFI_ERROR(Status
)) {
958 AsciiPrint("Write file error\n");
965 Chunk
= Size
- Offset
;
967 Status
= EfiRead(Source
, Buffer
, &Chunk
);
968 if (EFI_ERROR(Status
)) {
969 AsciiPrint("Read file error\n");
973 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
974 if (EFI_ERROR(Status
)) {
975 AsciiPrint("Write file error\n");
981 if (Source
!= NULL
) {
982 Status
= EfiClose(Source
);
983 if (EFI_ERROR(Status
)) {
984 AsciiPrint("Source close error");
988 if (Destination
!= NULL
) {
989 Status
= EfiClose(Destination
);
990 if (EFI_ERROR(Status
)) {
991 AsciiPrint("Destination close error");
995 if (Buffer
!= NULL
) {
1003 Use DeviceType and Index to form a valid PathName and try and open it.
1005 @param DeviceType Device type to open
1006 @param Index Device Index to use. Zero relative.
1008 @return NULL Open failed
1009 @return Valid EFI_OPEN_FILE handle
1013 EfiDeviceOpenByType (
1014 IN EFI_OPEN_FILE_TYPE DeviceType
,
1019 CHAR8 Path
[MAX_CMD_LINE
];
1021 switch (DeviceType
) {
1022 case EfiOpenLoadFile
:
1023 DevStr
= "loadfile%d:";
1025 case EfiOpenFirmwareVolume
:
1028 case EfiOpenFileSystem
:
1031 case EfiOpenBlockIo
:
1034 case EfiOpenMemoryBuffer
:
1041 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1043 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1048 Close a file handle opened by EfiOpen() and free all resources allocated by
1051 @param Stream Open File Handle
1053 @return EFI_INVALID_PARAMETER Stream is not an Open File
1054 @return EFI_SUCCESS Steam closed
1059 IN EFI_OPEN_FILE
*File
1063 UINT64 TftpBufferSize
;
1065 if (!FileHandleValid (File
)) {
1066 return EFI_INVALID_PARAMETER
;
1069 //Write the buffer contents to TFTP file.
1070 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1072 TftpBufferSize
= File
->Size
;
1074 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1080 (UINT8
*)File
->FileName
,
1084 if (EFI_ERROR(Status
)) {
1085 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1090 if ((File
->Type
== EfiOpenLoadFile
) ||
1091 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1092 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1093 EblFreePool(File
->Buffer
);
1096 EblFreePool (File
->DevicePath
);
1097 EblFreePool (File
->DeviceName
);
1098 EblFreePool (File
->FsFileInfo
);
1099 EblFreePool (File
->FsInfo
);
1101 if (File
->FsFileHandle
!= NULL
) {
1102 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1105 // Need to free File and it's Guard structures
1106 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1112 Return the size of the file represented by Stream. Also return the current
1113 Seek position. Opening a file will enable a valid file size to be returned.
1114 LoadFile is an exception as a load file size is set to zero.
1116 @param Stream Open File Handle
1118 @return 0 Stream is not an Open File or a valid LoadFile handle
1123 IN EFI_OPEN_FILE
*File
,
1124 OUT EFI_LBA
*CurrentPosition OPTIONAL
1128 UINT64 BufferSize
= 0;
1130 if (!FileHandleValid (File
)) {
1134 if (CurrentPosition
!= NULL
) {
1135 *CurrentPosition
= File
->CurrentPosition
;
1138 if (File
->Type
== EfiOpenLoadFile
) {
1139 // Figure out the File->Size
1140 File
->Buffer
= NULL
;
1142 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1143 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1147 File
->MaxPosition
= (UINT64
)File
->Size
;
1148 } else if (File
->Type
== EfiOpenTftp
) {
1151 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1157 (UINT8
*)File
->FileName
,
1161 if (EFI_ERROR(Status
)) {
1162 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1166 File
->Size
= (UINTN
)BufferSize
;
1167 File
->MaxPosition
= File
->Size
;
1175 Seek to the Offset locaiton in the file. LoadFile and FV device types do
1176 not support EfiSeek(). It is not possible to grow the file size using
1179 SeekType defines how use Offset to calculate the new file position:
1180 EfiSeekStart : Position = Offset
1181 EfiSeekCurrent: Position is Offset bytes from the current position
1182 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1184 @param Stream Open File Handle
1185 @param Offset Offset to seek too.
1186 @param SeekType Type of seek to perform
1189 @return EFI_INVALID_PARAMETER Stream is not an Open File
1190 @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek
1191 @return EFI_NOT_FOUND Seek past the end of the file.
1192 @return EFI_SUCCESS Steam closed
1197 IN EFI_OPEN_FILE
*File
,
1199 IN EFI_SEEK_TYPE SeekType
1203 UINT64 CurrentPosition
;
1205 if (!FileHandleValid (File
)) {
1206 return EFI_INVALID_PARAMETER
;
1209 if (File
->Type
== EfiOpenLoadFile
) {
1210 // LoadFile does not support Seek
1211 return EFI_UNSUPPORTED
;
1214 CurrentPosition
= File
->CurrentPosition
;
1217 if (Offset
> File
->MaxPosition
) {
1218 return EFI_NOT_FOUND
;
1220 CurrentPosition
= Offset
;
1223 case EfiSeekCurrent
:
1224 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1225 return EFI_NOT_FOUND
;
1227 CurrentPosition
+= Offset
;
1232 // We don't support growing file size via seeking past end of file
1233 return EFI_UNSUPPORTED
;
1235 CurrentPosition
= File
->MaxPosition
;
1239 return EFI_NOT_FOUND
;
1242 Status
= EFI_SUCCESS
;
1243 if (File
->FsFileHandle
!= NULL
) {
1244 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1247 if (!EFI_ERROR (Status
)) {
1248 File
->CurrentPosition
= CurrentPosition
;
1256 IN OUT EFI_OPEN_FILE
*File
1260 UINT64 TftpBufferSize
;
1262 if (File
->IsBufferValid
) {
1266 // Make sure the file size is set.
1267 EfiTell (File
, NULL
);
1269 //Allocate a buffer to hold the whole file.
1270 File
->Buffer
= AllocatePool(File
->Size
);
1271 if (File
->Buffer
== NULL
) {
1272 return EFI_OUT_OF_RESOURCES
;
1275 TftpBufferSize
= File
->Size
;
1278 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1284 (UINT8
*)File
->FileName
,
1287 if (EFI_ERROR(Status
)) {
1288 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1289 FreePool(File
->Buffer
);
1293 // Set the buffer valid flag.
1294 File
->IsBufferValid
= TRUE
;
1300 Read BufferSize bytes from the current locaiton in the file. For load file,
1301 FV, and TFTP case you must read the entire file.
1303 @param Stream Open File Handle
1304 @param Buffer Caller allocated buffer.
1305 @param BufferSize Size of buffer in bytes.
1308 @return EFI_SUCCESS Stream is not an Open File
1309 @return EFI_END_OF_FILE Tried to read past the end of the file
1310 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1311 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1312 @return "other" Error returned from device read
1317 IN EFI_OPEN_FILE
*File
,
1319 OUT UINTN
*BufferSize
1323 UINT32 AuthenticationStatus
;
1324 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1326 if (!FileHandleValid (File
)) {
1327 return EFI_INVALID_PARAMETER
;
1330 // Don't read past the end of the file.
1331 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1332 return EFI_END_OF_FILE
;
1335 switch (File
->Type
) {
1336 case EfiOpenLoadFile
:
1337 // Figure out the File->Size
1338 EfiTell (File
, NULL
);
1340 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1343 case EfiOpenFirmwareVolume
:
1344 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1345 // This is the entire FV device, so treat like a memory buffer
1346 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1347 File
->CurrentPosition
+= *BufferSize
;
1348 Status
= EFI_SUCCESS
;
1350 if (File
->Buffer
== NULL
) {
1351 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1352 Status
= File
->Fv
->ReadFile (
1355 (VOID
**)&File
->Buffer
,
1358 &File
->FvAttributes
,
1359 &AuthenticationStatus
1362 Status
= File
->Fv
->ReadSection (
1365 File
->FvSectionType
,
1367 (VOID
**)&File
->Buffer
,
1369 &AuthenticationStatus
1372 if (EFI_ERROR (Status
)) {
1375 File
->IsBufferValid
= TRUE
;
1377 // Operate on the cached buffer so Seek will work
1378 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1379 File
->CurrentPosition
+= *BufferSize
;
1380 Status
= EFI_SUCCESS
;
1384 case EfiOpenMemoryBuffer
:
1385 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1386 File
->CurrentPosition
+= *BufferSize
;
1387 Status
= EFI_SUCCESS
;
1390 case EfiOpenFileSystem
:
1391 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1392 File
->CurrentPosition
+= *BufferSize
;
1395 case EfiOpenBlockIo
:
1396 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1397 if (!EFI_ERROR(Status
)) {
1398 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
.MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1400 File
->CurrentPosition
+= *BufferSize
;
1404 // Cache the file if it hasn't been cached yet.
1405 if (File
->IsBufferValid
== FALSE
) {
1406 Status
= CacheTftpFile (File
);
1407 if (EFI_ERROR (Status
)) {
1412 // Copy out the requested data
1413 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1414 File
->CurrentPosition
+= *BufferSize
;
1416 Status
= EFI_SUCCESS
;
1420 return EFI_INVALID_PARAMETER
;
1428 Read the entire file into a buffer. This routine allocates the buffer and
1429 returns it to the user full of the read data.
1431 This is very useful for load flie where it's hard to know how big the buffer
1434 @param Stream Open File Handle
1435 @param Buffer Pointer to buffer to return.
1436 @param BufferSize Pointer to Size of buffer return..
1439 @return EFI_SUCCESS Stream is not an Open File
1440 @return EFI_END_OF_FILE Tried to read past the end of the file
1441 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1442 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1443 @return "other" Error returned from device read
1447 EfiReadAllocatePool (
1448 IN EFI_OPEN_FILE
*File
,
1450 OUT UINTN
*BufferSize
1453 if (!FileHandleValid (File
)) {
1454 return EFI_INVALID_PARAMETER
;
1457 // Loadfile defers file size determination on Open so use tell to find it
1458 EfiTell (File
, NULL
);
1460 *BufferSize
= File
->Size
;
1461 *Buffer
= AllocatePool (*BufferSize
);
1462 if (*Buffer
== NULL
) {
1463 return EFI_NOT_FOUND
;
1466 return EfiRead (File
, *Buffer
, BufferSize
);
1471 Write data back to the file. For TFTP case you must write the entire file.
1473 @param Stream Open File Handle
1474 @param Buffer Pointer to buffer to return.
1475 @param BufferSize Pointer to Size of buffer return..
1478 @return EFI_SUCCESS Stream is not an Open File
1479 @return EFI_END_OF_FILE Tried to read past the end of the file
1480 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1481 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1482 @return "other" Error returned from device write
1487 IN EFI_OPEN_FILE
*File
,
1489 OUT UINTN
*BufferSize
1493 EFI_FV_WRITE_FILE_DATA FileData
;
1494 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1496 if (!FileHandleValid (File
)) {
1497 return EFI_INVALID_PARAMETER
;
1500 switch (File
->Type
) {
1501 case EfiOpenMemoryBuffer
:
1502 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1503 return EFI_END_OF_FILE
;
1506 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1507 File
->CurrentPosition
+= *BufferSize
;
1508 Status
= EFI_SUCCESS
;
1510 case EfiOpenLoadFile
:
1511 // LoadFile device is read only be definition
1512 Status
= EFI_UNSUPPORTED
;
1514 case EfiOpenFirmwareVolume
:
1515 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1516 // Writes not support to a specific section. You have to update entire file
1517 return EFI_UNSUPPORTED
;
1520 FileData
.NameGuid
= &(File
->FvNameGuid
);
1521 FileData
.Type
= File
->FvType
;
1522 FileData
.FileAttributes
= File
->FvAttributes
;
1523 FileData
.Buffer
= Buffer
;
1524 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1525 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1528 case EfiOpenFileSystem
:
1529 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1530 File
->CurrentPosition
+= *BufferSize
;
1533 case EfiOpenBlockIo
:
1534 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1535 return EFI_END_OF_FILE
;
1538 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1539 if (!EFI_ERROR(Status
)) {
1540 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
.MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1542 File
->CurrentPosition
+= *BufferSize
;
1546 // Cache the file if it hasn't been cached yet.
1547 if (File
->IsBufferValid
== FALSE
) {
1548 Status
= CacheTftpFile(File
);
1549 if (EFI_ERROR(Status
)) {
1554 // Don't overwrite the buffer
1555 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1558 TempBuffer
= File
->Buffer
;
1560 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1561 if (File
->Buffer
== NULL
) {
1562 return EFI_OUT_OF_RESOURCES
;
1565 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1567 FreePool (TempBuffer
);
1569 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1570 File
->MaxPosition
= (UINT64
)File
->Size
;
1573 // Copy in the requested data
1574 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1575 File
->CurrentPosition
+= *BufferSize
;
1577 // Mark the file dirty
1578 File
->IsDirty
= TRUE
;
1580 Status
= EFI_SUCCESS
;
1584 Status
= EFI_INVALID_PARAMETER
;
1592 Given Cwd expand Path to remove .. and replace them with real
1595 @param Cwd Current Working Directory
1596 @param Path Path to expand
1598 @return NULL Cwd or Path are not valid
1599 @return 'other' Path with .. expanded
1609 CHAR8
*Work
, *Start
, *End
;
1613 if (Cwd
== NULL
|| Path
== NULL
) {
1617 StrLen
= AsciiStrSize (Cwd
);
1619 // Smallest valid path is 1 char and a null
1623 StrLen
= AsciiStrSize (Path
);
1624 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1625 if (NewPath
== NULL
) {
1628 AsciiStrCpy (NewPath
, Cwd
);
1630 End
= Path
+ StrLen
;
1631 for (Start
= Path
;;) {
1632 Work
= AsciiStrStr (Start
, "..") ;
1634 // Remaining part of Path contains no more ..
1638 // append path prior to ..
1639 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1640 StrLen
= AsciiStrLen (NewPath
);
1641 for (i
= StrLen
; i
>= 0; i
--) {
1642 if (NewPath
[i
] == ':') {
1646 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1647 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1648 // leave the / before a :
1649 NewPath
[i
+1] = '\0';
1651 // replace / will Null to remove trailing file/dir reference
1661 // Handle the path that remains after the ..
1662 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1669 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1670 the path does not contain a device name, The CWD is prepended to the path.
1672 @param Cwd Current Working Directory to set
1675 @return EFI_SUCCESS CWD is set
1676 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1684 EFI_OPEN_FILE
*File
;
1689 return EFI_INVALID_PARAMETER
;
1692 if (AsciiStrCmp (Cwd
, ".") == 0) {
1698 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1704 Len
= AsciiStrLen (gCwd
);
1705 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1706 // parent is device so nothing to do
1710 // Expand .. in Cwd, given we know current working directory
1711 Path
= ExpandPath (gCwd
, Cwd
);
1713 return EFI_NOT_FOUND
;
1717 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1719 return EFI_INVALID_PARAMETER
;
1726 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1727 // relative to the current gCwd or not.
1728 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1730 return EFI_INVALID_PARAMETER
;
1732 AsciiStrCpy (gCwd
, File
->DeviceName
);
1733 if (File
->FileName
== NULL
) {
1734 AsciiStrCat (gCwd
, ":\\");
1736 AsciiStrCat (gCwd
, ":");
1737 AsciiStrCat (gCwd
, File
->FileName
);
1749 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1750 the path does not contain a device name, The CWD is prepended to the path.
1751 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1752 a call to EfiSetCwd() it is not legal to use the pointer returned by
1755 @param Cwd Current Working Directory
1758 @return "" No CWD set
1759 @return 'other' Returns buffer that contains CWD.