/** @file | |
EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, | |
StdIn, StdOut, StdErr, etc...). | |
Copyright 2016 Dell Inc. | |
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "Shell.h" | |
#include "FileHandleInternal.h" | |
#define MEM_WRITE_REALLOC_OVERHEAD 1024 | |
/** | |
File style interface for console (Open). | |
@param[in] This Ignored. | |
@param[out] NewHandle Ignored. | |
@param[in] FileName Ignored. | |
@param[in] OpenMode Ignored. | |
@param[in] Attributes Ignored. | |
@retval EFI_NOT_FOUND | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceOpenNotFound ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT EFI_FILE_PROTOCOL **NewHandle, | |
IN CHAR16 *FileName, | |
IN UINT64 OpenMode, | |
IN UINT64 Attributes | |
) | |
{ | |
return (EFI_NOT_FOUND); | |
} | |
/** | |
File style interface for console (Close, Delete, & Flush) | |
@param[in] This Ignored. | |
@retval EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNopGeneric ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
return (EFI_SUCCESS); | |
} | |
/** | |
File style interface for console (GetPosition). | |
@param[in] This Ignored. | |
@param[out] Position Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNopGetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT UINT64 *Position | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for console (SetPosition). | |
@param[in] This Ignored. | |
@param[in] Position Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNopSetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN UINT64 Position | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for console (GetInfo). | |
@param[in] This Ignored. | |
@param[in] InformationType Ignored. | |
@param[in, out] BufferSize Ignored. | |
@param[out] Buffer Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNopGetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for console (SetInfo). | |
@param[in] This Ignored. | |
@param[in] InformationType Ignored. | |
@param[in] BufferSize Ignored. | |
@param[in] Buffer Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNopSetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN UINTN BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for StdOut (Write). | |
Writes data to the screen. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@retval EFI_UNSUPPORTED No output console is supported. | |
@return A return value from gST->ConOut->OutputString. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdOutWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { | |
return (EFI_UNSUPPORTED); | |
} | |
if (*((CHAR16 *)Buffer) == gUnicodeFileTag) { | |
return (gST->ConOut->OutputString (gST->ConOut, (CHAR16 *)Buffer + 1)); | |
} | |
return (gST->ConOut->OutputString (gST->ConOut, Buffer)); | |
} | |
/** | |
File style interface for StdIn (Write). | |
@param[in] This Ignored. | |
@param[in, out] BufferSize Ignored. | |
@param[in] Buffer Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdInWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for console StdErr (Write). | |
Writes error to the error output. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@return A return value from gST->StdErr->OutputString. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdErrWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
return (gST->StdErr->OutputString (gST->StdErr, Buffer)); | |
} | |
/** | |
File style interface for console StdOut (Read). | |
@param[in] This Ignored. | |
@param[in, out] BufferSize Ignored. | |
@param[out] Buffer Ignored. | |
@retval EFI_UNSUPPORTED | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdOutRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for console StdErr (Read). | |
@param[in] This Ignored. | |
@param[in, out] BufferSize Ignored. | |
@param[out] Buffer Ignored. | |
@retval EFI_UNSUPPORTED Always. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdErrRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
return (EFI_UNSUPPORTED); | |
} | |
/** | |
File style interface for NUL file (Read). | |
@param[in] This Ignored. | |
@param[in, out] BufferSize Poiner to 0 upon return. | |
@param[out] Buffer Ignored. | |
@retval EFI_SUCCESS Always. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNulRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
*BufferSize = 0; | |
return (EFI_SUCCESS); | |
} | |
/** | |
File style interface for NUL file (Write). | |
@param[in] This Ignored. | |
@param[in, out] BufferSize Ignored. | |
@param[in] Buffer Ignored. | |
@retval EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceNulWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
return (EFI_SUCCESS); | |
} | |
/** | |
Create the TAB completion list. | |
@param[in] InputString The command line to expand. | |
@param[in] StringLen Length of the command line. | |
@param[in] BufferSize Buffer size. | |
@param[in, out] TabCompletionList Return the TAB completion list. | |
@param[in, out] TabUpdatePos Return the TAB update position. | |
**/ | |
EFI_STATUS | |
CreateTabCompletionList ( | |
IN CONST CHAR16 *InputString, | |
IN CONST UINTN StringLen, | |
IN CONST UINTN BufferSize, | |
IN OUT EFI_SHELL_FILE_INFO **TabCompletionList, | |
IN OUT UINTN *TabUpdatePos | |
) | |
{ | |
BOOLEAN InQuotation; | |
UINTN TabPos; | |
UINTN Index; | |
CONST CHAR16 *Cwd; | |
EFI_STATUS Status; | |
CHAR16 *TabStr; | |
EFI_SHELL_FILE_INFO *FileList; | |
EFI_SHELL_FILE_INFO *FileInfo; | |
EFI_SHELL_FILE_INFO *TempFileInfo; | |
// | |
// Allocate buffers | |
// | |
TabStr = AllocateZeroPool (BufferSize); | |
if (TabStr == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// handle auto complete of file and directory names... | |
// E.g.: cd fs0:\EFI\Bo<TAB> | |
// ^ ^ | |
// TabPos TabUpdatePos | |
// | |
TabPos = 0; | |
*TabUpdatePos = 0; | |
FileList = NULL; | |
InQuotation = FALSE; | |
for (Index = 0; Index < StringLen; Index++) { | |
switch (InputString[Index]) { | |
case L'\"': | |
InQuotation = (BOOLEAN)(!InQuotation); | |
break; | |
case L' ': | |
if (!InQuotation) { | |
TabPos = Index + 1; | |
*TabUpdatePos = TabPos; | |
} | |
break; | |
case L':': | |
// | |
// handle the case "fs0:<TAB>" | |
// Update the TabUpdatePos as well. | |
// | |
case L'\\': | |
*TabUpdatePos = Index + 1; | |
break; | |
default: | |
break; | |
} | |
} | |
if (StrStr (InputString + TabPos, L":") == NULL) { | |
// | |
// If file path doesn't contain ":", ... | |
// | |
Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL); | |
if (Cwd != NULL) { | |
if (InputString[TabPos] != L'\\') { | |
// | |
// and it doesn't begin with "\\", it's a path relative to current directory. | |
// TabStr = "<cwd>\\" | |
// | |
StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1); | |
StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\"); | |
} else { | |
// | |
// and it begins with "\\", it's a path pointing to root directory of current map. | |
// TabStr = "fsx:" | |
// | |
Index = StrStr (Cwd, L":") - Cwd + 1; | |
StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index); | |
} | |
} | |
} | |
StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos); | |
StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr)); | |
Status = ShellInfoObject.NewEfiShellProtocol->FindFiles (TabStr, &FileList); | |
// | |
// Filter out the non-directory for "CD" command | |
// Filter "." and ".." for all | |
// | |
if (!EFI_ERROR (Status) && (FileList != NULL)) { | |
// | |
// Skip the spaces in the beginning | |
// | |
while (*InputString == L' ') { | |
InputString++; | |
} | |
for (FileInfo = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) { | |
if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) || | |
((((InputString[0] == L'c') || (InputString[0] == L'C')) && ((InputString[1] == L'd') || (InputString[1] == L'D'))) && | |
(ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) | |
{ | |
TempFileInfo = FileInfo; | |
FileInfo = (EFI_SHELL_FILE_INFO *)RemoveEntryList (&FileInfo->Link); | |
InternalFreeShellFileInfoNode (TempFileInfo); | |
} else { | |
FileInfo = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &FileInfo->Link); | |
} | |
} | |
} | |
if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) { | |
Status = EFI_SUCCESS; | |
} else { | |
ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList); | |
Status = EFI_NOT_FOUND; | |
} | |
FreePool (TabStr); | |
*TabCompletionList = FileList; | |
return Status; | |
} | |
/** | |
File style interface for console (Read). | |
This will return a single line of input from the console. | |
@param This A pointer to the EFI_FILE_PROTOCOL instance that is the | |
file handle to read data from. Not used. | |
@param BufferSize On input, the size of the Buffer. On output, the amount | |
of data returned in Buffer. In both cases, the size is | |
measured in bytes. | |
@param Buffer The buffer into which the data is read. | |
@retval EFI_SUCCESS The data was read. | |
@retval EFI_NO_MEDIA The device has no medium. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. | |
@retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory | |
entry. BufferSize has been updated with the size | |
needed to complete the request. | |
@retval EFI_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceStdInRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
CHAR16 *CurrentString; | |
BOOLEAN Done; | |
UINTN TabUpdatePos; // Start index of the string updated by TAB stroke | |
UINTN Column; // Column of current cursor | |
UINTN Row; // Row of current cursor | |
UINTN StartColumn; // Column at the beginning of the line | |
UINTN Update; // Line index for update | |
UINTN Delete; // Num of chars to delete from console after update | |
UINTN StringLen; // Total length of the line | |
UINTN StringCurPos; // Line index corresponding to the cursor | |
UINTN MaxStr; // Maximum possible line length | |
UINTN TotalColumn; // Num of columns in the console | |
UINTN TotalRow; // Num of rows in the console | |
UINTN SkipLength; | |
UINTN OutputLength; // Length of the update string | |
UINTN TailRow; // Row of end of line | |
UINTN TailColumn; // Column of end of line | |
EFI_INPUT_KEY Key; | |
BUFFER_LIST *LinePos; | |
BUFFER_LIST *NewPos; | |
BOOLEAN InScrolling; | |
EFI_STATUS Status; | |
BOOLEAN InTabScrolling; // Whether in TAB-completion state | |
EFI_SHELL_FILE_INFO *TabCompleteList; | |
EFI_SHELL_FILE_INFO *TabCurrent; | |
UINTN EventIndex; | |
CHAR16 *TabOutputStr; | |
// | |
// If buffer is not large enough to hold a CHAR16, return minimum buffer size | |
// | |
if (*BufferSize < sizeof (CHAR16) * 2) { | |
*BufferSize = sizeof (CHAR16) * 2; | |
return (EFI_BUFFER_TOO_SMALL); | |
} | |
Done = FALSE; | |
CurrentString = Buffer; | |
StringLen = 0; | |
StringCurPos = 0; | |
OutputLength = 0; | |
Update = 0; | |
Delete = 0; | |
LinePos = NewPos = (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory); | |
InScrolling = FALSE; | |
InTabScrolling = FALSE; | |
Status = EFI_SUCCESS; | |
TabOutputStr = NULL; | |
TabUpdatePos = 0; | |
TabCompleteList = NULL; | |
TabCurrent = NULL; | |
// | |
// Get the screen setting and the current cursor location | |
// | |
Column = StartColumn = gST->ConOut->Mode->CursorColumn; | |
Row = gST->ConOut->Mode->CursorRow; | |
gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow); | |
// | |
// Limit the line length to the buffer size or the minimum size of the | |
// screen. (The smaller takes effect) | |
// | |
MaxStr = TotalColumn * (TotalRow - 1) - StartColumn; | |
if (MaxStr > *BufferSize / sizeof (CHAR16)) { | |
MaxStr = *BufferSize / sizeof (CHAR16); | |
} | |
ZeroMem (CurrentString, MaxStr * sizeof (CHAR16)); | |
do { | |
// | |
// Read a key | |
// | |
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); | |
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); | |
if (EFI_ERROR (Status)) { | |
if (Status == EFI_NOT_READY) { | |
continue; | |
} | |
ZeroMem (CurrentString, MaxStr * sizeof (CHAR16)); | |
StringLen = 0; | |
break; | |
} | |
// | |
// Press PageUp or PageDown to scroll the history screen up or down. | |
// Press any other key to quit scrolling. | |
// | |
if ((Key.UnicodeChar == 0) && ((Key.ScanCode == SCAN_PAGE_UP) || (Key.ScanCode == SCAN_PAGE_DOWN))) { | |
if (Key.ScanCode == SCAN_PAGE_UP) { | |
ConsoleLoggerDisplayHistory (FALSE, 0, ShellInfoObject.ConsoleInfo); | |
} else if (Key.ScanCode == SCAN_PAGE_DOWN) { | |
ConsoleLoggerDisplayHistory (TRUE, 0, ShellInfoObject.ConsoleInfo); | |
} | |
InScrolling = TRUE; | |
} else { | |
if (InScrolling) { | |
ConsoleLoggerStopHistory (ShellInfoObject.ConsoleInfo); | |
InScrolling = FALSE; | |
} | |
} | |
// | |
// If we are quitting TAB scrolling... | |
// | |
if (InTabScrolling && (Key.UnicodeChar != CHAR_TAB)) { | |
if (TabCompleteList != NULL) { | |
ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList); | |
DEBUG_CODE ( | |
TabCompleteList = NULL; | |
); | |
} | |
InTabScrolling = FALSE; | |
} | |
switch (Key.UnicodeChar) { | |
case CHAR_CARRIAGE_RETURN: | |
// | |
// All done, print a newline at the end of the string | |
// | |
TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; | |
TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; | |
ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n"); | |
Done = TRUE; | |
break; | |
case CHAR_BACKSPACE: | |
if (StringCurPos != 0) { | |
// | |
// If not move back beyond string beginning, move all characters behind | |
// the current position one character forward | |
// | |
StringCurPos--; | |
Update = StringCurPos; | |
Delete = 1; | |
CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); | |
// | |
// Adjust the current column and row | |
// | |
MoveCursorBackward (TotalColumn, &Column, &Row); | |
} | |
break; | |
case CHAR_TAB: | |
if (!InTabScrolling) { | |
TabCurrent = NULL; | |
// | |
// Initialize a tab complete operation. | |
// | |
Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos); | |
if (!EFI_ERROR (Status)) { | |
InTabScrolling = TRUE; | |
} | |
// | |
// We do not set up the replacement. | |
// The next section will do that. | |
// | |
} | |
if (InTabScrolling) { | |
// | |
// We are in a tab complete operation. | |
// set up the next replacement. | |
// | |
ASSERT (TabCompleteList != NULL); | |
if (TabCurrent == NULL) { | |
TabCurrent = (EFI_SHELL_FILE_INFO *)GetFirstNode (&TabCompleteList->Link); | |
} else { | |
TabCurrent = (EFI_SHELL_FILE_INFO *)GetNextNode (&TabCompleteList->Link, &TabCurrent->Link); | |
} | |
// | |
// Skip over the empty list beginning node | |
// | |
if (IsNull (&TabCompleteList->Link, &TabCurrent->Link)) { | |
TabCurrent = (EFI_SHELL_FILE_INFO *)GetNextNode (&TabCompleteList->Link, &TabCurrent->Link); | |
} | |
} | |
break; | |
default: | |
if (Key.UnicodeChar >= ' ') { | |
// | |
// If we are at the buffer's end, drop the key | |
// | |
if ((StringLen == MaxStr - 1) && (ShellInfoObject.ViewingSettings.InsertMode || (StringCurPos == StringLen))) { | |
break; | |
} | |
// | |
// If in insert mode, make space by moving each other character 1 | |
// space higher in the array | |
// | |
if (ShellInfoObject.ViewingSettings.InsertMode) { | |
CopyMem (CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof (CurrentString[0])); | |
} | |
CurrentString[StringCurPos] = Key.UnicodeChar; | |
Update = StringCurPos; | |
StringCurPos += 1; | |
OutputLength = 1; | |
} | |
break; | |
case 0: | |
switch (Key.ScanCode) { | |
case SCAN_DELETE: | |
// | |
// Move characters behind current position one character forward | |
// | |
if (StringLen != 0) { | |
Update = StringCurPos; | |
Delete = 1; | |
CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); | |
} | |
break; | |
case SCAN_UP: | |
// | |
// Prepare to print the previous command | |
// | |
NewPos = (BUFFER_LIST *)GetPreviousNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); | |
if (IsNull (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) { | |
NewPos = (BUFFER_LIST *)GetPreviousNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); | |
} | |
break; | |
case SCAN_DOWN: | |
// | |
// Prepare to print the next command | |
// | |
NewPos = (BUFFER_LIST *)GetNextNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); | |
if (NewPos == (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory)) { | |
NewPos = (BUFFER_LIST *)GetNextNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link); | |
} | |
break; | |
case SCAN_LEFT: | |
// | |
// Adjust current cursor position | |
// | |
if (StringCurPos != 0) { | |
--StringCurPos; | |
MoveCursorBackward (TotalColumn, &Column, &Row); | |
} | |
break; | |
case SCAN_RIGHT: | |
// | |
// Adjust current cursor position | |
// | |
if (StringCurPos < StringLen) { | |
++StringCurPos; | |
MoveCursorForward (TotalColumn, TotalRow, &Column, &Row); | |
} | |
break; | |
case SCAN_HOME: | |
// | |
// Move current cursor position to the beginning of the command line | |
// | |
Row -= (StringCurPos + StartColumn) / TotalColumn; | |
Column = StartColumn; | |
StringCurPos = 0; | |
break; | |
case SCAN_END: | |
// | |
// Move current cursor position to the end of the command line | |
// | |
TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; | |
TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; | |
Row = TailRow; | |
Column = TailColumn; | |
StringCurPos = StringLen; | |
break; | |
case SCAN_ESC: | |
// | |
// Prepare to clear the current command line | |
// | |
CurrentString[0] = 0; | |
Update = 0; | |
Delete = StringLen; | |
Row -= (StringCurPos + StartColumn) / TotalColumn; | |
Column = StartColumn; | |
OutputLength = 0; | |
break; | |
case SCAN_INSERT: | |
// | |
// Toggle the SEnvInsertMode flag | |
// | |
ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN) !ShellInfoObject.ViewingSettings.InsertMode; | |
break; | |
case SCAN_F7: | |
// | |
// Print command history | |
// | |
PrintCommandHistory (TotalColumn, TotalRow, 4); | |
*CurrentString = CHAR_NULL; | |
Done = TRUE; | |
break; | |
} | |
} | |
if (Done) { | |
break; | |
} | |
// | |
// If we are in auto-complete mode, we are preparing to print | |
// the next file or directory name | |
// | |
if (InTabScrolling) { | |
TabOutputStr = AllocateZeroPool (*BufferSize); | |
if (TabOutputStr == NULL) { | |
Status = EFI_OUT_OF_RESOURCES; | |
} | |
} | |
if (InTabScrolling && (TabOutputStr != NULL)) { | |
// | |
// Adjust the column and row to the start of TAB-completion string. | |
// | |
Column = (StartColumn + TabUpdatePos) % TotalColumn; | |
Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn; | |
OutputLength = StrLen (TabCurrent->FileName); | |
// | |
// if the output string contains blank space, quotation marks L'\"' | |
// should be added to the output. | |
// | |
if (StrStr (TabCurrent->FileName, L" ") != NULL) { | |
TabOutputStr[0] = L'\"'; | |
CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16)); | |
TabOutputStr[OutputLength + 1] = L'\"'; | |
TabOutputStr[OutputLength + 2] = CHAR_NULL; | |
} else { | |
CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16)); | |
TabOutputStr[OutputLength] = CHAR_NULL; | |
} | |
OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1; | |
CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16)); | |
CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL; | |
StringCurPos = TabUpdatePos + OutputLength; | |
Update = TabUpdatePos; | |
if (StringLen > TabUpdatePos + OutputLength) { | |
Delete = StringLen - TabUpdatePos - OutputLength; | |
} | |
FreePool (TabOutputStr); | |
} | |
// | |
// If we have a new position, we are preparing to print a previous or | |
// next command. | |
// | |
if (NewPos != (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory)) { | |
Column = StartColumn; | |
Row -= (StringCurPos + StartColumn) / TotalColumn; | |
LinePos = NewPos; | |
NewPos = (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory); | |
OutputLength = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1; | |
CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16)); | |
CurrentString[OutputLength] = CHAR_NULL; | |
StringCurPos = OutputLength; | |
// | |
// Draw new input string | |
// | |
Update = 0; | |
if (StringLen > OutputLength) { | |
// | |
// If old string was longer, blank its tail | |
// | |
Delete = StringLen - OutputLength; | |
} | |
} | |
// | |
// If we need to update the output do so now | |
// | |
if (Update != (UINTN)-1) { | |
ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L""); | |
StringLen = StrLen (CurrentString); | |
if (Delete != 0) { | |
SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL); | |
} | |
if (StringCurPos > StringLen) { | |
StringCurPos = StringLen; | |
} | |
Update = (UINTN)-1; | |
// | |
// After using print to reflect newly updates, if we're not using | |
// BACKSPACE and DELETE, we need to move the cursor position forward, | |
// so adjust row and column here. | |
// | |
if ((Key.UnicodeChar != CHAR_BACKSPACE) && !((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_DELETE))) { | |
// | |
// Calculate row and column of the tail of current string | |
// | |
TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn; | |
TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn; | |
// | |
// If the tail of string reaches screen end, screen rolls up, so if | |
// Row does not equal TailRow, Row should be decremented | |
// | |
// (if we are recalling commands using UPPER and DOWN key, and if the | |
// old command is too long to fit the screen, TailColumn must be 79. | |
// | |
if ((TailColumn == 0) && (TailRow >= TotalRow) && (Row != TailRow)) { | |
Row--; | |
} | |
// | |
// Calculate the cursor position after current operation. If cursor | |
// reaches line end, update both row and column, otherwise, only | |
// column will be changed. | |
// | |
if (Column + OutputLength >= TotalColumn) { | |
SkipLength = OutputLength - (TotalColumn - Column); | |
Row += SkipLength / TotalColumn + 1; | |
if (Row > TotalRow - 1) { | |
Row = TotalRow - 1; | |
} | |
Column = SkipLength % TotalColumn; | |
} else { | |
Column += OutputLength; | |
} | |
} | |
Delete = 0; | |
} | |
// | |
// Set the cursor position for this key | |
// | |
gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row); | |
} while (!Done); | |
if ((CurrentString != NULL) && (StrLen (CurrentString) > 0)) { | |
// | |
// add the line to the history buffer | |
// | |
AddLineToCommandHistory (CurrentString); | |
} | |
// | |
// Return the data to the caller | |
// | |
*BufferSize = StringLen * sizeof (CHAR16); | |
// | |
// if this was used it should be deallocated by now... | |
// prevent memory leaks... | |
// | |
if (TabCompleteList != NULL) { | |
ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList); | |
} | |
ASSERT (TabCompleteList == NULL); | |
return Status; | |
} | |
// | |
// FILE style interfaces for StdIn/StdOut/StdErr | |
// | |
EFI_FILE_PROTOCOL FileInterfaceStdIn = { | |
EFI_FILE_REVISION, | |
FileInterfaceOpenNotFound, | |
FileInterfaceNopGeneric, | |
FileInterfaceNopGeneric, | |
FileInterfaceStdInRead, | |
FileInterfaceStdInWrite, | |
FileInterfaceNopGetPosition, | |
FileInterfaceNopSetPosition, | |
FileInterfaceNopGetInfo, | |
FileInterfaceNopSetInfo, | |
FileInterfaceNopGeneric | |
}; | |
EFI_FILE_PROTOCOL FileInterfaceStdOut = { | |
EFI_FILE_REVISION, | |
FileInterfaceOpenNotFound, | |
FileInterfaceNopGeneric, | |
FileInterfaceNopGeneric, | |
FileInterfaceStdOutRead, | |
FileInterfaceStdOutWrite, | |
FileInterfaceNopGetPosition, | |
FileInterfaceNopSetPosition, | |
FileInterfaceNopGetInfo, | |
FileInterfaceNopSetInfo, | |
FileInterfaceNopGeneric | |
}; | |
EFI_FILE_PROTOCOL FileInterfaceStdErr = { | |
EFI_FILE_REVISION, | |
FileInterfaceOpenNotFound, | |
FileInterfaceNopGeneric, | |
FileInterfaceNopGeneric, | |
FileInterfaceStdErrRead, | |
FileInterfaceStdErrWrite, | |
FileInterfaceNopGetPosition, | |
FileInterfaceNopSetPosition, | |
FileInterfaceNopGetInfo, | |
FileInterfaceNopSetInfo, | |
FileInterfaceNopGeneric | |
}; | |
EFI_FILE_PROTOCOL FileInterfaceNulFile = { | |
EFI_FILE_REVISION, | |
FileInterfaceOpenNotFound, | |
FileInterfaceNopGeneric, | |
FileInterfaceNopGeneric, | |
FileInterfaceNulRead, | |
FileInterfaceNulWrite, | |
FileInterfaceNopGetPosition, | |
FileInterfaceNopSetPosition, | |
FileInterfaceNopGetInfo, | |
FileInterfaceNopSetInfo, | |
FileInterfaceNopGeneric | |
}; | |
// | |
// This is identical to EFI_FILE_PROTOCOL except for the additional member | |
// for the name. | |
// | |
typedef struct { | |
UINT64 Revision; | |
EFI_FILE_OPEN Open; | |
EFI_FILE_CLOSE Close; | |
EFI_FILE_DELETE Delete; | |
EFI_FILE_READ Read; | |
EFI_FILE_WRITE Write; | |
EFI_FILE_GET_POSITION GetPosition; | |
EFI_FILE_SET_POSITION SetPosition; | |
EFI_FILE_GET_INFO GetInfo; | |
EFI_FILE_SET_INFO SetInfo; | |
EFI_FILE_FLUSH Flush; | |
CHAR16 Name[1]; | |
} EFI_FILE_PROTOCOL_ENVIRONMENT; | |
// ANSI compliance helper to get size of the struct. | |
#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name) | |
/** | |
File style interface for Environment Variable (Close). | |
Frees the memory for this object. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@retval EFI_SUCCESS | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceEnvClose ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
VOID *NewBuffer; | |
UINTN NewSize; | |
EFI_STATUS Status; | |
BOOLEAN Volatile; | |
UINTN TotalSize; | |
// | |
// Most if not all UEFI commands will have an '\r\n' at the end of any output. | |
// Since the output was redirected to a variable, it does not make sense to | |
// keep this. So, before closing, strip the trailing '\r\n' from the variable | |
// if it exists. | |
// | |
NewBuffer = NULL; | |
NewSize = 0; | |
TotalSize = 0; | |
Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &Volatile); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
TotalSize = NewSize + sizeof (CHAR16); | |
NewBuffer = AllocateZeroPool (TotalSize); | |
if (NewBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
} | |
if (!EFI_ERROR (Status) && (NewBuffer != NULL)) { | |
if (TotalSize / sizeof (CHAR16) >= 3) { | |
if ((((CHAR16 *)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) && | |
(((CHAR16 *)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN) | |
) | |
{ | |
((CHAR16 *)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL; | |
// | |
// If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize. | |
// | |
TotalSize -= sizeof (CHAR16) * 2; | |
} | |
if (Volatile) { | |
Status = SHELL_SET_ENVIRONMENT_VARIABLE_V ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
TotalSize - sizeof (CHAR16), | |
NewBuffer | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = ShellAddEnvVarToList ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
NewBuffer, | |
TotalSize, | |
EFI_VARIABLE_BOOTSERVICE_ACCESS | |
); | |
} | |
} else { | |
Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
TotalSize - sizeof (CHAR16), | |
NewBuffer | |
); | |
if (!EFI_ERROR (Status)) { | |
Status = ShellAddEnvVarToList ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
NewBuffer, | |
TotalSize, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
); | |
} | |
} | |
} | |
} | |
SHELL_FREE_NON_NULL (NewBuffer); | |
FreePool ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This); | |
return (Status); | |
} | |
/** | |
File style interface for Environment Variable (Delete). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@retval The return value from FileInterfaceEnvClose(). | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceEnvDelete ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
SHELL_DELETE_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name); | |
return (FileInterfaceEnvClose (This)); | |
} | |
/** | |
File style interface for Environment Variable (Read). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[out] Buffer The pointer to the buffer to fill. | |
@retval EFI_SUCCESS The data was read. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceEnvRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
*BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16); | |
if (*BufferSize != 0) { | |
// | |
// Make sure the first unicode character is \xFEFF | |
// | |
*(CHAR16 *)Buffer = gUnicodeFileTag; | |
Buffer = (CHAR16 *)Buffer + 1; | |
*BufferSize -= sizeof (gUnicodeFileTag); | |
} | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
BufferSize, | |
Buffer | |
); | |
if (!EFI_ERROR (Status) || (Status == EFI_BUFFER_TOO_SMALL)) { | |
// | |
// BufferSize is valid and needs update when Status is Success or BufferTooSmall. | |
// | |
*BufferSize += sizeof (gUnicodeFileTag); | |
} | |
return Status; | |
} | |
/** | |
File style interface for Volatile Environment Variable (Write). | |
This function also caches the environment variable into gShellEnvVarList. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@retval EFI_SUCCESS The data was successfully write to variable. | |
@retval SHELL_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceEnvVolWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
VOID *NewBuffer; | |
UINTN NewSize; | |
EFI_STATUS Status; | |
UINTN TotalSize; | |
NewBuffer = NULL; | |
NewSize = 0; | |
TotalSize = 0; | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
TotalSize = NewSize + *BufferSize + sizeof (CHAR16); | |
} else if (Status == EFI_NOT_FOUND) { | |
TotalSize = *BufferSize + sizeof (CHAR16); | |
} else { | |
return Status; | |
} | |
NewBuffer = AllocateZeroPool (TotalSize); | |
if (NewBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
} | |
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
FreePool (NewBuffer); | |
return Status; | |
} | |
CopyMem ((UINT8 *)NewBuffer + NewSize, Buffer, *BufferSize); | |
Status = ShellAddEnvVarToList ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
NewBuffer, | |
TotalSize, | |
EFI_VARIABLE_BOOTSERVICE_ACCESS | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (NewBuffer); | |
return Status; | |
} | |
Status = SHELL_SET_ENVIRONMENT_VARIABLE_V ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
TotalSize - sizeof (CHAR16), | |
NewBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name); | |
} | |
FreePool (NewBuffer); | |
return Status; | |
} | |
/** | |
File style interface for Non Volatile Environment Variable (Write). | |
This function also caches the environment variable into gShellEnvVarList. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@retval EFI_SUCCESS The data was successfully write to variable. | |
@retval SHELL_OUT_OF_RESOURCES A memory allocation failed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceEnvNonVolWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
VOID *NewBuffer; | |
UINTN NewSize; | |
EFI_STATUS Status; | |
UINTN TotalSize; | |
NewBuffer = NULL; | |
NewSize = 0; | |
TotalSize = 0; | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
TotalSize = NewSize + *BufferSize + sizeof (CHAR16); | |
} else if (Status == EFI_NOT_FOUND) { | |
TotalSize = *BufferSize + sizeof (CHAR16); | |
} else { | |
return Status; | |
} | |
NewBuffer = AllocateZeroPool (TotalSize); | |
if (NewBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer); | |
} | |
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { | |
FreePool (NewBuffer); | |
return Status; | |
} | |
CopyMem ((UINT8 *)NewBuffer + NewSize, Buffer, *BufferSize); | |
Status = ShellAddEnvVarToList ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
NewBuffer, | |
TotalSize, | |
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
); | |
if (EFI_ERROR (Status)) { | |
FreePool (NewBuffer); | |
return Status; | |
} | |
Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV ( | |
((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, | |
TotalSize - sizeof (CHAR16), | |
NewBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name); | |
} | |
FreePool (NewBuffer); | |
return Status; | |
} | |
/** | |
Creates a EFI_FILE_PROTOCOL (almost) object for using to access | |
environment variables through file operations. | |
@param EnvName The name of the Environment Variable to be operated on. | |
@retval NULL Memory could not be allocated. | |
@return other a pointer to an EFI_FILE_PROTOCOL structure | |
**/ | |
EFI_FILE_PROTOCOL * | |
CreateFileInterfaceEnv ( | |
IN CONST CHAR16 *EnvName | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface; | |
UINTN EnvNameSize; | |
BOOLEAN Volatile; | |
if (EnvName == NULL) { | |
return (NULL); | |
} | |
Status = IsVolatileEnv (EnvName, &Volatile); | |
if (EFI_ERROR (Status)) { | |
return NULL; | |
} | |
// | |
// Get some memory | |
// | |
EnvNameSize = StrSize (EnvName); | |
EnvFileInterface = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize); | |
if (EnvFileInterface == NULL) { | |
return (NULL); | |
} | |
// | |
// Assign the generic members | |
// | |
EnvFileInterface->Revision = EFI_FILE_REVISION; | |
EnvFileInterface->Open = FileInterfaceOpenNotFound; | |
EnvFileInterface->Close = FileInterfaceEnvClose; | |
EnvFileInterface->GetPosition = FileInterfaceNopGetPosition; | |
EnvFileInterface->SetPosition = FileInterfaceNopSetPosition; | |
EnvFileInterface->GetInfo = FileInterfaceNopGetInfo; | |
EnvFileInterface->SetInfo = FileInterfaceNopSetInfo; | |
EnvFileInterface->Flush = FileInterfaceNopGeneric; | |
EnvFileInterface->Delete = FileInterfaceEnvDelete; | |
EnvFileInterface->Read = FileInterfaceEnvRead; | |
CopyMem (EnvFileInterface->Name, EnvName, EnvNameSize); | |
// | |
// Assign the different members for Volatile and Non-Volatile variables | |
// | |
if (Volatile) { | |
EnvFileInterface->Write = FileInterfaceEnvVolWrite; | |
} else { | |
EnvFileInterface->Write = FileInterfaceEnvNonVolWrite; | |
} | |
return ((EFI_FILE_PROTOCOL *)EnvFileInterface); | |
} | |
/** | |
Move the cursor position one character backward. | |
@param[in] LineLength Length of a line. Get it by calling QueryMode | |
@param[in, out] Column Current column of the cursor position | |
@param[in, out] Row Current row of the cursor position | |
**/ | |
VOID | |
MoveCursorBackward ( | |
IN UINTN LineLength, | |
IN OUT UINTN *Column, | |
IN OUT UINTN *Row | |
) | |
{ | |
// | |
// If current column is 0, move to the last column of the previous line, | |
// otherwise, just decrement column. | |
// | |
if (*Column == 0) { | |
*Column = LineLength - 1; | |
if (*Row > 0) { | |
(*Row)--; | |
} | |
return; | |
} | |
(*Column)--; | |
} | |
/** | |
Move the cursor position one character forward. | |
@param[in] LineLength Length of a line. | |
@param[in] TotalRow Total row of a screen | |
@param[in, out] Column Current column of the cursor position | |
@param[in, out] Row Current row of the cursor position | |
**/ | |
VOID | |
MoveCursorForward ( | |
IN UINTN LineLength, | |
IN UINTN TotalRow, | |
IN OUT UINTN *Column, | |
IN OUT UINTN *Row | |
) | |
{ | |
// | |
// Increment Column. | |
// If this puts column past the end of the line, move to first column | |
// of the next row. | |
// | |
(*Column)++; | |
if (*Column >= LineLength) { | |
(*Column) = 0; | |
if ((*Row) < TotalRow - 1) { | |
(*Row)++; | |
} | |
} | |
} | |
/** | |
Prints out each previously typed command in the command list history log. | |
When each screen is full it will pause for a key before continuing. | |
@param[in] TotalCols How many columns are on the screen | |
@param[in] TotalRows How many rows are on the screen | |
@param[in] StartColumn which column to start at | |
**/ | |
VOID | |
PrintCommandHistory ( | |
IN CONST UINTN TotalCols, | |
IN CONST UINTN TotalRows, | |
IN CONST UINTN StartColumn | |
) | |
{ | |
BUFFER_LIST *Node; | |
UINTN Index; | |
UINTN LineNumber; | |
UINTN LineCount; | |
ShellPrintEx (-1, -1, L"\n"); | |
Index = 0; | |
LineNumber = 0; | |
// | |
// go through history list... | |
// | |
for ( Node = (BUFFER_LIST *)GetFirstNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link) | |
; !IsNull (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) | |
; Node = (BUFFER_LIST *)GetNextNode (&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) | |
) | |
{ | |
Index++; | |
LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1; | |
if (LineNumber + LineCount >= TotalRows) { | |
ShellPromptForResponseHii ( | |
ShellPromptResponseTypeEnterContinue, | |
STRING_TOKEN (STR_SHELL_ENTER_TO_CONT), | |
ShellInfoObject.HiiHandle, | |
NULL | |
); | |
LineNumber = 0; | |
} | |
ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer); | |
LineNumber += LineCount; | |
} | |
} | |
// | |
// This is identical to EFI_FILE_PROTOCOL except for the additional members | |
// for the buffer, size, and position. | |
// | |
typedef struct { | |
UINT64 Revision; | |
EFI_FILE_OPEN Open; | |
EFI_FILE_CLOSE Close; | |
EFI_FILE_DELETE Delete; | |
EFI_FILE_READ Read; | |
EFI_FILE_WRITE Write; | |
EFI_FILE_GET_POSITION GetPosition; | |
EFI_FILE_SET_POSITION SetPosition; | |
EFI_FILE_GET_INFO GetInfo; | |
EFI_FILE_SET_INFO SetInfo; | |
EFI_FILE_FLUSH Flush; | |
VOID *Buffer; | |
UINT64 Position; | |
UINT64 BufferSize; | |
BOOLEAN Unicode; | |
UINT64 FileSize; | |
} EFI_FILE_PROTOCOL_MEM; | |
/** | |
File style interface for Mem (SetPosition). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[out] Position The position to set. | |
@retval EFI_SUCCESS The position was successfully changed. | |
@retval EFI_INVALID_PARAMETER The Position was invalid. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemSetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT UINT64 Position | |
) | |
{ | |
if (Position <= ((EFI_FILE_PROTOCOL_MEM *)This)->FileSize) { | |
((EFI_FILE_PROTOCOL_MEM *)This)->Position = Position; | |
return (EFI_SUCCESS); | |
} else { | |
return (EFI_INVALID_PARAMETER); | |
} | |
} | |
/** | |
File style interface for Mem (GetPosition). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[out] Position The pointer to the position. | |
@retval EFI_SUCCESS The position was retrieved. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemGetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT UINT64 *Position | |
) | |
{ | |
*Position = ((EFI_FILE_PROTOCOL_MEM *)This)->Position; | |
return (EFI_SUCCESS); | |
} | |
/** | |
File style interface for Mem (GetInfo). | |
@param This Protocol instance pointer. | |
@param InformationType Type of information to return in Buffer. | |
@param BufferSize On input size of buffer, on output amount of data in buffer. | |
@param Buffer The buffer to return data. | |
@retval EFI_SUCCESS Data was returned. | |
@retval EFI_UNSUPPORT InformationType is not supported. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The device is write protected. | |
@retval EFI_ACCESS_DENIED The file was open for read only. | |
@retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemGetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
EFI_FILE_INFO *FileInfo; | |
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { | |
if (*BufferSize < sizeof (EFI_FILE_INFO)) { | |
*BufferSize = sizeof (EFI_FILE_INFO); | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
if (Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
FileInfo = (EFI_FILE_INFO *)Buffer; | |
FileInfo->Size = sizeof (*FileInfo); | |
ZeroMem (FileInfo, sizeof (*FileInfo)); | |
FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM *)This)->FileSize; | |
FileInfo->PhysicalSize = FileInfo->FileSize; | |
return EFI_SUCCESS; | |
} | |
return EFI_UNSUPPORTED; | |
} | |
/** | |
File style interface for Mem (Write). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources. | |
@retval EFI_SUCCESS The data was written. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
CHAR8 *AsciiBuffer; | |
EFI_FILE_PROTOCOL_MEM *MemFile; | |
MemFile = (EFI_FILE_PROTOCOL_MEM *)This; | |
if (MemFile->Unicode) { | |
// | |
// Unicode | |
// | |
if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) { | |
MemFile->Buffer = ReallocatePool ((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); | |
if (MemFile->Buffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD; | |
} | |
CopyMem (((UINT8 *)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize); | |
MemFile->Position += (*BufferSize); | |
MemFile->FileSize = MemFile->Position; | |
return (EFI_SUCCESS); | |
} else { | |
// | |
// Ascii | |
// | |
AsciiBuffer = AllocateZeroPool (*BufferSize); | |
if (AsciiBuffer == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
AsciiSPrint (AsciiBuffer, *BufferSize, "%S", Buffer); | |
if ((UINTN)(MemFile->Position + AsciiStrSize (AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) { | |
MemFile->Buffer = ReallocatePool ((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize (AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer); | |
if (MemFile->Buffer == NULL) { | |
FreePool (AsciiBuffer); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
MemFile->BufferSize += AsciiStrSize (AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD; | |
} | |
CopyMem (((UINT8 *)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize (AsciiBuffer)); | |
MemFile->Position += (*BufferSize / sizeof (CHAR16)); | |
MemFile->FileSize = MemFile->Position; | |
FreePool (AsciiBuffer); | |
return (EFI_SUCCESS); | |
} | |
} | |
/** | |
File style interface for Mem (Read). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to fill. | |
@retval EFI_SUCCESS The data was read. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
EFI_FILE_PROTOCOL_MEM *MemFile; | |
MemFile = (EFI_FILE_PROTOCOL_MEM *)This; | |
if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) { | |
(*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position)); | |
} | |
CopyMem (Buffer, ((UINT8 *)MemFile->Buffer) + MemFile->Position, (*BufferSize)); | |
MemFile->Position = MemFile->Position + (*BufferSize); | |
return (EFI_SUCCESS); | |
} | |
/** | |
File style interface for Mem (Close). | |
Frees all memory associated with this object. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@retval EFI_SUCCESS The 'file' was closed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceMemClose ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
SHELL_FREE_NON_NULL (((EFI_FILE_PROTOCOL_MEM *)This)->Buffer); | |
SHELL_FREE_NON_NULL (This); | |
return (EFI_SUCCESS); | |
} | |
/** | |
Creates a EFI_FILE_PROTOCOL (almost) object for using to access | |
a file entirely in memory through file operations. | |
@param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii. | |
@retval NULL Memory could not be allocated. | |
@return other A pointer to an EFI_FILE_PROTOCOL structure. | |
**/ | |
EFI_FILE_PROTOCOL * | |
CreateFileInterfaceMem ( | |
IN CONST BOOLEAN Unicode | |
) | |
{ | |
EFI_FILE_PROTOCOL_MEM *FileInterface; | |
// | |
// Get some memory | |
// | |
FileInterface = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_MEM)); | |
if (FileInterface == NULL) { | |
return (NULL); | |
} | |
// | |
// Assign the generic members | |
// | |
FileInterface->Revision = EFI_FILE_REVISION; | |
FileInterface->Open = FileInterfaceOpenNotFound; | |
FileInterface->Close = FileInterfaceMemClose; | |
FileInterface->GetPosition = FileInterfaceMemGetPosition; | |
FileInterface->SetPosition = FileInterfaceMemSetPosition; | |
FileInterface->GetInfo = FileInterfaceMemGetInfo; | |
FileInterface->SetInfo = FileInterfaceNopSetInfo; | |
FileInterface->Flush = FileInterfaceNopGeneric; | |
FileInterface->Delete = FileInterfaceNopGeneric; | |
FileInterface->Read = FileInterfaceMemRead; | |
FileInterface->Write = FileInterfaceMemWrite; | |
FileInterface->Unicode = Unicode; | |
ASSERT (FileInterface->Buffer == NULL); | |
ASSERT (FileInterface->BufferSize == 0); | |
ASSERT (FileInterface->Position == 0); | |
if (Unicode) { | |
FileInterface->Buffer = AllocateZeroPool (sizeof (gUnicodeFileTag)); | |
if (FileInterface->Buffer == NULL) { | |
FreePool (FileInterface); | |
return NULL; | |
} | |
*((CHAR16 *)(FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK; | |
FileInterface->BufferSize = 2; | |
FileInterface->Position = 2; | |
} | |
return ((EFI_FILE_PROTOCOL *)FileInterface); | |
} | |
typedef struct { | |
UINT64 Revision; | |
EFI_FILE_OPEN Open; | |
EFI_FILE_CLOSE Close; | |
EFI_FILE_DELETE Delete; | |
EFI_FILE_READ Read; | |
EFI_FILE_WRITE Write; | |
EFI_FILE_GET_POSITION GetPosition; | |
EFI_FILE_SET_POSITION SetPosition; | |
EFI_FILE_GET_INFO GetInfo; | |
EFI_FILE_SET_INFO SetInfo; | |
EFI_FILE_FLUSH Flush; | |
BOOLEAN Unicode; | |
EFI_FILE_PROTOCOL *Orig; | |
} EFI_FILE_PROTOCOL_FILE; | |
/** | |
Set a files current position | |
@param This Protocol instance pointer. | |
@param Position Byte position from the start of the file. | |
@retval EFI_SUCCESS Data was written. | |
@retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileSetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN UINT64 Position | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->SetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, Position); | |
} | |
/** | |
Get a file's current position | |
@param This Protocol instance pointer. | |
@param Position Byte position from the start of the file. | |
@retval EFI_SUCCESS Data was written. | |
@retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileGetPosition ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT UINT64 *Position | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, Position); | |
} | |
/** | |
Get information about a file. | |
@param This Protocol instance pointer. | |
@param InformationType Type of information to return in Buffer. | |
@param BufferSize On input size of buffer, on output amount of data in buffer. | |
@param Buffer The buffer to return data. | |
@retval EFI_SUCCESS Data was returned. | |
@retval EFI_UNSUPPORT InformationType is not supported. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The device is write protected. | |
@retval EFI_ACCESS_DENIED The file was open for read only. | |
@retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileGetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetInfo (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, InformationType, BufferSize, Buffer); | |
} | |
/** | |
Set information about a file | |
@param This Protocol instance pointer. | |
@param InformationType Type of information in Buffer. | |
@param BufferSize Size of buffer. | |
@param Buffer The data to write. | |
@retval EFI_SUCCESS Data was returned. | |
@retval EFI_UNSUPPORT InformationType is not supported. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The device is write protected. | |
@retval EFI_ACCESS_DENIED The file was open for read only. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileSetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN UINTN BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->SetInfo (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, InformationType, BufferSize, Buffer); | |
} | |
/** | |
Flush data back for the file handle. | |
@param This Protocol instance pointer. | |
@retval EFI_SUCCESS Data was written. | |
@retval EFI_UNSUPPORT Writes to Open directory are not supported. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_WRITE_PROTECTED The device is write protected. | |
@retval EFI_ACCESS_DENIED The file was open for read only. | |
@retval EFI_VOLUME_FULL The volume is full. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileFlush ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Flush (((EFI_FILE_PROTOCOL_FILE *)This)->Orig); | |
} | |
/** | |
Read data from the file. | |
@param This Protocol instance pointer. | |
@param BufferSize On input size of buffer, on output amount of data in buffer. | |
@param Buffer The buffer in which data is read. | |
@retval EFI_SUCCESS Data was read. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileRead ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
EFI_STATUS Status; | |
UINT64 Position; | |
CHAR8 *AsciiStrBuffer; | |
CHAR16 *UscStrBuffer; | |
UINTN Size; | |
if (((EFI_FILE_PROTOCOL_FILE *)This)->Unicode) { | |
// | |
// Unicode | |
// There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF. | |
// So we choose to leave the file content as is. | |
// | |
return (((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, BufferSize, Buffer)); | |
} else { | |
// | |
// Ascii | |
// | |
*BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16); | |
if (*BufferSize == 0) { | |
return EFI_SUCCESS; | |
} | |
Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, &Position); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (Position == 0) { | |
// | |
// First two bytes in Buffer is for the Unicode file tag. | |
// | |
*(CHAR16 *)Buffer = gUnicodeFileTag; | |
Buffer = (CHAR16 *)Buffer + 1; | |
Size = *BufferSize / sizeof (CHAR16) - 1; | |
} else { | |
Size = *BufferSize / sizeof (CHAR16); | |
} | |
AsciiStrBuffer = AllocateZeroPool (Size + 1); | |
if (AsciiStrBuffer == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
UscStrBuffer = AllocateZeroPool ((Size + 1) * sizeof (CHAR16)); | |
if (UscStrBuffer == NULL) { | |
SHELL_FREE_NON_NULL (AsciiStrBuffer); | |
return EFI_OUT_OF_RESOURCES; | |
} | |
Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, &Size, AsciiStrBuffer); | |
if (!EFI_ERROR (Status)) { | |
AsciiStrToUnicodeStrS (AsciiStrBuffer, UscStrBuffer, Size + 1); | |
*BufferSize = Size * sizeof (CHAR16); | |
CopyMem (Buffer, UscStrBuffer, *BufferSize); | |
} | |
SHELL_FREE_NON_NULL (AsciiStrBuffer); | |
SHELL_FREE_NON_NULL (UscStrBuffer); | |
return Status; | |
} | |
} | |
/** | |
Opens a new file relative to the source file's location. | |
@param[in] This The protocol instance pointer. | |
@param[out] NewHandle Returns File Handle for FileName. | |
@param[in] FileName Null terminated string. "\", ".", and ".." are supported. | |
@param[in] OpenMode Open mode for file. | |
@param[in] Attributes Only used for EFI_FILE_MODE_CREATE. | |
@retval EFI_SUCCESS The device was opened. | |
@retval EFI_NOT_FOUND The specified file could not be found on the device. | |
@retval EFI_NO_MEDIA The device has no media. | |
@retval EFI_MEDIA_CHANGED The media has changed. | |
@retval EFI_DEVICE_ERROR The device reported an error. | |
@retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. | |
@retval EFI_ACCESS_DENIED The service denied access to the file. | |
@retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. | |
@retval EFI_VOLUME_FULL The volume is full. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileOpen ( | |
IN EFI_FILE_PROTOCOL *This, | |
OUT EFI_FILE_PROTOCOL **NewHandle, | |
IN CHAR16 *FileName, | |
IN UINT64 OpenMode, | |
IN UINT64 Attributes | |
) | |
{ | |
return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Open (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, NewHandle, FileName, OpenMode, Attributes); | |
} | |
/** | |
Close and delete the file handle. | |
@param This Protocol instance pointer. | |
@retval EFI_SUCCESS The device was opened. | |
@retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileDelete ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
EFI_STATUS Status; | |
Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Delete (((EFI_FILE_PROTOCOL_FILE *)This)->Orig); | |
FreePool (This); | |
return (Status); | |
} | |
/** | |
File style interface for File (Close). | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@retval EFI_SUCCESS The file was closed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileClose ( | |
IN EFI_FILE_PROTOCOL *This | |
) | |
{ | |
EFI_STATUS Status; | |
Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Close (((EFI_FILE_PROTOCOL_FILE *)This)->Orig); | |
FreePool (This); | |
return (Status); | |
} | |
/** | |
File style interface for File (Write). | |
If the file was opened with ASCII mode the data will be processed through | |
AsciiSPrint before writing. | |
@param[in] This The pointer to the EFI_FILE_PROTOCOL object. | |
@param[in, out] BufferSize Size in bytes of Buffer. | |
@param[in] Buffer The pointer to the buffer to write. | |
@retval EFI_SUCCESS The data was written. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FileInterfaceFileWrite ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
IN VOID *Buffer | |
) | |
{ | |
CHAR8 *AsciiBuffer; | |
UINTN Size; | |
EFI_STATUS Status; | |
if (((EFI_FILE_PROTOCOL_FILE *)This)->Unicode) { | |
// | |
// Unicode | |
// | |
return (((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Write (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, BufferSize, Buffer)); | |
} else { | |
// | |
// Ascii | |
// | |
AsciiBuffer = AllocateZeroPool (*BufferSize); | |
AsciiSPrint (AsciiBuffer, *BufferSize, "%S", Buffer); | |
Size = AsciiStrSize (AsciiBuffer) - 1; // (we dont need the null terminator) | |
Status = (((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Write (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, &Size, AsciiBuffer)); | |
FreePool (AsciiBuffer); | |
return (Status); | |
} | |
} | |
/** | |
Create a file interface with unicode information. | |
This will create a new EFI_FILE_PROTOCOL identical to the Templace | |
except that the new one has Unicode and Ascii knowledge. | |
@param[in] Template A pointer to the EFI_FILE_PROTOCOL object. | |
@param[in] Unicode TRUE for UCS-2, FALSE for ASCII. | |
@return a new EFI_FILE_PROTOCOL object to be used instead of the template. | |
**/ | |
EFI_FILE_PROTOCOL * | |
CreateFileInterfaceFile ( | |
IN CONST EFI_FILE_PROTOCOL *Template, | |
IN CONST BOOLEAN Unicode | |
) | |
{ | |
EFI_FILE_PROTOCOL_FILE *NewOne; | |
NewOne = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_FILE)); | |
if (NewOne == NULL) { | |
return (NULL); | |
} | |
CopyMem (NewOne, Template, sizeof (EFI_FILE_PROTOCOL_FILE)); | |
NewOne->Orig = (EFI_FILE_PROTOCOL *)Template; | |
NewOne->Unicode = Unicode; | |
NewOne->Open = FileInterfaceFileOpen; | |
NewOne->Close = FileInterfaceFileClose; | |
NewOne->Delete = FileInterfaceFileDelete; | |
NewOne->Read = FileInterfaceFileRead; | |
NewOne->Write = FileInterfaceFileWrite; | |
NewOne->GetPosition = FileInterfaceFileGetPosition; | |
NewOne->SetPosition = FileInterfaceFileSetPosition; | |
NewOne->GetInfo = FileInterfaceFileGetInfo; | |
NewOne->SetInfo = FileInterfaceFileSetInfo; | |
NewOne->Flush = FileInterfaceFileFlush; | |
return ((EFI_FILE_PROTOCOL *)NewOne); | |
} |