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