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 AsciiStrToUnicodeStrS (FileName
, UnicodeFileName
,
388 ARRAY_SIZE (UnicodeFileName
));
390 AsciiStrToUnicodeStrS ("\\", UnicodeFileName
, ARRAY_SIZE (UnicodeFileName
));
393 Size
= StrSize (UnicodeFileName
);
394 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ sizeof (EFI_DEVICE_PATH_PROTOCOL
));
395 if (FileDevicePath
!= NULL
) {
396 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
397 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
398 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
399 CopyMem (&FilePath
->PathName
, UnicodeFileName
, Size
);
400 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
401 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
403 if (File
->EfiHandle
!= NULL
) {
404 File
->DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
407 File
->DevicePath
= AppendDevicePath (File
->DevicePath
, FileDevicePath
);
408 FreePool (FileDevicePath
);
411 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
412 if (!EFI_ERROR (Status
)) {
413 File
->FsBlockIoMedia
= BlkIo
->Media
;
414 File
->FsBlockIo
= BlkIo
;
416 // If we are not opening the device this will get over written with file info
417 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
420 if (File
->Type
== EfiOpenFileSystem
) {
421 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
422 if (!EFI_ERROR (Status
)) {
423 Status
= Fs
->OpenVolume (Fs
, &Root
);
424 if (!EFI_ERROR (Status
)) {
425 // Get information about the volume
427 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
428 if (Status
== EFI_BUFFER_TOO_SMALL
) {
429 File
->FsInfo
= AllocatePool (Size
);
430 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
433 // Get information about the file
434 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
435 if (!EFI_ERROR (Status
)) {
437 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
438 if (Status
== EFI_BUFFER_TOO_SMALL
) {
439 File
->FsFileInfo
= AllocatePool (Size
);
440 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
441 if (!EFI_ERROR (Status
)) {
442 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
443 File
->MaxPosition
= (UINT64
)File
->Size
;
451 } else if (File
->Type
== EfiOpenBlockIo
) {
452 File
->Size
= (UINTN
)File
->MaxPosition
;
458 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
461 CompareGuidToString (
470 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
475 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
477 if (*StringPtr
== '-') {
482 if (*GuidPtr
== '-') {
487 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
488 return EFI_NOT_FOUND
;
500 Internal work function to fill in EFI_OPEN_FILE information for the FV
502 @param File Open file handle
503 @param FileName Name of file after device stripped off
508 EblFvFileDevicePath (
509 IN OUT EFI_OPEN_FILE
*File
,
511 IN CONST UINT64 OpenMode
515 EFI_STATUS GetNextFileStatus
;
516 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
517 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
519 UINT32 AuthenticationStatus
;
520 CHAR8 AsciiSection
[MAX_PATHNAME
];
523 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
526 UINTN NumberOfBlocks
;
527 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
531 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
532 if (EFI_ERROR (Status
)) {
536 // Get FVB Info about the handle
537 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
538 if (!EFI_ERROR (Status
)) {
539 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
540 if (!EFI_ERROR (Status
)) {
541 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
542 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
543 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
544 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
547 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
548 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
549 if (EFI_ERROR (Status
)) {
557 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
559 if (*FileName
== '\0') {
560 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
561 File
->Size
= File
->FvSize
;
562 File
->MaxPosition
= File
->Size
;
566 File
->FvType
= EFI_FV_FILETYPE_ALL
;
567 GetNextFileStatus
= File
->Fv
->GetNextFile (
575 if (!EFI_ERROR (GetNextFileStatus
)) {
576 // Compare GUID first
577 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
578 if (!EFI_ERROR(Status
)) {
583 Status
= File
->Fv
->ReadSection (
586 EFI_SECTION_USER_INTERFACE
,
590 &AuthenticationStatus
592 if (!EFI_ERROR (Status
)) {
593 UnicodeStrToAsciiStrS (Section
, AsciiSection
, MAX_PATHNAME
);
594 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
601 } while (!EFI_ERROR (GetNextFileStatus
));
603 if (EFI_ERROR (GetNextFileStatus
)) {
604 return GetNextFileStatus
;
607 if (OpenMode
!= EFI_SECTION_ALL
) {
608 // Calculate the size of the section we are targeting
611 Status
= File
->Fv
->ReadSection (
614 (EFI_SECTION_TYPE
)OpenMode
,
618 &AuthenticationStatus
620 if (EFI_ERROR (Status
)) {
625 File
->MaxPosition
= File
->Size
;
626 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
627 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
631 // FVB not required if FV was soft loaded...
639 Open a device named by PathName. The PathName includes a device name and
640 path separated by a :. See file header for more details on the PathName
641 syntax. There is no checking to prevent a file from being opened more than
644 SectionType is only used to open an FV. Each file in an FV contains multiple
645 sections and only the SectionType section is opened.
647 For any file that is opened with EfiOpen() must be closed with EfiClose().
649 @param PathName Path to parse to open
650 @param OpenMode Same as EFI_FILE.Open()
651 @param SectionType Section in FV to open.
653 @return NULL Open failed
654 @return Valid EFI_OPEN_FILE handle
660 IN CONST UINT64 OpenMode
,
661 IN CONST EFI_SECTION_TYPE SectionType
666 EFI_OPEN_FILE FileData
;
670 EFI_OPEN_FILE_GUARD
*GuardFile
;
671 BOOLEAN VolumeNameMatch
;
672 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
675 CHAR8
*CwdPlusPathName
;
677 EFI_SECTION_TYPE ModifiedSectionType
;
680 EblUpdateDeviceLists ();
683 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
685 StrLen
= AsciiStrSize (PathName
);
687 // Smallest valid path is 1 char and a null
691 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
692 if (PathName
[FileStart
] == ':') {
699 // Matching volume name has precedence over handle based names
701 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
702 if (!VolumeNameMatch
) {
703 if (FileStart
== StrLen
) {
704 // No Volume name or device name, so try Current Working Directory
710 // We could add a current working directory concept
711 AsciiLength
= AsciiStrSize (gCwd
) + AsciiStrSize (PathName
);
712 CwdPlusPathName
= AllocatePool (AsciiLength
);
713 if (CwdPlusPathName
== NULL
) {
717 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
718 // PathName starts in / so this means we go to the root of the device in the CWD.
719 CwdPlusPathName
[0] = '\0';
720 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
721 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
722 if (gCwd
[FileStart
] == ':') {
724 CwdPlusPathName
[FileStart
] = '\0';
729 AsciiStrCpyS (CwdPlusPathName
, AsciiLength
, gCwd
);
730 StrLen
= AsciiStrLen (gCwd
);
731 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
732 AsciiStrCatS (CwdPlusPathName
, AsciiLength
, "\\");
736 AsciiStrCatS (CwdPlusPathName
, AsciiLength
, PathName
);
737 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
738 // Extra error check to make sure we don't recurse and blow stack
742 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
743 FreePool (CwdPlusPathName
);
747 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
750 File
->DeviceName
= AllocatePool (StrLen
);
751 AsciiStrCpyS (File
->DeviceName
, StrLen
, PathName
);
752 File
->DeviceName
[FileStart
- 1] = '\0';
753 File
->FileName
= &File
->DeviceName
[FileStart
];
754 if (File
->FileName
[0] == '\0') {
755 // if it is just a file name use / as root
756 File
->FileName
= "\\";
760 // Use best match algorithm on the dev names so we only need to look at the
761 // first few charters to match the full device name. Short name forms are
762 // legal from the caller.
764 Status
= EFI_SUCCESS
;
765 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
766 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
767 if (DevNumber
>= mFsCount
) {
770 File
->Type
= EfiOpenFileSystem
;
771 File
->EfiHandle
= mFs
[DevNumber
];
772 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
774 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
775 if (DevNumber
>= mFvCount
) {
778 File
->Type
= EfiOpenFirmwareVolume
;
779 File
->EfiHandle
= mFv
[DevNumber
];
781 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
782 // Skip leading / as its not really needed for the FV since no directories are supported
787 ModifiedSectionType
= SectionType
;
788 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
789 if (PathName
[Index
] == ':') {
790 // Support fv0:\DxeCore:0x10
791 // This means open the PE32 Section of the file
792 ModifiedSectionType
= (EFI_SECTION_TYPE
)AsciiStrHexToUintn (&PathName
[Index
+ 1]);
793 PathName
[Index
] = '\0';
796 File
->FvSectionType
= ModifiedSectionType
;
797 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
799 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
800 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
801 File
->Type
= EfiOpenMemoryBuffer
;
802 // 1st colon is at PathName[FileStart - 1]
803 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
806 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
810 // If we ran out of string, there's no extra data
811 if (PathName
[FileStart
] == '\0') {
814 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
817 // if there's no number after the second colon, default
819 if (File
->Size
== 0) {
820 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
823 File
->MaxPosition
= File
->Size
;
824 File
->BaseOffset
= (UINTN
)File
->Buffer
;
826 } else if (*PathName
== 'l' || *PathName
== 'L') {
827 if (DevNumber
>= mLoadFileCount
) {
830 File
->Type
= EfiOpenLoadFile
;
831 File
->EfiHandle
= mLoadFile
[DevNumber
];
833 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
834 if (EFI_ERROR (Status
)) {
838 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
839 if (EFI_ERROR (Status
)) {
842 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
844 } else if (*PathName
== 'b' || *PathName
== 'B') {
845 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
846 if (DevNumber
>= mBlkIoCount
) {
849 File
->Type
= EfiOpenBlockIo
;
850 File
->EfiHandle
= mBlkIo
[DevNumber
];
851 EblFileDevicePath (File
, "", OpenMode
);
853 // 1st colon is at PathName[FileStart - 1]
854 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
857 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
861 // If we ran out of string, there's no extra data
862 if (PathName
[FileStart
] == '\0') {
865 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
868 // if a zero size is passed in (or the size is left out entirely),
869 // go to the end of the device.
871 File
->Size
= File
->Size
- File
->DiskOffset
;
876 File
->MaxPosition
= File
->Size
;
877 File
->BaseOffset
= File
->DiskOffset
;
878 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
880 // Get current IP address
881 Status
= EblGetCurrentIpAddress (&Ip
);
882 if (EFI_ERROR(Status
)) {
883 AsciiPrint("Device IP Address is not configured.\n");
888 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
889 File
->Type
= EfiOpenTftp
;
890 File
->IsDirty
= FALSE
;
891 File
->IsBufferValid
= FALSE
;
893 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
896 if (EFI_ERROR (Status
)) {
900 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
901 if (GuardFile
== NULL
) {
905 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
906 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
907 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
909 return &(GuardFile
->File
);
912 FreePool (File
->DeviceName
);
916 #define FILE_COPY_CHUNK 0x01000000
920 IN CHAR8
*DestinationFile
,
924 EFI_OPEN_FILE
*Source
= NULL
;
925 EFI_OPEN_FILE
*Destination
= NULL
;
926 EFI_STATUS Status
= EFI_SUCCESS
;
930 UINTN Chunk
= FILE_COPY_CHUNK
;
932 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
933 if (Source
== NULL
) {
934 AsciiPrint("Source file open error.\n");
935 Status
= EFI_NOT_FOUND
;
939 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
940 if (Destination
== NULL
) {
941 AsciiPrint("Destination file open error.\n");
942 Status
= EFI_NOT_FOUND
;
946 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
947 if (Buffer
== NULL
) {
948 Status
= EFI_OUT_OF_RESOURCES
;
952 Size
= EfiTell(Source
, NULL
);
954 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
955 Chunk
= FILE_COPY_CHUNK
;
957 Status
= EfiRead(Source
, Buffer
, &Chunk
);
958 if (EFI_ERROR(Status
)) {
959 AsciiPrint("Read file error %r\n", Status
);
963 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
964 if (EFI_ERROR(Status
)) {
965 AsciiPrint("Write file error %r\n", Status
);
972 Chunk
= Size
- Offset
;
974 Status
= EfiRead(Source
, Buffer
, &Chunk
);
975 if (EFI_ERROR(Status
)) {
976 AsciiPrint("Read file error\n");
980 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
981 if (EFI_ERROR(Status
)) {
982 AsciiPrint("Write file error\n");
988 if (Source
!= NULL
) {
989 Status
= EfiClose(Source
);
990 if (EFI_ERROR(Status
)) {
991 AsciiPrint("Source close error");
995 if (Destination
!= NULL
) {
996 Status
= EfiClose(Destination
);
997 if (EFI_ERROR(Status
)) {
998 AsciiPrint("Destination close error");
1002 if (Buffer
!= NULL
) {
1010 Use DeviceType and Index to form a valid PathName and try and open it.
1012 @param DeviceType Device type to open
1013 @param Index Device Index to use. Zero relative.
1015 @return NULL Open failed
1016 @return Valid EFI_OPEN_FILE handle
1020 EfiDeviceOpenByType (
1021 IN EFI_OPEN_FILE_TYPE DeviceType
,
1026 CHAR8 Path
[MAX_CMD_LINE
];
1028 switch (DeviceType
) {
1029 case EfiOpenLoadFile
:
1030 DevStr
= "loadfile%d:";
1032 case EfiOpenFirmwareVolume
:
1035 case EfiOpenFileSystem
:
1038 case EfiOpenBlockIo
:
1041 case EfiOpenMemoryBuffer
:
1048 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1050 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1055 Close a file handle opened by EfiOpen() and free all resources allocated by
1058 @param Stream Open File Handle
1060 @return EFI_INVALID_PARAMETER Stream is not an Open File
1061 @return EFI_SUCCESS Steam closed
1066 IN EFI_OPEN_FILE
*File
1070 UINT64 TftpBufferSize
;
1072 if (!FileHandleValid (File
)) {
1073 return EFI_INVALID_PARAMETER
;
1076 //Write the buffer contents to TFTP file.
1077 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1079 TftpBufferSize
= File
->Size
;
1081 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1087 (UINT8
*)File
->FileName
,
1091 if (EFI_ERROR(Status
)) {
1092 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1097 if ((File
->Type
== EfiOpenLoadFile
) ||
1098 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1099 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1100 EblFreePool(File
->Buffer
);
1103 EblFreePool (File
->DevicePath
);
1104 EblFreePool (File
->DeviceName
);
1105 EblFreePool (File
->FsFileInfo
);
1106 EblFreePool (File
->FsInfo
);
1108 if (File
->FsFileHandle
!= NULL
) {
1109 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1112 // Need to free File and it's Guard structures
1113 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1119 Return the size of the file represented by Stream. Also return the current
1120 Seek position. Opening a file will enable a valid file size to be returned.
1121 LoadFile is an exception as a load file size is set to zero.
1123 @param Stream Open File Handle
1125 @return 0 Stream is not an Open File or a valid LoadFile handle
1130 IN EFI_OPEN_FILE
*File
,
1131 OUT EFI_LBA
*CurrentPosition OPTIONAL
1135 UINT64 BufferSize
= 0;
1137 if (!FileHandleValid (File
)) {
1141 if (CurrentPosition
!= NULL
) {
1142 *CurrentPosition
= File
->CurrentPosition
;
1145 if (File
->Type
== EfiOpenLoadFile
) {
1146 // Figure out the File->Size
1147 File
->Buffer
= NULL
;
1149 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1150 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1154 File
->MaxPosition
= (UINT64
)File
->Size
;
1155 } else if (File
->Type
== EfiOpenTftp
) {
1158 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1164 (UINT8
*)File
->FileName
,
1168 if (EFI_ERROR(Status
)) {
1169 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1173 File
->Size
= (UINTN
)BufferSize
;
1174 File
->MaxPosition
= File
->Size
;
1182 Seek to the Offset location in the file. LoadFile and FV device types do
1183 not support EfiSeek(). It is not possible to grow the file size using
1186 SeekType defines how use Offset to calculate the new file position:
1187 EfiSeekStart : Position = Offset
1188 EfiSeekCurrent: Position is Offset bytes from the current position
1189 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1191 @param Stream Open File Handle
1192 @param Offset Offset to seek too.
1193 @param SeekType Type of seek to perform
1196 @return EFI_INVALID_PARAMETER Stream is not an Open File
1197 @return EFI_UNSUPPORTED LoadFile and FV do not support Seek
1198 @return EFI_NOT_FOUND Seek past the end of the file.
1199 @return EFI_SUCCESS Steam closed
1204 IN EFI_OPEN_FILE
*File
,
1206 IN EFI_SEEK_TYPE SeekType
1210 UINT64 CurrentPosition
;
1212 if (!FileHandleValid (File
)) {
1213 return EFI_INVALID_PARAMETER
;
1216 if (File
->Type
== EfiOpenLoadFile
) {
1217 // LoadFile does not support Seek
1218 return EFI_UNSUPPORTED
;
1221 CurrentPosition
= File
->CurrentPosition
;
1224 if (Offset
> File
->MaxPosition
) {
1225 return EFI_NOT_FOUND
;
1227 CurrentPosition
= Offset
;
1230 case EfiSeekCurrent
:
1231 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1232 return EFI_NOT_FOUND
;
1234 CurrentPosition
+= Offset
;
1239 // We don't support growing file size via seeking past end of file
1240 return EFI_UNSUPPORTED
;
1242 CurrentPosition
= File
->MaxPosition
;
1246 return EFI_NOT_FOUND
;
1249 Status
= EFI_SUCCESS
;
1250 if (File
->FsFileHandle
!= NULL
) {
1251 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1254 if (!EFI_ERROR (Status
)) {
1255 File
->CurrentPosition
= CurrentPosition
;
1263 IN OUT EFI_OPEN_FILE
*File
1267 UINT64 TftpBufferSize
;
1269 if (File
->IsBufferValid
) {
1273 // Make sure the file size is set.
1274 EfiTell (File
, NULL
);
1276 //Allocate a buffer to hold the whole file.
1277 File
->Buffer
= AllocatePool(File
->Size
);
1278 if (File
->Buffer
== NULL
) {
1279 return EFI_OUT_OF_RESOURCES
;
1282 TftpBufferSize
= File
->Size
;
1285 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1291 (UINT8
*)File
->FileName
,
1294 if (EFI_ERROR(Status
)) {
1295 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1296 FreePool(File
->Buffer
);
1300 // Set the buffer valid flag.
1301 File
->IsBufferValid
= TRUE
;
1307 Read BufferSize bytes from the current location in the file. For load file,
1308 FV, and TFTP case you must read the entire file.
1310 @param Stream Open File Handle
1311 @param Buffer Caller allocated buffer.
1312 @param BufferSize Size of buffer in bytes.
1315 @return EFI_SUCCESS Stream is not an Open File
1316 @return EFI_END_OF_FILE Tried to read past the end of the file
1317 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1318 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1319 @return "other" Error returned from device read
1324 IN EFI_OPEN_FILE
*File
,
1326 OUT UINTN
*BufferSize
1330 UINT32 AuthenticationStatus
;
1331 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1333 if (!FileHandleValid (File
)) {
1334 return EFI_INVALID_PARAMETER
;
1337 // Don't read past the end of the file.
1338 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1339 return EFI_END_OF_FILE
;
1342 switch (File
->Type
) {
1343 case EfiOpenLoadFile
:
1344 // Figure out the File->Size
1345 EfiTell (File
, NULL
);
1347 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1350 case EfiOpenFirmwareVolume
:
1351 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1352 // This is the entire FV device, so treat like a memory buffer
1353 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1354 File
->CurrentPosition
+= *BufferSize
;
1355 Status
= EFI_SUCCESS
;
1357 if (File
->Buffer
== NULL
) {
1358 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1359 Status
= File
->Fv
->ReadFile (
1362 (VOID
**)&File
->Buffer
,
1365 &File
->FvAttributes
,
1366 &AuthenticationStatus
1369 Status
= File
->Fv
->ReadSection (
1372 File
->FvSectionType
,
1374 (VOID
**)&File
->Buffer
,
1376 &AuthenticationStatus
1379 if (EFI_ERROR (Status
)) {
1382 File
->IsBufferValid
= TRUE
;
1384 // Operate on the cached buffer so Seek will work
1385 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1386 File
->CurrentPosition
+= *BufferSize
;
1387 Status
= EFI_SUCCESS
;
1391 case EfiOpenMemoryBuffer
:
1392 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1393 File
->CurrentPosition
+= *BufferSize
;
1394 Status
= EFI_SUCCESS
;
1397 case EfiOpenFileSystem
:
1398 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1399 File
->CurrentPosition
+= *BufferSize
;
1402 case EfiOpenBlockIo
:
1403 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1404 if (!EFI_ERROR(Status
)) {
1405 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1407 File
->CurrentPosition
+= *BufferSize
;
1411 // Cache the file if it hasn't been cached yet.
1412 if (File
->IsBufferValid
== FALSE
) {
1413 Status
= CacheTftpFile (File
);
1414 if (EFI_ERROR (Status
)) {
1419 // Copy out the requested data
1420 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1421 File
->CurrentPosition
+= *BufferSize
;
1423 Status
= EFI_SUCCESS
;
1427 return EFI_INVALID_PARAMETER
;
1435 Read the entire file into a buffer. This routine allocates the buffer and
1436 returns it to the user full of the read data.
1438 This is very useful for load file where it's hard to know how big the buffer
1441 @param Stream Open File Handle
1442 @param Buffer Pointer to buffer to return.
1443 @param BufferSize Pointer to Size of buffer return..
1446 @return EFI_SUCCESS Stream is not an Open File
1447 @return EFI_END_OF_FILE Tried to read past the end of the file
1448 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1449 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1450 @return "other" Error returned from device read
1454 EfiReadAllocatePool (
1455 IN EFI_OPEN_FILE
*File
,
1457 OUT UINTN
*BufferSize
1460 if (!FileHandleValid (File
)) {
1461 return EFI_INVALID_PARAMETER
;
1464 // Loadfile defers file size determination on Open so use tell to find it
1465 EfiTell (File
, NULL
);
1467 *BufferSize
= File
->Size
;
1468 *Buffer
= AllocatePool (*BufferSize
);
1469 if (*Buffer
== NULL
) {
1470 return EFI_NOT_FOUND
;
1473 return EfiRead (File
, *Buffer
, BufferSize
);
1478 Write data back to the file. For TFTP case you must write the entire file.
1480 @param Stream Open File Handle
1481 @param Buffer Pointer to buffer to return.
1482 @param BufferSize Pointer to Size of buffer return..
1485 @return EFI_SUCCESS Stream is not an Open File
1486 @return EFI_END_OF_FILE Tried to read past the end of the file
1487 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1488 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1489 @return "other" Error returned from device write
1494 IN EFI_OPEN_FILE
*File
,
1496 OUT UINTN
*BufferSize
1500 EFI_FV_WRITE_FILE_DATA FileData
;
1501 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1503 if (!FileHandleValid (File
)) {
1504 return EFI_INVALID_PARAMETER
;
1507 switch (File
->Type
) {
1508 case EfiOpenMemoryBuffer
:
1509 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1510 return EFI_END_OF_FILE
;
1513 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1514 File
->CurrentPosition
+= *BufferSize
;
1515 Status
= EFI_SUCCESS
;
1517 case EfiOpenLoadFile
:
1518 // LoadFile device is read only be definition
1519 Status
= EFI_UNSUPPORTED
;
1521 case EfiOpenFirmwareVolume
:
1522 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1523 // Writes not support to a specific section. You have to update entire file
1524 return EFI_UNSUPPORTED
;
1527 FileData
.NameGuid
= &(File
->FvNameGuid
);
1528 FileData
.Type
= File
->FvType
;
1529 FileData
.FileAttributes
= File
->FvAttributes
;
1530 FileData
.Buffer
= Buffer
;
1531 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1532 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1535 case EfiOpenFileSystem
:
1536 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1537 File
->CurrentPosition
+= *BufferSize
;
1540 case EfiOpenBlockIo
:
1541 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1542 return EFI_END_OF_FILE
;
1545 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1546 if (!EFI_ERROR(Status
)) {
1547 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1549 File
->CurrentPosition
+= *BufferSize
;
1553 // Cache the file if it hasn't been cached yet.
1554 if (File
->IsBufferValid
== FALSE
) {
1555 Status
= CacheTftpFile(File
);
1556 if (EFI_ERROR(Status
)) {
1561 // Don't overwrite the buffer
1562 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1565 TempBuffer
= File
->Buffer
;
1567 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1568 if (File
->Buffer
== NULL
) {
1569 return EFI_OUT_OF_RESOURCES
;
1572 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1574 FreePool (TempBuffer
);
1576 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1577 File
->MaxPosition
= (UINT64
)File
->Size
;
1580 // Copy in the requested data
1581 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1582 File
->CurrentPosition
+= *BufferSize
;
1584 // Mark the file dirty
1585 File
->IsDirty
= TRUE
;
1587 Status
= EFI_SUCCESS
;
1591 Status
= EFI_INVALID_PARAMETER
;
1599 Given Cwd expand Path to remove .. and replace them with real
1602 @param Cwd Current Working Directory
1603 @param Path Path to expand
1605 @return NULL Cwd or Path are not valid
1606 @return 'other' Path with .. expanded
1616 CHAR8
*Work
, *Start
, *End
;
1617 UINTN StrLen
, AllocLen
;
1620 if (Cwd
== NULL
|| Path
== NULL
) {
1624 StrLen
= AsciiStrSize (Cwd
);
1626 // Smallest valid path is 1 char and a null
1630 StrLen
= AsciiStrSize (Path
);
1631 AllocLen
= AsciiStrSize (Cwd
) + StrLen
+ 1;
1632 NewPath
= AllocatePool (AllocLen
);
1633 if (NewPath
== NULL
) {
1636 AsciiStrCpyS (NewPath
, AllocLen
, Cwd
);
1638 End
= Path
+ StrLen
;
1639 for (Start
= Path
;;) {
1640 Work
= AsciiStrStr (Start
, "..") ;
1642 // Remaining part of Path contains no more ..
1646 // append path prior to ..
1647 AsciiStrnCatS (NewPath
, AllocLen
, Start
, Work
- Start
);
1648 StrLen
= AsciiStrLen (NewPath
);
1649 for (i
= StrLen
; i
>= 0; i
--) {
1650 if (NewPath
[i
] == ':') {
1654 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1655 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1656 // leave the / before a :
1657 NewPath
[i
+1] = '\0';
1659 // replace / will Null to remove trailing file/dir reference
1669 // Handle the path that remains after the ..
1670 AsciiStrnCatS (NewPath
, AllocLen
, Start
, End
- Start
);
1677 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1678 the path does not contain a device name, The CWD is prepended to the path.
1680 @param Cwd Current Working Directory to set
1683 @return EFI_SUCCESS CWD is set
1684 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1692 EFI_OPEN_FILE
*File
;
1693 UINTN Len
, AllocLen
;
1697 return EFI_INVALID_PARAMETER
;
1700 if (AsciiStrCmp (Cwd
, ".") == 0) {
1706 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1712 Len
= AsciiStrLen (gCwd
);
1713 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1714 // parent is device so nothing to do
1718 // Expand .. in Cwd, given we know current working directory
1719 Path
= ExpandPath (gCwd
, Cwd
);
1721 return EFI_NOT_FOUND
;
1725 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1727 return EFI_INVALID_PARAMETER
;
1734 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1735 // relative to the current gCwd or not.
1736 AllocLen
= AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10;
1737 gCwd
= AllocatePool (AllocLen
);
1739 return EFI_INVALID_PARAMETER
;
1742 AsciiStrCpyS (gCwd
, AllocLen
, File
->DeviceName
);
1743 if (File
->FileName
== NULL
) {
1744 AsciiStrCatS (gCwd
, AllocLen
, ":\\");
1746 AsciiStrCatS (gCwd
, AllocLen
, ":");
1747 AsciiStrCatS (gCwd
, AllocLen
, File
->FileName
);
1760 Set the Current Working Directory (CWD). If a call is made to EfiOpen () and
1761 the path does not contain a device name, The CWD is prepended to the path.
1762 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1763 a call to EfiSetCwd() it is not legal to use the pointer returned by
1766 @param Cwd Current Working Directory
1769 @return "" No CWD set
1770 @return 'other' Returns buffer that contains CWD.