Home | History | Annotate | Download | only in Shell
      1 /** @file
      2   EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
      3   StdIn, StdOut, StdErr, etc...).
      4 
      5   Copyright 2016 Dell Inc.
      6   Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
      7   (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
      8   This program and the accompanying materials
      9   are licensed and made available under the terms and conditions of the BSD License
     10   which accompanies this distribution.  The full text of the license may be found at
     11   http://opensource.org/licenses/bsd-license.php
     12 
     13   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 **/
     17 
     18 #include "Shell.h"
     19 #include "FileHandleInternal.h"
     20 
     21 #define MEM_WRITE_REALLOC_OVERHEAD 1024
     22 
     23 /**
     24   File style interface for console (Open).
     25 
     26   @param[in] This       Ignored.
     27   @param[out] NewHandle Ignored.
     28   @param[in] FileName   Ignored.
     29   @param[in] OpenMode   Ignored.
     30   @param[in] Attributes Ignored.
     31 
     32   @retval EFI_NOT_FOUND
     33 **/
     34 EFI_STATUS
     35 EFIAPI
     36 FileInterfaceOpenNotFound(
     37   IN EFI_FILE_PROTOCOL *This,
     38   OUT EFI_FILE_PROTOCOL **NewHandle,
     39   IN CHAR16 *FileName,
     40   IN UINT64 OpenMode,
     41   IN UINT64 Attributes
     42   )
     43 {
     44   return (EFI_NOT_FOUND);
     45 }
     46 
     47 /**
     48   File style interface for console (Close, Delete, & Flush)
     49 
     50   @param[in] This       Ignored.
     51 
     52   @retval EFI_SUCCESS
     53 **/
     54 EFI_STATUS
     55 EFIAPI
     56 FileInterfaceNopGeneric(
     57   IN EFI_FILE_PROTOCOL *This
     58   )
     59 {
     60   return (EFI_SUCCESS);
     61 }
     62 
     63 /**
     64   File style interface for console (GetPosition).
     65 
     66   @param[in] This       Ignored.
     67   @param[out] Position  Ignored.
     68 
     69   @retval EFI_UNSUPPORTED
     70 **/
     71 EFI_STATUS
     72 EFIAPI
     73 FileInterfaceNopGetPosition(
     74   IN EFI_FILE_PROTOCOL *This,
     75   OUT UINT64 *Position
     76   )
     77 {
     78   return (EFI_UNSUPPORTED);
     79 }
     80 
     81 /**
     82   File style interface for console (SetPosition).
     83 
     84   @param[in] This       Ignored.
     85   @param[in] Position   Ignored.
     86 
     87   @retval EFI_UNSUPPORTED
     88 **/
     89 EFI_STATUS
     90 EFIAPI
     91 FileInterfaceNopSetPosition(
     92   IN EFI_FILE_PROTOCOL *This,
     93   IN UINT64 Position
     94   )
     95 {
     96   return (EFI_UNSUPPORTED);
     97 }
     98 
     99 /**
    100   File style interface for console (GetInfo).
    101 
    102   @param[in] This              Ignored.
    103   @param[in] InformationType   Ignored.
    104   @param[in, out] BufferSize   Ignored.
    105   @param[out] Buffer           Ignored.
    106 
    107   @retval EFI_UNSUPPORTED
    108 **/
    109 EFI_STATUS
    110 EFIAPI
    111 FileInterfaceNopGetInfo(
    112   IN EFI_FILE_PROTOCOL *This,
    113   IN EFI_GUID *InformationType,
    114   IN OUT UINTN *BufferSize,
    115   OUT VOID *Buffer
    116   )
    117 {
    118   return (EFI_UNSUPPORTED);
    119 }
    120 
    121 /**
    122   File style interface for console (SetInfo).
    123 
    124   @param[in] This       Ignored.
    125   @param[in] InformationType   Ignored.
    126   @param[in] BufferSize Ignored.
    127   @param[in] Buffer     Ignored.
    128 
    129   @retval EFI_UNSUPPORTED
    130 **/
    131 EFI_STATUS
    132 EFIAPI
    133 FileInterfaceNopSetInfo(
    134   IN EFI_FILE_PROTOCOL *This,
    135   IN EFI_GUID *InformationType,
    136   IN UINTN BufferSize,
    137   IN VOID *Buffer
    138   )
    139 {
    140   return (EFI_UNSUPPORTED);
    141 }
    142 
    143 /**
    144   File style interface for StdOut (Write).
    145 
    146   Writes data to the screen.
    147 
    148   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
    149   @param[in, out] BufferSize   Size in bytes of Buffer.
    150   @param[in] Buffer            The pointer to the buffer to write.
    151 
    152   @retval EFI_UNSUPPORTED No output console is supported.
    153   @return A return value from gST->ConOut->OutputString.
    154 **/
    155 EFI_STATUS
    156 EFIAPI
    157 FileInterfaceStdOutWrite(
    158   IN EFI_FILE_PROTOCOL *This,
    159   IN OUT UINTN *BufferSize,
    160   IN VOID *Buffer
    161   )
    162 {
    163   if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
    164     return (EFI_UNSUPPORTED);
    165   }
    166   if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {
    167     return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));
    168   }
    169   return (gST->ConOut->OutputString(gST->ConOut, Buffer));
    170 }
    171 
    172 /**
    173   File style interface for StdIn (Write).
    174 
    175   @param[in] This            Ignored.
    176   @param[in, out] BufferSize Ignored.
    177   @param[in] Buffer          Ignored.
    178 
    179   @retval EFI_UNSUPPORTED
    180 **/
    181 EFI_STATUS
    182 EFIAPI
    183 FileInterfaceStdInWrite(
    184   IN      EFI_FILE_PROTOCOL *This,
    185   IN OUT  UINTN             *BufferSize,
    186   IN      VOID              *Buffer
    187   )
    188 {
    189   return (EFI_UNSUPPORTED);
    190 }
    191 
    192 /**
    193   File style interface for console StdErr (Write).
    194 
    195   Writes error to the error output.
    196 
    197   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
    198   @param[in, out] BufferSize   Size in bytes of Buffer.
    199   @param[in] Buffer            The pointer to the buffer to write.
    200 
    201   @return A return value from gST->StdErr->OutputString.
    202 **/
    203 EFI_STATUS
    204 EFIAPI
    205 FileInterfaceStdErrWrite(
    206   IN EFI_FILE_PROTOCOL *This,
    207   IN OUT UINTN *BufferSize,
    208   IN VOID *Buffer
    209   )
    210 {
    211   return (gST->StdErr->OutputString(gST->StdErr, Buffer));
    212 }
    213 
    214 /**
    215   File style interface for console StdOut (Read).
    216 
    217   @param[in] This              Ignored.
    218   @param[in, out] BufferSize   Ignored.
    219   @param[out] Buffer           Ignored.
    220 
    221   @retval EFI_UNSUPPORTED
    222 **/
    223 EFI_STATUS
    224 EFIAPI
    225 FileInterfaceStdOutRead(
    226   IN EFI_FILE_PROTOCOL *This,
    227   IN OUT UINTN *BufferSize,
    228   OUT VOID *Buffer
    229   )
    230 {
    231   return (EFI_UNSUPPORTED);
    232 }
    233 
    234 /**
    235   File style interface for console StdErr (Read).
    236 
    237   @param[in] This              Ignored.
    238   @param[in, out] BufferSize   Ignored.
    239   @param[out] Buffer           Ignored.
    240 
    241   @retval EFI_UNSUPPORTED Always.
    242 **/
    243 EFI_STATUS
    244 EFIAPI
    245 FileInterfaceStdErrRead(
    246   IN EFI_FILE_PROTOCOL *This,
    247   IN OUT UINTN *BufferSize,
    248   OUT VOID *Buffer
    249   )
    250 {
    251   return (EFI_UNSUPPORTED);
    252 }
    253 
    254 /**
    255   File style interface for NUL file (Read).
    256 
    257   @param[in] This              Ignored.
    258   @param[in, out] BufferSize   Poiner to 0 upon return.
    259   @param[out] Buffer           Ignored.
    260 
    261   @retval EFI_SUCCESS Always.
    262 **/
    263 EFI_STATUS
    264 EFIAPI
    265 FileInterfaceNulRead(
    266   IN      EFI_FILE_PROTOCOL *This,
    267   IN OUT  UINTN             *BufferSize,
    268   OUT     VOID              *Buffer
    269   )
    270 {
    271   *BufferSize = 0;
    272   return (EFI_SUCCESS);
    273 }
    274 
    275 /**
    276   File style interface for NUL file (Write).
    277 
    278   @param[in] This              Ignored.
    279   @param[in, out] BufferSize   Ignored.
    280   @param[in] Buffer            Ignored.
    281 
    282   @retval EFI_SUCCESS
    283 **/
    284 EFI_STATUS
    285 EFIAPI
    286 FileInterfaceNulWrite(
    287   IN EFI_FILE_PROTOCOL *This,
    288   IN OUT UINTN *BufferSize,
    289   IN VOID *Buffer
    290   )
    291 {
    292   return (EFI_SUCCESS);
    293 }
    294 
    295 /**
    296   Create the TAB completion list.
    297 
    298   @param[in]  InputString       The command line to expand.
    299   @param[in]  StringLen         Length of the command line.
    300   @param[in]  BufferSize        Buffer size.
    301   @param[in, out] TabCompletionList Return the TAB completion list.
    302   @param[in, out] TabUpdatePos      Return the TAB update position.
    303 **/
    304 EFI_STATUS
    305 CreateTabCompletionList (
    306   IN CONST CHAR16             *InputString,
    307   IN CONST UINTN              StringLen,
    308   IN CONST UINTN              BufferSize,
    309   IN OUT EFI_SHELL_FILE_INFO  **TabCompletionList,
    310   IN OUT   UINTN              *TabUpdatePos
    311 )
    312 {
    313   BOOLEAN             InQuotation;
    314   UINTN               TabPos;
    315   UINTN               Index;
    316   CONST CHAR16        *Cwd;
    317   EFI_STATUS          Status;
    318   CHAR16              *TabStr;
    319   EFI_SHELL_FILE_INFO *FileList;
    320   EFI_SHELL_FILE_INFO *FileInfo;
    321   EFI_SHELL_FILE_INFO *TempFileInfo;
    322 
    323   //
    324   // Allocate buffers
    325   //
    326   TabStr = AllocateZeroPool (BufferSize);
    327   if (TabStr == NULL) {
    328     return EFI_OUT_OF_RESOURCES;
    329   }
    330 
    331   //
    332   // handle auto complete of file and directory names...
    333   // E.g.: cd fs0:\EFI\Bo<TAB>
    334   //          ^        ^
    335   //          TabPos   TabUpdatePos
    336   //
    337   TabPos        = 0;
    338   *TabUpdatePos = 0;
    339   FileList      = NULL;
    340   InQuotation   = FALSE;
    341   for (Index = 0; Index < StringLen; Index++) {
    342     switch (InputString[Index]) {
    343     case L'\"':
    344       InQuotation = (BOOLEAN) (!InQuotation);
    345       break;
    346 
    347     case L' ':
    348       if (!InQuotation) {
    349         TabPos = Index + 1;
    350         *TabUpdatePos = TabPos;
    351       }
    352       break;
    353 
    354     case L':':
    355       //
    356       // handle the case "fs0:<TAB>"
    357       // Update the TabUpdatePos as well.
    358       //
    359     case L'\\':
    360       *TabUpdatePos = Index + 1;
    361       break;
    362 
    363     default:
    364       break;
    365     }
    366   }
    367 
    368   if (StrStr (InputString + TabPos, L":") == NULL) {
    369     //
    370     // If file path doesn't contain ":", ...
    371     //
    372     Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);
    373     if (Cwd != NULL) {
    374       if (InputString[TabPos] != L'\\') {
    375         //
    376         // and it doesn't begin with "\\", it's a path relative to current directory.
    377         // TabStr = "<cwd>\\"
    378         //
    379         StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);
    380         StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");
    381       } else {
    382         //
    383         // and it begins with "\\", it's a path pointing to root directory of current map.
    384         // TabStr = "fsx:"
    385         //
    386         Index = StrStr (Cwd, L":") - Cwd + 1;
    387         StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);
    388       }
    389     }
    390   }
    391   StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);
    392   StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));
    393   Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);
    394 
    395   //
    396   // Filter out the non-directory for "CD" command
    397   // Filter "." and ".." for all
    398   //
    399   if (!EFI_ERROR (Status) && FileList != NULL) {
    400     //
    401     // Skip the spaces in the beginning
    402     //
    403     while (*InputString == L' ') {
    404       InputString++;
    405     }
    406 
    407     for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {
    408       if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||
    409           (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&
    410            (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {
    411         TempFileInfo = FileInfo;
    412         FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);
    413         InternalFreeShellFileInfoNode (TempFileInfo);
    414       } else {
    415         FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);
    416       }
    417     }
    418   }
    419 
    420   if (FileList != NULL && !IsListEmpty (&FileList->Link)) {
    421     Status = EFI_SUCCESS;
    422   } else {
    423     ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);
    424     Status = EFI_NOT_FOUND;
    425   }
    426 
    427   FreePool (TabStr);
    428 
    429   *TabCompletionList = FileList;
    430   return Status;
    431 }
    432 
    433 /**
    434   File style interface for console (Read).
    435 
    436   This will return a single line of input from the console.
    437 
    438   @param This           A pointer to the EFI_FILE_PROTOCOL instance that is the
    439                         file handle to read data from. Not used.
    440   @param BufferSize     On input, the size of the Buffer. On output, the amount
    441                         of data returned in Buffer. In both cases, the size is
    442                         measured in bytes.
    443   @param Buffer         The buffer into which the data is read.
    444 
    445 
    446   @retval EFI_SUCCESS           The data was read.
    447   @retval EFI_NO_MEDIA          The device has no medium.
    448   @retval EFI_DEVICE_ERROR      The device reported an error.
    449   @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted file.
    450   @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond the end of the file.
    451   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
    452   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current directory
    453                                 entry. BufferSize has been updated with the size
    454                                 needed to complete the request.
    455   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
    456 **/
    457 EFI_STATUS
    458 EFIAPI
    459 FileInterfaceStdInRead(
    460   IN EFI_FILE_PROTOCOL *This,
    461   IN OUT UINTN *BufferSize,
    462   OUT VOID *Buffer
    463   )
    464 {
    465   CHAR16              *CurrentString;
    466   BOOLEAN             Done;
    467   UINTN               TabUpdatePos;   // Start index of the string updated by TAB stroke
    468   UINTN               Column;         // Column of current cursor
    469   UINTN               Row;            // Row of current cursor
    470   UINTN               StartColumn;    // Column at the beginning of the line
    471   UINTN               Update;         // Line index for update
    472   UINTN               Delete;         // Num of chars to delete from console after update
    473   UINTN               StringLen;      // Total length of the line
    474   UINTN               StringCurPos;   // Line index corresponding to the cursor
    475   UINTN               MaxStr;         // Maximum possible line length
    476   UINTN               TotalColumn;     // Num of columns in the console
    477   UINTN               TotalRow;       // Num of rows in the console
    478   UINTN               SkipLength;
    479   UINTN               OutputLength;   // Length of the update string
    480   UINTN               TailRow;        // Row of end of line
    481   UINTN               TailColumn;     // Column of end of line
    482   EFI_INPUT_KEY       Key;
    483 
    484   BUFFER_LIST         *LinePos;
    485   BUFFER_LIST         *NewPos;
    486   BOOLEAN             InScrolling;
    487   EFI_STATUS          Status;
    488   BOOLEAN             InTabScrolling; // Whether in TAB-completion state
    489   EFI_SHELL_FILE_INFO *TabCompleteList;
    490   EFI_SHELL_FILE_INFO *TabCurrent;
    491   UINTN               EventIndex;
    492   CHAR16              *TabOutputStr;
    493 
    494   //
    495   // If buffer is not large enough to hold a CHAR16, return minimum buffer size
    496   //
    497   if (*BufferSize < sizeof (CHAR16) * 2) {
    498     *BufferSize = sizeof (CHAR16) * 2;
    499     return (EFI_BUFFER_TOO_SMALL);
    500   }
    501 
    502   Done              = FALSE;
    503   CurrentString     = Buffer;
    504   StringLen         = 0;
    505   StringCurPos      = 0;
    506   OutputLength      = 0;
    507   Update            = 0;
    508   Delete            = 0;
    509   LinePos           = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
    510   InScrolling       = FALSE;
    511   InTabScrolling    = FALSE;
    512   Status            = EFI_SUCCESS;
    513   TabOutputStr      = NULL;
    514   TabUpdatePos      = 0;
    515   TabCompleteList   = NULL;
    516   TabCurrent        = NULL;
    517 
    518   //
    519   // Get the screen setting and the current cursor location
    520   //
    521   Column      = StartColumn = gST->ConOut->Mode->CursorColumn;
    522   Row         = gST->ConOut->Mode->CursorRow;
    523   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);
    524 
    525   //
    526   // Limit the line length to the buffer size or the minimun size of the
    527   // screen. (The smaller takes effect)
    528   //
    529   MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;
    530   if (MaxStr > *BufferSize / sizeof (CHAR16)) {
    531     MaxStr = *BufferSize / sizeof (CHAR16);
    532   }
    533   ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
    534   do {
    535     //
    536     // Read a key
    537     //
    538     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
    539     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    540     if (EFI_ERROR (Status)) {
    541 
    542       if (Status == EFI_NOT_READY)
    543         continue;
    544 
    545       ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));
    546       StringLen = 0;
    547       break;
    548     }
    549 
    550     //
    551     // Press PageUp or PageDown to scroll the history screen up or down.
    552     // Press any other key to quit scrolling.
    553     //
    554     if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {
    555       if (Key.ScanCode == SCAN_PAGE_UP) {
    556         ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);
    557       } else if (Key.ScanCode == SCAN_PAGE_DOWN) {
    558         ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);
    559       }
    560 
    561       InScrolling = TRUE;
    562     } else {
    563       if (InScrolling) {
    564         ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);
    565         InScrolling = FALSE;
    566       }
    567     }
    568 
    569     //
    570     // If we are quitting TAB scrolling...
    571     //
    572     if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {
    573       if (TabCompleteList != NULL) {
    574         ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
    575         DEBUG_CODE(TabCompleteList = NULL;);
    576       }
    577       InTabScrolling = FALSE;
    578     }
    579 
    580     switch (Key.UnicodeChar) {
    581     case CHAR_CARRIAGE_RETURN:
    582       //
    583       // All done, print a newline at the end of the string
    584       //
    585       TailRow     = Row + (StringLen - StringCurPos + Column) / TotalColumn;
    586       TailColumn  = (StringLen - StringCurPos + Column) % TotalColumn;
    587       ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");
    588       Done = TRUE;
    589       break;
    590 
    591     case CHAR_BACKSPACE:
    592       if (StringCurPos != 0) {
    593         //
    594         // If not move back beyond string beginning, move all characters behind
    595         // the current position one character forward
    596         //
    597         StringCurPos--;
    598         Update  = StringCurPos;
    599         Delete  = 1;
    600         CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
    601 
    602         //
    603         // Adjust the current column and row
    604         //
    605         MoveCursorBackward (TotalColumn, &Column, &Row);
    606       }
    607       break;
    608 
    609     case CHAR_TAB:
    610       if (!InTabScrolling) {
    611         TabCurrent = NULL;
    612         //
    613         // Initialize a tab complete operation.
    614         //
    615         Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);
    616         if (!EFI_ERROR(Status)) {
    617           InTabScrolling = TRUE;
    618         }
    619 
    620         //
    621         // We do not set up the replacement.
    622         // The next section will do that.
    623         //
    624       }
    625 
    626       if (InTabScrolling) {
    627         //
    628         // We are in a tab complete operation.
    629         // set up the next replacement.
    630         //
    631         ASSERT(TabCompleteList != NULL);
    632         if (TabCurrent == NULL) {
    633           TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);
    634         } else {
    635           TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
    636         }
    637 
    638         //
    639         // Skip over the empty list beginning node
    640         //
    641         if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {
    642           TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
    643         }
    644       }
    645       break;
    646 
    647     default:
    648       if (Key.UnicodeChar >= ' ') {
    649         //
    650         // If we are at the buffer's end, drop the key
    651         //
    652         if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {
    653           break;
    654         }
    655         //
    656         // If in insert mode, make space by moving each other character 1
    657         // space higher in the array
    658         //
    659         if (ShellInfoObject.ViewingSettings.InsertMode) {
    660           CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));
    661         }
    662 
    663         CurrentString[StringCurPos] = Key.UnicodeChar;
    664         Update      = StringCurPos;
    665 
    666         StringCurPos += 1;
    667         OutputLength = 1;
    668       }
    669       break;
    670 
    671     case 0:
    672       switch (Key.ScanCode) {
    673       case SCAN_DELETE:
    674         //
    675         // Move characters behind current position one character forward
    676         //
    677         if (StringLen != 0) {
    678           Update  = StringCurPos;
    679           Delete  = 1;
    680           CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
    681         }
    682         break;
    683 
    684       case SCAN_UP:
    685         //
    686         // Prepare to print the previous command
    687         //
    688         NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
    689         if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {
    690           NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
    691         }
    692         break;
    693 
    694       case SCAN_DOWN:
    695         //
    696         // Prepare to print the next command
    697         //
    698         NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
    699         if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
    700           NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
    701         }
    702         break;
    703 
    704       case SCAN_LEFT:
    705         //
    706         // Adjust current cursor position
    707         //
    708         if (StringCurPos != 0) {
    709           --StringCurPos;
    710           MoveCursorBackward (TotalColumn, &Column, &Row);
    711         }
    712         break;
    713 
    714       case SCAN_RIGHT:
    715         //
    716         // Adjust current cursor position
    717         //
    718         if (StringCurPos < StringLen) {
    719           ++StringCurPos;
    720           MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
    721         }
    722         break;
    723 
    724       case SCAN_HOME:
    725         //
    726         // Move current cursor position to the beginning of the command line
    727         //
    728         Row -= (StringCurPos + StartColumn) / TotalColumn;
    729         Column  = StartColumn;
    730         StringCurPos  = 0;
    731         break;
    732 
    733       case SCAN_END:
    734         //
    735         // Move current cursor position to the end of the command line
    736         //
    737         TailRow       = Row + (StringLen - StringCurPos + Column) / TotalColumn;
    738         TailColumn    = (StringLen - StringCurPos + Column) % TotalColumn;
    739         Row           = TailRow;
    740         Column        = TailColumn;
    741         StringCurPos  = StringLen;
    742         break;
    743 
    744       case SCAN_ESC:
    745         //
    746         // Prepare to clear the current command line
    747         //
    748         CurrentString[0]  = 0;
    749         Update  = 0;
    750         Delete  = StringLen;
    751         Row -= (StringCurPos + StartColumn) / TotalColumn;
    752         Column        = StartColumn;
    753         OutputLength  = 0;
    754         break;
    755 
    756       case SCAN_INSERT:
    757         //
    758         // Toggle the SEnvInsertMode flag
    759         //
    760         ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;
    761         break;
    762 
    763       case SCAN_F7:
    764         //
    765         // Print command history
    766         //
    767         PrintCommandHistory (TotalColumn, TotalRow, 4);
    768         *CurrentString  = CHAR_NULL;
    769         Done  = TRUE;
    770         break;
    771       }
    772     }
    773 
    774     if (Done) {
    775       break;
    776     }
    777 
    778     //
    779     // If we are in auto-complete mode, we are preparing to print
    780     // the next file or directory name
    781     //
    782     if (InTabScrolling) {
    783       TabOutputStr = AllocateZeroPool (*BufferSize);
    784       if (TabOutputStr == NULL) {
    785         Status = EFI_OUT_OF_RESOURCES;
    786       }
    787     }
    788 
    789     if (InTabScrolling && TabOutputStr != NULL) {
    790 
    791       //
    792       // Adjust the column and row to the start of TAB-completion string.
    793       //
    794       Column = (StartColumn + TabUpdatePos) % TotalColumn;
    795       Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
    796       OutputLength = StrLen (TabCurrent->FileName);
    797       //
    798       // if the output string contains  blank space, quotation marks L'\"'
    799       // should be added to the output.
    800       //
    801       if (StrStr(TabCurrent->FileName, L" ") != NULL){
    802         TabOutputStr[0] = L'\"';
    803         CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
    804         TabOutputStr[OutputLength + 1] = L'\"';
    805         TabOutputStr[OutputLength + 2] = CHAR_NULL;
    806       } else {
    807         CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
    808         TabOutputStr[OutputLength] = CHAR_NULL;
    809       }
    810       OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;
    811       CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));
    812       CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;
    813       StringCurPos = TabUpdatePos + OutputLength;
    814       Update = TabUpdatePos;
    815       if (StringLen > TabUpdatePos + OutputLength) {
    816         Delete = StringLen - TabUpdatePos - OutputLength;
    817       }
    818 
    819       FreePool(TabOutputStr);
    820     }
    821 
    822     //
    823     // If we have a new position, we are preparing to print a previous or
    824     // next command.
    825     //
    826     if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
    827       Column = StartColumn;
    828       Row -= (StringCurPos + StartColumn) / TotalColumn;
    829 
    830       LinePos       = NewPos;
    831       NewPos        = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
    832 
    833       OutputLength  = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;
    834       CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));
    835       CurrentString[OutputLength] = CHAR_NULL;
    836 
    837       StringCurPos            = OutputLength;
    838 
    839       //
    840       // Draw new input string
    841       //
    842       Update = 0;
    843       if (StringLen > OutputLength) {
    844         //
    845         // If old string was longer, blank its tail
    846         //
    847         Delete = StringLen - OutputLength;
    848       }
    849     }
    850     //
    851     // If we need to update the output do so now
    852     //
    853     if (Update != (UINTN) -1) {
    854       ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
    855       StringLen = StrLen (CurrentString);
    856 
    857       if (Delete != 0) {
    858         SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
    859       }
    860 
    861       if (StringCurPos > StringLen) {
    862         StringCurPos = StringLen;
    863       }
    864 
    865       Update = (UINTN) -1;
    866 
    867       //
    868       // After using print to reflect newly updates, if we're not using
    869       // BACKSPACE and DELETE, we need to move the cursor position forward,
    870       // so adjust row and column here.
    871       //
    872       if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
    873         //
    874         // Calulate row and column of the tail of current string
    875         //
    876         TailRow     = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
    877         TailColumn  = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
    878 
    879         //
    880         // If the tail of string reaches screen end, screen rolls up, so if
    881         // Row does not equal TailRow, Row should be decremented
    882         //
    883         // (if we are recalling commands using UPPER and DOWN key, and if the
    884         // old command is too long to fit the screen, TailColumn must be 79.
    885         //
    886         if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
    887           Row--;
    888         }
    889         //
    890         // Calculate the cursor position after current operation. If cursor
    891         // reaches line end, update both row and column, otherwise, only
    892         // column will be changed.
    893         //
    894         if (Column + OutputLength >= TotalColumn) {
    895           SkipLength = OutputLength - (TotalColumn - Column);
    896 
    897           Row += SkipLength / TotalColumn + 1;
    898           if (Row > TotalRow - 1) {
    899             Row = TotalRow - 1;
    900           }
    901 
    902           Column = SkipLength % TotalColumn;
    903         } else {
    904           Column += OutputLength;
    905         }
    906       }
    907 
    908       Delete = 0;
    909     }
    910     //
    911     // Set the cursor position for this key
    912     //
    913     gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
    914   } while (!Done);
    915 
    916   if (CurrentString != NULL && StrLen(CurrentString) > 0) {
    917     //
    918     // add the line to the history buffer
    919     //
    920     AddLineToCommandHistory(CurrentString);
    921   }
    922 
    923   //
    924   // Return the data to the caller
    925   //
    926   *BufferSize = StringLen * sizeof (CHAR16);
    927 
    928   //
    929   // if this was used it should be deallocated by now...
    930   // prevent memory leaks...
    931   //
    932   if (TabCompleteList != NULL) {
    933     ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
    934   }
    935   ASSERT(TabCompleteList == NULL);
    936 
    937   return Status;
    938 }
    939 
    940 //
    941 // FILE sytle interfaces for StdIn/StdOut/StdErr
    942 //
    943 EFI_FILE_PROTOCOL FileInterfaceStdIn = {
    944   EFI_FILE_REVISION,
    945   FileInterfaceOpenNotFound,
    946   FileInterfaceNopGeneric,
    947   FileInterfaceNopGeneric,
    948   FileInterfaceStdInRead,
    949   FileInterfaceStdInWrite,
    950   FileInterfaceNopGetPosition,
    951   FileInterfaceNopSetPosition,
    952   FileInterfaceNopGetInfo,
    953   FileInterfaceNopSetInfo,
    954   FileInterfaceNopGeneric
    955 };
    956 
    957 EFI_FILE_PROTOCOL FileInterfaceStdOut = {
    958   EFI_FILE_REVISION,
    959   FileInterfaceOpenNotFound,
    960   FileInterfaceNopGeneric,
    961   FileInterfaceNopGeneric,
    962   FileInterfaceStdOutRead,
    963   FileInterfaceStdOutWrite,
    964   FileInterfaceNopGetPosition,
    965   FileInterfaceNopSetPosition,
    966   FileInterfaceNopGetInfo,
    967   FileInterfaceNopSetInfo,
    968   FileInterfaceNopGeneric
    969 };
    970 
    971 EFI_FILE_PROTOCOL FileInterfaceStdErr = {
    972   EFI_FILE_REVISION,
    973   FileInterfaceOpenNotFound,
    974   FileInterfaceNopGeneric,
    975   FileInterfaceNopGeneric,
    976   FileInterfaceStdErrRead,
    977   FileInterfaceStdErrWrite,
    978   FileInterfaceNopGetPosition,
    979   FileInterfaceNopSetPosition,
    980   FileInterfaceNopGetInfo,
    981   FileInterfaceNopSetInfo,
    982   FileInterfaceNopGeneric
    983 };
    984 
    985 EFI_FILE_PROTOCOL FileInterfaceNulFile = {
    986   EFI_FILE_REVISION,
    987   FileInterfaceOpenNotFound,
    988   FileInterfaceNopGeneric,
    989   FileInterfaceNopGeneric,
    990   FileInterfaceNulRead,
    991   FileInterfaceNulWrite,
    992   FileInterfaceNopGetPosition,
    993   FileInterfaceNopSetPosition,
    994   FileInterfaceNopGetInfo,
    995   FileInterfaceNopSetInfo,
    996   FileInterfaceNopGeneric
    997 };
    998 
    999 
   1000 
   1001 
   1002 //
   1003 // This is identical to EFI_FILE_PROTOCOL except for the additional member
   1004 // for the name.
   1005 //
   1006 
   1007 typedef struct {
   1008   UINT64                Revision;
   1009   EFI_FILE_OPEN         Open;
   1010   EFI_FILE_CLOSE        Close;
   1011   EFI_FILE_DELETE       Delete;
   1012   EFI_FILE_READ         Read;
   1013   EFI_FILE_WRITE        Write;
   1014   EFI_FILE_GET_POSITION GetPosition;
   1015   EFI_FILE_SET_POSITION SetPosition;
   1016   EFI_FILE_GET_INFO     GetInfo;
   1017   EFI_FILE_SET_INFO     SetInfo;
   1018   EFI_FILE_FLUSH        Flush;
   1019   CHAR16                Name[1];
   1020 } EFI_FILE_PROTOCOL_ENVIRONMENT;
   1021 //ANSI compliance helper to get size of the struct.
   1022 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
   1023 
   1024 /**
   1025   File style interface for Environment Variable (Close).
   1026 
   1027   Frees the memory for this object.
   1028 
   1029   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1030 
   1031   @retval EFI_SUCCESS
   1032 **/
   1033 EFI_STATUS
   1034 EFIAPI
   1035 FileInterfaceEnvClose(
   1036   IN EFI_FILE_PROTOCOL *This
   1037   )
   1038 {
   1039   VOID*       NewBuffer;
   1040   UINTN       NewSize;
   1041   EFI_STATUS  Status;
   1042   BOOLEAN     Volatile;
   1043   UINTN       TotalSize;
   1044 
   1045   //
   1046   // Most if not all UEFI commands will have an '\r\n' at the end of any output.
   1047   // Since the output was redirected to a variable, it does not make sense to
   1048   // keep this.  So, before closing, strip the trailing '\r\n' from the variable
   1049   // if it exists.
   1050   //
   1051   NewBuffer   = NULL;
   1052   NewSize     = 0;
   1053   TotalSize   = 0;
   1054 
   1055   Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);
   1056   if (EFI_ERROR (Status)) {
   1057     return Status;
   1058   }
   1059 
   1060   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1061   if (Status == EFI_BUFFER_TOO_SMALL) {
   1062     TotalSize = NewSize + sizeof (CHAR16);
   1063     NewBuffer = AllocateZeroPool (TotalSize);
   1064     if (NewBuffer == NULL) {
   1065       return EFI_OUT_OF_RESOURCES;
   1066     }
   1067     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1068   }
   1069 
   1070   if (!EFI_ERROR(Status) && NewBuffer != NULL) {
   1071 
   1072     if (TotalSize / sizeof (CHAR16) >= 3) {
   1073       if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) &&
   1074            (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN)
   1075          ) {
   1076         ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;
   1077       }
   1078 
   1079       if (Volatile) {
   1080         Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
   1081                    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1082                    TotalSize - sizeof (CHAR16),
   1083                    NewBuffer
   1084                    );
   1085 
   1086         if (!EFI_ERROR(Status)) {
   1087           Status = ShellAddEnvVarToList (
   1088                      ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1089                      NewBuffer,
   1090                      TotalSize,
   1091                      EFI_VARIABLE_BOOTSERVICE_ACCESS
   1092                      );
   1093         }
   1094       } else {
   1095         Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
   1096                    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1097                    TotalSize - sizeof (CHAR16),
   1098                    NewBuffer
   1099                    );
   1100 
   1101         if (!EFI_ERROR(Status)) {
   1102           Status = ShellAddEnvVarToList (
   1103                      ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1104                      NewBuffer,
   1105                      TotalSize,
   1106                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
   1107                      );
   1108         }
   1109       }
   1110     }
   1111   }
   1112 
   1113   SHELL_FREE_NON_NULL(NewBuffer);
   1114   FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);
   1115   return (Status);
   1116 }
   1117 
   1118 /**
   1119   File style interface for Environment Variable (Delete).
   1120 
   1121   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1122 
   1123   @retval The return value from FileInterfaceEnvClose().
   1124 **/
   1125 EFI_STATUS
   1126 EFIAPI
   1127 FileInterfaceEnvDelete(
   1128   IN EFI_FILE_PROTOCOL *This
   1129   )
   1130 {
   1131   SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
   1132   return (FileInterfaceEnvClose(This));
   1133 }
   1134 
   1135 /**
   1136   File style interface for Environment Variable (Read).
   1137 
   1138   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1139   @param[in, out] BufferSize   Size in bytes of Buffer.
   1140   @param[out] Buffer           The pointer to the buffer to fill.
   1141 
   1142   @retval EFI_SUCCESS   The data was read.
   1143 **/
   1144 EFI_STATUS
   1145 EFIAPI
   1146 FileInterfaceEnvRead(
   1147   IN EFI_FILE_PROTOCOL *This,
   1148   IN OUT UINTN *BufferSize,
   1149   OUT VOID *Buffer
   1150   )
   1151 {
   1152   return (SHELL_GET_ENVIRONMENT_VARIABLE(
   1153     ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1154     BufferSize,
   1155     Buffer));
   1156 }
   1157 
   1158 /**
   1159   File style interface for Volatile Environment Variable (Write).
   1160   This function also caches the environment variable into gShellEnvVarList.
   1161 
   1162   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1163   @param[in, out] BufferSize   Size in bytes of Buffer.
   1164   @param[in] Buffer            The pointer to the buffer to write.
   1165 
   1166   @retval EFI_SUCCESS             The data was successfully write to variable.
   1167   @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.
   1168 **/
   1169 EFI_STATUS
   1170 EFIAPI
   1171 FileInterfaceEnvVolWrite(
   1172   IN EFI_FILE_PROTOCOL *This,
   1173   IN OUT UINTN *BufferSize,
   1174   IN VOID *Buffer
   1175   )
   1176 {
   1177   VOID*       NewBuffer;
   1178   UINTN       NewSize;
   1179   EFI_STATUS  Status;
   1180   UINTN       TotalSize;
   1181 
   1182   NewBuffer   = NULL;
   1183   NewSize     = 0;
   1184   TotalSize   = 0;
   1185 
   1186   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1187   if (Status == EFI_BUFFER_TOO_SMALL) {
   1188     TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
   1189   } else if (Status == EFI_NOT_FOUND) {
   1190     TotalSize = *BufferSize + sizeof(CHAR16);
   1191   } else {
   1192     return Status;
   1193   }
   1194 
   1195   NewBuffer = AllocateZeroPool (TotalSize);
   1196   if (NewBuffer == NULL) {
   1197     return EFI_OUT_OF_RESOURCES;
   1198   }
   1199 
   1200   if (Status == EFI_BUFFER_TOO_SMALL) {
   1201     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1202   }
   1203 
   1204   if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
   1205     FreePool (NewBuffer);
   1206     return Status;
   1207   }
   1208 
   1209   CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
   1210   Status = ShellAddEnvVarToList (
   1211              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1212              NewBuffer,
   1213              TotalSize,
   1214              EFI_VARIABLE_BOOTSERVICE_ACCESS
   1215              );
   1216   if (EFI_ERROR(Status)) {
   1217     FreePool (NewBuffer);
   1218     return Status;
   1219   }
   1220 
   1221   Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
   1222              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1223              TotalSize - sizeof (CHAR16),
   1224              NewBuffer
   1225              );
   1226   if (EFI_ERROR(Status)) {
   1227     ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
   1228   }
   1229 
   1230   FreePool (NewBuffer);
   1231   return Status;
   1232 }
   1233 
   1234 
   1235 /**
   1236   File style interface for Non Volatile Environment Variable (Write).
   1237   This function also caches the environment variable into gShellEnvVarList.
   1238 
   1239   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1240   @param[in, out] BufferSize   Size in bytes of Buffer.
   1241   @param[in] Buffer            The pointer to the buffer to write.
   1242 
   1243   @retval EFI_SUCCESS             The data was successfully write to variable.
   1244   @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.
   1245 **/
   1246 EFI_STATUS
   1247 EFIAPI
   1248 FileInterfaceEnvNonVolWrite(
   1249   IN EFI_FILE_PROTOCOL *This,
   1250   IN OUT UINTN *BufferSize,
   1251   IN VOID *Buffer
   1252   )
   1253 {
   1254   VOID*       NewBuffer;
   1255   UINTN       NewSize;
   1256   EFI_STATUS  Status;
   1257   UINTN       TotalSize;
   1258 
   1259   NewBuffer   = NULL;
   1260   NewSize     = 0;
   1261   TotalSize   = 0;
   1262 
   1263   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1264   if (Status == EFI_BUFFER_TOO_SMALL) {
   1265     TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
   1266   } else if (Status == EFI_NOT_FOUND) {
   1267     TotalSize = *BufferSize + sizeof (CHAR16);
   1268   } else {
   1269     return Status;
   1270   }
   1271 
   1272   NewBuffer = AllocateZeroPool (TotalSize);
   1273   if (NewBuffer == NULL) {
   1274     return EFI_OUT_OF_RESOURCES;
   1275   }
   1276 
   1277   if (Status == EFI_BUFFER_TOO_SMALL) {
   1278     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
   1279   }
   1280 
   1281   if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {
   1282     FreePool (NewBuffer);
   1283     return Status;
   1284   }
   1285 
   1286   CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize);
   1287   Status = ShellAddEnvVarToList (
   1288              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1289              NewBuffer,
   1290              TotalSize,
   1291              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
   1292              );
   1293   if (EFI_ERROR (Status)) {
   1294     FreePool (NewBuffer);
   1295     return Status;
   1296   }
   1297 
   1298   Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
   1299              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
   1300              TotalSize - sizeof (CHAR16),
   1301              NewBuffer
   1302              );
   1303   if (EFI_ERROR (Status)) {
   1304     ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
   1305   }
   1306 
   1307   FreePool (NewBuffer);
   1308   return Status;
   1309 }
   1310 
   1311 /**
   1312   Creates a EFI_FILE_PROTOCOL (almost) object for using to access
   1313   environment variables through file operations.
   1314 
   1315   @param EnvName    The name of the Environment Variable to be operated on.
   1316 
   1317   @retval NULL      Memory could not be allocated.
   1318   @return other     a pointer to an EFI_FILE_PROTOCOL structure
   1319 **/
   1320 EFI_FILE_PROTOCOL*
   1321 CreateFileInterfaceEnv(
   1322   IN CONST CHAR16 *EnvName
   1323   )
   1324 {
   1325   EFI_STATUS                     Status;
   1326   EFI_FILE_PROTOCOL_ENVIRONMENT  *EnvFileInterface;
   1327   UINTN                          EnvNameSize;
   1328   BOOLEAN                        Volatile;
   1329 
   1330   if (EnvName == NULL) {
   1331     return (NULL);
   1332   }
   1333 
   1334   Status = IsVolatileEnv (EnvName, &Volatile);
   1335   if (EFI_ERROR (Status)) {
   1336     return NULL;
   1337   }
   1338 
   1339   //
   1340   // Get some memory
   1341   //
   1342   EnvNameSize = StrSize(EnvName);
   1343   EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);
   1344   if (EnvFileInterface == NULL){
   1345     return (NULL);
   1346   }
   1347 
   1348   //
   1349   // Assign the generic members
   1350   //
   1351   EnvFileInterface->Revision    = EFI_FILE_REVISION;
   1352   EnvFileInterface->Open        = FileInterfaceOpenNotFound;
   1353   EnvFileInterface->Close       = FileInterfaceEnvClose;
   1354   EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;
   1355   EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;
   1356   EnvFileInterface->GetInfo     = FileInterfaceNopGetInfo;
   1357   EnvFileInterface->SetInfo     = FileInterfaceNopSetInfo;
   1358   EnvFileInterface->Flush       = FileInterfaceNopGeneric;
   1359   EnvFileInterface->Delete      = FileInterfaceEnvDelete;
   1360   EnvFileInterface->Read        = FileInterfaceEnvRead;
   1361 
   1362   CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);
   1363 
   1364   //
   1365   // Assign the different members for Volatile and Non-Volatile variables
   1366   //
   1367   if (Volatile) {
   1368     EnvFileInterface->Write       = FileInterfaceEnvVolWrite;
   1369   } else {
   1370     EnvFileInterface->Write       = FileInterfaceEnvNonVolWrite;
   1371   }
   1372   return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
   1373 }
   1374 
   1375 /**
   1376   Move the cursor position one character backward.
   1377 
   1378   @param[in] LineLength       Length of a line. Get it by calling QueryMode
   1379   @param[in, out] Column      Current column of the cursor position
   1380   @param[in, out] Row         Current row of the cursor position
   1381 **/
   1382 VOID
   1383 MoveCursorBackward (
   1384   IN     UINTN                   LineLength,
   1385   IN OUT UINTN                   *Column,
   1386   IN OUT UINTN                   *Row
   1387   )
   1388 {
   1389   //
   1390   // If current column is 0, move to the last column of the previous line,
   1391   // otherwise, just decrement column.
   1392   //
   1393   if (*Column == 0) {
   1394     *Column = LineLength - 1;
   1395     if (*Row > 0) {
   1396       (*Row)--;
   1397     }
   1398     return;
   1399   }
   1400   (*Column)--;
   1401 }
   1402 
   1403 /**
   1404   Move the cursor position one character forward.
   1405 
   1406   @param[in] LineLength       Length of a line.
   1407   @param[in] TotalRow         Total row of a screen
   1408   @param[in, out] Column      Current column of the cursor position
   1409   @param[in, out] Row         Current row of the cursor position
   1410 **/
   1411 VOID
   1412 MoveCursorForward (
   1413   IN     UINTN                   LineLength,
   1414   IN     UINTN                   TotalRow,
   1415   IN OUT UINTN                   *Column,
   1416   IN OUT UINTN                   *Row
   1417   )
   1418 {
   1419   //
   1420   // Increment Column.
   1421   // If this puts column past the end of the line, move to first column
   1422   // of the next row.
   1423   //
   1424   (*Column)++;
   1425   if (*Column >= LineLength) {
   1426     (*Column) = 0;
   1427     if ((*Row) < TotalRow - 1) {
   1428       (*Row)++;
   1429     }
   1430   }
   1431 }
   1432 
   1433 /**
   1434   Prints out each previously typed command in the command list history log.
   1435 
   1436   When each screen is full it will pause for a key before continuing.
   1437 
   1438   @param[in] TotalCols    How many columns are on the screen
   1439   @param[in] TotalRows    How many rows are on the screen
   1440   @param[in] StartColumn  which column to start at
   1441 **/
   1442 VOID
   1443 PrintCommandHistory (
   1444   IN CONST UINTN TotalCols,
   1445   IN CONST UINTN TotalRows,
   1446   IN CONST UINTN StartColumn
   1447   )
   1448 {
   1449   BUFFER_LIST     *Node;
   1450   UINTN           Index;
   1451   UINTN           LineNumber;
   1452   UINTN           LineCount;
   1453 
   1454   ShellPrintEx (-1, -1, L"\n");
   1455   Index       = 0;
   1456   LineNumber  = 0;
   1457   //
   1458   // go through history list...
   1459   //
   1460   for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)
   1461       ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
   1462       ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
   1463    ){
   1464     Index++;
   1465     LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
   1466 
   1467     if (LineNumber + LineCount >= TotalRows) {
   1468       ShellPromptForResponseHii(
   1469         ShellPromptResponseTypeEnterContinue,
   1470         STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
   1471         ShellInfoObject.HiiHandle,
   1472         NULL
   1473        );
   1474       LineNumber = 0;
   1475     }
   1476     ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
   1477     LineNumber += LineCount;
   1478   }
   1479 }
   1480 
   1481 
   1482 
   1483 
   1484 
   1485 
   1486 //
   1487 // This is identical to EFI_FILE_PROTOCOL except for the additional members
   1488 // for the buffer, size, and position.
   1489 //
   1490 
   1491 typedef struct {
   1492   UINT64                Revision;
   1493   EFI_FILE_OPEN         Open;
   1494   EFI_FILE_CLOSE        Close;
   1495   EFI_FILE_DELETE       Delete;
   1496   EFI_FILE_READ         Read;
   1497   EFI_FILE_WRITE        Write;
   1498   EFI_FILE_GET_POSITION GetPosition;
   1499   EFI_FILE_SET_POSITION SetPosition;
   1500   EFI_FILE_GET_INFO     GetInfo;
   1501   EFI_FILE_SET_INFO     SetInfo;
   1502   EFI_FILE_FLUSH        Flush;
   1503   VOID                  *Buffer;
   1504   UINT64                Position;
   1505   UINT64                BufferSize;
   1506   BOOLEAN               Unicode;
   1507   UINT64                FileSize;
   1508 } EFI_FILE_PROTOCOL_MEM;
   1509 
   1510 /**
   1511   File style interface for Mem (SetPosition).
   1512 
   1513   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1514   @param[out] Position  The position to set.
   1515 
   1516   @retval EFI_SUCCESS             The position was successfully changed.
   1517   @retval EFI_INVALID_PARAMETER   The Position was invalid.
   1518 **/
   1519 EFI_STATUS
   1520 EFIAPI
   1521 FileInterfaceMemSetPosition(
   1522   IN EFI_FILE_PROTOCOL *This,
   1523   OUT UINT64 Position
   1524   )
   1525 {
   1526   if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) {
   1527     ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;
   1528     return (EFI_SUCCESS);
   1529   } else {
   1530     return (EFI_INVALID_PARAMETER);
   1531   }
   1532 }
   1533 
   1534 /**
   1535   File style interface for Mem (GetPosition).
   1536 
   1537   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1538   @param[out] Position  The pointer to the position.
   1539 
   1540   @retval EFI_SUCCESS   The position was retrieved.
   1541 **/
   1542 EFI_STATUS
   1543 EFIAPI
   1544 FileInterfaceMemGetPosition(
   1545   IN EFI_FILE_PROTOCOL *This,
   1546   OUT UINT64 *Position
   1547   )
   1548 {
   1549   *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;
   1550   return (EFI_SUCCESS);
   1551 }
   1552 
   1553 /**
   1554   File style interface for Mem (Write).
   1555 
   1556   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1557   @param[in, out] BufferSize   Size in bytes of Buffer.
   1558   @param[in] Buffer            The pointer to the buffer to write.
   1559 
   1560   @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
   1561   @retval EFI_SUCCESS          The data was written.
   1562 **/
   1563 EFI_STATUS
   1564 EFIAPI
   1565 FileInterfaceMemWrite(
   1566   IN EFI_FILE_PROTOCOL *This,
   1567   IN OUT UINTN *BufferSize,
   1568   IN VOID *Buffer
   1569   )
   1570 {
   1571   CHAR8                  *AsciiBuffer;
   1572   EFI_FILE_PROTOCOL_MEM  *MemFile;
   1573 
   1574   MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
   1575   if (MemFile->Unicode) {
   1576     //
   1577     // Unicode
   1578     //
   1579     if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {
   1580       MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
   1581       MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;
   1582     }
   1583     CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);
   1584     MemFile->Position += (*BufferSize);
   1585     MemFile->FileSize = MemFile->Position;
   1586     return (EFI_SUCCESS);
   1587   } else {
   1588     //
   1589     // Ascii
   1590     //
   1591     AsciiBuffer = AllocateZeroPool(*BufferSize);
   1592     if (AsciiBuffer == NULL) {
   1593       return (EFI_OUT_OF_RESOURCES);
   1594     }
   1595     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
   1596     if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {
   1597       MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
   1598       MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;
   1599     }
   1600     CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));
   1601     MemFile->Position += (*BufferSize / sizeof(CHAR16));
   1602     MemFile->FileSize = MemFile->Position;
   1603     FreePool(AsciiBuffer);
   1604     return (EFI_SUCCESS);
   1605   }
   1606 }
   1607 
   1608 /**
   1609   File style interface for Mem (Read).
   1610 
   1611   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1612   @param[in, out] BufferSize   Size in bytes of Buffer.
   1613   @param[in] Buffer            The pointer to the buffer to fill.
   1614 
   1615   @retval EFI_SUCCESS   The data was read.
   1616 **/
   1617 EFI_STATUS
   1618 EFIAPI
   1619 FileInterfaceMemRead(
   1620   IN EFI_FILE_PROTOCOL *This,
   1621   IN OUT UINTN *BufferSize,
   1622   IN VOID *Buffer
   1623   )
   1624 {
   1625   EFI_FILE_PROTOCOL_MEM  *MemFile;
   1626 
   1627   MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
   1628   if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {
   1629     (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));
   1630   }
   1631   CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize));
   1632   MemFile->Position = MemFile->Position + (*BufferSize);
   1633   return (EFI_SUCCESS);
   1634 }
   1635 
   1636 /**
   1637   File style interface for Mem (Close).
   1638 
   1639   Frees all memory associated with this object.
   1640 
   1641   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1642 
   1643   @retval EFI_SUCCESS   The 'file' was closed.
   1644 **/
   1645 EFI_STATUS
   1646 EFIAPI
   1647 FileInterfaceMemClose(
   1648   IN EFI_FILE_PROTOCOL *This
   1649   )
   1650 {
   1651   SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);
   1652   SHELL_FREE_NON_NULL(This);
   1653   return (EFI_SUCCESS);
   1654 }
   1655 
   1656 /**
   1657   Creates a EFI_FILE_PROTOCOL (almost) object for using to access
   1658   a file entirely in memory through file operations.
   1659 
   1660   @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
   1661 
   1662   @retval NULL      Memory could not be allocated.
   1663   @return other     A pointer to an EFI_FILE_PROTOCOL structure.
   1664 **/
   1665 EFI_FILE_PROTOCOL*
   1666 CreateFileInterfaceMem(
   1667   IN CONST BOOLEAN Unicode
   1668   )
   1669 {
   1670   EFI_FILE_PROTOCOL_MEM  *FileInterface;
   1671 
   1672   //
   1673   // Get some memory
   1674   //
   1675   FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));
   1676   if (FileInterface == NULL){
   1677     return (NULL);
   1678   }
   1679 
   1680   //
   1681   // Assign the generic members
   1682   //
   1683   FileInterface->Revision    = EFI_FILE_REVISION;
   1684   FileInterface->Open        = FileInterfaceOpenNotFound;
   1685   FileInterface->Close       = FileInterfaceMemClose;
   1686   FileInterface->GetPosition = FileInterfaceMemGetPosition;
   1687   FileInterface->SetPosition = FileInterfaceMemSetPosition;
   1688   FileInterface->GetInfo     = FileInterfaceNopGetInfo;
   1689   FileInterface->SetInfo     = FileInterfaceNopSetInfo;
   1690   FileInterface->Flush       = FileInterfaceNopGeneric;
   1691   FileInterface->Delete      = FileInterfaceNopGeneric;
   1692   FileInterface->Read        = FileInterfaceMemRead;
   1693   FileInterface->Write       = FileInterfaceMemWrite;
   1694   FileInterface->Unicode     = Unicode;
   1695 
   1696   ASSERT(FileInterface->Buffer      == NULL);
   1697   ASSERT(FileInterface->BufferSize  == 0);
   1698   ASSERT(FileInterface->Position    == 0);
   1699 
   1700   if (Unicode) {
   1701     FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag));
   1702     if (FileInterface->Buffer == NULL) {
   1703       FreePool (FileInterface);
   1704       return NULL;
   1705     }
   1706     *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;
   1707     FileInterface->BufferSize = 2;
   1708     FileInterface->Position = 2;
   1709   }
   1710 
   1711   return ((EFI_FILE_PROTOCOL *)FileInterface);
   1712 }
   1713 
   1714 typedef struct {
   1715   UINT64                Revision;
   1716   EFI_FILE_OPEN         Open;
   1717   EFI_FILE_CLOSE        Close;
   1718   EFI_FILE_DELETE       Delete;
   1719   EFI_FILE_READ         Read;
   1720   EFI_FILE_WRITE        Write;
   1721   EFI_FILE_GET_POSITION GetPosition;
   1722   EFI_FILE_SET_POSITION SetPosition;
   1723   EFI_FILE_GET_INFO     GetInfo;
   1724   EFI_FILE_SET_INFO     SetInfo;
   1725   EFI_FILE_FLUSH        Flush;
   1726   BOOLEAN               Unicode;
   1727   EFI_FILE_PROTOCOL     *Orig;
   1728 } EFI_FILE_PROTOCOL_FILE;
   1729 
   1730 /**
   1731   Set a files current position
   1732 
   1733   @param  This            Protocol instance pointer.
   1734   @param  Position        Byte position from the start of the file.
   1735 
   1736   @retval EFI_SUCCESS     Data was written.
   1737   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
   1738 
   1739 **/
   1740 EFI_STATUS
   1741 EFIAPI
   1742 FileInterfaceFileSetPosition(
   1743   IN EFI_FILE_PROTOCOL        *This,
   1744   IN UINT64                   Position
   1745   )
   1746 {
   1747   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
   1748 }
   1749 
   1750 /**
   1751   Get a file's current position
   1752 
   1753   @param  This            Protocol instance pointer.
   1754   @param  Position        Byte position from the start of the file.
   1755 
   1756   @retval EFI_SUCCESS     Data was written.
   1757   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
   1758 
   1759 **/
   1760 EFI_STATUS
   1761 EFIAPI
   1762 FileInterfaceFileGetPosition(
   1763   IN EFI_FILE_PROTOCOL        *This,
   1764   OUT UINT64                  *Position
   1765   )
   1766 {
   1767   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
   1768 }
   1769 
   1770 /**
   1771   Get information about a file.
   1772 
   1773   @param  This            Protocol instance pointer.
   1774   @param  InformationType Type of information to return in Buffer.
   1775   @param  BufferSize      On input size of buffer, on output amount of data in buffer.
   1776   @param  Buffer          The buffer to return data.
   1777 
   1778   @retval EFI_SUCCESS          Data was returned.
   1779   @retval EFI_UNSUPPORT        InformationType is not supported.
   1780   @retval EFI_NO_MEDIA         The device has no media.
   1781   @retval EFI_DEVICE_ERROR     The device reported an error.
   1782   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
   1783   @retval EFI_WRITE_PROTECTED  The device is write protected.
   1784   @retval EFI_ACCESS_DENIED    The file was open for read only.
   1785   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
   1786 
   1787 **/
   1788 EFI_STATUS
   1789 EFIAPI
   1790 FileInterfaceFileGetInfo(
   1791   IN EFI_FILE_PROTOCOL        *This,
   1792   IN EFI_GUID                 *InformationType,
   1793   IN OUT UINTN                *BufferSize,
   1794   OUT VOID                    *Buffer
   1795   )
   1796 {
   1797   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
   1798 }
   1799 
   1800 /**
   1801   Set information about a file
   1802 
   1803   @param  This            Protocol instance pointer.
   1804   @param  InformationType Type of information in Buffer.
   1805   @param  BufferSize      Size of buffer.
   1806   @param  Buffer          The data to write.
   1807 
   1808   @retval EFI_SUCCESS          Data was returned.
   1809   @retval EFI_UNSUPPORT        InformationType is not supported.
   1810   @retval EFI_NO_MEDIA         The device has no media.
   1811   @retval EFI_DEVICE_ERROR     The device reported an error.
   1812   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
   1813   @retval EFI_WRITE_PROTECTED  The device is write protected.
   1814   @retval EFI_ACCESS_DENIED    The file was open for read only.
   1815 
   1816 **/
   1817 EFI_STATUS
   1818 EFIAPI
   1819 FileInterfaceFileSetInfo(
   1820   IN EFI_FILE_PROTOCOL        *This,
   1821   IN EFI_GUID                 *InformationType,
   1822   IN UINTN                    BufferSize,
   1823   IN VOID                     *Buffer
   1824   )
   1825 {
   1826   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
   1827 }
   1828 
   1829 /**
   1830   Flush data back for the file handle.
   1831 
   1832   @param  This Protocol instance pointer.
   1833 
   1834   @retval EFI_SUCCESS          Data was written.
   1835   @retval EFI_UNSUPPORT        Writes to Open directory are not supported.
   1836   @retval EFI_NO_MEDIA         The device has no media.
   1837   @retval EFI_DEVICE_ERROR     The device reported an error.
   1838   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
   1839   @retval EFI_WRITE_PROTECTED  The device is write protected.
   1840   @retval EFI_ACCESS_DENIED    The file was open for read only.
   1841   @retval EFI_VOLUME_FULL      The volume is full.
   1842 
   1843 **/
   1844 EFI_STATUS
   1845 EFIAPI
   1846 FileInterfaceFileFlush(
   1847   IN EFI_FILE_PROTOCOL  *This
   1848   )
   1849 {
   1850   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
   1851 }
   1852 
   1853 /**
   1854   Read data from the file.
   1855 
   1856   @param  This       Protocol instance pointer.
   1857   @param  BufferSize On input size of buffer, on output amount of data in buffer.
   1858   @param  Buffer     The buffer in which data is read.
   1859 
   1860   @retval EFI_SUCCESS          Data was read.
   1861   @retval EFI_NO_MEDIA         The device has no media.
   1862   @retval EFI_DEVICE_ERROR     The device reported an error.
   1863   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
   1864   @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
   1865 
   1866 **/
   1867 EFI_STATUS
   1868 EFIAPI
   1869 FileInterfaceFileRead(
   1870   IN EFI_FILE_PROTOCOL        *This,
   1871   IN OUT UINTN                *BufferSize,
   1872   OUT VOID                    *Buffer
   1873   )
   1874 {
   1875   CHAR8       *AsciiStrBuffer;
   1876   CHAR16      *UscStrBuffer;
   1877   UINTN       Size;
   1878   UINTN       CharNum;
   1879   EFI_STATUS  Status;
   1880   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
   1881     //
   1882     // Unicode
   1883     //
   1884     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
   1885   } else {
   1886     //
   1887     // Ascii
   1888     //
   1889     Size  = (*BufferSize) / sizeof(CHAR16);
   1890     AsciiStrBuffer = AllocateZeroPool(Size + sizeof(CHAR8));
   1891     if (AsciiStrBuffer == NULL) {
   1892       return EFI_OUT_OF_RESOURCES;
   1893     }
   1894     UscStrBuffer = AllocateZeroPool(*BufferSize + sizeof(CHAR16));
   1895     if (UscStrBuffer== NULL) {
   1896       SHELL_FREE_NON_NULL(AsciiStrBuffer);
   1897       return EFI_OUT_OF_RESOURCES;
   1898     }
   1899     Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer));
   1900     if (!EFI_ERROR(Status)) {
   1901       CharNum = UnicodeSPrint(UscStrBuffer, *BufferSize + sizeof(CHAR16), L"%a", AsciiStrBuffer);
   1902       if (CharNum == Size) {
   1903         CopyMem (Buffer, UscStrBuffer, *BufferSize);
   1904       } else {
   1905         Status = EFI_UNSUPPORTED;
   1906       }
   1907     }
   1908     SHELL_FREE_NON_NULL(AsciiStrBuffer);
   1909     SHELL_FREE_NON_NULL(UscStrBuffer);
   1910     return (Status);
   1911   }
   1912 }
   1913 
   1914 /**
   1915   Opens a new file relative to the source file's location.
   1916 
   1917   @param[in]  This       The protocol instance pointer.
   1918   @param[out]  NewHandle Returns File Handle for FileName.
   1919   @param[in]  FileName   Null terminated string. "\", ".", and ".." are supported.
   1920   @param[in]  OpenMode   Open mode for file.
   1921   @param[in]  Attributes Only used for EFI_FILE_MODE_CREATE.
   1922 
   1923   @retval EFI_SUCCESS          The device was opened.
   1924   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
   1925   @retval EFI_NO_MEDIA         The device has no media.
   1926   @retval EFI_MEDIA_CHANGED    The media has changed.
   1927   @retval EFI_DEVICE_ERROR     The device reported an error.
   1928   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
   1929   @retval EFI_ACCESS_DENIED    The service denied access to the file.
   1930   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
   1931   @retval EFI_VOLUME_FULL      The volume is full.
   1932 **/
   1933 EFI_STATUS
   1934 EFIAPI
   1935 FileInterfaceFileOpen (
   1936   IN EFI_FILE_PROTOCOL        *This,
   1937   OUT EFI_FILE_PROTOCOL       **NewHandle,
   1938   IN CHAR16                   *FileName,
   1939   IN UINT64                   OpenMode,
   1940   IN UINT64                   Attributes
   1941   )
   1942 {
   1943   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);
   1944 }
   1945 
   1946 /**
   1947   Close and delete the file handle.
   1948 
   1949   @param  This                     Protocol instance pointer.
   1950 
   1951   @retval EFI_SUCCESS              The device was opened.
   1952   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
   1953 
   1954 **/
   1955 EFI_STATUS
   1956 EFIAPI
   1957 FileInterfaceFileDelete(
   1958   IN EFI_FILE_PROTOCOL  *This
   1959   )
   1960 {
   1961   EFI_STATUS Status;
   1962   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
   1963   FreePool(This);
   1964   return (Status);
   1965 }
   1966 
   1967 /**
   1968   File style interface for File (Close).
   1969 
   1970   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
   1971 
   1972   @retval EFI_SUCCESS   The file was closed.
   1973 **/
   1974 EFI_STATUS
   1975 EFIAPI
   1976 FileInterfaceFileClose(
   1977   IN EFI_FILE_PROTOCOL *This
   1978   )
   1979 {
   1980   EFI_STATUS Status;
   1981   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
   1982   FreePool(This);
   1983   return (Status);
   1984 }
   1985 
   1986 /**
   1987   File style interface for File (Write).
   1988 
   1989   If the file was opened with ASCII mode the data will be processed through
   1990   AsciiSPrint before writing.
   1991 
   1992   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
   1993   @param[in, out] BufferSize   Size in bytes of Buffer.
   1994   @param[in] Buffer            The pointer to the buffer to write.
   1995 
   1996   @retval EFI_SUCCESS   The data was written.
   1997 **/
   1998 EFI_STATUS
   1999 EFIAPI
   2000 FileInterfaceFileWrite(
   2001   IN     EFI_FILE_PROTOCOL  *This,
   2002   IN OUT UINTN              *BufferSize,
   2003   IN     VOID               *Buffer
   2004   )
   2005 {
   2006   CHAR8       *AsciiBuffer;
   2007   UINTN       Size;
   2008   EFI_STATUS  Status;
   2009   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
   2010     //
   2011     // Unicode
   2012     //
   2013     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
   2014   } else {
   2015     //
   2016     // Ascii
   2017     //
   2018     AsciiBuffer = AllocateZeroPool(*BufferSize);
   2019     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
   2020     Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)
   2021     Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
   2022     FreePool(AsciiBuffer);
   2023     return (Status);
   2024   }
   2025 }
   2026 
   2027 /**
   2028   Create a file interface with unicode information.
   2029 
   2030   This will create a new EFI_FILE_PROTOCOL identical to the Templace
   2031   except that the new one has Unicode and Ascii knowledge.
   2032 
   2033   @param[in] Template   A pointer to the EFI_FILE_PROTOCOL object.
   2034   @param[in] Unicode    TRUE for UCS-2, FALSE for ASCII.
   2035 
   2036   @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
   2037 **/
   2038 EFI_FILE_PROTOCOL*
   2039 CreateFileInterfaceFile(
   2040   IN CONST EFI_FILE_PROTOCOL  *Template,
   2041   IN CONST BOOLEAN            Unicode
   2042   )
   2043 {
   2044   EFI_FILE_PROTOCOL_FILE *NewOne;
   2045 
   2046   NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));
   2047   if (NewOne == NULL) {
   2048     return (NULL);
   2049   }
   2050   CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));
   2051   NewOne->Orig        = (EFI_FILE_PROTOCOL *)Template;
   2052   NewOne->Unicode     = Unicode;
   2053   NewOne->Open        = FileInterfaceFileOpen;
   2054   NewOne->Close       = FileInterfaceFileClose;
   2055   NewOne->Delete      = FileInterfaceFileDelete;
   2056   NewOne->Read        = FileInterfaceFileRead;
   2057   NewOne->Write       = FileInterfaceFileWrite;
   2058   NewOne->GetPosition = FileInterfaceFileGetPosition;
   2059   NewOne->SetPosition = FileInterfaceFileSetPosition;
   2060   NewOne->GetInfo     = FileInterfaceFileGetInfo;
   2061   NewOne->SetInfo     = FileInterfaceFileSetInfo;
   2062   NewOne->Flush       = FileInterfaceFileFlush;
   2063 
   2064   return ((EFI_FILE_PROTOCOL *)NewOne);
   2065 }
   2066