Home | History | Annotate | Download | only in Shell
      1 /** @file
      2   Member functions of EFI_SHELL_PARAMETERS_PROTOCOL and functions for creation,
      3   manipulation, and initialization of EFI_SHELL_PARAMETERS_PROTOCOL.
      4 
      5   Copyright (C) 2014, Red Hat, Inc.
      6   (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
      7   Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<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 
     20 BOOLEAN AsciiRedirection = FALSE;
     21 
     22 /**
     23   Return the next parameter's end from a command line string.
     24 
     25   @param[in] String        the string to parse
     26 **/
     27 CONST CHAR16*
     28 EFIAPI
     29 FindEndOfParameter(
     30   IN CONST CHAR16 *String
     31   )
     32 {
     33   CONST CHAR16 *First;
     34   CONST CHAR16 *CloseQuote;
     35 
     36   First = FindFirstCharacter(String, L" \"", L'^');
     37 
     38   //
     39   // nothing, all one parameter remaining
     40   //
     41   if (*First == CHAR_NULL) {
     42     return (First);
     43   }
     44 
     45   //
     46   // If space before a quote (or neither found, i.e. both CHAR_NULL),
     47   // then that's the end.
     48   //
     49   if (*First == L' ') {
     50     return (First);
     51   }
     52 
     53   CloseQuote = FindFirstCharacter (First+1, L"\"", L'^');
     54 
     55   //
     56   // We did not find a terminator...
     57   //
     58   if (*CloseQuote == CHAR_NULL) {
     59     return (NULL);
     60   }
     61 
     62   return (FindEndOfParameter (CloseQuote+1));
     63 }
     64 
     65 /**
     66   Return the next parameter from a command line string.
     67 
     68   This function moves the next parameter from Walker into TempParameter and moves
     69   Walker up past that parameter for recursive calling.  When the final parameter
     70   is moved *Walker will be set to NULL;
     71 
     72   Temp Parameter must be large enough to hold the parameter before calling this
     73   function.
     74 
     75   This will also remove all remaining ^ characters after processing.
     76 
     77   @param[in, out] Walker          pointer to string of command line.  Adjusted to
     78                                   reminaing command line on return
     79   @param[in, out] TempParameter   pointer to string of command line item extracted.
     80   @param[in]      Length          buffer size of TempParameter.
     81   @param[in]      StripQuotation  if TRUE then strip the quotation marks surrounding
     82                                   the parameters.
     83 
     84   @return   EFI_INALID_PARAMETER  A required parameter was NULL or pointed to a NULL or empty string.
     85   @return   EFI_NOT_FOUND         A closing " could not be found on the specified string
     86 **/
     87 EFI_STATUS
     88 EFIAPI
     89 GetNextParameter(
     90   IN OUT CHAR16   **Walker,
     91   IN OUT CHAR16   **TempParameter,
     92   IN CONST UINTN  Length,
     93   IN BOOLEAN      StripQuotation
     94   )
     95 {
     96   CONST CHAR16 *NextDelim;
     97 
     98   if (Walker           == NULL
     99     ||*Walker          == NULL
    100     ||TempParameter    == NULL
    101     ||*TempParameter   == NULL
    102     ){
    103     return (EFI_INVALID_PARAMETER);
    104   }
    105 
    106 
    107   //
    108   // make sure we dont have any leading spaces
    109   //
    110   while ((*Walker)[0] == L' ') {
    111       (*Walker)++;
    112   }
    113 
    114   //
    115   // make sure we still have some params now...
    116   //
    117   if (StrLen(*Walker) == 0) {
    118 DEBUG_CODE_BEGIN();
    119     *Walker        = NULL;
    120 DEBUG_CODE_END();
    121     return (EFI_INVALID_PARAMETER);
    122   }
    123 
    124   NextDelim = FindEndOfParameter(*Walker);
    125 
    126   if (NextDelim == NULL){
    127 DEBUG_CODE_BEGIN();
    128     *Walker        = NULL;
    129 DEBUG_CODE_END();
    130     return (EFI_NOT_FOUND);
    131   }
    132 
    133   StrnCpyS(*TempParameter, Length / sizeof(CHAR16), (*Walker), NextDelim - *Walker);
    134 
    135   //
    136   // Add a CHAR_NULL if we didnt get one via the copy
    137   //
    138   if (*NextDelim != CHAR_NULL) {
    139     (*TempParameter)[NextDelim - *Walker] = CHAR_NULL;
    140   }
    141 
    142   //
    143   // Update Walker for the next iteration through the function
    144   //
    145   *Walker = (CHAR16*)NextDelim;
    146 
    147   //
    148   // Remove any non-escaped quotes in the string
    149   // Remove any remaining escape characters in the string
    150   //
    151   for (NextDelim = FindFirstCharacter(*TempParameter, L"\"^", CHAR_NULL)
    152     ; *NextDelim != CHAR_NULL
    153     ; NextDelim = FindFirstCharacter(NextDelim, L"\"^", CHAR_NULL)
    154     ) {
    155     if (*NextDelim == L'^') {
    156 
    157       //
    158       // eliminate the escape ^
    159       //
    160       CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
    161       NextDelim++;
    162     } else if (*NextDelim == L'\"') {
    163 
    164       //
    165       // eliminate the unescaped quote
    166       //
    167       if (StripQuotation) {
    168         CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
    169 	  } else{
    170         NextDelim++;
    171 	  }
    172     }
    173   }
    174 
    175   return EFI_SUCCESS;
    176 }
    177 
    178 /**
    179   Function to populate Argc and Argv.
    180 
    181   This function parses the CommandLine and divides it into standard C style Argc/Argv
    182   parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL.  this supports space
    183   delimited and quote surrounded parameter definition.
    184 
    185   All special character processing (alias, environment variable, redirection,
    186   etc... must be complete before calling this API.
    187 
    188   @param[in] CommandLine          String of command line to parse
    189   @param[in] StripQuotation       if TRUE then strip the quotation marks surrounding
    190                                   the parameters.
    191   @param[in, out] Argv            pointer to array of strings; one for each parameter
    192   @param[in, out] Argc            pointer to number of strings in Argv array
    193 
    194   @return EFI_SUCCESS           the operation was sucessful
    195   @return EFI_OUT_OF_RESOURCES  a memory allocation failed.
    196 **/
    197 EFI_STATUS
    198 EFIAPI
    199 ParseCommandLineToArgs(
    200   IN CONST CHAR16 *CommandLine,
    201   IN BOOLEAN      StripQuotation,
    202   IN OUT CHAR16   ***Argv,
    203   IN OUT UINTN    *Argc
    204   )
    205 {
    206   UINTN       Count;
    207   CHAR16      *TempParameter;
    208   CHAR16      *Walker;
    209   CHAR16      *NewParam;
    210   CHAR16      *NewCommandLine;
    211   UINTN       Size;
    212   EFI_STATUS  Status;
    213 
    214   ASSERT(Argc != NULL);
    215   ASSERT(Argv != NULL);
    216 
    217   if (CommandLine == NULL || StrLen(CommandLine)==0) {
    218     (*Argc) = 0;
    219     (*Argv) = NULL;
    220     return (EFI_SUCCESS);
    221   }
    222 
    223   NewCommandLine = AllocateCopyPool(StrSize(CommandLine), CommandLine);
    224   if (NewCommandLine == NULL){
    225     return (EFI_OUT_OF_RESOURCES);
    226   }
    227 
    228   TrimSpaces(&NewCommandLine);
    229   Size = StrSize(NewCommandLine);
    230   TempParameter = AllocateZeroPool(Size);
    231   if (TempParameter == NULL) {
    232     SHELL_FREE_NON_NULL(NewCommandLine);
    233     return (EFI_OUT_OF_RESOURCES);
    234   }
    235 
    236   for ( Count = 0
    237       , Walker = (CHAR16*)NewCommandLine
    238       ; Walker != NULL && *Walker != CHAR_NULL
    239       ; Count++
    240       ) {
    241     if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, TRUE))) {
    242       break;
    243     }
    244   }
    245 
    246   //
    247   // lets allocate the pointer array
    248   //
    249   (*Argv) = AllocateZeroPool((Count)*sizeof(CHAR16*));
    250   if (*Argv == NULL) {
    251     Status = EFI_OUT_OF_RESOURCES;
    252     goto Done;
    253   }
    254 
    255   *Argc = 0;
    256   Walker = (CHAR16*)NewCommandLine;
    257   while(Walker != NULL && *Walker != CHAR_NULL) {
    258     SetMem16(TempParameter, Size, CHAR_NULL);
    259     if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, StripQuotation))) {
    260       Status = EFI_INVALID_PARAMETER;
    261       goto Done;
    262     }
    263 
    264     NewParam = AllocateCopyPool(StrSize(TempParameter), TempParameter);
    265     if (NewParam == NULL){
    266       Status = EFI_OUT_OF_RESOURCES;
    267       goto Done;
    268     }
    269     ((CHAR16**)(*Argv))[(*Argc)] = NewParam;
    270     (*Argc)++;
    271   }
    272   ASSERT(Count >= (*Argc));
    273   Status = EFI_SUCCESS;
    274 
    275 Done:
    276   SHELL_FREE_NON_NULL(TempParameter);
    277   SHELL_FREE_NON_NULL(NewCommandLine);
    278   return (Status);
    279 }
    280 
    281 /**
    282   creates a new EFI_SHELL_PARAMETERS_PROTOCOL instance and populates it and then
    283   installs it on our handle and if there is an existing version of the protocol
    284   that one is cached for removal later.
    285 
    286   @param[in, out] NewShellParameters on a successful return, a pointer to pointer
    287                                      to the newly installed interface.
    288   @param[in, out] RootShellInstance  on a successful return, pointer to boolean.
    289                                      TRUE if this is the root shell instance.
    290 
    291   @retval EFI_SUCCESS               the operation completed successfully.
    292   @return other                     the operation failed.
    293   @sa ReinstallProtocolInterface
    294   @sa InstallProtocolInterface
    295   @sa ParseCommandLineToArgs
    296 **/
    297 EFI_STATUS
    298 EFIAPI
    299 CreatePopulateInstallShellParametersProtocol (
    300   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  **NewShellParameters,
    301   IN OUT BOOLEAN                        *RootShellInstance
    302   )
    303 {
    304   EFI_STATUS Status;
    305   EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
    306   CHAR16                    *FullCommandLine;
    307   UINTN                     Size;
    308 
    309   Size = 0;
    310   FullCommandLine = NULL;
    311   LoadedImage = NULL;
    312 
    313   //
    314   // Assert for valid parameters
    315   //
    316   ASSERT(NewShellParameters != NULL);
    317   ASSERT(RootShellInstance  != NULL);
    318 
    319   //
    320   // See if we have a shell parameters placed on us
    321   //
    322   Status = gBS->OpenProtocol (
    323                 gImageHandle,
    324                 &gEfiShellParametersProtocolGuid,
    325                 (VOID **) &ShellInfoObject.OldShellParameters,
    326                 gImageHandle,
    327                 NULL,
    328                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
    329                );
    330   //
    331   // if we don't then we must be the root shell (error is expected)
    332   //
    333   if (EFI_ERROR (Status)) {
    334     *RootShellInstance = TRUE;
    335   }
    336 
    337   //
    338   // Allocate the new structure
    339   //
    340   *NewShellParameters = AllocateZeroPool(sizeof(EFI_SHELL_PARAMETERS_PROTOCOL));
    341   if ((*NewShellParameters) == NULL) {
    342     return (EFI_OUT_OF_RESOURCES);
    343   }
    344 
    345   //
    346   // get loaded image protocol
    347   //
    348   Status = gBS->OpenProtocol (
    349                 gImageHandle,
    350                 &gEfiLoadedImageProtocolGuid,
    351                 (VOID **) &LoadedImage,
    352                 gImageHandle,
    353                 NULL,
    354                 EFI_OPEN_PROTOCOL_GET_PROTOCOL
    355                );
    356   ASSERT_EFI_ERROR(Status);
    357   //
    358   // Build the full command line
    359   //
    360   Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, FullCommandLine);
    361   if (Status == EFI_BUFFER_TOO_SMALL) {
    362     FullCommandLine = AllocateZeroPool(Size + LoadedImage->LoadOptionsSize);
    363     Status = SHELL_GET_ENVIRONMENT_VARIABLE(L"ShellOpt", &Size, FullCommandLine);
    364   }
    365   if (Status == EFI_NOT_FOUND) {
    366     //
    367     // no parameters via environment... ok
    368     //
    369   } else {
    370     if (EFI_ERROR(Status)) {
    371       return (Status);
    372     }
    373   }
    374   if (Size == 0 && LoadedImage->LoadOptionsSize != 0) {
    375     ASSERT(FullCommandLine == NULL);
    376     //
    377     // Now we need to include a NULL terminator in the size.
    378     //
    379     Size = LoadedImage->LoadOptionsSize + sizeof(FullCommandLine[0]);
    380     FullCommandLine = AllocateZeroPool(Size);
    381   }
    382   if (FullCommandLine != NULL) {
    383     CopyMem (FullCommandLine, LoadedImage->LoadOptions, LoadedImage->LoadOptionsSize);
    384     //
    385     // Populate Argc and Argv
    386     //
    387     Status = ParseCommandLineToArgs(FullCommandLine,
    388                                     TRUE,
    389                                     &(*NewShellParameters)->Argv,
    390                                     &(*NewShellParameters)->Argc);
    391 
    392     FreePool(FullCommandLine);
    393 
    394     ASSERT_EFI_ERROR(Status);
    395   } else {
    396     (*NewShellParameters)->Argv = NULL;
    397     (*NewShellParameters)->Argc = 0;
    398   }
    399 
    400   //
    401   // Populate the 3 faked file systems...
    402   //
    403   if (*RootShellInstance) {
    404     (*NewShellParameters)->StdIn  = &FileInterfaceStdIn;
    405     (*NewShellParameters)->StdOut = &FileInterfaceStdOut;
    406     (*NewShellParameters)->StdErr = &FileInterfaceStdErr;
    407     Status = gBS->InstallProtocolInterface(&gImageHandle,
    408                                            &gEfiShellParametersProtocolGuid,
    409                                            EFI_NATIVE_INTERFACE,
    410                                            (VOID*)(*NewShellParameters));
    411   } else {
    412     //
    413     // copy from the existing ones
    414     //
    415     (*NewShellParameters)->StdIn  = ShellInfoObject.OldShellParameters->StdIn;
    416     (*NewShellParameters)->StdOut = ShellInfoObject.OldShellParameters->StdOut;
    417     (*NewShellParameters)->StdErr = ShellInfoObject.OldShellParameters->StdErr;
    418     Status = gBS->ReinstallProtocolInterface(gImageHandle,
    419                                              &gEfiShellParametersProtocolGuid,
    420                                              (VOID*)ShellInfoObject.OldShellParameters,
    421                                              (VOID*)(*NewShellParameters));
    422   }
    423 
    424   return (Status);
    425 }
    426 
    427 /**
    428   frees all memory used by createion and installation of shell parameters protocol
    429   and if there was an old version installed it will restore that one.
    430 
    431   @param NewShellParameters the interface of EFI_SHELL_PARAMETERS_PROTOCOL that is
    432   being cleaned up.
    433 
    434   @retval EFI_SUCCESS     the cleanup was successful
    435   @return other           the cleanup failed
    436   @sa ReinstallProtocolInterface
    437   @sa UninstallProtocolInterface
    438 **/
    439 EFI_STATUS
    440 EFIAPI
    441 CleanUpShellParametersProtocol (
    442   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  *NewShellParameters
    443   )
    444 {
    445   EFI_STATUS Status;
    446   UINTN LoopCounter;
    447 
    448   //
    449   // If the old exists we need to restore it
    450   //
    451   if (ShellInfoObject.OldShellParameters != NULL) {
    452     Status = gBS->ReinstallProtocolInterface(gImageHandle,
    453                                              &gEfiShellParametersProtocolGuid,
    454                                              (VOID*)NewShellParameters,
    455                                              (VOID*)ShellInfoObject.OldShellParameters);
    456     DEBUG_CODE(ShellInfoObject.OldShellParameters = NULL;);
    457   } else {
    458     //
    459     // No old one, just uninstall us...
    460     //
    461     Status = gBS->UninstallProtocolInterface(gImageHandle,
    462                                              &gEfiShellParametersProtocolGuid,
    463                                              (VOID*)NewShellParameters);
    464   }
    465   if (NewShellParameters->Argv != NULL) {
    466     for ( LoopCounter = 0
    467         ; LoopCounter < NewShellParameters->Argc
    468         ; LoopCounter++
    469        ){
    470       FreePool(NewShellParameters->Argv[LoopCounter]);
    471     }
    472     FreePool(NewShellParameters->Argv);
    473   }
    474   FreePool(NewShellParameters);
    475   return (Status);
    476 }
    477 
    478 /**
    479   Determin if a file name represents a unicode file.
    480 
    481   @param[in] FileName     Pointer to the filename to open.
    482 
    483   @retval EFI_SUCCESS     The file is a unicode file.
    484   @return An error upon failure.
    485 **/
    486 EFI_STATUS
    487 EFIAPI
    488 IsUnicodeFile(
    489   IN CONST CHAR16 *FileName
    490   )
    491 {
    492   SHELL_FILE_HANDLE Handle;
    493   EFI_STATUS        Status;
    494   UINT64            OriginalFilePosition;
    495   UINTN             CharSize;
    496   CHAR16            CharBuffer;
    497 
    498   Status = gEfiShellProtocol->OpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ);
    499   if (EFI_ERROR(Status)) {
    500     return (Status);
    501   }
    502   gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);
    503   gEfiShellProtocol->SetFilePosition(Handle, 0);
    504   CharSize = sizeof(CHAR16);
    505   Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
    506   if (EFI_ERROR(Status) || CharBuffer != gUnicodeFileTag) {
    507     Status = EFI_BUFFER_TOO_SMALL;
    508   }
    509   gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
    510   gEfiShellProtocol->CloseFile(Handle);
    511   return (Status);
    512 }
    513 
    514 /**
    515   Strips out quotes sections of a string.
    516 
    517   All of the characters between quotes is replaced with spaces.
    518 
    519   @param[in, out] TheString  A pointer to the string to update.
    520 **/
    521 VOID
    522 EFIAPI
    523 StripQuotes (
    524   IN OUT CHAR16 *TheString
    525   )
    526 {
    527   BOOLEAN RemoveNow;
    528 
    529   for (RemoveNow = FALSE ; TheString != NULL && *TheString != CHAR_NULL ; TheString++) {
    530     if (*TheString == L'^' && *(TheString + 1) == L'\"') {
    531       TheString++;
    532     } else if (*TheString == L'\"') {
    533       RemoveNow = (BOOLEAN)!RemoveNow;
    534     } else if (RemoveNow) {
    535       *TheString = L' ';
    536     }
    537   }
    538 }
    539 
    540 /**
    541   Calcualte the 32-bit CRC in a EFI table using the service provided by the
    542   gRuntime service.
    543 
    544   @param  Hdr                    Pointer to an EFI standard header
    545 
    546 **/
    547 VOID
    548 CalculateEfiHdrCrc (
    549   IN  OUT EFI_TABLE_HEADER    *Hdr
    550   )
    551 {
    552   UINT32 Crc;
    553 
    554   Hdr->CRC32 = 0;
    555 
    556   //
    557   // If gBS->CalculateCrce32 () == CoreEfiNotAvailableYet () then
    558   //  Crc will come back as zero if we set it to zero here
    559   //
    560   Crc = 0;
    561   gBS->CalculateCrc32 ((UINT8 *)Hdr, Hdr->HeaderSize, &Crc);
    562   Hdr->CRC32 = Crc;
    563 }
    564 
    565 /**
    566   Fix a string to only have the file name, removing starting at the first space of whatever is quoted.
    567 
    568   @param[in]  FileName    The filename to start with.
    569 
    570   @retval NULL  FileName was invalid.
    571   @return       The modified FileName.
    572 **/
    573 CHAR16*
    574 EFIAPI
    575 FixFileName (
    576   IN CHAR16 *FileName
    577   )
    578 {
    579   CHAR16  *Copy;
    580   CHAR16  *TempLocation;
    581 
    582   if (FileName == NULL) {
    583     return (NULL);
    584   }
    585 
    586   if (FileName[0] == L'\"') {
    587     Copy = FileName+1;
    588     if ((TempLocation = StrStr(Copy , L"\"")) != NULL) {
    589       TempLocation[0] = CHAR_NULL;
    590     }
    591   } else {
    592     Copy = FileName;
    593     while(Copy[0] == L' ') {
    594       Copy++;
    595     }
    596     if ((TempLocation = StrStr(Copy , L" ")) != NULL) {
    597       TempLocation[0] = CHAR_NULL;
    598     }
    599   }
    600 
    601   if (Copy[0] == CHAR_NULL) {
    602     return (NULL);
    603   }
    604 
    605   return (Copy);
    606 }
    607 
    608 /**
    609   Fix a string to only have the environment variable name, removing starting at the first space of whatever is quoted and removing the leading and trailing %.
    610 
    611   @param[in]  FileName    The filename to start with.
    612 
    613   @retval NULL  FileName was invalid.
    614   @return       The modified FileName.
    615 **/
    616 CHAR16*
    617 EFIAPI
    618 FixVarName (
    619   IN CHAR16 *FileName
    620   )
    621 {
    622   CHAR16  *Copy;
    623   CHAR16  *TempLocation;
    624 
    625   Copy = FileName;
    626 
    627   if (FileName[0] == L'%') {
    628     Copy = FileName+1;
    629     if ((TempLocation = StrStr(Copy , L"%")) != NULL) {
    630       TempLocation[0] = CHAR_NULL;
    631     }
    632   }
    633 
    634   return (FixFileName(Copy));
    635 }
    636 
    637 /**
    638   Remove the unicode file tag from the begining of the file buffer since that will not be
    639   used by StdIn.
    640 
    641   @param[in]  Handle    Pointer to the handle of the file to be processed.
    642 
    643   @retval EFI_SUCCESS   The unicode file tag has been moved successfully.
    644 **/
    645 EFI_STATUS
    646 EFIAPI
    647 RemoveFileTag(
    648   IN SHELL_FILE_HANDLE *Handle
    649   )
    650 {
    651   UINTN             CharSize;
    652   CHAR16            CharBuffer;
    653 
    654   CharSize    = sizeof(CHAR16);
    655   CharBuffer  = 0;
    656   gEfiShellProtocol->ReadFile(*Handle, &CharSize, &CharBuffer);
    657   if (CharBuffer != gUnicodeFileTag) {
    658     gEfiShellProtocol->SetFilePosition(*Handle, 0);
    659   }
    660   return (EFI_SUCCESS);
    661 }
    662 
    663 /**
    664   Write the unicode file tag to the specified file.
    665 
    666   It is the caller's responsibility to ensure that
    667   ShellInfoObject.NewEfiShellProtocol has been initialized before calling this
    668   function.
    669 
    670   @param[in] FileHandle  The file to write the unicode file tag to.
    671 
    672   @return  Status code from ShellInfoObject.NewEfiShellProtocol->WriteFile.
    673 **/
    674 EFI_STATUS
    675 WriteFileTag (
    676   IN SHELL_FILE_HANDLE FileHandle
    677   )
    678 {
    679   CHAR16     FileTag;
    680   UINTN      Size;
    681   EFI_STATUS Status;
    682 
    683   FileTag = gUnicodeFileTag;
    684   Size = sizeof FileTag;
    685   Status = ShellInfoObject.NewEfiShellProtocol->WriteFile (FileHandle, &Size,
    686                                                   &FileTag);
    687   ASSERT (EFI_ERROR (Status) || Size == sizeof FileTag);
    688   return Status;
    689 }
    690 
    691 
    692 /**
    693   Funcion will replace the current StdIn and StdOut in the ShellParameters protocol
    694   structure by parsing NewCommandLine.  The current values are returned to the
    695   user.
    696 
    697   This will also update the system table.
    698 
    699   @param[in, out] ShellParameters        Pointer to parameter structure to modify.
    700   @param[in] NewCommandLine              The new command line to parse and use.
    701   @param[out] OldStdIn                   Pointer to old StdIn.
    702   @param[out] OldStdOut                  Pointer to old StdOut.
    703   @param[out] OldStdErr                  Pointer to old StdErr.
    704   @param[out] SystemTableInfo            Pointer to old system table information.
    705 
    706   @retval   EFI_SUCCESS                 Operation was sucessful, Argv and Argc are valid.
    707   @retval   EFI_OUT_OF_RESOURCES        A memory allocation failed.
    708 **/
    709 EFI_STATUS
    710 EFIAPI
    711 UpdateStdInStdOutStdErr(
    712   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  *ShellParameters,
    713   IN CHAR16                             *NewCommandLine,
    714   OUT SHELL_FILE_HANDLE                 *OldStdIn,
    715   OUT SHELL_FILE_HANDLE                 *OldStdOut,
    716   OUT SHELL_FILE_HANDLE                 *OldStdErr,
    717   OUT SYSTEM_TABLE_INFO                 *SystemTableInfo
    718   )
    719 {
    720   CHAR16            *CommandLineCopy;
    721   CHAR16            *CommandLineWalker;
    722   CHAR16            *StdErrFileName;
    723   CHAR16            *StdOutFileName;
    724   CHAR16            *StdInFileName;
    725   CHAR16            *StdInVarName;
    726   CHAR16            *StdOutVarName;
    727   CHAR16            *StdErrVarName;
    728   EFI_STATUS        Status;
    729   SHELL_FILE_HANDLE TempHandle;
    730   UINT64            FileSize;
    731   BOOLEAN           OutUnicode;
    732   BOOLEAN           InUnicode;
    733   BOOLEAN           ErrUnicode;
    734   BOOLEAN           OutAppend;
    735   BOOLEAN           ErrAppend;
    736   UINTN             Size;
    737   SPLIT_LIST        *Split;
    738   CHAR16            *FirstLocation;
    739 
    740   OutUnicode      = TRUE;
    741   InUnicode       = TRUE;
    742   AsciiRedirection = FALSE;
    743   ErrUnicode      = TRUE;
    744   StdInVarName    = NULL;
    745   StdOutVarName   = NULL;
    746   StdErrVarName   = NULL;
    747   StdErrFileName  = NULL;
    748   StdInFileName   = NULL;
    749   StdOutFileName  = NULL;
    750   ErrAppend       = FALSE;
    751   OutAppend       = FALSE;
    752   CommandLineCopy = NULL;
    753   FirstLocation   = NULL;
    754 
    755   if (ShellParameters == NULL || SystemTableInfo == NULL || OldStdIn == NULL || OldStdOut == NULL || OldStdErr == NULL) {
    756     return (EFI_INVALID_PARAMETER);
    757   }
    758 
    759   SystemTableInfo->ConIn          = gST->ConIn;
    760   SystemTableInfo->ConInHandle    = gST->ConsoleInHandle;
    761   SystemTableInfo->ConOut         = gST->ConOut;
    762   SystemTableInfo->ConOutHandle   = gST->ConsoleOutHandle;
    763   SystemTableInfo->ErrOut         = gST->StdErr;
    764   SystemTableInfo->ErrOutHandle   = gST->StandardErrorHandle;
    765   *OldStdIn                       = ShellParameters->StdIn;
    766   *OldStdOut                      = ShellParameters->StdOut;
    767   *OldStdErr                      = ShellParameters->StdErr;
    768 
    769   if (NewCommandLine == NULL) {
    770     return (EFI_SUCCESS);
    771   }
    772 
    773   CommandLineCopy = StrnCatGrow(&CommandLineCopy, NULL, NewCommandLine, 0);
    774   if (CommandLineCopy == NULL) {
    775     return (EFI_OUT_OF_RESOURCES);
    776   }
    777   Status          = EFI_SUCCESS;
    778   Split           = NULL;
    779   FirstLocation   = CommandLineCopy + StrLen(CommandLineCopy);
    780 
    781   StripQuotes(CommandLineCopy);
    782 
    783   if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {
    784     Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);
    785     if (Split != NULL && Split->SplitStdIn != NULL) {
    786       ShellParameters->StdIn  = Split->SplitStdIn;
    787     }
    788     if (Split != NULL && Split->SplitStdOut != NULL) {
    789       ShellParameters->StdOut = Split->SplitStdOut;
    790     }
    791   }
    792 
    793   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>>v ")) != NULL) {
    794     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    795     SetMem16(CommandLineWalker, 12, L' ');
    796     StdErrVarName   = CommandLineWalker += 6;
    797     ErrAppend       = TRUE;
    798     if (StrStr(CommandLineWalker, L" 2>>v ") != NULL) {
    799       Status = EFI_NOT_FOUND;
    800     }
    801   }
    802   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>v ")) != NULL) {
    803     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    804     SetMem16(CommandLineWalker, 12, L' ');
    805     StdOutVarName   = CommandLineWalker += 6;
    806     OutAppend       = TRUE;
    807     if (StrStr(CommandLineWalker, L" 1>>v ") != NULL) {
    808       Status = EFI_NOT_FOUND;
    809     }
    810   } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>v ")) != NULL) {
    811     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    812     SetMem16(CommandLineWalker, 10, L' ');
    813     StdOutVarName   = CommandLineWalker += 5;
    814     OutAppend       = TRUE;
    815     if (StrStr(CommandLineWalker, L" >>v ") != NULL) {
    816       Status = EFI_NOT_FOUND;
    817     }
    818   } else if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >v ")) != NULL) {
    819     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    820     SetMem16(CommandLineWalker, 8, L' ');
    821     StdOutVarName   = CommandLineWalker += 4;
    822     OutAppend       = FALSE;
    823     if (StrStr(CommandLineWalker, L" >v ") != NULL) {
    824       Status = EFI_NOT_FOUND;
    825     }
    826   }
    827   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>>a ")) != NULL) {
    828     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    829     SetMem16(CommandLineWalker, 12, L' ');
    830     StdOutFileName  = CommandLineWalker += 6;
    831     OutAppend       = TRUE;
    832     OutUnicode      = FALSE;
    833     if (StrStr(CommandLineWalker, L" 1>>a ") != NULL) {
    834       Status = EFI_NOT_FOUND;
    835     }
    836   }
    837   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>> ")) != NULL) {
    838     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    839     SetMem16(CommandLineWalker, 10, L' ');
    840     if (StdOutFileName != NULL) {
    841       Status = EFI_INVALID_PARAMETER;
    842     } else {
    843       StdOutFileName  = CommandLineWalker += 5;
    844       OutAppend       = TRUE;
    845     }
    846     if (StrStr(CommandLineWalker, L" 1>> ") != NULL) {
    847       Status = EFI_NOT_FOUND;
    848     }
    849   }
    850   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >> ")) != NULL) {
    851     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    852     SetMem16(CommandLineWalker, 8, L' ');
    853     if (StdOutFileName != NULL) {
    854       Status = EFI_INVALID_PARAMETER;
    855     } else {
    856       StdOutFileName  = CommandLineWalker += 4;
    857       OutAppend       = TRUE;
    858     }
    859     if (StrStr(CommandLineWalker, L" >> ") != NULL) {
    860       Status = EFI_NOT_FOUND;
    861     }
    862   }
    863   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >>a ")) != NULL) {
    864     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    865     SetMem16(CommandLineWalker, 10, L' ');
    866     if (StdOutFileName != NULL) {
    867       Status = EFI_INVALID_PARAMETER;
    868     } else {
    869       StdOutFileName  = CommandLineWalker += 5;
    870       OutAppend       = TRUE;
    871       OutUnicode      = FALSE;
    872     }
    873     if (StrStr(CommandLineWalker, L" >>a ") != NULL) {
    874       Status = EFI_NOT_FOUND;
    875     }
    876   }
    877   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>a ")) != NULL) {
    878     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    879     SetMem16(CommandLineWalker, 10, L' ');
    880     if (StdOutFileName != NULL) {
    881       Status = EFI_INVALID_PARAMETER;
    882     } else {
    883       StdOutFileName  = CommandLineWalker += 5;
    884       OutAppend       = FALSE;
    885       OutUnicode      = FALSE;
    886     }
    887     if (StrStr(CommandLineWalker, L" 1>a ") != NULL) {
    888       Status = EFI_NOT_FOUND;
    889     }
    890   }
    891   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" >a ")) != NULL) {
    892     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    893     SetMem16(CommandLineWalker, 8, L' ');
    894     if (StdOutFileName != NULL) {
    895       Status = EFI_INVALID_PARAMETER;
    896     } else {
    897       StdOutFileName  = CommandLineWalker += 4;
    898       OutAppend       = FALSE;
    899       OutUnicode      = FALSE;
    900     }
    901     if (StrStr(CommandLineWalker, L" >a ") != NULL) {
    902       Status = EFI_NOT_FOUND;
    903     }
    904   }
    905   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>> ")) != NULL) {
    906     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    907     SetMem16(CommandLineWalker, 10, L' ');
    908     if (StdErrFileName != NULL) {
    909       Status = EFI_INVALID_PARAMETER;
    910     } else {
    911       StdErrFileName  = CommandLineWalker += 5;
    912       ErrAppend       = TRUE;
    913     }
    914     if (StrStr(CommandLineWalker, L" 2>> ") != NULL) {
    915       Status = EFI_NOT_FOUND;
    916     }
    917   }
    918 
    919   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>v ")) != NULL) {
    920     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    921     SetMem16(CommandLineWalker, 10, L' ');
    922     if (StdErrVarName != NULL) {
    923       Status = EFI_INVALID_PARAMETER;
    924     } else {
    925       StdErrVarName   = CommandLineWalker += 5;
    926       ErrAppend       = FALSE;
    927     }
    928     if (StrStr(CommandLineWalker, L" 2>v ") != NULL) {
    929       Status = EFI_NOT_FOUND;
    930     }
    931   }
    932   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1>v ")) != NULL) {
    933     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    934     SetMem16(CommandLineWalker, 10, L' ');
    935     if (StdOutVarName != NULL) {
    936       Status = EFI_INVALID_PARAMETER;
    937     } else {
    938       StdOutVarName   = CommandLineWalker += 5;
    939       OutAppend       = FALSE;
    940     }
    941     if (StrStr(CommandLineWalker, L" 1>v ") != NULL) {
    942       Status = EFI_NOT_FOUND;
    943     }
    944   }
    945   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2>a ")) != NULL) {
    946     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    947     SetMem16(CommandLineWalker, 10, L' ');
    948     if (StdErrFileName != NULL) {
    949       Status = EFI_INVALID_PARAMETER;
    950     } else {
    951       StdErrFileName  = CommandLineWalker += 5;
    952       ErrAppend       = FALSE;
    953       ErrUnicode      = FALSE;
    954     }
    955     if (StrStr(CommandLineWalker, L" 2>a ") != NULL) {
    956       Status = EFI_NOT_FOUND;
    957     }
    958   }
    959   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 2> ")) != NULL) {
    960     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    961     SetMem16(CommandLineWalker, 8, L' ');
    962     if (StdErrFileName != NULL) {
    963       Status = EFI_INVALID_PARAMETER;
    964     } else {
    965       StdErrFileName  = CommandLineWalker += 4;
    966       ErrAppend       = FALSE;
    967     }
    968     if (StrStr(CommandLineWalker, L" 2> ") != NULL) {
    969       Status = EFI_NOT_FOUND;
    970     }
    971   }
    972 
    973   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" 1> ")) != NULL) {
    974     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    975     SetMem16(CommandLineWalker, 8, L' ');
    976     if (StdOutFileName != NULL) {
    977       Status = EFI_INVALID_PARAMETER;
    978     } else {
    979       StdOutFileName  = CommandLineWalker += 4;
    980       OutAppend       = FALSE;
    981     }
    982     if (StrStr(CommandLineWalker, L" 1> ") != NULL) {
    983       Status = EFI_NOT_FOUND;
    984     }
    985   }
    986 
    987   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" > ")) != NULL) {
    988     FirstLocation = MIN(CommandLineWalker, FirstLocation);
    989     SetMem16(CommandLineWalker, 6, L' ');
    990     if (StdOutFileName != NULL) {
    991       Status = EFI_INVALID_PARAMETER;
    992     } else {
    993       StdOutFileName  = CommandLineWalker += 3;
    994       OutAppend       = FALSE;
    995     }
    996     if (StrStr(CommandLineWalker, L" > ") != NULL) {
    997       Status = EFI_NOT_FOUND;
    998     }
    999   }
   1000 
   1001   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" < ")) != NULL) {
   1002     FirstLocation = MIN(CommandLineWalker, FirstLocation);
   1003     SetMem16(CommandLineWalker, 6, L' ');
   1004     if (StdInFileName != NULL) {
   1005       Status = EFI_INVALID_PARAMETER;
   1006     } else {
   1007       StdInFileName  = CommandLineWalker += 3;
   1008     }
   1009     if (StrStr(CommandLineWalker, L" < ") != NULL) {
   1010       Status = EFI_NOT_FOUND;
   1011     }
   1012   }
   1013   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" <a ")) != NULL) {
   1014     FirstLocation = MIN(CommandLineWalker, FirstLocation);
   1015     SetMem16(CommandLineWalker, 8, L' ');
   1016     if (StdInFileName != NULL) {
   1017       Status = EFI_INVALID_PARAMETER;
   1018     } else {
   1019       StdInFileName   = CommandLineWalker += 4;
   1020       InUnicode       = FALSE;
   1021       AsciiRedirection = TRUE;
   1022     }
   1023     if (StrStr(CommandLineWalker, L" <a ") != NULL) {
   1024       Status = EFI_NOT_FOUND;
   1025     }
   1026   }
   1027   if (!EFI_ERROR(Status) && (CommandLineWalker = StrStr(CommandLineCopy, L" <v ")) != NULL) {
   1028     FirstLocation = MIN(CommandLineWalker, FirstLocation);
   1029     SetMem16(CommandLineWalker, 8, L' ');
   1030     if (StdInVarName != NULL) {
   1031       Status = EFI_INVALID_PARAMETER;
   1032     } else {
   1033       StdInVarName  = CommandLineWalker += 4;
   1034     }
   1035     if (StrStr(CommandLineWalker, L" <v ") != NULL) {
   1036       Status = EFI_NOT_FOUND;
   1037     }
   1038   }
   1039 
   1040   //
   1041   // re-populate the string to support any filenames that were in quotes.
   1042   //
   1043   StrnCpyS(CommandLineCopy, StrSize(CommandLineCopy)/sizeof(CHAR16), NewCommandLine, StrLen(NewCommandLine));
   1044 
   1045   if (FirstLocation != CommandLineCopy + StrLen(CommandLineCopy)
   1046     && ((UINTN)(FirstLocation - CommandLineCopy) < StrLen(NewCommandLine))
   1047     ){
   1048     *(NewCommandLine + (UINTN)(FirstLocation - CommandLineCopy)) = CHAR_NULL;
   1049   }
   1050 
   1051   if (!EFI_ERROR(Status)) {
   1052 
   1053     if (StdErrFileName != NULL) {
   1054       if ((StdErrFileName    = FixFileName(StdErrFileName)) == NULL) {
   1055         Status = EFI_INVALID_PARAMETER;
   1056       }
   1057     }
   1058     if (StdOutFileName != NULL) {
   1059       if ((StdOutFileName    = FixFileName(StdOutFileName)) == NULL) {
   1060         Status = EFI_INVALID_PARAMETER;
   1061       }
   1062     }
   1063     if (StdInFileName  != NULL) {
   1064       if ((StdInFileName     = FixFileName(StdInFileName)) == NULL) {
   1065         Status = EFI_INVALID_PARAMETER;
   1066       }
   1067     }
   1068     if (StdErrVarName  != NULL) {
   1069       if ((StdErrVarName     = FixVarName(StdErrVarName)) == NULL) {
   1070         Status = EFI_INVALID_PARAMETER;
   1071       }
   1072     }
   1073     if (StdOutVarName  != NULL) {
   1074       if ((StdOutVarName     = FixVarName(StdOutVarName)) == NULL) {
   1075         Status = EFI_INVALID_PARAMETER;
   1076       }
   1077     }
   1078     if (StdInVarName   != NULL) {
   1079       if ((StdInVarName      = FixVarName(StdInVarName)) == NULL) {
   1080         Status = EFI_INVALID_PARAMETER;
   1081       }
   1082     }
   1083 
   1084     //
   1085     // Verify not the same and not duplicating something from a split
   1086     //
   1087     if (
   1088       //
   1089       // Check that no 2 filenames are the same
   1090       //
   1091       (StdErrFileName != NULL && StdOutFileName!= NULL && StringNoCaseCompare(&StdErrFileName, &StdOutFileName) == 0)
   1092       ||(StdErrFileName != NULL && StdInFileName != NULL && StringNoCaseCompare(&StdErrFileName, &StdInFileName ) == 0)
   1093       ||(StdOutFileName != NULL && StdInFileName != NULL && StringNoCaseCompare(&StdOutFileName, &StdInFileName ) == 0)
   1094       //
   1095       // Check that no 2 variable names are the same
   1096       //
   1097       ||(StdErrVarName  != NULL && StdInVarName  != NULL && StringNoCaseCompare(&StdErrVarName , &StdInVarName  ) == 0)
   1098       ||(StdOutVarName  != NULL && StdInVarName != NULL && StringNoCaseCompare(&StdOutVarName , &StdInVarName  ) == 0)
   1099       ||(StdErrVarName  != NULL && StdOutVarName != NULL && StringNoCaseCompare(&StdErrVarName , &StdOutVarName ) == 0)
   1100       //
   1101       // When a split (using | operator) is in place some are not allowed
   1102       //
   1103       ||(Split != NULL && Split->SplitStdIn  != NULL && (StdInVarName  != NULL || StdInFileName  != NULL))
   1104       ||(Split != NULL && Split->SplitStdOut != NULL && (StdOutVarName != NULL || StdOutFileName != NULL))
   1105       //
   1106       // Check that nothing is trying to be output to 2 locations.
   1107       //
   1108       ||(StdErrFileName != NULL && StdErrVarName != NULL)
   1109       ||(StdOutFileName != NULL && StdOutVarName != NULL)
   1110       ||(StdInFileName  != NULL && StdInVarName  != NULL)
   1111       //
   1112       // Check for no volatile environment variables
   1113       //
   1114       ||(StdErrVarName  != NULL && !IsVolatileEnv(StdErrVarName))
   1115       ||(StdOutVarName  != NULL && !IsVolatileEnv(StdOutVarName))
   1116       //
   1117       // Cant redirect during a reconnect operation.
   1118       //
   1119       ||(StrStr(NewCommandLine, L"connect -r") != NULL
   1120          && (StdOutVarName != NULL || StdOutFileName != NULL || StdErrFileName != NULL || StdErrVarName != NULL))
   1121       //
   1122       // Check that filetypes (Unicode/Ascii) do not change during an append
   1123       //
   1124       ||(StdOutFileName != NULL && OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && EFI_ERROR(IsUnicodeFile(StdOutFileName))))
   1125       ||(StdErrFileName != NULL && ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && EFI_ERROR(IsUnicodeFile(StdErrFileName))))
   1126       ||(StdOutFileName != NULL && !OutUnicode && OutAppend && (!EFI_ERROR(ShellFileExists(StdOutFileName)) && !EFI_ERROR(IsUnicodeFile(StdOutFileName))))
   1127       ||(StdErrFileName != NULL && !ErrUnicode && ErrAppend && (!EFI_ERROR(ShellFileExists(StdErrFileName)) && !EFI_ERROR(IsUnicodeFile(StdErrFileName))))
   1128       ){
   1129       Status = EFI_INVALID_PARAMETER;
   1130       ShellParameters->StdIn  = *OldStdIn;
   1131       ShellParameters->StdOut = *OldStdOut;
   1132       ShellParameters->StdErr = *OldStdErr;
   1133     } else if (!EFI_ERROR(Status)){
   1134       //
   1135       // Open the Std<Whatever> and we should not have conflicts here...
   1136       //
   1137 
   1138       //
   1139       // StdErr to a file
   1140       //
   1141       if (StdErrFileName != NULL) {
   1142         if (!ErrAppend) {
   1143           //
   1144           // delete existing file.
   1145           //
   1146           ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdErrFileName);
   1147         }
   1148         Status = ShellOpenFileByName(StdErrFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0);
   1149         if (!ErrAppend && ErrUnicode && !EFI_ERROR(Status)) {
   1150           Status = WriteFileTag (TempHandle);
   1151         }
   1152         if (!ErrUnicode && !EFI_ERROR(Status)) {
   1153           TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
   1154           ASSERT(TempHandle != NULL);
   1155         }
   1156         if (!EFI_ERROR(Status)) {
   1157           ShellParameters->StdErr = TempHandle;
   1158           gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr);
   1159         }
   1160       }
   1161 
   1162       //
   1163       // StdOut to a file
   1164       //
   1165       if (!EFI_ERROR(Status) && StdOutFileName != NULL) {
   1166         if (!OutAppend) {
   1167           //
   1168           // delete existing file.
   1169           //
   1170           ShellInfoObject.NewEfiShellProtocol->DeleteFileByName(StdOutFileName);
   1171         }
   1172         Status = ShellOpenFileByName(StdOutFileName, &TempHandle, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE,0);
   1173         if (TempHandle == NULL) {
   1174           Status = EFI_INVALID_PARAMETER;
   1175         } else {
   1176           if (StrStr(StdOutFileName, L"NUL")==StdOutFileName) {
   1177             //no-op
   1178           } else if (!OutAppend && OutUnicode && !EFI_ERROR(Status)) {
   1179             Status = WriteFileTag (TempHandle);
   1180           } else if (OutAppend) {
   1181             Status = ShellInfoObject.NewEfiShellProtocol->GetFileSize(TempHandle, &FileSize);
   1182             if (!EFI_ERROR(Status)) {
   1183               //
   1184               // When appending to a new unicode file, write the file tag.
   1185               // Otherwise (ie. when appending to a new ASCII file, or an
   1186               // existent file with any encoding), just seek to the end.
   1187               //
   1188               Status = (FileSize == 0 && OutUnicode) ?
   1189                          WriteFileTag (TempHandle) :
   1190                          ShellInfoObject.NewEfiShellProtocol->SetFilePosition (
   1191                                                                 TempHandle,
   1192                                                                 FileSize);
   1193             }
   1194           }
   1195           if (!OutUnicode && !EFI_ERROR(Status)) {
   1196             TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
   1197             ASSERT(TempHandle != NULL);
   1198           }
   1199           if (!EFI_ERROR(Status)) {
   1200             ShellParameters->StdOut = TempHandle;
   1201             gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
   1202           }
   1203         }
   1204       }
   1205 
   1206       //
   1207       // StdOut to a var
   1208       //
   1209       if (!EFI_ERROR(Status) && StdOutVarName != NULL) {
   1210         if (!OutAppend) {
   1211           //
   1212           // delete existing variable.
   1213           //
   1214           SHELL_SET_ENVIRONMENT_VARIABLE_V(StdOutVarName, 0, L"");
   1215         }
   1216         TempHandle = CreateFileInterfaceEnv(StdOutVarName);
   1217         ASSERT(TempHandle != NULL);
   1218         ShellParameters->StdOut = TempHandle;
   1219         gST->ConOut = CreateSimpleTextOutOnFile(TempHandle, &gST->ConsoleOutHandle, gST->ConOut);
   1220       }
   1221 
   1222       //
   1223       // StdErr to a var
   1224       //
   1225       if (!EFI_ERROR(Status) && StdErrVarName != NULL) {
   1226         if (!ErrAppend) {
   1227           //
   1228           // delete existing variable.
   1229           //
   1230           SHELL_SET_ENVIRONMENT_VARIABLE_V(StdErrVarName, 0, L"");
   1231         }
   1232         TempHandle = CreateFileInterfaceEnv(StdErrVarName);
   1233         ASSERT(TempHandle != NULL);
   1234         ShellParameters->StdErr = TempHandle;
   1235         gST->StdErr = CreateSimpleTextOutOnFile(TempHandle, &gST->StandardErrorHandle, gST->StdErr);
   1236       }
   1237 
   1238       //
   1239       // StdIn from a var
   1240       //
   1241       if (!EFI_ERROR(Status) && StdInVarName != NULL) {
   1242         TempHandle = CreateFileInterfaceEnv(StdInVarName);
   1243         if (TempHandle == NULL) {
   1244           Status = EFI_OUT_OF_RESOURCES;
   1245         } else {
   1246           if (!InUnicode) {
   1247             TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
   1248           }
   1249           Size = 0;
   1250           if (TempHandle == NULL || ((EFI_FILE_PROTOCOL*)TempHandle)->Read(TempHandle, &Size, NULL) != EFI_BUFFER_TOO_SMALL) {
   1251             Status = EFI_INVALID_PARAMETER;
   1252           } else {
   1253             ShellParameters->StdIn = TempHandle;
   1254             gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle);
   1255           }
   1256         }
   1257       }
   1258 
   1259       //
   1260       // StdIn from a file
   1261       //
   1262       if (!EFI_ERROR(Status) && StdInFileName != NULL) {
   1263         Status = ShellOpenFileByName(
   1264           StdInFileName,
   1265           &TempHandle,
   1266           EFI_FILE_MODE_READ,
   1267           0);
   1268         if (InUnicode) {
   1269           //
   1270           // Chop off the 0xFEFF if it's there...
   1271           //
   1272           RemoveFileTag(&TempHandle);
   1273         } else if (!EFI_ERROR(Status)) {
   1274           //
   1275           // Create the ASCII->Unicode conversion layer
   1276           //
   1277           TempHandle = CreateFileInterfaceFile(TempHandle, FALSE);
   1278         }
   1279         if (!EFI_ERROR(Status)) {
   1280           ShellParameters->StdIn = TempHandle;
   1281           gST->ConIn = CreateSimpleTextInOnFile(TempHandle, &gST->ConsoleInHandle);
   1282         }
   1283       }
   1284     }
   1285   }
   1286   FreePool(CommandLineCopy);
   1287 
   1288   CalculateEfiHdrCrc(&gST->Hdr);
   1289 
   1290   if (gST->ConIn == NULL ||gST->ConOut == NULL) {
   1291     Status = EFI_OUT_OF_RESOURCES;
   1292   }
   1293 
   1294   if (Status == EFI_NOT_FOUND) {
   1295     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_REDUNDA_REDIR), ShellInfoObject.HiiHandle);
   1296   } else if (EFI_ERROR(Status)) {
   1297     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_REDIR), ShellInfoObject.HiiHandle);
   1298   }
   1299 
   1300   return (Status);
   1301 }
   1302 
   1303 /**
   1304   Funcion will replace the current StdIn and StdOut in the ShellParameters protocol
   1305   structure with StdIn and StdOut.  The current values are de-allocated.
   1306 
   1307   @param[in, out] ShellParameters      Pointer to parameter structure to modify.
   1308   @param[in] OldStdIn                  Pointer to old StdIn.
   1309   @param[in] OldStdOut                 Pointer to old StdOut.
   1310   @param[in] OldStdErr                 Pointer to old StdErr.
   1311   @param[in] SystemTableInfo           Pointer to old system table information.
   1312 **/
   1313 EFI_STATUS
   1314 EFIAPI
   1315 RestoreStdInStdOutStdErr (
   1316   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  *ShellParameters,
   1317   IN  SHELL_FILE_HANDLE                 *OldStdIn,
   1318   IN  SHELL_FILE_HANDLE                 *OldStdOut,
   1319   IN  SHELL_FILE_HANDLE                 *OldStdErr,
   1320   IN  SYSTEM_TABLE_INFO                 *SystemTableInfo
   1321   )
   1322 {
   1323   SPLIT_LIST        *Split;
   1324 
   1325   if (ShellParameters == NULL
   1326     ||OldStdIn        == NULL
   1327     ||OldStdOut       == NULL
   1328     ||OldStdErr       == NULL
   1329     ||SystemTableInfo == NULL) {
   1330     return (EFI_INVALID_PARAMETER);
   1331   }
   1332   if (!IsListEmpty(&ShellInfoObject.SplitList.Link)) {
   1333     Split = (SPLIT_LIST*)GetFirstNode(&ShellInfoObject.SplitList.Link);
   1334   } else {
   1335     Split = NULL;
   1336   }
   1337   if (ShellParameters->StdIn  != *OldStdIn) {
   1338     if ((Split != NULL && Split->SplitStdIn != ShellParameters->StdIn) || Split == NULL) {
   1339       gEfiShellProtocol->CloseFile(ShellParameters->StdIn);
   1340     }
   1341     ShellParameters->StdIn = *OldStdIn;
   1342   }
   1343   if (ShellParameters->StdOut != *OldStdOut) {
   1344     if ((Split != NULL && Split->SplitStdOut != ShellParameters->StdOut) || Split == NULL) {
   1345       gEfiShellProtocol->CloseFile(ShellParameters->StdOut);
   1346     }
   1347     ShellParameters->StdOut = *OldStdOut;
   1348   }
   1349   if (ShellParameters->StdErr != *OldStdErr) {
   1350     gEfiShellProtocol->CloseFile(ShellParameters->StdErr);
   1351     ShellParameters->StdErr = *OldStdErr;
   1352   }
   1353 
   1354   if (gST->ConIn != SystemTableInfo->ConIn) {
   1355     CloseSimpleTextInOnFile(gST->ConIn);
   1356     gST->ConIn                = SystemTableInfo->ConIn;
   1357     gST->ConsoleInHandle      = SystemTableInfo->ConInHandle;
   1358   }
   1359   if (gST->ConOut != SystemTableInfo->ConOut) {
   1360     CloseSimpleTextOutOnFile(gST->ConOut);
   1361     gST->ConOut               = SystemTableInfo->ConOut;
   1362     gST->ConsoleOutHandle     = SystemTableInfo->ConOutHandle;
   1363   }
   1364   if (gST->StdErr != SystemTableInfo->ErrOut) {
   1365     CloseSimpleTextOutOnFile(gST->StdErr);
   1366     gST->StdErr               = SystemTableInfo->ErrOut;
   1367     gST->StandardErrorHandle  = SystemTableInfo->ErrOutHandle;
   1368   }
   1369 
   1370   CalculateEfiHdrCrc(&gST->Hdr);
   1371 
   1372   return (EFI_SUCCESS);
   1373 }
   1374 /**
   1375   Funcion will replace the current Argc and Argv in the ShellParameters protocol
   1376   structure by parsing NewCommandLine.  The current values are returned to the
   1377   user.
   1378 
   1379   If OldArgv or OldArgc is NULL then that value is not returned.
   1380 
   1381   @param[in, out] ShellParameters        Pointer to parameter structure to modify.
   1382   @param[in] NewCommandLine              The new command line to parse and use.
   1383   @param[in] Type                        The type of operation.
   1384   @param[out] OldArgv                    Pointer to old list of parameters.
   1385   @param[out] OldArgc                    Pointer to old number of items in Argv list.
   1386 
   1387   @retval   EFI_SUCCESS                 Operation was sucessful, Argv and Argc are valid.
   1388   @retval   EFI_OUT_OF_RESOURCES        A memory allocation failed.
   1389 **/
   1390 EFI_STATUS
   1391 EFIAPI
   1392 UpdateArgcArgv(
   1393   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  *ShellParameters,
   1394   IN CONST CHAR16                       *NewCommandLine,
   1395   IN SHELL_OPERATION_TYPES              Type,
   1396   OUT CHAR16                            ***OldArgv OPTIONAL,
   1397   OUT UINTN                             *OldArgc OPTIONAL
   1398   )
   1399 {
   1400   BOOLEAN                 StripParamQuotation;
   1401 
   1402   ASSERT(ShellParameters != NULL);
   1403   StripParamQuotation = TRUE;
   1404 
   1405   if (OldArgc != NULL) {
   1406     *OldArgc = ShellParameters->Argc;
   1407   }
   1408   if (OldArgc != NULL) {
   1409     *OldArgv = ShellParameters->Argv;
   1410   }
   1411 
   1412   if (Type == Script_File_Name) {
   1413     StripParamQuotation = FALSE;
   1414   }
   1415 
   1416   return ParseCommandLineToArgs( NewCommandLine,
   1417                                  StripParamQuotation,
   1418                                  &(ShellParameters->Argv),
   1419                                  &(ShellParameters->Argc)
   1420                                 );
   1421 }
   1422 
   1423 /**
   1424   Funcion will replace the current Argc and Argv in the ShellParameters protocol
   1425   structure with Argv and Argc.  The current values are de-allocated and the
   1426   OldArgv must not be deallocated by the caller.
   1427 
   1428   @param[in, out] ShellParameters       pointer to parameter structure to modify
   1429   @param[in] OldArgv                    pointer to old list of parameters
   1430   @param[in] OldArgc                    pointer to old number of items in Argv list
   1431 **/
   1432 VOID
   1433 EFIAPI
   1434 RestoreArgcArgv(
   1435   IN OUT EFI_SHELL_PARAMETERS_PROTOCOL  *ShellParameters,
   1436   IN CHAR16                             ***OldArgv,
   1437   IN UINTN                              *OldArgc
   1438   )
   1439 {
   1440   UINTN LoopCounter;
   1441   ASSERT(ShellParameters != NULL);
   1442   ASSERT(OldArgv         != NULL);
   1443   ASSERT(OldArgc         != NULL);
   1444 
   1445   if (ShellParameters->Argv != NULL) {
   1446     for ( LoopCounter = 0
   1447         ; LoopCounter < ShellParameters->Argc
   1448         ; LoopCounter++
   1449        ){
   1450       FreePool(ShellParameters->Argv[LoopCounter]);
   1451     }
   1452     FreePool(ShellParameters->Argv);
   1453   }
   1454   ShellParameters->Argv = *OldArgv;
   1455   *OldArgv = NULL;
   1456   ShellParameters->Argc = *OldArgc;
   1457   *OldArgc = 0;
   1458 }
   1459