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 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_BLOCK_IO_PROTOCOL
*BlkIo
;
147 EFI_FILE_HANDLE Root
;
151 if (mBlkIo
!= NULL
) {
154 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &mBlkIoCount
, &mBlkIo
);
157 // This is a trick to trigger the gBS->ReinstallProtocolInterface () in a removable media
158 // device to make a filesystem layer on. Probing devices will detect if media has been
159 // inserted and create
161 for (Index
=0, Update
= FALSE
; Index
< mBlkIoCount
; Index
++) {
162 Status
= gBS
->HandleProtocol (mBlkIo
[Index
], &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
163 if (!EFI_ERROR (Status
)) {
164 if (BlkIo
->Media
->RemovableMedia
) {
165 gBS
->DisconnectController (mBlkIo
[Index
], NULL
, NULL
);
166 gBS
->ConnectController (mBlkIo
[Index
], NULL
, NULL
, TRUE
);
173 // In case we caused media to be detected that contains a partition (SD Card, ...) rescan
174 if (mBlkIo
!= NULL
) {
177 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiBlockIoProtocolGuid
, NULL
, &mBlkIoCount
, &mBlkIo
);
184 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiFirmwareVolume2ProtocolGuid
, NULL
, &mFvCount
, &mFv
);
186 if (mLoadFile
!= NULL
) {
187 FreePool (mLoadFile
);
189 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiLoadFileProtocolGuid
, NULL
, &mLoadFileCount
, &mLoadFile
);
195 if (&mFsInfo
[0] != NULL
) {
196 // Need to Free the mFsInfo prior to reclaculating mFsCount so don't move this code
197 for (Index
= 0; Index
< mFsCount
; Index
++) {
198 if (mFsInfo
[Index
] != NULL
) {
199 FreePool (mFsInfo
[Index
]);
205 gBS
->LocateHandleBuffer (ByProtocol
, &gEfiSimpleFileSystemProtocolGuid
, NULL
, &mFsCount
, &mFs
);
208 mFsInfo
= AllocateZeroPool (mFsCount
* sizeof (EFI_FILE_SYSTEM_INFO
*));
209 if (mFsInfo
== NULL
) {
210 // If we can't do this then we can't support file system entries
213 // Loop through all the file system structures and cache the file system info data
214 for (Index
=0; Index
< mFsCount
; Index
++) {
215 Status
= gBS
->HandleProtocol (mFs
[Index
], &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
216 if (!EFI_ERROR (Status
)) {
217 Status
= Fs
->OpenVolume (Fs
, &Root
);
218 if (!EFI_ERROR (Status
)) {
219 // Get information about the volume
221 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
222 if (Status
== EFI_BUFFER_TOO_SMALL
) {
223 mFsInfo
[Index
] = AllocatePool (Size
);
224 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, mFsInfo
[Index
]);
236 PathName is in the form <device name>:<path> for example fs1:\ or ROOT:\.
237 Return TRUE if the <devce name> prefix of PathName matches a file system
238 Volume Name. MatchIndex is the array index in mFsInfo[] of the match,
239 and it can be used with mFs[] to find the handle that needs to be opened
241 @param PathName PathName to check
242 @param FileStart Index of the first character of the <path>
243 @param MatchIndex Index in mFsInfo[] that matches
245 @return TRUE PathName matches a Volume Label and MatchIndex is valid
246 @return FALSE PathName does not match a Volume Label MatchIndex undefined
253 OUT UINTN
*MatchIndex
261 for (Index
=0; Index
< mFsCount
; Index
++) {
262 if (mFsInfo
[Index
] == NULL
) {
263 // FsInfo is not valid so skip it
266 VolStrLen
= StrLen (mFsInfo
[Index
]->VolumeLabel
);
267 for (Compare
= 0, Match
= TRUE
; Compare
< (FileStart
- 1); Compare
++) {
268 if (Compare
> VolStrLen
) {
272 if (PathName
[Compare
] != (CHAR8
)mFsInfo
[Index
]->VolumeLabel
[Compare
]) {
273 // If the VolumeLabel has a space allow a _ to match with it in addition to ' '
274 if (!((PathName
[Compare
] == '_') && (mFsInfo
[Index
]->VolumeLabel
[Compare
] == L
' '))) {
291 Return the number of devices of the current type active in the system
293 @param Type Device type to check
295 @return 0 Invalid type
300 IN EFI_OPEN_FILE_TYPE DeviceType
303 switch (DeviceType
) {
304 case EfiOpenLoadFile
:
305 return mLoadFileCount
;
306 case EfiOpenFirmwareVolume
:
308 case EfiOpenFileSystem
:
318 ConvertIpStringToEfiIp (
320 OUT EFI_IP_ADDRESS
*ServerIp
326 ServerIp
->v4
.Addr
[0] = (UINT8
)AsciiStrDecimalToUintn (Str
);
328 Str
= AsciiStrStr (Str
, ".");
330 return EFI_DEVICE_ERROR
;
333 ServerIp
->v4
.Addr
[1] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
335 Str
= AsciiStrStr (Str
, ".");
337 return EFI_DEVICE_ERROR
;
340 ServerIp
->v4
.Addr
[2] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
342 Str
= AsciiStrStr (Str
, ".");
344 return EFI_DEVICE_ERROR
;
347 ServerIp
->v4
.Addr
[3] = (UINT8
)AsciiStrDecimalToUintn (++Str
);
354 Internal work function to extract a device number from a string skipping
355 text. Easy way to extract numbers from strings like blk7:.
357 @param Str String to extract device number form
359 @return -1 Device string is not valid
364 EblConvertDevStringToNumber (
372 // Find the first digit
373 Max
= AsciiStrLen (Str
);
374 for (Index
= 0; !((*Str
>= '0') && (*Str
<= '9')) && (Index
< Max
); Index
++) {
381 return AsciiStrDecimalToUintn (Str
);
386 Internal work function to fill in EFI_OPEN_FILE information for the Fs and BlkIo
388 @param File Open file handle
389 @param FileName Name of file after device stripped off
395 IN OUT EFI_OPEN_FILE
*File
,
397 IN CONST UINT64 OpenMode
402 FILEPATH_DEVICE_PATH
*FilePath
;
403 EFI_DEVICE_PATH_PROTOCOL
*FileDevicePath
;
404 CHAR16 UnicodeFileName
[MAX_PATHNAME
];
405 EFI_BLOCK_IO_PROTOCOL
*BlkIo
;
406 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*Fs
;
407 EFI_FILE_HANDLE Root
;
410 if ( *FileName
!= 0 ) {
411 AsciiStrToUnicodeStr (FileName
, UnicodeFileName
);
413 AsciiStrToUnicodeStr ("\\", UnicodeFileName
);
416 Size
= StrSize (UnicodeFileName
);
417 FileDevicePath
= AllocatePool (Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
+ sizeof (EFI_DEVICE_PATH_PROTOCOL
));
418 if (FileDevicePath
!= NULL
) {
419 FilePath
= (FILEPATH_DEVICE_PATH
*) FileDevicePath
;
420 FilePath
->Header
.Type
= MEDIA_DEVICE_PATH
;
421 FilePath
->Header
.SubType
= MEDIA_FILEPATH_DP
;
422 CopyMem (&FilePath
->PathName
, UnicodeFileName
, Size
);
423 SetDevicePathNodeLength (&FilePath
->Header
, Size
+ SIZE_OF_FILEPATH_DEVICE_PATH
);
424 SetDevicePathEndNode (NextDevicePathNode (&FilePath
->Header
));
426 if (File
->EfiHandle
!= NULL
) {
427 File
->DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
430 File
->DevicePath
= AppendDevicePath (File
->DevicePath
, FileDevicePath
);
431 FreePool (FileDevicePath
);
434 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiBlockIoProtocolGuid
, (VOID
**)&BlkIo
);
435 if (!EFI_ERROR (Status
)) {
436 File
->FsBlockIoMedia
= BlkIo
->Media
;
438 // If we are not opening the device this will get over written with file info
439 File
->MaxPosition
= MultU64x32 (BlkIo
->Media
->LastBlock
+ 1, BlkIo
->Media
->BlockSize
);
442 if (File
->Type
== EfiOpenFileSystem
) {
443 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiSimpleFileSystemProtocolGuid
, (VOID
**)&Fs
);
444 if (!EFI_ERROR (Status
)) {
445 Status
= Fs
->OpenVolume (Fs
, &Root
);
446 if (!EFI_ERROR (Status
)) {
447 // Get information about the volume
449 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
450 if (Status
== EFI_BUFFER_TOO_SMALL
) {
451 File
->FsInfo
= AllocatePool (Size
);
452 Status
= Root
->GetInfo (Root
, &gEfiFileSystemInfoGuid
, &Size
, File
->FsInfo
);
455 // Get information about the file
456 Status
= Root
->Open (Root
, &File
->FsFileHandle
, UnicodeFileName
, OpenMode
, 0);
457 if (!EFI_ERROR (Status
)) {
459 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, NULL
);
460 if (Status
== EFI_BUFFER_TOO_SMALL
) {
461 File
->FsFileInfo
= AllocatePool (Size
);
462 Status
= File
->FsFileHandle
->GetInfo (File
->FsFileHandle
, &gEfiFileInfoGuid
, &Size
, File
->FsFileInfo
);
463 if (!EFI_ERROR (Status
)) {
464 File
->Size
= (UINTN
)File
->FsFileInfo
->FileSize
;
465 File
->MaxPosition
= (UINT64
)File
->Size
;
473 } else if (File
->Type
== EfiOpenBlockIo
) {
474 File
->Size
= (UINTN
)File
->MaxPosition
;
480 #define ToUpper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
483 CompareGuidToString (
492 AsciiSPrint (AsciiGuid
, sizeof(AsciiGuid
), "%g", Guid
);
497 while ((*StringPtr
!= '\0') && (*GuidPtr
!= '\0')) {
499 if (*StringPtr
== '-') {
504 if (*GuidPtr
== '-') {
509 if (ToUpper(*StringPtr
) != ToUpper(*GuidPtr
)) {
510 return EFI_NOT_FOUND
;
522 Internal work function to fill in EFI_OPEN_FILE information for the FV
524 @param File Open file handle
525 @param FileName Name of file after device stripped off
530 EblFvFileDevicePath (
531 IN OUT EFI_OPEN_FILE
*File
,
533 IN CONST UINT64 OpenMode
537 EFI_STATUS GetNextFileStatus
;
538 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH DevicePathNode
;
539 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
541 UINT32 AuthenticationStatus
;
542 CHAR8 AsciiSection
[MAX_PATHNAME
];
545 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
548 UINTN NumberOfBlocks
;
549 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
= NULL
;
553 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&File
->Fv
);
554 if (EFI_ERROR (Status
)) {
558 // Get FVB Info about the handle
559 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
560 if (!EFI_ERROR (Status
)) {
561 Status
= Fvb
->GetPhysicalAddress (Fvb
, &File
->FvStart
);
562 if (!EFI_ERROR (Status
)) {
563 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)File
->FvStart
;
564 File
->FvHeaderSize
= sizeof (EFI_FIRMWARE_VOLUME_HEADER
);
565 for (Index
= 0; FvHeader
->BlockMap
[Index
].Length
!=0; Index
++) {
566 File
->FvHeaderSize
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
569 for (Lba
= 0, File
->FvSize
= 0, NumberOfBlocks
= 0; ; File
->FvSize
+= (BlockSize
* NumberOfBlocks
), Lba
+= NumberOfBlocks
) {
570 Status
= Fvb
->GetBlockSize (Fvb
, Lba
, &BlockSize
, &NumberOfBlocks
);
571 if (EFI_ERROR (Status
)) {
579 DevicePath
= DevicePathFromHandle (File
->EfiHandle
);
581 if (*FileName
== '\0') {
582 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
583 File
->Size
= File
->FvSize
;
584 File
->MaxPosition
= File
->Size
;
588 File
->FvType
= EFI_FV_FILETYPE_ALL
;
589 GetNextFileStatus
= File
->Fv
->GetNextFile (
597 if (!EFI_ERROR (GetNextFileStatus
)) {
598 // Compare GUID first
599 Status
= CompareGuidToString (&File
->FvNameGuid
, FileName
);
600 if (!EFI_ERROR(Status
)) {
605 Status
= File
->Fv
->ReadSection (
608 EFI_SECTION_USER_INTERFACE
,
612 &AuthenticationStatus
614 if (!EFI_ERROR (Status
)) {
615 UnicodeStrToAsciiStr (Section
, AsciiSection
);
616 if (AsciiStriCmp (FileName
, AsciiSection
) == 0) {
623 } while (!EFI_ERROR (GetNextFileStatus
));
625 if (EFI_ERROR (GetNextFileStatus
)) {
626 return GetNextFileStatus
;
629 if (OpenMode
!= EFI_SECTION_ALL
) {
630 // Calculate the size of the section we are targeting
633 Status
= File
->Fv
->ReadSection (
636 (EFI_SECTION_TYPE
)OpenMode
,
640 &AuthenticationStatus
642 if (EFI_ERROR (Status
)) {
647 File
->MaxPosition
= File
->Size
;
648 EfiInitializeFwVolDevicepathNode (&DevicePathNode
, &File
->FvNameGuid
);
649 File
->DevicePath
= AppendDevicePathNode (DevicePath
, (EFI_DEVICE_PATH_PROTOCOL
*)&DevicePathNode
);
653 // FVB not required if FV was soft loaded...
661 Open a device named by PathName. The PathName includes a device name and
662 path seperated by a :. See file header for more details on the PathName
663 syntax. There is no checking to prevent a file from being opened more than
666 SectionType is only used to open an FV. Each file in an FV contains multiple
667 secitons and only the SectionType section is opened.
669 For any file that is opened with EfiOpen() must be closed with EfiClose().
671 @param PathName Path to parse to open
672 @param OpenMode Same as EFI_FILE.Open()
673 @param SectionType Section in FV to open.
675 @return NULL Open failed
676 @return Valid EFI_OPEN_FILE handle
682 IN CONST UINT64 OpenMode
,
683 IN CONST EFI_SECTION_TYPE SectionType
688 EFI_OPEN_FILE FileData
;
692 EFI_OPEN_FILE_GUARD
*GuardFile
;
693 BOOLEAN VolumeNameMatch
;
694 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
697 CHAR8
*CwdPlusPathName
;
699 EFI_SECTION_TYPE ModifiedSectionType
;
701 EblUpdateDeviceLists ();
704 ZeroMem (File
, sizeof (EFI_OPEN_FILE
));
706 StrLen
= AsciiStrSize (PathName
);
708 // Smallest valid path is 1 char and a null
712 for (FileStart
= 0; FileStart
< StrLen
; FileStart
++) {
713 if (PathName
[FileStart
] == ':') {
720 // Matching volume name has precedence over handle based names
722 VolumeNameMatch
= EblMatchVolumeName (PathName
, FileStart
, &DevNumber
);
723 if (!VolumeNameMatch
) {
724 if (FileStart
== StrLen
) {
725 // No Volume name or device name, so try Current Working Directory
731 // We could add a current working diretory concept
732 CwdPlusPathName
= AllocatePool (AsciiStrSize (gCwd
) + AsciiStrSize (PathName
));
733 if (CwdPlusPathName
== NULL
) {
737 if ((PathName
[0] == '/') || (PathName
[0] == '\\')) {
738 // PathName starts in / so this means we go to the root of the device in the CWD.
739 CwdPlusPathName
[0] = '\0';
740 for (FileStart
= 0; gCwd
[FileStart
] != '\0'; FileStart
++) {
741 CwdPlusPathName
[FileStart
] = gCwd
[FileStart
];
742 if (gCwd
[FileStart
] == ':') {
744 CwdPlusPathName
[FileStart
] = '\0';
749 AsciiStrCpy (CwdPlusPathName
, gCwd
);
750 StrLen
= AsciiStrLen (gCwd
);
751 if ((*PathName
!= '/') && (*PathName
!= '\\') && (gCwd
[StrLen
-1] != '/') && (gCwd
[StrLen
-1] != '\\')) {
752 AsciiStrCat (CwdPlusPathName
, "\\");
756 AsciiStrCat (CwdPlusPathName
, PathName
);
757 if (AsciiStrStr (CwdPlusPathName
, ":") == NULL
) {
758 // Extra error check to make sure we don't recusre and blow stack
762 File
= EfiOpen (CwdPlusPathName
, OpenMode
, SectionType
);
763 FreePool (CwdPlusPathName
);
767 DevNumber
= EblConvertDevStringToNumber ((CHAR8
*)PathName
);
770 File
->DeviceName
= AllocatePool (StrLen
);
771 AsciiStrCpy (File
->DeviceName
, PathName
);
772 File
->DeviceName
[FileStart
- 1] = '\0';
773 File
->FileName
= &File
->DeviceName
[FileStart
];
774 if (File
->FileName
[0] == '\0') {
775 // if it is just a file name use / as root
776 File
->FileName
= "\\";
780 // Use best match algorithm on the dev names so we only need to look at the
781 // first few charters to match the full device name. Short name forms are
782 // legal from the caller.
784 Status
= EFI_SUCCESS
;
785 if (*PathName
== 'f' || *PathName
== 'F' || VolumeNameMatch
) {
786 if (PathName
[1] == 's' || PathName
[1] == 'S' || VolumeNameMatch
) {
787 if (DevNumber
>= mFsCount
) {
790 File
->Type
= EfiOpenFileSystem
;
791 File
->EfiHandle
= mFs
[DevNumber
];
792 Status
= EblFileDevicePath (File
, &PathName
[FileStart
], OpenMode
);
794 } else if (PathName
[1] == 'v' || PathName
[1] == 'V') {
795 if (DevNumber
>= mFvCount
) {
798 File
->Type
= EfiOpenFirmwareVolume
;
799 File
->EfiHandle
= mFv
[DevNumber
];
801 if ((PathName
[FileStart
] == '/') || (PathName
[FileStart
] == '\\')) {
802 // Skip leading / as its not really needed for the FV since no directories are supported
807 ModifiedSectionType
= SectionType
;
808 for (Index
= FileStart
; PathName
[Index
] != '\0'; Index
++) {
809 if (PathName
[Index
] == ':') {
810 // Support fv0:\DxeCore:0x10
811 // This means open the PE32 Section of the file
812 ModifiedSectionType
= (EFI_SECTION_TYPE
)AsciiStrHexToUintn (&PathName
[Index
+ 1]);
813 PathName
[Index
] = '\0';
816 File
->FvSectionType
= ModifiedSectionType
;
817 Status
= EblFvFileDevicePath (File
, &PathName
[FileStart
], ModifiedSectionType
);
819 } else if ((*PathName
== 'A') || (*PathName
== 'a')) {
820 // Handle a:0x10000000:0x1234 address form a:ADDRESS:SIZE
821 File
->Type
= EfiOpenMemoryBuffer
;
822 // 1st colon is at PathName[FileStart - 1]
823 File
->Buffer
= (VOID
*)AsciiStrHexToUintn (&PathName
[FileStart
]);
826 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
830 // If we ran out of string, there's no extra data
831 if (PathName
[FileStart
] == '\0') {
834 File
->Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
837 // if there's no number after the second colon, default
839 if (File
->Size
== 0) {
840 File
->Size
= (UINTN
)(0 - (UINTN
)File
->Buffer
);
843 File
->MaxPosition
= File
->Size
;
844 File
->BaseOffset
= (UINTN
)File
->Buffer
;
846 } else if (*PathName
== 'l' || *PathName
== 'L') {
847 if (DevNumber
>= mLoadFileCount
) {
850 File
->Type
= EfiOpenLoadFile
;
851 File
->EfiHandle
= mLoadFile
[DevNumber
];
853 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiLoadFileProtocolGuid
, (VOID
**)&File
->LoadFile
);
854 if (EFI_ERROR (Status
)) {
858 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&DevicePath
);
859 if (EFI_ERROR (Status
)) {
862 File
->DevicePath
= DuplicateDevicePath (DevicePath
);
864 } else if (*PathName
== 'b' || *PathName
== 'B') {
865 // Handle b#:0x10000000:0x1234 address form b#:ADDRESS:SIZE
866 if (DevNumber
>= mBlkIoCount
) {
869 File
->Type
= EfiOpenBlockIo
;
870 File
->EfiHandle
= mBlkIo
[DevNumber
];
871 EblFileDevicePath (File
, "", OpenMode
);
873 // 1st colon is at PathName[FileStart - 1]
874 File
->DiskOffset
= AsciiStrHexToUintn (&PathName
[FileStart
]);
877 while ((PathName
[FileStart
] != ':') && (PathName
[FileStart
] != '\0')) {
881 // If we ran out of string, there's no extra data
882 if (PathName
[FileStart
] == '\0') {
885 Size
= AsciiStrHexToUintn (&PathName
[FileStart
+ 1]);
888 // if a zero size is passed in (or the size is left out entirely),
889 // go to the end of the device.
891 File
->Size
= File
->Size
- File
->DiskOffset
;
896 File
->MaxPosition
= File
->Size
;
897 File
->BaseOffset
= File
->DiskOffset
;
898 } else if ((*PathName
) >= '0' && (*PathName
<= '9')) {
900 // Get current IP address
901 Status
= EblGetCurrentIpAddress (&Ip
);
902 if (EFI_ERROR(Status
)) {
903 AsciiPrint("Device IP Address is not configured.\n");
908 // Parse X.X.X.X:Filename, only support IPv4 TFTP for now...
909 File
->Type
= EfiOpenTftp
;
910 File
->IsDirty
= FALSE
;
911 File
->IsBufferValid
= FALSE
;
913 Status
= ConvertIpStringToEfiIp (PathName
, &File
->ServerIp
);
916 if (EFI_ERROR (Status
)) {
920 GuardFile
= (EFI_OPEN_FILE_GUARD
*)AllocateZeroPool (sizeof (EFI_OPEN_FILE_GUARD
));
921 if (GuardFile
== NULL
) {
925 GuardFile
->Header
= EFI_OPEN_FILE_GUARD_HEADER
;
926 CopyMem (&(GuardFile
->File
), &FileData
, sizeof (EFI_OPEN_FILE
));
927 GuardFile
->Footer
= EFI_OPEN_FILE_GUARD_FOOTER
;
929 return &(GuardFile
->File
);
932 FreePool (File
->DeviceName
);
936 #define FILE_COPY_CHUNK 0x01000000
940 IN CHAR8
*DestinationFile
,
944 EFI_OPEN_FILE
*Source
= NULL
;
945 EFI_OPEN_FILE
*Destination
= NULL
;
946 EFI_STATUS Status
= EFI_SUCCESS
;
950 UINTN Chunk
= FILE_COPY_CHUNK
;
952 Source
= EfiOpen (SourceFile
, EFI_FILE_MODE_READ
, 0);
953 if (Source
== NULL
) {
954 AsciiPrint("Source file open error.\n");
955 Status
= EFI_NOT_FOUND
;
959 Destination
= EfiOpen (DestinationFile
, EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0);
960 if (Destination
== NULL
) {
961 AsciiPrint("Destination file open error.\n");
962 Status
= EFI_NOT_FOUND
;
966 Buffer
= AllocatePool(FILE_COPY_CHUNK
);
967 if (Buffer
== NULL
) {
968 Status
= EFI_OUT_OF_RESOURCES
;
972 Size
= EfiTell(Source
, NULL
);
974 for (Offset
= 0; Offset
+ FILE_COPY_CHUNK
<= Size
; Offset
+= Chunk
) {
975 Chunk
= FILE_COPY_CHUNK
;
977 Status
= EfiRead(Source
, Buffer
, &Chunk
);
978 if (EFI_ERROR(Status
)) {
979 AsciiPrint("Read file error\n");
983 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
984 if (EFI_ERROR(Status
)) {
985 AsciiPrint("Write file error\n");
992 Chunk
= Size
- Offset
;
994 Status
= EfiRead(Source
, Buffer
, &Chunk
);
995 if (EFI_ERROR(Status
)) {
996 AsciiPrint("Read file error\n");
1000 Status
= EfiWrite(Destination
, Buffer
, &Chunk
);
1001 if (EFI_ERROR(Status
)) {
1002 AsciiPrint("Write file error\n");
1008 if (Source
!= NULL
) {
1009 Status
= EfiClose(Source
);
1010 if (EFI_ERROR(Status
)) {
1011 AsciiPrint("Source close error");
1015 if (Destination
!= NULL
) {
1016 Status
= EfiClose(Destination
);
1017 if (EFI_ERROR(Status
)) {
1018 AsciiPrint("Destination close error");
1022 if (Buffer
!= NULL
) {
1030 Use DeviceType and Index to form a valid PathName and try and open it.
1032 @param DeviceType Device type to open
1033 @param Index Device Index to use. Zero relative.
1035 @return NULL Open failed
1036 @return Valid EFI_OPEN_FILE handle
1040 EfiDeviceOpenByType (
1041 IN EFI_OPEN_FILE_TYPE DeviceType
,
1046 CHAR8 Path
[MAX_CMD_LINE
];
1048 switch (DeviceType
) {
1049 case EfiOpenLoadFile
:
1050 DevStr
= "loadfile%d:";
1052 case EfiOpenFirmwareVolume
:
1055 case EfiOpenFileSystem
:
1058 case EfiOpenBlockIo
:
1061 case EfiOpenMemoryBuffer
:
1068 AsciiSPrint (Path
, MAX_PATHNAME
, DevStr
, Index
);
1070 return EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1075 Close a file handle opened by EfiOpen() and free all resources allocated by
1078 @param Stream Open File Handle
1080 @return EFI_INVALID_PARAMETER Stream is not an Open File
1081 @return EFI_SUCCESS Steam closed
1086 IN EFI_OPEN_FILE
*File
1090 UINT64 TftpBufferSize
;
1092 if (!FileHandleValid (File
)) {
1093 return EFI_INVALID_PARAMETER
;
1096 //Write the buffer contents to TFTP file.
1097 if ((File
->Type
== EfiOpenTftp
) && (File
->IsDirty
)) {
1099 TftpBufferSize
= File
->Size
;
1101 EFI_PXE_BASE_CODE_TFTP_WRITE_FILE
,
1107 (UINT8
*)File
->FileName
,
1111 if (EFI_ERROR(Status
)) {
1112 AsciiPrint("TFTP error during APPLE_NSP_TFTP_WRITE_FILE: %r\n", Status
);
1117 if ((File
->Type
== EfiOpenLoadFile
) ||
1118 ((File
->Type
== EfiOpenTftp
) && (File
->IsBufferValid
== TRUE
)) ||
1119 ((File
->Type
== EfiOpenFirmwareVolume
) && (File
->IsBufferValid
== TRUE
))) {
1120 EblFreePool(File
->Buffer
);
1123 EblFreePool (File
->DevicePath
);
1124 EblFreePool (File
->DeviceName
);
1125 EblFreePool (File
->FsFileInfo
);
1126 EblFreePool (File
->FsInfo
);
1128 if (File
->FsFileHandle
!= NULL
) {
1129 File
->FsFileHandle
->Close (File
->FsFileHandle
);
1132 // Need to free File and it's Guard structures
1133 EblFreePool (BASE_CR (File
, EFI_OPEN_FILE_GUARD
, File
));
1139 Return the size of the file represented by Stream. Also return the current
1140 Seek position. Opening a file will enable a valid file size to be returned.
1141 LoadFile is an exception as a load file size is set to zero.
1143 @param Stream Open File Handle
1145 @return 0 Stream is not an Open File or a valid LoadFile handle
1150 IN EFI_OPEN_FILE
*File
,
1151 OUT EFI_LBA
*CurrentPosition OPTIONAL
1155 UINT64 BufferSize
= 0;
1157 if (!FileHandleValid (File
)) {
1161 if (CurrentPosition
!= NULL
) {
1162 *CurrentPosition
= File
->CurrentPosition
;
1165 if (File
->Type
== EfiOpenLoadFile
) {
1166 // Figure out the File->Size
1167 File
->Buffer
= NULL
;
1169 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, &File
->Size
, File
->Buffer
);
1170 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
1174 File
->MaxPosition
= (UINT64
)File
->Size
;
1175 } else if (File
->Type
== EfiOpenTftp
) {
1178 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE
,
1184 (UINT8
*)File
->FileName
,
1188 if (EFI_ERROR(Status
)) {
1189 AsciiPrint("TFTP error during APPLE_NSP_TFTP_GET_FILE_SIZE: %r\n", Status
);
1193 File
->Size
= (UINTN
)BufferSize
;
1194 File
->MaxPosition
= File
->Size
;
1202 Seek to the Offset locaiton in the file. LoadFile and FV device types do
1203 not support EfiSeek(). It is not possible to grow the file size using
1206 SeekType defines how use Offset to calculate the new file position:
1207 EfiSeekStart : Position = Offset
1208 EfiSeekCurrent: Position is Offset bytes from the current position
1209 EfiSeekEnd : Only supported if Offset is zero to seek to end of file.
1211 @param Stream Open File Handle
1212 @param Offset Offset to seek too.
1213 @param SeekType Type of seek to perform
1216 @return EFI_INVALID_PARAMETER Stream is not an Open File
1217 @return EFI_UNSUPPORTED LoadFile and FV doe not support Seek
1218 @return EFI_NOT_FOUND Seek past the end of the file.
1219 @return EFI_SUCCESS Steam closed
1224 IN EFI_OPEN_FILE
*File
,
1226 IN EFI_SEEK_TYPE SeekType
1230 UINT64 CurrentPosition
;
1232 if (!FileHandleValid (File
)) {
1233 return EFI_INVALID_PARAMETER
;
1236 if (File
->Type
== EfiOpenLoadFile
) {
1237 // LoadFile does not support Seek
1238 return EFI_UNSUPPORTED
;
1241 CurrentPosition
= File
->CurrentPosition
;
1244 if (Offset
> File
->MaxPosition
) {
1245 return EFI_NOT_FOUND
;
1247 CurrentPosition
= Offset
;
1250 case EfiSeekCurrent
:
1251 if ((File
->CurrentPosition
+ Offset
) > File
->MaxPosition
) {
1252 return EFI_NOT_FOUND
;
1254 CurrentPosition
+= Offset
;
1259 // We don't support growing file size via seeking past end of file
1260 return EFI_UNSUPPORTED
;
1262 CurrentPosition
= File
->MaxPosition
;
1266 return EFI_NOT_FOUND
;
1269 Status
= EFI_SUCCESS
;
1270 if (File
->FsFileHandle
!= NULL
) {
1271 Status
= File
->FsFileHandle
->SetPosition (File
->FsFileHandle
, CurrentPosition
);
1274 if (!EFI_ERROR (Status
)) {
1275 File
->CurrentPosition
= CurrentPosition
;
1283 IN OUT EFI_OPEN_FILE
*File
1287 UINT64 TftpBufferSize
;
1289 if (File
->IsBufferValid
) {
1293 // Make sure the file size is set.
1294 EfiTell (File
, NULL
);
1296 //Allocate a buffer to hold the whole file.
1297 File
->Buffer
= AllocatePool(File
->Size
);
1298 if (File
->Buffer
== NULL
) {
1299 return EFI_OUT_OF_RESOURCES
;
1302 TftpBufferSize
= File
->Size
;
1305 EFI_PXE_BASE_CODE_TFTP_READ_FILE
,
1311 (UINT8
*)File
->FileName
,
1314 if (EFI_ERROR(Status
)) {
1315 AsciiPrint("TFTP error during APPLE_NSP_TFTP_READ_FILE: %r\n", Status
);
1316 FreePool(File
->Buffer
);
1320 // Set the buffer valid flag.
1321 File
->IsBufferValid
= TRUE
;
1327 Read BufferSize bytes from the current locaiton in the file. For load file,
1328 FV, and TFTP case you must read the entire file.
1330 @param Stream Open File Handle
1331 @param Buffer Caller allocated buffer.
1332 @param BufferSize Size of buffer in bytes.
1335 @return EFI_SUCCESS Stream is not an Open File
1336 @return EFI_END_OF_FILE Tried to read past the end of the file
1337 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1338 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1339 @return "other" Error returned from device read
1344 IN EFI_OPEN_FILE
*File
,
1346 OUT UINTN
*BufferSize
1350 UINT32 AuthenticationStatus
;
1351 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1353 if (!FileHandleValid (File
)) {
1354 return EFI_INVALID_PARAMETER
;
1357 // Don't read past the end of the file.
1358 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1359 return EFI_END_OF_FILE
;
1362 switch (File
->Type
) {
1363 case EfiOpenLoadFile
:
1364 // Figure out the File->Size
1365 EfiTell (File
, NULL
);
1367 Status
= File
->LoadFile
->LoadFile (File
->LoadFile
, File
->DevicePath
, FALSE
, BufferSize
, Buffer
);
1370 case EfiOpenFirmwareVolume
:
1371 if (CompareGuid (&File
->FvNameGuid
, &gZeroGuid
)) {
1372 // This is the entire FV device, so treat like a memory buffer
1373 CopyMem (Buffer
, (VOID
*)(UINTN
)(File
->FvStart
+ File
->CurrentPosition
), *BufferSize
);
1374 File
->CurrentPosition
+= *BufferSize
;
1375 Status
= EFI_SUCCESS
;
1377 if (File
->Buffer
== NULL
) {
1378 if (File
->FvSectionType
== EFI_SECTION_ALL
) {
1379 Status
= File
->Fv
->ReadFile (
1382 (VOID
**)&File
->Buffer
,
1385 &File
->FvAttributes
,
1386 &AuthenticationStatus
1389 Status
= File
->Fv
->ReadSection (
1392 File
->FvSectionType
,
1394 (VOID
**)&File
->Buffer
,
1396 &AuthenticationStatus
1399 if (EFI_ERROR (Status
)) {
1402 File
->IsBufferValid
= TRUE
;
1404 // Operate on the cached buffer so Seek will work
1405 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1406 File
->CurrentPosition
+= *BufferSize
;
1407 Status
= EFI_SUCCESS
;
1411 case EfiOpenMemoryBuffer
:
1412 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1413 File
->CurrentPosition
+= *BufferSize
;
1414 Status
= EFI_SUCCESS
;
1417 case EfiOpenFileSystem
:
1418 Status
= File
->FsFileHandle
->Read (File
->FsFileHandle
, BufferSize
, Buffer
);
1419 File
->CurrentPosition
+= *BufferSize
;
1422 case EfiOpenBlockIo
:
1423 Status
= gBS
->HandleProtocol(File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1424 if (!EFI_ERROR(Status
)) {
1425 Status
= DiskIo
->ReadDisk(DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1427 File
->CurrentPosition
+= *BufferSize
;
1431 // Cache the file if it hasn't been cached yet.
1432 if (File
->IsBufferValid
== FALSE
) {
1433 Status
= CacheTftpFile (File
);
1434 if (EFI_ERROR (Status
)) {
1439 // Copy out the requested data
1440 CopyMem (Buffer
, File
->Buffer
+ File
->CurrentPosition
, *BufferSize
);
1441 File
->CurrentPosition
+= *BufferSize
;
1443 Status
= EFI_SUCCESS
;
1447 return EFI_INVALID_PARAMETER
;
1455 Read the entire file into a buffer. This routine allocates the buffer and
1456 returns it to the user full of the read data.
1458 This is very useful for load flie where it's hard to know how big the buffer
1461 @param Stream Open File Handle
1462 @param Buffer Pointer to buffer to return.
1463 @param BufferSize Pointer to Size of buffer return..
1466 @return EFI_SUCCESS Stream is not an Open File
1467 @return EFI_END_OF_FILE Tried to read past the end of the file
1468 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1469 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1470 @return "other" Error returned from device read
1474 EfiReadAllocatePool (
1475 IN EFI_OPEN_FILE
*File
,
1477 OUT UINTN
*BufferSize
1480 if (!FileHandleValid (File
)) {
1481 return EFI_INVALID_PARAMETER
;
1484 // Loadfile defers file size determination on Open so use tell to find it
1485 EfiTell (File
, NULL
);
1487 *BufferSize
= File
->Size
;
1488 *Buffer
= AllocatePool (*BufferSize
);
1489 if (*Buffer
== NULL
) {
1490 return EFI_NOT_FOUND
;
1493 return EfiRead (File
, *Buffer
, BufferSize
);
1498 Write data back to the file. For TFTP case you must write the entire file.
1500 @param Stream Open File Handle
1501 @param Buffer Pointer to buffer to return.
1502 @param BufferSize Pointer to Size of buffer return..
1505 @return EFI_SUCCESS Stream is not an Open File
1506 @return EFI_END_OF_FILE Tried to read past the end of the file
1507 @return EFI_INVALID_PARAMETER Stream is not an open file handle
1508 @return EFI_BUFFER_TOO_SMALL Buffer is not big enough to do the read
1509 @return "other" Error returned from device write
1514 IN EFI_OPEN_FILE
*File
,
1516 OUT UINTN
*BufferSize
1520 EFI_FV_WRITE_FILE_DATA FileData
;
1521 EFI_DISK_IO_PROTOCOL
*DiskIo
;
1523 if (!FileHandleValid (File
)) {
1524 return EFI_INVALID_PARAMETER
;
1527 switch (File
->Type
) {
1528 case EfiOpenMemoryBuffer
:
1529 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1530 return EFI_END_OF_FILE
;
1533 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1534 File
->CurrentPosition
+= *BufferSize
;
1535 Status
= EFI_SUCCESS
;
1537 case EfiOpenLoadFile
:
1538 // LoadFile device is read only be definition
1539 Status
= EFI_UNSUPPORTED
;
1541 case EfiOpenFirmwareVolume
:
1542 if (File
->FvSectionType
!= EFI_SECTION_ALL
) {
1543 // Writes not support to a specific section. You have to update entire file
1544 return EFI_UNSUPPORTED
;
1547 FileData
.NameGuid
= &(File
->FvNameGuid
);
1548 FileData
.Type
= File
->FvType
;
1549 FileData
.FileAttributes
= File
->FvAttributes
;
1550 FileData
.Buffer
= Buffer
;
1551 FileData
.BufferSize
= (UINT32
)*BufferSize
;
1552 Status
= File
->Fv
->WriteFile (File
->Fv
, 1, EFI_FV_UNRELIABLE_WRITE
, &FileData
);
1555 case EfiOpenFileSystem
:
1556 Status
= File
->FsFileHandle
->Write (File
->FsFileHandle
, BufferSize
, Buffer
);
1557 File
->CurrentPosition
+= *BufferSize
;
1560 case EfiOpenBlockIo
:
1561 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1562 return EFI_END_OF_FILE
;
1565 Status
= gBS
->HandleProtocol (File
->EfiHandle
, &gEfiDiskIoProtocolGuid
, (VOID
**)&DiskIo
);
1566 if (!EFI_ERROR(Status
)) {
1567 Status
= DiskIo
->WriteDisk (DiskIo
, File
->FsBlockIoMedia
->MediaId
, File
->DiskOffset
+ File
->CurrentPosition
, *BufferSize
, Buffer
);
1569 File
->CurrentPosition
+= *BufferSize
;
1573 // Cache the file if it hasn't been cached yet.
1574 if (File
->IsBufferValid
== FALSE
) {
1575 Status
= CacheTftpFile(File
);
1576 if (EFI_ERROR(Status
)) {
1581 // Don't overwrite the buffer
1582 if ((File
->CurrentPosition
+ *BufferSize
) > File
->MaxPosition
) {
1585 TempBuffer
= File
->Buffer
;
1587 File
->Buffer
= AllocatePool ((UINTN
)(File
->CurrentPosition
+ *BufferSize
));
1588 if (File
->Buffer
== NULL
) {
1589 return EFI_OUT_OF_RESOURCES
;
1592 CopyMem (File
->Buffer
, TempBuffer
, File
->Size
);
1594 FreePool (TempBuffer
);
1596 File
->Size
= (UINTN
)(File
->CurrentPosition
+ *BufferSize
);
1597 File
->MaxPosition
= (UINT64
)File
->Size
;
1600 // Copy in the requested data
1601 CopyMem (File
->Buffer
+ File
->CurrentPosition
, Buffer
, *BufferSize
);
1602 File
->CurrentPosition
+= *BufferSize
;
1604 // Mark the file dirty
1605 File
->IsDirty
= TRUE
;
1607 Status
= EFI_SUCCESS
;
1611 Status
= EFI_INVALID_PARAMETER
;
1619 Given Cwd expand Path to remove .. and replace them with real
1622 @param Cwd Current Working Directory
1623 @param Path Path to expand
1625 @return NULL Cwd or Path are not valid
1626 @return 'other' Path with .. expanded
1636 CHAR8
*Work
, *Start
, *End
;
1640 if (Cwd
== NULL
|| Path
== NULL
) {
1644 StrLen
= AsciiStrSize (Cwd
);
1646 // Smallest valid path is 1 char and a null
1650 StrLen
= AsciiStrSize (Path
);
1651 NewPath
= AllocatePool (AsciiStrSize (Cwd
) + StrLen
+ 1);
1652 if (NewPath
== NULL
) {
1655 AsciiStrCpy (NewPath
, Cwd
);
1657 End
= Path
+ StrLen
;
1658 for (Start
= Path
;;) {
1659 Work
= AsciiStrStr (Start
, "..") ;
1661 // Remaining part of Path contains no more ..
1665 // append path prior to ..
1666 AsciiStrnCat (NewPath
, Start
, Work
- Start
);
1667 StrLen
= AsciiStrLen (NewPath
);
1668 for (i
= StrLen
; i
>= 0; i
--) {
1669 if (NewPath
[i
] == ':') {
1673 if (NewPath
[i
] == '/' || NewPath
[i
] == '\\') {
1674 if ((i
> 0) && (NewPath
[i
-1] == ':')) {
1675 // leave the / before a :
1676 NewPath
[i
+1] = '\0';
1678 // replace / will Null to remove trailing file/dir reference
1688 // Handle the path that remains after the ..
1689 AsciiStrnCat (NewPath
, Start
, End
- Start
);
1696 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1697 the path does not contain a device name, The CWD is prepended to the path.
1699 @param Cwd Current Working Directory to set
1702 @return EFI_SUCCESS CWD is set
1703 @return EFI_INVALID_PARAMETER Cwd is not a valid device:path
1711 EFI_OPEN_FILE
*File
;
1716 return EFI_INVALID_PARAMETER
;
1719 if (AsciiStrCmp (Cwd
, ".") == 0) {
1725 if (AsciiStrStr (Cwd
, "..") != NULL
) {
1731 Len
= AsciiStrLen (gCwd
);
1732 if ((gCwd
[Len
-2] == ':') && ((gCwd
[Len
-1] == '/') || (gCwd
[Len
-1] == '\\'))) {
1733 // parent is device so nothing to do
1737 // Expand .. in Cwd, given we know current working directory
1738 Path
= ExpandPath (gCwd
, Cwd
);
1740 return EFI_NOT_FOUND
;
1744 File
= EfiOpen (Path
, EFI_FILE_MODE_READ
, 0);
1746 return EFI_INVALID_PARAMETER
;
1753 // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
1754 // relative to the current gCwd or not.
1755 gCwd
= AllocatePool (AsciiStrSize (File
->DeviceName
) + AsciiStrSize (File
->FileName
) + 10);
1757 return EFI_INVALID_PARAMETER
;
1769 Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and
1770 the path does not contain a device name, The CWD is prepended to the path.
1771 The CWD buffer is only valid until a new call is made to EfiSetCwd(). After
1772 a call to EfiSetCwd() it is not legal to use the pointer returned by
1775 @param Cwd Current Working Directory
1778 @return "" No CWD set
1779 @return 'other' Returns buffer that contains CWD.