| /** @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; | |
| ShellPrintDefaultEx (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; | |
| } | |
| ShellPrintDefaultEx (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); | |
| if (AsciiBuffer == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| 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); | |
| } |