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