1 /** @file
2   Provides interface to shell functionality for shell commands and applications.
3 
4   Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5   This program and the accompanying materials
6   are licensed and made available under the terms and conditions of the BSD License
7   which accompanies this distribution.  The full text of the license may be found at
8   http://opensource.org/licenses/bsd-license.php
9 
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "UefiShellLib.h"
16 #include <ShellBase.h>
17 #include <Library/SortLib.h>
18 #include <Library/BaseLib.h>
19 
20 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
21 
22 //
23 // globals...
24 //
25 SHELL_PARAM_ITEM EmptyParamList[] = {
26   {NULL, TypeMax}
27   };
28 SHELL_PARAM_ITEM SfoParamList[] = {
29   {L"-sfo", TypeFlag},
30   {NULL, TypeMax}
31   };
32 EFI_SHELL_ENVIRONMENT2        *mEfiShellEnvironment2;
33 EFI_SHELL_INTERFACE           *mEfiShellInterface;
34 EFI_SHELL_PROTOCOL            *gEfiShellProtocol;
35 EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
36 EFI_HANDLE                    mEfiShellEnvironment2Handle;
37 FILE_HANDLE_FUNCTION_MAP      FileFunctionMap;
38 
39 /**
40   Check if a Unicode character is a hexadecimal character.
41 
42   This internal function checks if a Unicode character is a
43   numeric character.  The valid hexadecimal characters are
44   L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
45 
46   @param  Char  The character to check against.
47 
48   @retval TRUE  If the Char is a hexadecmial character.
49   @retval FALSE If the Char is not a hexadecmial character.
50 
51 **/
52 BOOLEAN
53 EFIAPI
ShellIsHexaDecimalDigitCharacter(IN CHAR16 Char)54 ShellIsHexaDecimalDigitCharacter (
55   IN      CHAR16                    Char
56   )
57 {
58   return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
59 }
60 
61 /**
62   Check if a Unicode character is a decimal character.
63 
64   This internal function checks if a Unicode character is a
65   decimal character.  The valid characters are
66   L'0' to L'9'.
67 
68 
69   @param  Char  The character to check against.
70 
71   @retval TRUE  If the Char is a hexadecmial character.
72   @retval FALSE If the Char is not a hexadecmial character.
73 
74 **/
75 BOOLEAN
76 EFIAPI
ShellIsDecimalDigitCharacter(IN CHAR16 Char)77 ShellIsDecimalDigitCharacter (
78   IN      CHAR16                    Char
79   )
80 {
81   return (BOOLEAN) (Char >= L'0' && Char <= L'9');
82 }
83 
84 /**
85   Helper function to find ShellEnvironment2 for constructor.
86 
87   @param[in] ImageHandle    A copy of the calling image's handle.
88 
89   @retval EFI_OUT_OF_RESOURCES    Memory allocation failed.
90 **/
91 EFI_STATUS
92 EFIAPI
ShellFindSE2(IN EFI_HANDLE ImageHandle)93 ShellFindSE2 (
94   IN EFI_HANDLE        ImageHandle
95   )
96 {
97   EFI_STATUS  Status;
98   EFI_HANDLE  *Buffer;
99   UINTN       BufferSize;
100   UINTN       HandleIndex;
101 
102   BufferSize = 0;
103   Buffer = NULL;
104   Status = gBS->OpenProtocol(ImageHandle,
105                              &gEfiShellEnvironment2Guid,
106                              (VOID **)&mEfiShellEnvironment2,
107                              ImageHandle,
108                              NULL,
109                              EFI_OPEN_PROTOCOL_GET_PROTOCOL
110                             );
111   //
112   // look for the mEfiShellEnvironment2 protocol at a higher level
113   //
114   if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))){
115     //
116     // figure out how big of a buffer we need.
117     //
118     Status = gBS->LocateHandle (ByProtocol,
119                                 &gEfiShellEnvironment2Guid,
120                                 NULL, // ignored for ByProtocol
121                                 &BufferSize,
122                                 Buffer
123                                );
124     //
125     // maybe it's not there???
126     //
127     if (Status == EFI_BUFFER_TOO_SMALL) {
128       Buffer = (EFI_HANDLE*)AllocateZeroPool(BufferSize);
129       if (Buffer == NULL) {
130         return (EFI_OUT_OF_RESOURCES);
131       }
132       Status = gBS->LocateHandle (ByProtocol,
133                                   &gEfiShellEnvironment2Guid,
134                                   NULL, // ignored for ByProtocol
135                                   &BufferSize,
136                                   Buffer
137                                  );
138     }
139     if (!EFI_ERROR (Status) && Buffer != NULL) {
140       //
141       // now parse the list of returned handles
142       //
143       Status = EFI_NOT_FOUND;
144       for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) {
145         Status = gBS->OpenProtocol(Buffer[HandleIndex],
146                                    &gEfiShellEnvironment2Guid,
147                                    (VOID **)&mEfiShellEnvironment2,
148                                    ImageHandle,
149                                    NULL,
150                                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
151                                   );
152          if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) {
153           mEfiShellEnvironment2Handle = Buffer[HandleIndex];
154           Status = EFI_SUCCESS;
155           break;
156         }
157       }
158     }
159   }
160   if (Buffer != NULL) {
161     FreePool (Buffer);
162   }
163   return (Status);
164 }
165 
166 /**
167   Function to do most of the work of the constructor.  Allows for calling
168   multiple times without complete re-initialization.
169 
170   @param[in] ImageHandle  A copy of the ImageHandle.
171   @param[in] SystemTable  A pointer to the SystemTable for the application.
172 
173   @retval EFI_SUCCESS   The operationw as successful.
174 **/
175 EFI_STATUS
176 EFIAPI
ShellLibConstructorWorker(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)177 ShellLibConstructorWorker (
178   IN EFI_HANDLE        ImageHandle,
179   IN EFI_SYSTEM_TABLE  *SystemTable
180   )
181 {
182   EFI_STATUS  Status;
183 
184   //
185   // UEFI 2.0 shell interfaces (used preferentially)
186   //
187   Status = gBS->OpenProtocol(
188     ImageHandle,
189     &gEfiShellProtocolGuid,
190     (VOID **)&gEfiShellProtocol,
191     ImageHandle,
192     NULL,
193     EFI_OPEN_PROTOCOL_GET_PROTOCOL
194    );
195   if (EFI_ERROR(Status)) {
196     //
197     // Search for the shell protocol
198     //
199     Status = gBS->LocateProtocol(
200       &gEfiShellProtocolGuid,
201       NULL,
202       (VOID **)&gEfiShellProtocol
203      );
204     if (EFI_ERROR(Status)) {
205       gEfiShellProtocol = NULL;
206     }
207   }
208   Status = gBS->OpenProtocol(
209     ImageHandle,
210     &gEfiShellParametersProtocolGuid,
211     (VOID **)&gEfiShellParametersProtocol,
212     ImageHandle,
213     NULL,
214     EFI_OPEN_PROTOCOL_GET_PROTOCOL
215    );
216   if (EFI_ERROR(Status)) {
217     gEfiShellParametersProtocol = NULL;
218   }
219 
220   if (gEfiShellParametersProtocol == NULL || gEfiShellProtocol == NULL) {
221     //
222     // Moved to seperate function due to complexity
223     //
224     Status = ShellFindSE2(ImageHandle);
225 
226     if (EFI_ERROR(Status)) {
227       DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
228       mEfiShellEnvironment2 = NULL;
229     }
230     Status = gBS->OpenProtocol(ImageHandle,
231                                &gEfiShellInterfaceGuid,
232                                (VOID **)&mEfiShellInterface,
233                                ImageHandle,
234                                NULL,
235                                EFI_OPEN_PROTOCOL_GET_PROTOCOL
236                               );
237     if (EFI_ERROR(Status)) {
238       mEfiShellInterface = NULL;
239     }
240   }
241 
242   //
243   // only success getting 2 of either the old or new, but no 1/2 and 1/2
244   //
245   if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface          != NULL) ||
246       (gEfiShellProtocol     != NULL && gEfiShellParametersProtocol != NULL)   ) {
247     if (gEfiShellProtocol != NULL) {
248       FileFunctionMap.GetFileInfo     = gEfiShellProtocol->GetFileInfo;
249       FileFunctionMap.SetFileInfo     = gEfiShellProtocol->SetFileInfo;
250       FileFunctionMap.ReadFile        = gEfiShellProtocol->ReadFile;
251       FileFunctionMap.WriteFile       = gEfiShellProtocol->WriteFile;
252       FileFunctionMap.CloseFile       = gEfiShellProtocol->CloseFile;
253       FileFunctionMap.DeleteFile      = gEfiShellProtocol->DeleteFile;
254       FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition;
255       FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition;
256       FileFunctionMap.FlushFile       = gEfiShellProtocol->FlushFile;
257       FileFunctionMap.GetFileSize     = gEfiShellProtocol->GetFileSize;
258     } else {
259       FileFunctionMap.GetFileInfo     = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo;
260       FileFunctionMap.SetFileInfo     = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo;
261       FileFunctionMap.ReadFile        = (EFI_SHELL_READ_FILE)FileHandleRead;
262       FileFunctionMap.WriteFile       = (EFI_SHELL_WRITE_FILE)FileHandleWrite;
263       FileFunctionMap.CloseFile       = (EFI_SHELL_CLOSE_FILE)FileHandleClose;
264       FileFunctionMap.DeleteFile      = (EFI_SHELL_DELETE_FILE)FileHandleDelete;
265       FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition;
266       FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition;
267       FileFunctionMap.FlushFile       = (EFI_SHELL_FLUSH_FILE)FileHandleFlush;
268       FileFunctionMap.GetFileSize     = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize;
269     }
270     return (EFI_SUCCESS);
271   }
272   return (EFI_NOT_FOUND);
273 }
274 /**
275   Constructor for the Shell library.
276 
277   Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
278 
279   @param ImageHandle    the image handle of the process
280   @param SystemTable    the EFI System Table pointer
281 
282   @retval EFI_SUCCESS   the initialization was complete sucessfully
283   @return others        an error ocurred during initialization
284 **/
285 EFI_STATUS
286 EFIAPI
ShellLibConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)287 ShellLibConstructor (
288   IN EFI_HANDLE        ImageHandle,
289   IN EFI_SYSTEM_TABLE  *SystemTable
290   )
291 {
292   mEfiShellEnvironment2       = NULL;
293   gEfiShellProtocol           = NULL;
294   gEfiShellParametersProtocol = NULL;
295   mEfiShellInterface          = NULL;
296   mEfiShellEnvironment2Handle = NULL;
297 
298   //
299   // verify that auto initialize is not set false
300   //
301   if (PcdGetBool(PcdShellLibAutoInitialize) == 0) {
302     return (EFI_SUCCESS);
303   }
304 
305   return (ShellLibConstructorWorker(ImageHandle, SystemTable));
306 }
307 
308 /**
309   Destructor for the library.  free any resources.
310 
311   @param[in] ImageHandle  A copy of the ImageHandle.
312   @param[in] SystemTable  A pointer to the SystemTable for the application.
313 
314   @retval EFI_SUCCESS   The operation was successful.
315   @return               An error from the CloseProtocol function.
316 **/
317 EFI_STATUS
318 EFIAPI
ShellLibDestructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)319 ShellLibDestructor (
320   IN EFI_HANDLE        ImageHandle,
321   IN EFI_SYSTEM_TABLE  *SystemTable
322   )
323 {
324   if (mEfiShellEnvironment2 != NULL) {
325     gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
326                        &gEfiShellEnvironment2Guid,
327                        ImageHandle,
328                        NULL);
329     mEfiShellEnvironment2 = NULL;
330   }
331   if (mEfiShellInterface != NULL) {
332     gBS->CloseProtocol(ImageHandle,
333                        &gEfiShellInterfaceGuid,
334                        ImageHandle,
335                        NULL);
336     mEfiShellInterface = NULL;
337   }
338   if (gEfiShellProtocol != NULL) {
339     gBS->CloseProtocol(ImageHandle,
340                        &gEfiShellProtocolGuid,
341                        ImageHandle,
342                        NULL);
343     gEfiShellProtocol = NULL;
344   }
345   if (gEfiShellParametersProtocol != NULL) {
346     gBS->CloseProtocol(ImageHandle,
347                        &gEfiShellParametersProtocolGuid,
348                        ImageHandle,
349                        NULL);
350     gEfiShellParametersProtocol = NULL;
351   }
352   mEfiShellEnvironment2Handle = NULL;
353 
354   return (EFI_SUCCESS);
355 }
356 
357 /**
358   This function causes the shell library to initialize itself.  If the shell library
359   is already initialized it will de-initialize all the current protocol poitners and
360   re-populate them again.
361 
362   When the library is used with PcdShellLibAutoInitialize set to true this function
363   will return EFI_SUCCESS and perform no actions.
364 
365   This function is intended for internal access for shell commands only.
366 
367   @retval EFI_SUCCESS   the initialization was complete sucessfully
368 
369 **/
370 EFI_STATUS
371 EFIAPI
ShellInitialize()372 ShellInitialize (
373   )
374 {
375   //
376   // if auto initialize is not false then skip
377   //
378   if (PcdGetBool(PcdShellLibAutoInitialize) != 0) {
379     return (EFI_SUCCESS);
380   }
381 
382   //
383   // deinit the current stuff
384   //
385   ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));
386 
387   //
388   // init the new stuff
389   //
390   return (ShellLibConstructorWorker(gImageHandle, gST));
391 }
392 
393 /**
394   This function will retrieve the information about the file for the handle
395   specified and store it in allocated pool memory.
396 
397   This function allocates a buffer to store the file's information. It is the
398   caller's responsibility to free the buffer
399 
400   @param  FileHandle  The file handle of the file for which information is
401   being requested.
402 
403   @retval NULL information could not be retrieved.
404 
405   @return the information about the file
406 **/
407 EFI_FILE_INFO*
408 EFIAPI
ShellGetFileInfo(IN SHELL_FILE_HANDLE FileHandle)409 ShellGetFileInfo (
410   IN SHELL_FILE_HANDLE                     FileHandle
411   )
412 {
413   return (FileFunctionMap.GetFileInfo(FileHandle));
414 }
415 
416 /**
417   This function sets the information about the file for the opened handle
418   specified.
419 
420   @param[in]  FileHandle        The file handle of the file for which information
421                                 is being set.
422 
423   @param[in]  FileInfo          The information to set.
424 
425   @retval EFI_SUCCESS           The information was set.
426   @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
427   @retval EFI_UNSUPPORTED       The FileHandle does not support FileInfo.
428   @retval EFI_NO_MEDIA          The device has no medium.
429   @retval EFI_DEVICE_ERROR      The device reported an error.
430   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
431   @retval EFI_WRITE_PROTECTED   The file or medium is write protected.
432   @retval EFI_ACCESS_DENIED     The file was opened read only.
433   @retval EFI_VOLUME_FULL       The volume is full.
434 **/
435 EFI_STATUS
436 EFIAPI
ShellSetFileInfo(IN SHELL_FILE_HANDLE FileHandle,IN EFI_FILE_INFO * FileInfo)437 ShellSetFileInfo (
438   IN SHELL_FILE_HANDLE                    FileHandle,
439   IN EFI_FILE_INFO              *FileInfo
440   )
441 {
442   return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));
443 }
444 
445   /**
446   This function will open a file or directory referenced by DevicePath.
447 
448   This function opens a file with the open mode according to the file path. The
449   Attributes is valid only for EFI_FILE_MODE_CREATE.
450 
451   @param  FilePath        on input the device path to the file.  On output
452                           the remaining device path.
453   @param  DeviceHandle    pointer to the system device handle.
454   @param  FileHandle      pointer to the file handle.
455   @param  OpenMode        the mode to open the file with.
456   @param  Attributes      the file's file attributes.
457 
458   @retval EFI_SUCCESS           The information was set.
459   @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
460   @retval EFI_UNSUPPORTED       Could not open the file path.
461   @retval EFI_NOT_FOUND         The specified file could not be found on the
462                                 device or the file system could not be found on
463                                 the device.
464   @retval EFI_NO_MEDIA          The device has no medium.
465   @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
466                                 medium is no longer supported.
467   @retval EFI_DEVICE_ERROR      The device reported an error.
468   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
469   @retval EFI_WRITE_PROTECTED   The file or medium is write protected.
470   @retval EFI_ACCESS_DENIED     The file was opened read only.
471   @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
472                                 file.
473   @retval EFI_VOLUME_FULL       The volume is full.
474 **/
475 EFI_STATUS
476 EFIAPI
ShellOpenFileByDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL ** FilePath,OUT EFI_HANDLE * DeviceHandle,OUT SHELL_FILE_HANDLE * FileHandle,IN UINT64 OpenMode,IN UINT64 Attributes)477 ShellOpenFileByDevicePath(
478   IN OUT EFI_DEVICE_PATH_PROTOCOL     **FilePath,
479   OUT EFI_HANDLE                      *DeviceHandle,
480   OUT SHELL_FILE_HANDLE               *FileHandle,
481   IN UINT64                           OpenMode,
482   IN UINT64                           Attributes
483   )
484 {
485   CHAR16                          *FileName;
486   EFI_STATUS                      Status;
487   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
488   EFI_FILE_PROTOCOL               *Handle1;
489   EFI_FILE_PROTOCOL               *Handle2;
490   CHAR16                          *FnafPathName;
491   UINTN                           PathLen;
492 
493   if (FilePath == NULL || FileHandle == NULL || DeviceHandle == NULL) {
494     return (EFI_INVALID_PARAMETER);
495   }
496 
497   //
498   // which shell interface should we use
499   //
500   if (gEfiShellProtocol != NULL) {
501     //
502     // use UEFI Shell 2.0 method.
503     //
504     FileName = gEfiShellProtocol->GetFilePathFromDevicePath(*FilePath);
505     if (FileName == NULL) {
506       return (EFI_INVALID_PARAMETER);
507     }
508     Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes);
509     FreePool(FileName);
510     return (Status);
511   }
512 
513 
514   //
515   // use old shell method.
516   //
517   Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
518                                   FilePath,
519                                   DeviceHandle);
520   if (EFI_ERROR (Status)) {
521     return Status;
522   }
523   Status = gBS->OpenProtocol(*DeviceHandle,
524                              &gEfiSimpleFileSystemProtocolGuid,
525                              (VOID**)&EfiSimpleFileSystemProtocol,
526                              gImageHandle,
527                              NULL,
528                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);
529   if (EFI_ERROR (Status)) {
530     return Status;
531   }
532   Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
533   if (EFI_ERROR (Status)) {
534     FileHandle = NULL;
535     return Status;
536   }
537 
538   //
539   // go down directories one node at a time.
540   //
541   while (!IsDevicePathEnd (*FilePath)) {
542     //
543     // For file system access each node should be a file path component
544     //
545     if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||
546         DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
547        ) {
548       FileHandle = NULL;
549       return (EFI_INVALID_PARAMETER);
550     }
551     //
552     // Open this file path node
553     //
554     Handle2  = Handle1;
555     Handle1 = NULL;
556 
557     //
558     // File Name Alignment Fix (FNAF)
559     // Handle2->Open may be incapable of handling a unaligned CHAR16 data.
560     // The structure pointed to by FilePath may be not CHAR16 aligned.
561     // This code copies the potentially unaligned PathName data from the
562     // FilePath structure to the aligned FnafPathName for use in the
563     // calls to Handl2->Open.
564     //
565 
566     //
567     // Determine length of PathName, in bytes.
568     //
569     PathLen = DevicePathNodeLength (*FilePath) - SIZE_OF_FILEPATH_DEVICE_PATH;
570 
571     //
572     // Allocate memory for the aligned copy of the string Extra allocation is to allow for forced alignment
573     // Copy bytes from possibly unaligned location to aligned location
574     //
575     FnafPathName = AllocateCopyPool(PathLen, (UINT8 *)((FILEPATH_DEVICE_PATH*)*FilePath)->PathName);
576     if (FnafPathName == NULL) {
577       return EFI_OUT_OF_RESOURCES;
578     }
579 
580     //
581     // Try to test opening an existing file
582     //
583     Status = Handle2->Open (
584                           Handle2,
585                           &Handle1,
586                           FnafPathName,
587                           OpenMode &~EFI_FILE_MODE_CREATE,
588                           0
589                          );
590 
591     //
592     // see if the error was that it needs to be created
593     //
594     if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
595       Status = Handle2->Open (
596                             Handle2,
597                             &Handle1,
598                             FnafPathName,
599                             OpenMode,
600                             Attributes
601                            );
602     }
603 
604     //
605     // Free the alignment buffer
606     //
607     FreePool(FnafPathName);
608 
609     //
610     // Close the last node
611     //
612     Handle2->Close (Handle2);
613 
614     if (EFI_ERROR(Status)) {
615       return (Status);
616     }
617 
618     //
619     // Get the next node
620     //
621     *FilePath = NextDevicePathNode (*FilePath);
622   }
623 
624   //
625   // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
626   //
627   *FileHandle = (VOID*)Handle1;
628   return (EFI_SUCCESS);
629 }
630 
631 /**
632   This function will open a file or directory referenced by filename.
633 
634   If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
635   otherwise, the Filehandle is NULL. The Attributes is valid only for
636   EFI_FILE_MODE_CREATE.
637 
638   if FileName is NULL then ASSERT()
639 
640   @param  FileName      pointer to file name
641   @param  FileHandle    pointer to the file handle.
642   @param  OpenMode      the mode to open the file with.
643   @param  Attributes    the file's file attributes.
644 
645   @retval EFI_SUCCESS           The information was set.
646   @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
647   @retval EFI_UNSUPPORTED       Could not open the file path.
648   @retval EFI_NOT_FOUND         The specified file could not be found on the
649                                 device or the file system could not be found
650                                 on the device.
651   @retval EFI_NO_MEDIA          The device has no medium.
652   @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
653                                 medium is no longer supported.
654   @retval EFI_DEVICE_ERROR      The device reported an error.
655   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
656   @retval EFI_WRITE_PROTECTED   The file or medium is write protected.
657   @retval EFI_ACCESS_DENIED     The file was opened read only.
658   @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
659                                 file.
660   @retval EFI_VOLUME_FULL       The volume is full.
661 **/
662 EFI_STATUS
663 EFIAPI
ShellOpenFileByName(IN CONST CHAR16 * FileName,OUT SHELL_FILE_HANDLE * FileHandle,IN UINT64 OpenMode,IN UINT64 Attributes)664 ShellOpenFileByName(
665   IN CONST CHAR16               *FileName,
666   OUT SHELL_FILE_HANDLE         *FileHandle,
667   IN UINT64                     OpenMode,
668   IN UINT64                     Attributes
669   )
670 {
671   EFI_HANDLE                    DeviceHandle;
672   EFI_DEVICE_PATH_PROTOCOL      *FilePath;
673   EFI_STATUS                    Status;
674   EFI_FILE_INFO                 *FileInfo;
675   CHAR16                        *FileNameCopy;
676   EFI_STATUS                    Status2;
677 
678   //
679   // ASSERT if FileName is NULL
680   //
681   ASSERT(FileName != NULL);
682 
683   if (FileName == NULL) {
684     return (EFI_INVALID_PARAMETER);
685   }
686 
687   if (gEfiShellProtocol != NULL) {
688     if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
689 
690       //
691       // Create only a directory
692       //
693       if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
694         return ShellCreateDirectory(FileName, FileHandle);
695       }
696 
697       //
698       // Create the directory to create the file in
699       //
700       FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
701       if (FileName == NULL) {
702         return (EFI_OUT_OF_RESOURCES);
703       }
704       PathCleanUpDirectories (FileNameCopy);
705       if (PathRemoveLastItem (FileNameCopy)) {
706         if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {
707           ShellCloseFile (FileHandle);
708         }
709       }
710       SHELL_FREE_NON_NULL (FileNameCopy);
711     }
712 
713     //
714     // Use UEFI Shell 2.0 method to create the file
715     //
716     Status = gEfiShellProtocol->OpenFileByName(FileName,
717                                                FileHandle,
718                                                OpenMode);
719     if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){
720       FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);
721       ASSERT(FileInfo != NULL);
722       FileInfo->Attribute = Attributes;
723       Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);
724       FreePool(FileInfo);
725       if (EFI_ERROR (Status2)) {
726         gEfiShellProtocol->CloseFile(*FileHandle);
727       }
728       Status = Status2;
729     }
730     return (Status);
731   }
732   //
733   // Using EFI Shell version
734   // this means convert name to path and call that function
735   // since this will use EFI method again that will open it.
736   //
737   ASSERT(mEfiShellEnvironment2 != NULL);
738   FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);
739   if (FilePath != NULL) {
740     return (ShellOpenFileByDevicePath(&FilePath,
741                                       &DeviceHandle,
742                                       FileHandle,
743                                       OpenMode,
744                                       Attributes));
745   }
746   return (EFI_DEVICE_ERROR);
747 }
748 /**
749   This function create a directory
750 
751   If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
752   otherwise, the Filehandle is NULL. If the directory already existed, this
753   function opens the existing directory.
754 
755   @param  DirectoryName   pointer to directory name
756   @param  FileHandle      pointer to the file handle.
757 
758   @retval EFI_SUCCESS           The information was set.
759   @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
760   @retval EFI_UNSUPPORTED       Could not open the file path.
761   @retval EFI_NOT_FOUND         The specified file could not be found on the
762                                 device or the file system could not be found
763                                 on the device.
764   @retval EFI_NO_MEDIA          The device has no medium.
765   @retval EFI_MEDIA_CHANGED     The device has a different medium in it or the
766                                 medium is no longer supported.
767   @retval EFI_DEVICE_ERROR      The device reported an error.
768   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
769   @retval EFI_WRITE_PROTECTED   The file or medium is write protected.
770   @retval EFI_ACCESS_DENIED     The file was opened read only.
771   @retval EFI_OUT_OF_RESOURCES  Not enough resources were available to open the
772                                 file.
773   @retval EFI_VOLUME_FULL       The volume is full.
774   @sa ShellOpenFileByName
775 **/
776 EFI_STATUS
777 EFIAPI
ShellCreateDirectory(IN CONST CHAR16 * DirectoryName,OUT SHELL_FILE_HANDLE * FileHandle)778 ShellCreateDirectory(
779   IN CONST CHAR16             *DirectoryName,
780   OUT SHELL_FILE_HANDLE                  *FileHandle
781   )
782 {
783   if (gEfiShellProtocol != NULL) {
784     //
785     // Use UEFI Shell 2.0 method
786     //
787     return (gEfiShellProtocol->CreateFile(DirectoryName,
788                           EFI_FILE_DIRECTORY,
789                           FileHandle
790                          ));
791   } else {
792     return (ShellOpenFileByName(DirectoryName,
793                                 FileHandle,
794                                 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
795                                 EFI_FILE_DIRECTORY
796                                ));
797   }
798 }
799 
800 /**
801   This function reads information from an opened file.
802 
803   If FileHandle is not a directory, the function reads the requested number of
804   bytes from the file at the file's current position and returns them in Buffer.
805   If the read goes beyond the end of the file, the read length is truncated to the
806   end of the file. The file's current position is increased by the number of bytes
807   returned.  If FileHandle is a directory, the function reads the directory entry
808   at the file's current position and returns the entry in Buffer. If the Buffer
809   is not large enough to hold the current directory entry, then
810   EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
811   BufferSize is set to be the size of the buffer needed to read the entry. On
812   success, the current position is updated to the next directory entry. If there
813   are no more directory entries, the read returns a zero-length buffer.
814   EFI_FILE_INFO is the structure returned as the directory entry.
815 
816   @param FileHandle             the opened file handle
817   @param BufferSize             on input the size of buffer in bytes.  on return
818                                 the number of bytes written.
819   @param Buffer                 the buffer to put read data into.
820 
821   @retval EFI_SUCCESS           Data was read.
822   @retval EFI_NO_MEDIA          The device has no media.
823   @retval EFI_DEVICE_ERROR  The device reported an error.
824   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
825   @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
826                                 size.
827 
828 **/
829 EFI_STATUS
830 EFIAPI
ShellReadFile(IN SHELL_FILE_HANDLE FileHandle,IN OUT UINTN * BufferSize,OUT VOID * Buffer)831 ShellReadFile(
832   IN SHELL_FILE_HANDLE                     FileHandle,
833   IN OUT UINTN                  *BufferSize,
834   OUT VOID                      *Buffer
835   )
836 {
837   return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));
838 }
839 
840 
841 /**
842   Write data to a file.
843 
844   This function writes the specified number of bytes to the file at the current
845   file position. The current file position is advanced the actual number of bytes
846   written, which is returned in BufferSize. Partial writes only occur when there
847   has been a data error during the write attempt (such as "volume space full").
848   The file is automatically grown to hold the data if required. Direct writes to
849   opened directories are not supported.
850 
851   @param FileHandle           The opened file for writing
852   @param BufferSize           on input the number of bytes in Buffer.  On output
853                               the number of bytes written.
854   @param Buffer               the buffer containing data to write is stored.
855 
856  @retval EFI_SUCCESS          Data was written.
857  @retval EFI_UNSUPPORTED      Writes to an open directory are not supported.
858  @retval EFI_NO_MEDIA         The device has no media.
859  @retval EFI_DEVICE_ERROR     The device reported an error.
860  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
861  @retval EFI_WRITE_PROTECTED  The device is write-protected.
862  @retval EFI_ACCESS_DENIED    The file was open for read only.
863  @retval EFI_VOLUME_FULL      The volume is full.
864 **/
865 EFI_STATUS
866 EFIAPI
ShellWriteFile(IN SHELL_FILE_HANDLE FileHandle,IN OUT UINTN * BufferSize,IN VOID * Buffer)867 ShellWriteFile(
868   IN SHELL_FILE_HANDLE          FileHandle,
869   IN OUT UINTN                  *BufferSize,
870   IN VOID                       *Buffer
871   )
872 {
873   return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));
874 }
875 
876 /**
877   Close an open file handle.
878 
879   This function closes a specified file handle. All "dirty" cached file data is
880   flushed to the device, and the file is closed. In all cases the handle is
881   closed.
882 
883 @param FileHandle               the file handle to close.
884 
885 @retval EFI_SUCCESS             the file handle was closed sucessfully.
886 **/
887 EFI_STATUS
888 EFIAPI
ShellCloseFile(IN SHELL_FILE_HANDLE * FileHandle)889 ShellCloseFile (
890   IN SHELL_FILE_HANDLE                     *FileHandle
891   )
892 {
893   return (FileFunctionMap.CloseFile(*FileHandle));
894 }
895 
896 /**
897   Delete a file and close the handle
898 
899   This function closes and deletes a file. In all cases the file handle is closed.
900   If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
901   returned, but the handle is still closed.
902 
903   @param FileHandle             the file handle to delete
904 
905   @retval EFI_SUCCESS           the file was closed sucessfully
906   @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
907                                 deleted
908   @retval INVALID_PARAMETER     One of the parameters has an invalid value.
909 **/
910 EFI_STATUS
911 EFIAPI
ShellDeleteFile(IN SHELL_FILE_HANDLE * FileHandle)912 ShellDeleteFile (
913   IN SHELL_FILE_HANDLE            *FileHandle
914   )
915 {
916   return (FileFunctionMap.DeleteFile(*FileHandle));
917 }
918 
919 /**
920   Set the current position in a file.
921 
922   This function sets the current file position for the handle to the position
923   supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
924   absolute positioning is supported, and seeking past the end of the file is
925   allowed (a subsequent write would grow the file). Seeking to position
926   0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
927   If FileHandle is a directory, the only position that may be set is zero. This
928   has the effect of starting the read process of the directory entries over.
929 
930   @param FileHandle             The file handle on which the position is being set
931   @param Position               Byte position from begining of file
932 
933   @retval EFI_SUCCESS           Operation completed sucessfully.
934   @retval EFI_UNSUPPORTED       the seek request for non-zero is not valid on
935                                 directories.
936   @retval INVALID_PARAMETER     One of the parameters has an invalid value.
937 **/
938 EFI_STATUS
939 EFIAPI
ShellSetFilePosition(IN SHELL_FILE_HANDLE FileHandle,IN UINT64 Position)940 ShellSetFilePosition (
941   IN SHELL_FILE_HANDLE              FileHandle,
942   IN UINT64             Position
943   )
944 {
945   return (FileFunctionMap.SetFilePosition(FileHandle, Position));
946 }
947 
948 /**
949   Gets a file's current position
950 
951   This function retrieves the current file position for the file handle. For
952   directories, the current file position has no meaning outside of the file
953   system driver and as such the operation is not supported. An error is returned
954   if FileHandle is a directory.
955 
956   @param FileHandle             The open file handle on which to get the position.
957   @param Position               Byte position from begining of file.
958 
959   @retval EFI_SUCCESS           the operation completed sucessfully.
960   @retval INVALID_PARAMETER     One of the parameters has an invalid value.
961   @retval EFI_UNSUPPORTED       the request is not valid on directories.
962 **/
963 EFI_STATUS
964 EFIAPI
ShellGetFilePosition(IN SHELL_FILE_HANDLE FileHandle,OUT UINT64 * Position)965 ShellGetFilePosition (
966   IN SHELL_FILE_HANDLE                     FileHandle,
967   OUT UINT64                    *Position
968   )
969 {
970   return (FileFunctionMap.GetFilePosition(FileHandle, Position));
971 }
972 /**
973   Flushes data on a file
974 
975   This function flushes all modified data associated with a file to a device.
976 
977   @param FileHandle             The file handle on which to flush data
978 
979   @retval EFI_SUCCESS           The data was flushed.
980   @retval EFI_NO_MEDIA          The device has no media.
981   @retval EFI_DEVICE_ERROR      The device reported an error.
982   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
983   @retval EFI_WRITE_PROTECTED   The file or medium is write protected.
984   @retval EFI_ACCESS_DENIED     The file was opened for read only.
985 **/
986 EFI_STATUS
987 EFIAPI
ShellFlushFile(IN SHELL_FILE_HANDLE FileHandle)988 ShellFlushFile (
989   IN SHELL_FILE_HANDLE                     FileHandle
990   )
991 {
992   return (FileFunctionMap.FlushFile(FileHandle));
993 }
994 
995 /** Retrieve first entry from a directory.
996 
997   This function takes an open directory handle and gets information from the
998   first entry in the directory.  A buffer is allocated to contain
999   the information and a pointer to the buffer is returned in *Buffer.  The
1000   caller can use ShellFindNextFile() to get subsequent directory entries.
1001 
1002   The buffer will be freed by ShellFindNextFile() when the last directory
1003   entry is read.  Otherwise, the caller must free the buffer, using FreePool,
1004   when finished with it.
1005 
1006   @param[in]  DirHandle         The file handle of the directory to search.
1007   @param[out] Buffer            The pointer to the buffer for the file's information.
1008 
1009   @retval EFI_SUCCESS           Found the first file.
1010   @retval EFI_NOT_FOUND         Cannot find the directory.
1011   @retval EFI_NO_MEDIA          The device has no media.
1012   @retval EFI_DEVICE_ERROR      The device reported an error.
1013   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
1014   @return Others                status of ShellGetFileInfo, ShellSetFilePosition,
1015                                 or ShellReadFile
1016 **/
1017 EFI_STATUS
1018 EFIAPI
ShellFindFirstFile(IN SHELL_FILE_HANDLE DirHandle,OUT EFI_FILE_INFO ** Buffer)1019 ShellFindFirstFile (
1020   IN SHELL_FILE_HANDLE                     DirHandle,
1021   OUT EFI_FILE_INFO             **Buffer
1022   )
1023 {
1024   //
1025   // pass to file handle lib
1026   //
1027   return (FileHandleFindFirstFile(DirHandle, Buffer));
1028 }
1029 /** Retrieve next entries from a directory.
1030 
1031   To use this function, the caller must first call the ShellFindFirstFile()
1032   function to get the first directory entry.  Subsequent directory entries are
1033   retrieved by using the ShellFindNextFile() function.  This function can
1034   be called several times to get each entry from the directory.  If the call of
1035   ShellFindNextFile() retrieved the last directory entry, the next call of
1036   this function will set *NoFile to TRUE and free the buffer.
1037 
1038   @param[in]  DirHandle         The file handle of the directory.
1039   @param[out] Buffer            The pointer to buffer for file's information.
1040   @param[out] NoFile            The pointer to boolean when last file is found.
1041 
1042   @retval EFI_SUCCESS           Found the next file, or reached last file
1043   @retval EFI_NO_MEDIA          The device has no media.
1044   @retval EFI_DEVICE_ERROR      The device reported an error.
1045   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
1046 **/
1047 EFI_STATUS
1048 EFIAPI
ShellFindNextFile(IN SHELL_FILE_HANDLE DirHandle,OUT EFI_FILE_INFO * Buffer,OUT BOOLEAN * NoFile)1049 ShellFindNextFile(
1050   IN SHELL_FILE_HANDLE                      DirHandle,
1051   OUT EFI_FILE_INFO              *Buffer,
1052   OUT BOOLEAN                    *NoFile
1053   )
1054 {
1055   //
1056   // pass to file handle lib
1057   //
1058   return (FileHandleFindNextFile(DirHandle, Buffer, NoFile));
1059 }
1060 /**
1061   Retrieve the size of a file.
1062 
1063   if FileHandle is NULL then ASSERT()
1064   if Size is NULL then ASSERT()
1065 
1066   This function extracts the file size info from the FileHandle's EFI_FILE_INFO
1067   data.
1068 
1069   @param FileHandle             file handle from which size is retrieved
1070   @param Size                   pointer to size
1071 
1072   @retval EFI_SUCCESS           operation was completed sucessfully
1073   @retval EFI_DEVICE_ERROR      cannot access the file
1074 **/
1075 EFI_STATUS
1076 EFIAPI
ShellGetFileSize(IN SHELL_FILE_HANDLE FileHandle,OUT UINT64 * Size)1077 ShellGetFileSize (
1078   IN SHELL_FILE_HANDLE                     FileHandle,
1079   OUT UINT64                    *Size
1080   )
1081 {
1082   return (FileFunctionMap.GetFileSize(FileHandle, Size));
1083 }
1084 /**
1085   Retrieves the status of the break execution flag
1086 
1087   this function is useful to check whether the application is being asked to halt by the shell.
1088 
1089   @retval TRUE                  the execution break is enabled
1090   @retval FALSE                 the execution break is not enabled
1091 **/
1092 BOOLEAN
1093 EFIAPI
ShellGetExecutionBreakFlag(VOID)1094 ShellGetExecutionBreakFlag(
1095   VOID
1096   )
1097 {
1098   //
1099   // Check for UEFI Shell 2.0 protocols
1100   //
1101   if (gEfiShellProtocol != NULL) {
1102 
1103     //
1104     // We are using UEFI Shell 2.0; see if the event has been triggered
1105     //
1106     if (gBS->CheckEvent(gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
1107       return (FALSE);
1108     }
1109     return (TRUE);
1110   }
1111 
1112   //
1113   // using EFI Shell; call the function to check
1114   //
1115   if (mEfiShellEnvironment2 != NULL) {
1116     return (mEfiShellEnvironment2->GetExecutionBreak());
1117   }
1118 
1119   return (FALSE);
1120 }
1121 /**
1122   return the value of an environment variable
1123 
1124   this function gets the value of the environment variable set by the
1125   ShellSetEnvironmentVariable function
1126 
1127   @param EnvKey                 The key name of the environment variable.
1128 
1129   @retval NULL                  the named environment variable does not exist.
1130   @return != NULL               pointer to the value of the environment variable
1131 **/
1132 CONST CHAR16*
1133 EFIAPI
ShellGetEnvironmentVariable(IN CONST CHAR16 * EnvKey)1134 ShellGetEnvironmentVariable (
1135   IN CONST CHAR16                *EnvKey
1136   )
1137 {
1138   //
1139   // Check for UEFI Shell 2.0 protocols
1140   //
1141   if (gEfiShellProtocol != NULL) {
1142     return (gEfiShellProtocol->GetEnv(EnvKey));
1143   }
1144 
1145   //
1146   // Check for EFI shell
1147   //
1148   if (mEfiShellEnvironment2 != NULL) {
1149     return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey));
1150   }
1151 
1152   return NULL;
1153 }
1154 /**
1155   set the value of an environment variable
1156 
1157 This function changes the current value of the specified environment variable. If the
1158 environment variable exists and the Value is an empty string, then the environment
1159 variable is deleted. If the environment variable exists and the Value is not an empty
1160 string, then the value of the environment variable is changed. If the environment
1161 variable does not exist and the Value is an empty string, there is no action. If the
1162 environment variable does not exist and the Value is a non-empty string, then the
1163 environment variable is created and assigned the specified value.
1164 
1165   This is not supported pre-UEFI Shell 2.0.
1166 
1167   @param EnvKey                 The key name of the environment variable.
1168   @param EnvVal                 The Value of the environment variable
1169   @param Volatile               Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1170 
1171   @retval EFI_SUCCESS           the operation was completed sucessfully
1172   @retval EFI_UNSUPPORTED       This operation is not allowed in pre UEFI 2.0 Shell environments
1173 **/
1174 EFI_STATUS
1175 EFIAPI
ShellSetEnvironmentVariable(IN CONST CHAR16 * EnvKey,IN CONST CHAR16 * EnvVal,IN BOOLEAN Volatile)1176 ShellSetEnvironmentVariable (
1177   IN CONST CHAR16               *EnvKey,
1178   IN CONST CHAR16               *EnvVal,
1179   IN BOOLEAN                    Volatile
1180   )
1181 {
1182   //
1183   // Check for UEFI Shell 2.0 protocols
1184   //
1185   if (gEfiShellProtocol != NULL) {
1186     return (gEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile));
1187   }
1188 
1189   //
1190   // This feature does not exist under EFI shell
1191   //
1192   return (EFI_UNSUPPORTED);
1193 }
1194 
1195 /**
1196   Cause the shell to parse and execute a command line.
1197 
1198   This function creates a nested instance of the shell and executes the specified
1199   command (CommandLine) with the specified environment (Environment). Upon return,
1200   the status code returned by the specified command is placed in StatusCode.
1201   If Environment is NULL, then the current environment is used and all changes made
1202   by the commands executed will be reflected in the current environment. If the
1203   Environment is non-NULL, then the changes made will be discarded.
1204   The CommandLine is executed from the current working directory on the current
1205   device.
1206 
1207   The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
1208   environment.  The values pointed to by the parameters will be unchanged by the
1209   ShellExecute() function.  The Output parameter has no effect in a
1210   UEFI Shell 2.0 environment.
1211 
1212   @param[in] ParentHandle         The parent image starting the operation.
1213   @param[in] CommandLine          The pointer to a NULL terminated command line.
1214   @param[in] Output               True to display debug output.  False to hide it.
1215   @param[in] EnvironmentVariables Optional pointer to array of environment variables
1216                                   in the form "x=y".  If NULL, the current set is used.
1217   @param[out] Status              The status of the run command line.
1218 
1219   @retval EFI_SUCCESS             The operation completed sucessfully.  Status
1220                                   contains the status code returned.
1221   @retval EFI_INVALID_PARAMETER   A parameter contains an invalid value.
1222   @retval EFI_OUT_OF_RESOURCES    Out of resources.
1223   @retval EFI_UNSUPPORTED         The operation is not allowed.
1224 **/
1225 EFI_STATUS
1226 EFIAPI
ShellExecute(IN EFI_HANDLE * ParentHandle,IN CHAR16 * CommandLine OPTIONAL,IN BOOLEAN Output OPTIONAL,IN CHAR16 ** EnvironmentVariables OPTIONAL,OUT EFI_STATUS * Status OPTIONAL)1227 ShellExecute (
1228   IN EFI_HANDLE                 *ParentHandle,
1229   IN CHAR16                     *CommandLine OPTIONAL,
1230   IN BOOLEAN                    Output OPTIONAL,
1231   IN CHAR16                     **EnvironmentVariables OPTIONAL,
1232   OUT EFI_STATUS                *Status OPTIONAL
1233   )
1234 {
1235   EFI_STATUS                CmdStatus;
1236   //
1237   // Check for UEFI Shell 2.0 protocols
1238   //
1239   if (gEfiShellProtocol != NULL) {
1240     //
1241     // Call UEFI Shell 2.0 version (not using Output parameter)
1242     //
1243     return (gEfiShellProtocol->Execute(ParentHandle,
1244                                       CommandLine,
1245                                       EnvironmentVariables,
1246                                       Status));
1247   }
1248 
1249   //
1250   // Check for EFI shell
1251   //
1252   if (mEfiShellEnvironment2 != NULL) {
1253     //
1254     // Call EFI Shell version.
1255     // Due to oddity in the EFI shell we want to dereference the ParentHandle here
1256     //
1257     CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,
1258                                           CommandLine,
1259                                           Output));
1260     //
1261     // No Status output parameter so just use the returned status
1262     //
1263     if (Status != NULL) {
1264       *Status = CmdStatus;
1265     }
1266     //
1267     // If there was an error, we can't tell if it was from the command or from
1268     // the Execute() function, so we'll just assume the shell ran successfully
1269     // and the error came from the command.
1270     //
1271     return EFI_SUCCESS;
1272   }
1273 
1274   return (EFI_UNSUPPORTED);
1275 }
1276 
1277 /**
1278   Retreives the current directory path
1279 
1280   If the DeviceName is NULL, it returns the current device's current directory
1281   name. If the DeviceName is not NULL, it returns the current directory name
1282   on specified drive.
1283 
1284   Note that the current directory string should exclude the tailing backslash character.
1285 
1286   @param DeviceName             the name of the drive to get directory on
1287 
1288   @retval NULL                  the directory does not exist
1289   @return != NULL               the directory
1290 **/
1291 CONST CHAR16*
1292 EFIAPI
ShellGetCurrentDir(IN CHAR16 * CONST DeviceName OPTIONAL)1293 ShellGetCurrentDir (
1294   IN CHAR16                     * CONST DeviceName OPTIONAL
1295   )
1296 {
1297   //
1298   // Check for UEFI Shell 2.0 protocols
1299   //
1300   if (gEfiShellProtocol != NULL) {
1301     return (gEfiShellProtocol->GetCurDir(DeviceName));
1302   }
1303 
1304   //
1305   // Check for EFI shell
1306   //
1307   if (mEfiShellEnvironment2 != NULL) {
1308     return (mEfiShellEnvironment2->CurDir(DeviceName));
1309   }
1310 
1311   return (NULL);
1312 }
1313 /**
1314   sets (enabled or disabled) the page break mode
1315 
1316   when page break mode is enabled the screen will stop scrolling
1317   and wait for operator input before scrolling a subsequent screen.
1318 
1319   @param CurrentState           TRUE to enable and FALSE to disable
1320 **/
1321 VOID
1322 EFIAPI
ShellSetPageBreakMode(IN BOOLEAN CurrentState)1323 ShellSetPageBreakMode (
1324   IN BOOLEAN                    CurrentState
1325   )
1326 {
1327   //
1328   // check for enabling
1329   //
1330   if (CurrentState != 0x00) {
1331     //
1332     // check for UEFI Shell 2.0
1333     //
1334     if (gEfiShellProtocol != NULL) {
1335       //
1336       // Enable with UEFI 2.0 Shell
1337       //
1338       gEfiShellProtocol->EnablePageBreak();
1339       return;
1340     } else {
1341       //
1342       // Check for EFI shell
1343       //
1344       if (mEfiShellEnvironment2 != NULL) {
1345         //
1346         // Enable with EFI Shell
1347         //
1348         mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
1349         return;
1350       }
1351     }
1352   } else {
1353     //
1354     // check for UEFI Shell 2.0
1355     //
1356     if (gEfiShellProtocol != NULL) {
1357       //
1358       // Disable with UEFI 2.0 Shell
1359       //
1360       gEfiShellProtocol->DisablePageBreak();
1361       return;
1362     } else {
1363       //
1364       // Check for EFI shell
1365       //
1366       if (mEfiShellEnvironment2 != NULL) {
1367         //
1368         // Disable with EFI Shell
1369         //
1370         mEfiShellEnvironment2->DisablePageBreak ();
1371         return;
1372       }
1373     }
1374   }
1375 }
1376 
1377 ///
1378 /// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1379 /// This allows for the struct to be populated.
1380 ///
1381 typedef struct {
1382   LIST_ENTRY Link;
1383   EFI_STATUS Status;
1384   CHAR16 *FullName;
1385   CHAR16 *FileName;
1386   SHELL_FILE_HANDLE          Handle;
1387   EFI_FILE_INFO *Info;
1388 } EFI_SHELL_FILE_INFO_NO_CONST;
1389 
1390 /**
1391   Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1392 
1393   if OldStyleFileList is NULL then ASSERT()
1394 
1395   this function will convert a SHELL_FILE_ARG based list into a callee allocated
1396   EFI_SHELL_FILE_INFO based list.  it is up to the caller to free the memory via
1397   the ShellCloseFileMetaArg function.
1398 
1399   @param[in] FileList           the EFI shell list type
1400   @param[in, out] ListHead      the list to add to
1401 
1402   @retval the resultant head of the double linked new format list;
1403 **/
1404 LIST_ENTRY*
1405 EFIAPI
InternalShellConvertFileListType(IN LIST_ENTRY * FileList,IN OUT LIST_ENTRY * ListHead)1406 InternalShellConvertFileListType (
1407   IN LIST_ENTRY                 *FileList,
1408   IN OUT LIST_ENTRY             *ListHead
1409   )
1410 {
1411   SHELL_FILE_ARG                *OldInfo;
1412   LIST_ENTRY                    *Link;
1413   EFI_SHELL_FILE_INFO_NO_CONST  *NewInfo;
1414 
1415   //
1416   // ASSERTs
1417   //
1418   ASSERT(FileList  != NULL);
1419   ASSERT(ListHead  != NULL);
1420 
1421   //
1422   // enumerate through each member of the old list and copy
1423   //
1424   for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {
1425     OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
1426     ASSERT(OldInfo           != NULL);
1427 
1428     //
1429     // Skip ones that failed to open...
1430     //
1431     if (OldInfo->Status != EFI_SUCCESS) {
1432       continue;
1433     }
1434 
1435     //
1436     // make sure the old list was valid
1437     //
1438     ASSERT(OldInfo->Info     != NULL);
1439     ASSERT(OldInfo->FullName != NULL);
1440     ASSERT(OldInfo->FileName != NULL);
1441 
1442     //
1443     // allocate a new EFI_SHELL_FILE_INFO object
1444     //
1445     NewInfo               = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1446     if (NewInfo == NULL) {
1447       ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
1448       ListHead = NULL;
1449       break;
1450     }
1451 
1452     //
1453     // copy the simple items
1454     //
1455     NewInfo->Handle       = OldInfo->Handle;
1456     NewInfo->Status       = OldInfo->Status;
1457 
1458     // old shell checks for 0 not NULL
1459     OldInfo->Handle = 0;
1460 
1461     //
1462     // allocate new space to copy strings and structure
1463     //
1464     NewInfo->FullName     = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);
1465     NewInfo->FileName     = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);
1466     NewInfo->Info         = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);
1467 
1468     //
1469     // make sure all the memory allocations were sucessful
1470     //
1471     if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {
1472       //
1473       // Free the partially allocated new node
1474       //
1475       SHELL_FREE_NON_NULL(NewInfo->FullName);
1476       SHELL_FREE_NON_NULL(NewInfo->FileName);
1477       SHELL_FREE_NON_NULL(NewInfo->Info);
1478       SHELL_FREE_NON_NULL(NewInfo);
1479 
1480       //
1481       // Free the previously converted stuff
1482       //
1483       ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
1484       ListHead = NULL;
1485       break;
1486     }
1487 
1488     //
1489     // add that to the list
1490     //
1491     InsertTailList(ListHead, &NewInfo->Link);
1492   }
1493   return (ListHead);
1494 }
1495 /**
1496   Opens a group of files based on a path.
1497 
1498   This function uses the Arg to open all the matching files. Each matched
1499   file has a SHELL_FILE_INFO structure to record the file information. These
1500   structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
1501   structures from ListHead to access each file. This function supports wildcards
1502   and will process '?' and '*' as such.  the list must be freed with a call to
1503   ShellCloseFileMetaArg().
1504 
1505   If you are NOT appending to an existing list *ListHead must be NULL.  If
1506   *ListHead is NULL then it must be callee freed.
1507 
1508   @param Arg                    pointer to path string
1509   @param OpenMode               mode to open files with
1510   @param ListHead               head of linked list of results
1511 
1512   @retval EFI_SUCCESS           the operation was sucessful and the list head
1513                                 contains the list of opened files
1514   @return != EFI_SUCCESS        the operation failed
1515 
1516   @sa InternalShellConvertFileListType
1517 **/
1518 EFI_STATUS
1519 EFIAPI
ShellOpenFileMetaArg(IN CHAR16 * Arg,IN UINT64 OpenMode,IN OUT EFI_SHELL_FILE_INFO ** ListHead)1520 ShellOpenFileMetaArg (
1521   IN CHAR16                     *Arg,
1522   IN UINT64                     OpenMode,
1523   IN OUT EFI_SHELL_FILE_INFO    **ListHead
1524   )
1525 {
1526   EFI_STATUS                    Status;
1527   LIST_ENTRY                    mOldStyleFileList;
1528   CHAR16                        *CleanFilePathStr;
1529 
1530   //
1531   // ASSERT that Arg and ListHead are not NULL
1532   //
1533   ASSERT(Arg      != NULL);
1534   ASSERT(ListHead != NULL);
1535 
1536   CleanFilePathStr = NULL;
1537 
1538   Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
1539   if (EFI_ERROR (Status)) {
1540     return Status;
1541   }
1542 
1543   //
1544   // Check for UEFI Shell 2.0 protocols
1545   //
1546   if (gEfiShellProtocol != NULL) {
1547     if (*ListHead == NULL) {
1548       *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1549       if (*ListHead == NULL) {
1550         FreePool(CleanFilePathStr);
1551         return (EFI_OUT_OF_RESOURCES);
1552       }
1553       InitializeListHead(&((*ListHead)->Link));
1554     }
1555     Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,
1556                                            OpenMode,
1557                                            ListHead);
1558     if (EFI_ERROR(Status)) {
1559       gEfiShellProtocol->RemoveDupInFileList(ListHead);
1560     } else {
1561       Status = gEfiShellProtocol->RemoveDupInFileList(ListHead);
1562     }
1563     if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {
1564       FreePool(*ListHead);
1565       FreePool(CleanFilePathStr);
1566       *ListHead = NULL;
1567       return (EFI_NOT_FOUND);
1568     }
1569     FreePool(CleanFilePathStr);
1570     return (Status);
1571   }
1572 
1573   //
1574   // Check for EFI shell
1575   //
1576   if (mEfiShellEnvironment2 != NULL) {
1577     //
1578     // make sure the list head is initialized
1579     //
1580     InitializeListHead(&mOldStyleFileList);
1581 
1582     //
1583     // Get the EFI Shell list of files
1584     //
1585     Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);
1586     if (EFI_ERROR(Status)) {
1587       *ListHead = NULL;
1588       FreePool(CleanFilePathStr);
1589       return (Status);
1590     }
1591 
1592     if (*ListHead == NULL) {
1593       *ListHead = (EFI_SHELL_FILE_INFO    *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1594       if (*ListHead == NULL) {
1595         FreePool(CleanFilePathStr);
1596         return (EFI_OUT_OF_RESOURCES);
1597       }
1598       InitializeListHead(&((*ListHead)->Link));
1599     }
1600 
1601     //
1602     // Convert that to equivalent of UEFI Shell 2.0 structure
1603     //
1604     InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link);
1605 
1606     //
1607     // Free the EFI Shell version that was converted.
1608     //
1609     mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList);
1610 
1611     if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) {
1612       FreePool(*ListHead);
1613       *ListHead = NULL;
1614       Status = EFI_NOT_FOUND;
1615     }
1616     FreePool(CleanFilePathStr);
1617     return (Status);
1618   }
1619 
1620   FreePool(CleanFilePathStr);
1621   return (EFI_UNSUPPORTED);
1622 }
1623 /**
1624   Free the linked list returned from ShellOpenFileMetaArg.
1625 
1626   if ListHead is NULL then ASSERT().
1627 
1628   @param ListHead               the pointer to free.
1629 
1630   @retval EFI_SUCCESS           the operation was sucessful.
1631 **/
1632 EFI_STATUS
1633 EFIAPI
ShellCloseFileMetaArg(IN OUT EFI_SHELL_FILE_INFO ** ListHead)1634 ShellCloseFileMetaArg (
1635   IN OUT EFI_SHELL_FILE_INFO    **ListHead
1636   )
1637 {
1638   LIST_ENTRY                    *Node;
1639 
1640   //
1641   // ASSERT that ListHead is not NULL
1642   //
1643   ASSERT(ListHead != NULL);
1644 
1645   //
1646   // Check for UEFI Shell 2.0 protocols
1647   //
1648   if (gEfiShellProtocol != NULL) {
1649     return (gEfiShellProtocol->FreeFileList(ListHead));
1650   } else if (mEfiShellEnvironment2 != NULL) {
1651     //
1652     // Since this is EFI Shell version we need to free our internally made copy
1653     // of the list
1654     //
1655     for ( Node = GetFirstNode(&(*ListHead)->Link)
1656         ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link)
1657         ; Node = GetFirstNode(&(*ListHead)->Link)) {
1658       RemoveEntryList(Node);
1659       ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);
1660       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);
1661       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);
1662       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);
1663       FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);
1664     }
1665     SHELL_FREE_NON_NULL(*ListHead);
1666     return EFI_SUCCESS;
1667   }
1668 
1669   return (EFI_UNSUPPORTED);
1670 }
1671 
1672 /**
1673   Find a file by searching the CWD and then the path.
1674 
1675   If FileName is NULL then ASSERT.
1676 
1677   If the return value is not NULL then the memory must be caller freed.
1678 
1679   @param FileName               Filename string.
1680 
1681   @retval NULL                  the file was not found
1682   @return !NULL                 the full path to the file.
1683 **/
1684 CHAR16 *
1685 EFIAPI
ShellFindFilePath(IN CONST CHAR16 * FileName)1686 ShellFindFilePath (
1687   IN CONST CHAR16 *FileName
1688   )
1689 {
1690   CONST CHAR16      *Path;
1691   SHELL_FILE_HANDLE Handle;
1692   EFI_STATUS        Status;
1693   CHAR16            *RetVal;
1694   CHAR16            *TestPath;
1695   CONST CHAR16      *Walker;
1696   UINTN             Size;
1697   CHAR16            *TempChar;
1698 
1699   RetVal = NULL;
1700 
1701   //
1702   // First make sure its not an absolute path.
1703   //
1704   Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0);
1705   if (!EFI_ERROR(Status)){
1706     if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1707       ASSERT(RetVal == NULL);
1708       RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0);
1709       ShellCloseFile(&Handle);
1710       return (RetVal);
1711     } else {
1712       ShellCloseFile(&Handle);
1713     }
1714   }
1715 
1716   Path = ShellGetEnvironmentVariable(L"cwd");
1717   if (Path != NULL) {
1718     Size = StrSize(Path) + sizeof(CHAR16);
1719     Size += StrSize(FileName);
1720     TestPath = AllocateZeroPool(Size);
1721     if (TestPath == NULL) {
1722       return (NULL);
1723     }
1724     StrCpyS(TestPath, Size/sizeof(CHAR16), Path);
1725     StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
1726     StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
1727     Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1728     if (!EFI_ERROR(Status)){
1729       if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1730         ASSERT(RetVal == NULL);
1731         RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1732         ShellCloseFile(&Handle);
1733         FreePool(TestPath);
1734         return (RetVal);
1735       } else {
1736         ShellCloseFile(&Handle);
1737       }
1738     }
1739     FreePool(TestPath);
1740   }
1741   Path = ShellGetEnvironmentVariable(L"path");
1742   if (Path != NULL) {
1743     Size = StrSize(Path)+sizeof(CHAR16);
1744     Size += StrSize(FileName);
1745     TestPath = AllocateZeroPool(Size);
1746     if (TestPath == NULL) {
1747       return (NULL);
1748     }
1749     Walker = (CHAR16*)Path;
1750     do {
1751       CopyMem(TestPath, Walker, StrSize(Walker));
1752       if (TestPath != NULL) {
1753         TempChar = StrStr(TestPath, L";");
1754         if (TempChar != NULL) {
1755           *TempChar = CHAR_NULL;
1756         }
1757         if (TestPath[StrLen(TestPath)-1] != L'\\') {
1758           StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
1759         }
1760         if (FileName[0] == L'\\') {
1761           FileName++;
1762         }
1763         StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
1764         if (StrStr(Walker, L";") != NULL) {
1765           Walker = StrStr(Walker, L";") + 1;
1766         } else {
1767           Walker = NULL;
1768         }
1769         Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1770         if (!EFI_ERROR(Status)){
1771           if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1772             ASSERT(RetVal == NULL);
1773             RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1774             ShellCloseFile(&Handle);
1775             break;
1776           } else {
1777             ShellCloseFile(&Handle);
1778           }
1779         }
1780       }
1781     } while (Walker != NULL && Walker[0] != CHAR_NULL);
1782     FreePool(TestPath);
1783   }
1784   return (RetVal);
1785 }
1786 
1787 /**
1788   Find a file by searching the CWD and then the path with a variable set of file
1789   extensions.  If the file is not found it will append each extension in the list
1790   in the order provided and return the first one that is successful.
1791 
1792   If FileName is NULL, then ASSERT.
1793   If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
1794 
1795   If the return value is not NULL then the memory must be caller freed.
1796 
1797   @param[in] FileName           Filename string.
1798   @param[in] FileExtension      Semi-colon delimeted list of possible extensions.
1799 
1800   @retval NULL                  The file was not found.
1801   @retval !NULL                 The path to the file.
1802 **/
1803 CHAR16 *
1804 EFIAPI
ShellFindFilePathEx(IN CONST CHAR16 * FileName,IN CONST CHAR16 * FileExtension)1805 ShellFindFilePathEx (
1806   IN CONST CHAR16 *FileName,
1807   IN CONST CHAR16 *FileExtension
1808   )
1809 {
1810   CHAR16            *TestPath;
1811   CHAR16            *RetVal;
1812   CONST CHAR16      *ExtensionWalker;
1813   UINTN             Size;
1814   CHAR16            *TempChar;
1815   CHAR16            *TempChar2;
1816 
1817   ASSERT(FileName != NULL);
1818   if (FileExtension == NULL) {
1819     return (ShellFindFilePath(FileName));
1820   }
1821   RetVal = ShellFindFilePath(FileName);
1822   if (RetVal != NULL) {
1823     return (RetVal);
1824   }
1825   Size =  StrSize(FileName);
1826   Size += StrSize(FileExtension);
1827   TestPath = AllocateZeroPool(Size);
1828   if (TestPath == NULL) {
1829     return (NULL);
1830   }
1831   for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension;  TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){
1832     StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);
1833     if (ExtensionWalker != NULL) {
1834       StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);
1835     }
1836     TempChar = StrStr(TestPath, L";");
1837     if (TempChar != NULL) {
1838       *TempChar = CHAR_NULL;
1839     }
1840     RetVal = ShellFindFilePath(TestPath);
1841     if (RetVal != NULL) {
1842       break;
1843     }
1844     ASSERT(ExtensionWalker != NULL);
1845     TempChar2 = StrStr(ExtensionWalker, L";");
1846   }
1847   FreePool(TestPath);
1848   return (RetVal);
1849 }
1850 
1851 typedef struct {
1852   LIST_ENTRY     Link;
1853   CHAR16         *Name;
1854   SHELL_PARAM_TYPE      Type;
1855   CHAR16         *Value;
1856   UINTN          OriginalPosition;
1857 } SHELL_PARAM_PACKAGE;
1858 
1859 /**
1860   Checks the list of valid arguments and returns TRUE if the item was found.  If the
1861   return value is TRUE then the type parameter is set also.
1862 
1863   if CheckList is NULL then ASSERT();
1864   if Name is NULL then ASSERT();
1865   if Type is NULL then ASSERT();
1866 
1867   @param Name                   pointer to Name of parameter found
1868   @param CheckList              List to check against
1869   @param Type                   pointer to type of parameter if it was found
1870 
1871   @retval TRUE                  the Parameter was found.  Type is valid.
1872   @retval FALSE                 the Parameter was not found.  Type is not valid.
1873 **/
1874 BOOLEAN
1875 EFIAPI
InternalIsOnCheckList(IN CONST CHAR16 * Name,IN CONST SHELL_PARAM_ITEM * CheckList,OUT SHELL_PARAM_TYPE * Type)1876 InternalIsOnCheckList (
1877   IN CONST CHAR16               *Name,
1878   IN CONST SHELL_PARAM_ITEM     *CheckList,
1879   OUT SHELL_PARAM_TYPE          *Type
1880   )
1881 {
1882   SHELL_PARAM_ITEM              *TempListItem;
1883   CHAR16                        *TempString;
1884 
1885   //
1886   // ASSERT that all 3 pointer parameters aren't NULL
1887   //
1888   ASSERT(CheckList  != NULL);
1889   ASSERT(Type       != NULL);
1890   ASSERT(Name       != NULL);
1891 
1892   //
1893   // question mark and page break mode are always supported
1894   //
1895   if ((StrCmp(Name, L"-?") == 0) ||
1896       (StrCmp(Name, L"-b") == 0)
1897      ) {
1898      *Type = TypeFlag;
1899      return (TRUE);
1900   }
1901 
1902   //
1903   // Enumerate through the list
1904   //
1905   for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {
1906     //
1907     // If the Type is TypeStart only check the first characters of the passed in param
1908     // If it matches set the type and return TRUE
1909     //
1910     if (TempListItem->Type == TypeStart) {
1911       if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {
1912         *Type = TempListItem->Type;
1913         return (TRUE);
1914       }
1915       TempString = NULL;
1916       TempString = StrnCatGrow(&TempString, NULL, Name, StrLen(TempListItem->Name));
1917       if (TempString != NULL) {
1918         if (StringNoCaseCompare(&TempString, &TempListItem->Name) == 0) {
1919           *Type = TempListItem->Type;
1920           FreePool(TempString);
1921           return (TRUE);
1922         }
1923         FreePool(TempString);
1924       }
1925     } else if (StringNoCaseCompare(&Name, &TempListItem->Name) == 0) {
1926       *Type = TempListItem->Type;
1927       return (TRUE);
1928     }
1929   }
1930 
1931   return (FALSE);
1932 }
1933 /**
1934   Checks the string for indicators of "flag" status.  this is a leading '/', '-', or '+'
1935 
1936   @param[in] Name               pointer to Name of parameter found
1937   @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
1938   @param[in] TimeNumbers        TRUE to allow numbers with ":", FALSE otherwise.
1939 
1940   @retval TRUE                  the Parameter is a flag.
1941   @retval FALSE                 the Parameter not a flag.
1942 **/
1943 BOOLEAN
1944 EFIAPI
InternalIsFlag(IN CONST CHAR16 * Name,IN CONST BOOLEAN AlwaysAllowNumbers,IN CONST BOOLEAN TimeNumbers)1945 InternalIsFlag (
1946   IN CONST CHAR16               *Name,
1947   IN CONST BOOLEAN              AlwaysAllowNumbers,
1948   IN CONST BOOLEAN              TimeNumbers
1949   )
1950 {
1951   //
1952   // ASSERT that Name isn't NULL
1953   //
1954   ASSERT(Name != NULL);
1955 
1956   //
1957   // If we accept numbers then dont return TRUE. (they will be values)
1958   //
1959   if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
1960     return (FALSE);
1961   }
1962 
1963   //
1964   // If the Name has a /, +, or - as the first character return TRUE
1965   //
1966   if ((Name[0] == L'/') ||
1967       (Name[0] == L'-') ||
1968       (Name[0] == L'+')
1969      ) {
1970       return (TRUE);
1971   }
1972   return (FALSE);
1973 }
1974 
1975 /**
1976   Checks the command line arguments passed against the list of valid ones.
1977 
1978   If no initialization is required, then return RETURN_SUCCESS.
1979 
1980   @param[in] CheckList          pointer to list of parameters to check
1981   @param[out] CheckPackage      pointer to pointer to list checked values
1982   @param[out] ProblemParam      optional pointer to pointer to unicode string for
1983                                 the paramater that caused failure.  If used then the
1984                                 caller is responsible for freeing the memory.
1985   @param[in] AutoPageBreak      will automatically set PageBreakEnabled for "b" parameter
1986   @param[in] Argv               pointer to array of parameters
1987   @param[in] Argc               Count of parameters in Argv
1988   @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
1989 
1990   @retval EFI_SUCCESS           The operation completed sucessfully.
1991   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed
1992   @retval EFI_INVALID_PARAMETER A parameter was invalid
1993   @retval EFI_VOLUME_CORRUPTED  the command line was corrupt.  an argument was
1994                                 duplicated.  the duplicated command line argument
1995                                 was returned in ProblemParam if provided.
1996   @retval EFI_NOT_FOUND         a argument required a value that was missing.
1997                                 the invalid command line argument was returned in
1998                                 ProblemParam if provided.
1999 **/
2000 EFI_STATUS
2001 EFIAPI
InternalCommandLineParse(IN CONST SHELL_PARAM_ITEM * CheckList,OUT LIST_ENTRY ** CheckPackage,OUT CHAR16 ** ProblemParam OPTIONAL,IN BOOLEAN AutoPageBreak,IN CONST CHAR16 ** Argv,IN UINTN Argc,IN BOOLEAN AlwaysAllowNumbers)2002 InternalCommandLineParse (
2003   IN CONST SHELL_PARAM_ITEM     *CheckList,
2004   OUT LIST_ENTRY                **CheckPackage,
2005   OUT CHAR16                    **ProblemParam OPTIONAL,
2006   IN BOOLEAN                    AutoPageBreak,
2007   IN CONST CHAR16               **Argv,
2008   IN UINTN                      Argc,
2009   IN BOOLEAN                    AlwaysAllowNumbers
2010   )
2011 {
2012   UINTN                         LoopCounter;
2013   SHELL_PARAM_TYPE              CurrentItemType;
2014   SHELL_PARAM_PACKAGE           *CurrentItemPackage;
2015   UINTN                         GetItemValue;
2016   UINTN                         ValueSize;
2017   UINTN                         Count;
2018   CONST CHAR16                  *TempPointer;
2019   UINTN                         CurrentValueSize;
2020 
2021   CurrentItemPackage = NULL;
2022   GetItemValue = 0;
2023   ValueSize = 0;
2024   Count = 0;
2025 
2026   //
2027   // If there is only 1 item we dont need to do anything
2028   //
2029   if (Argc < 1) {
2030     *CheckPackage = NULL;
2031     return (EFI_SUCCESS);
2032   }
2033 
2034   //
2035   // ASSERTs
2036   //
2037   ASSERT(CheckList  != NULL);
2038   ASSERT(Argv       != NULL);
2039 
2040   //
2041   // initialize the linked list
2042   //
2043   *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));
2044   if (*CheckPackage == NULL) {
2045     return (EFI_OUT_OF_RESOURCES);
2046   }
2047 
2048   InitializeListHead(*CheckPackage);
2049 
2050   //
2051   // loop through each of the arguments
2052   //
2053   for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) {
2054     if (Argv[LoopCounter] == NULL) {
2055       //
2056       // do nothing for NULL argv
2057       //
2058     } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) {
2059       //
2060       // We might have leftover if last parameter didnt have optional value
2061       //
2062       if (GetItemValue != 0) {
2063         GetItemValue = 0;
2064         InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2065       }
2066       //
2067       // this is a flag
2068       //
2069       CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
2070       if (CurrentItemPackage == NULL) {
2071         ShellCommandLineFreeVarList(*CheckPackage);
2072         *CheckPackage = NULL;
2073         return (EFI_OUT_OF_RESOURCES);
2074       }
2075       CurrentItemPackage->Name  = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
2076       if (CurrentItemPackage->Name == NULL) {
2077         ShellCommandLineFreeVarList(*CheckPackage);
2078         *CheckPackage = NULL;
2079         return (EFI_OUT_OF_RESOURCES);
2080       }
2081       CurrentItemPackage->Type  = CurrentItemType;
2082       CurrentItemPackage->OriginalPosition = (UINTN)(-1);
2083       CurrentItemPackage->Value = NULL;
2084 
2085       //
2086       // Does this flag require a value
2087       //
2088       switch (CurrentItemPackage->Type) {
2089         //
2090         // possibly trigger the next loop(s) to populate the value of this item
2091         //
2092         case TypeValue:
2093         case TypeTimeValue:
2094           GetItemValue = 1;
2095           ValueSize = 0;
2096           break;
2097         case TypeDoubleValue:
2098           GetItemValue = 2;
2099           ValueSize = 0;
2100           break;
2101         case TypeMaxValue:
2102           GetItemValue = (UINTN)(-1);
2103           ValueSize = 0;
2104           break;
2105         default:
2106           //
2107           // this item has no value expected; we are done
2108           //
2109           InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2110           ASSERT(GetItemValue == 0);
2111           break;
2112       }
2113     } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
2114       //
2115       // get the item VALUE for a previous flag
2116       //
2117       CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2118       CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);
2119       ASSERT(CurrentItemPackage->Value != NULL);
2120       if (ValueSize == 0) {
2121         StrCpyS( CurrentItemPackage->Value,
2122                   CurrentValueSize/sizeof(CHAR16),
2123                   Argv[LoopCounter]
2124                   );
2125       } else {
2126         StrCatS( CurrentItemPackage->Value,
2127                   CurrentValueSize/sizeof(CHAR16),
2128                   L" "
2129                   );
2130         StrCatS( CurrentItemPackage->Value,
2131                   CurrentValueSize/sizeof(CHAR16),
2132                   Argv[LoopCounter]
2133                   );
2134       }
2135       ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2136 
2137       GetItemValue--;
2138       if (GetItemValue == 0) {
2139         InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2140       }
2141     } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){
2142       //
2143       // add this one as a non-flag
2144       //
2145 
2146       TempPointer = Argv[LoopCounter];
2147       if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')
2148        || (*TempPointer == L'^' && *(TempPointer+1) == L'/')
2149        || (*TempPointer == L'^' && *(TempPointer+1) == L'+')
2150       ){
2151         TempPointer++;
2152       }
2153       CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
2154       if (CurrentItemPackage == NULL) {
2155         ShellCommandLineFreeVarList(*CheckPackage);
2156         *CheckPackage = NULL;
2157         return (EFI_OUT_OF_RESOURCES);
2158       }
2159       CurrentItemPackage->Name  = NULL;
2160       CurrentItemPackage->Type  = TypePosition;
2161       CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);
2162       if (CurrentItemPackage->Value == NULL) {
2163         ShellCommandLineFreeVarList(*CheckPackage);
2164         *CheckPackage = NULL;
2165         return (EFI_OUT_OF_RESOURCES);
2166       }
2167       CurrentItemPackage->OriginalPosition = Count++;
2168       InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2169     } else {
2170       //
2171       // this was a non-recognised flag... error!
2172       //
2173       if (ProblemParam != NULL) {
2174         *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
2175       }
2176       ShellCommandLineFreeVarList(*CheckPackage);
2177       *CheckPackage = NULL;
2178       return (EFI_VOLUME_CORRUPTED);
2179     }
2180   }
2181   if (GetItemValue != 0) {
2182     GetItemValue = 0;
2183     InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2184   }
2185   //
2186   // support for AutoPageBreak
2187   //
2188   if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) {
2189     ShellSetPageBreakMode(TRUE);
2190   }
2191   return (EFI_SUCCESS);
2192 }
2193 
2194 /**
2195   Checks the command line arguments passed against the list of valid ones.
2196   Optionally removes NULL values first.
2197 
2198   If no initialization is required, then return RETURN_SUCCESS.
2199 
2200   @param[in] CheckList          The pointer to list of parameters to check.
2201   @param[out] CheckPackage      The package of checked values.
2202   @param[out] ProblemParam      Optional pointer to pointer to unicode string for
2203                                 the paramater that caused failure.
2204   @param[in] AutoPageBreak      Will automatically set PageBreakEnabled.
2205   @param[in] AlwaysAllowNumbers Will never fail for number based flags.
2206 
2207   @retval EFI_SUCCESS           The operation completed sucessfully.
2208   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
2209   @retval EFI_INVALID_PARAMETER A parameter was invalid.
2210   @retval EFI_VOLUME_CORRUPTED  The command line was corrupt.
2211   @retval EFI_DEVICE_ERROR      The commands contained 2 opposing arguments.  One
2212                                 of the command line arguments was returned in
2213                                 ProblemParam if provided.
2214   @retval EFI_NOT_FOUND         A argument required a value that was missing.
2215                                 The invalid command line argument was returned in
2216                                 ProblemParam if provided.
2217 **/
2218 EFI_STATUS
2219 EFIAPI
ShellCommandLineParseEx(IN CONST SHELL_PARAM_ITEM * CheckList,OUT LIST_ENTRY ** CheckPackage,OUT CHAR16 ** ProblemParam OPTIONAL,IN BOOLEAN AutoPageBreak,IN BOOLEAN AlwaysAllowNumbers)2220 ShellCommandLineParseEx (
2221   IN CONST SHELL_PARAM_ITEM     *CheckList,
2222   OUT LIST_ENTRY                **CheckPackage,
2223   OUT CHAR16                    **ProblemParam OPTIONAL,
2224   IN BOOLEAN                    AutoPageBreak,
2225   IN BOOLEAN                    AlwaysAllowNumbers
2226   )
2227 {
2228   //
2229   // ASSERT that CheckList and CheckPackage aren't NULL
2230   //
2231   ASSERT(CheckList    != NULL);
2232   ASSERT(CheckPackage != NULL);
2233 
2234   //
2235   // Check for UEFI Shell 2.0 protocols
2236   //
2237   if (gEfiShellParametersProtocol != NULL) {
2238     return (InternalCommandLineParse(CheckList,
2239                                      CheckPackage,
2240                                      ProblemParam,
2241                                      AutoPageBreak,
2242                                      (CONST CHAR16**) gEfiShellParametersProtocol->Argv,
2243                                      gEfiShellParametersProtocol->Argc,
2244                                      AlwaysAllowNumbers));
2245   }
2246 
2247   //
2248   // ASSERT That EFI Shell is not required
2249   //
2250   ASSERT (mEfiShellInterface != NULL);
2251   return (InternalCommandLineParse(CheckList,
2252                                    CheckPackage,
2253                                    ProblemParam,
2254                                    AutoPageBreak,
2255                                    (CONST CHAR16**) mEfiShellInterface->Argv,
2256                                    mEfiShellInterface->Argc,
2257                                    AlwaysAllowNumbers));
2258 }
2259 
2260 /**
2261   Frees shell variable list that was returned from ShellCommandLineParse.
2262 
2263   This function will free all the memory that was used for the CheckPackage
2264   list of postprocessed shell arguments.
2265 
2266   this function has no return value.
2267 
2268   if CheckPackage is NULL, then return
2269 
2270   @param CheckPackage           the list to de-allocate
2271   **/
2272 VOID
2273 EFIAPI
ShellCommandLineFreeVarList(IN LIST_ENTRY * CheckPackage)2274 ShellCommandLineFreeVarList (
2275   IN LIST_ENTRY                 *CheckPackage
2276   )
2277 {
2278   LIST_ENTRY                    *Node;
2279 
2280   //
2281   // check for CheckPackage == NULL
2282   //
2283   if (CheckPackage == NULL) {
2284     return;
2285   }
2286 
2287   //
2288   // for each node in the list
2289   //
2290   for ( Node = GetFirstNode(CheckPackage)
2291       ; !IsListEmpty(CheckPackage)
2292       ; Node = GetFirstNode(CheckPackage)
2293      ){
2294     //
2295     // Remove it from the list
2296     //
2297     RemoveEntryList(Node);
2298 
2299     //
2300     // if it has a name free the name
2301     //
2302     if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2303       FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name);
2304     }
2305 
2306     //
2307     // if it has a value free the value
2308     //
2309     if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) {
2310       FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value);
2311     }
2312 
2313     //
2314     // free the node structure
2315     //
2316     FreePool((SHELL_PARAM_PACKAGE*)Node);
2317   }
2318   //
2319   // free the list head node
2320   //
2321   FreePool(CheckPackage);
2322 }
2323 /**
2324   Checks for presence of a flag parameter
2325 
2326   flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
2327 
2328   if CheckPackage is NULL then return FALSE.
2329   if KeyString is NULL then ASSERT()
2330 
2331   @param CheckPackage           The package of parsed command line arguments
2332   @param KeyString              the Key of the command line argument to check for
2333 
2334   @retval TRUE                  the flag is on the command line
2335   @retval FALSE                 the flag is not on the command line
2336   **/
2337 BOOLEAN
2338 EFIAPI
ShellCommandLineGetFlag(IN CONST LIST_ENTRY * CONST CheckPackage,IN CONST CHAR16 * CONST KeyString)2339 ShellCommandLineGetFlag (
2340   IN CONST LIST_ENTRY         * CONST CheckPackage,
2341   IN CONST CHAR16             * CONST KeyString
2342   )
2343 {
2344   LIST_ENTRY                    *Node;
2345   CHAR16                        *TempString;
2346 
2347   //
2348   // return FALSE for no package or KeyString is NULL
2349   //
2350   if (CheckPackage == NULL || KeyString == NULL) {
2351     return (FALSE);
2352   }
2353 
2354   //
2355   // enumerate through the list of parametrs
2356   //
2357   for ( Node = GetFirstNode(CheckPackage)
2358       ; !IsNull (CheckPackage, Node)
2359       ; Node = GetNextNode(CheckPackage, Node)
2360       ){
2361     //
2362     // If the Name matches, return TRUE (and there may be NULL name)
2363     //
2364     if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2365       //
2366       // If Type is TypeStart then only compare the begining of the strings
2367       //
2368       if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2369         if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2370           return (TRUE);
2371         }
2372         TempString = NULL;
2373         TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2374         if (TempString != NULL) {
2375           if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2376             FreePool(TempString);
2377             return (TRUE);
2378           }
2379           FreePool(TempString);
2380         }
2381       } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2382         return (TRUE);
2383       }
2384     }
2385   }
2386   return (FALSE);
2387 }
2388 /**
2389   Returns value from command line argument.
2390 
2391   Value parameters are in the form of "-<Key> value" or "/<Key> value".
2392 
2393   If CheckPackage is NULL, then return NULL.
2394 
2395   @param[in] CheckPackage       The package of parsed command line arguments.
2396   @param[in] KeyString          The Key of the command line argument to check for.
2397 
2398   @retval NULL                  The flag is not on the command line.
2399   @retval !=NULL                The pointer to unicode string of the value.
2400 **/
2401 CONST CHAR16*
2402 EFIAPI
ShellCommandLineGetValue(IN CONST LIST_ENTRY * CheckPackage,IN CHAR16 * KeyString)2403 ShellCommandLineGetValue (
2404   IN CONST LIST_ENTRY           *CheckPackage,
2405   IN CHAR16                     *KeyString
2406   )
2407 {
2408   LIST_ENTRY                    *Node;
2409   CHAR16                        *TempString;
2410 
2411   //
2412   // return NULL for no package or KeyString is NULL
2413   //
2414   if (CheckPackage == NULL || KeyString == NULL) {
2415     return (NULL);
2416   }
2417 
2418   //
2419   // enumerate through the list of parametrs
2420   //
2421   for ( Node = GetFirstNode(CheckPackage)
2422       ; !IsNull (CheckPackage, Node)
2423       ; Node = GetNextNode(CheckPackage, Node)
2424       ){
2425     //
2426     // If the Name matches, return TRUE (and there may be NULL name)
2427     //
2428     if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2429       //
2430       // If Type is TypeStart then only compare the begining of the strings
2431       //
2432       if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2433         if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2434           return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2435         }
2436         TempString = NULL;
2437         TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2438         if (TempString != NULL) {
2439           if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2440             FreePool(TempString);
2441             return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2442           }
2443           FreePool(TempString);
2444         }
2445       } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2446         return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2447       }
2448     }
2449   }
2450   return (NULL);
2451 }
2452 
2453 /**
2454   Returns raw value from command line argument.
2455 
2456   Raw value parameters are in the form of "value" in a specific position in the list.
2457 
2458   If CheckPackage is NULL, then return NULL.
2459 
2460   @param[in] CheckPackage       The package of parsed command line arguments.
2461   @param[in] Position           The position of the value.
2462 
2463   @retval NULL                  The flag is not on the command line.
2464   @retval !=NULL                The pointer to unicode string of the value.
2465   **/
2466 CONST CHAR16*
2467 EFIAPI
ShellCommandLineGetRawValue(IN CONST LIST_ENTRY * CONST CheckPackage,IN UINTN Position)2468 ShellCommandLineGetRawValue (
2469   IN CONST LIST_ENTRY           * CONST CheckPackage,
2470   IN UINTN                      Position
2471   )
2472 {
2473   LIST_ENTRY                    *Node;
2474 
2475   //
2476   // check for CheckPackage == NULL
2477   //
2478   if (CheckPackage == NULL) {
2479     return (NULL);
2480   }
2481 
2482   //
2483   // enumerate through the list of parametrs
2484   //
2485   for ( Node = GetFirstNode(CheckPackage)
2486       ; !IsNull (CheckPackage, Node)
2487       ; Node = GetNextNode(CheckPackage, Node)
2488      ){
2489     //
2490     // If the position matches, return the value
2491     //
2492     if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) {
2493       return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2494     }
2495   }
2496   return (NULL);
2497 }
2498 
2499 /**
2500   returns the number of command line value parameters that were parsed.
2501 
2502   this will not include flags.
2503 
2504   @param[in] CheckPackage       The package of parsed command line arguments.
2505 
2506   @retval (UINTN)-1     No parsing has ocurred
2507   @return other         The number of value parameters found
2508 **/
2509 UINTN
2510 EFIAPI
ShellCommandLineGetCount(IN CONST LIST_ENTRY * CheckPackage)2511 ShellCommandLineGetCount(
2512   IN CONST LIST_ENTRY              *CheckPackage
2513   )
2514 {
2515   LIST_ENTRY  *Node1;
2516   UINTN       Count;
2517 
2518   if (CheckPackage == NULL) {
2519     return (0);
2520   }
2521   for ( Node1 = GetFirstNode(CheckPackage), Count = 0
2522       ; !IsNull (CheckPackage, Node1)
2523       ; Node1 = GetNextNode(CheckPackage, Node1)
2524      ){
2525     if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) {
2526       Count++;
2527     }
2528   }
2529   return (Count);
2530 }
2531 
2532 /**
2533   Determines if a parameter is duplicated.
2534 
2535   If Param is not NULL then it will point to a callee allocated string buffer
2536   with the parameter value if a duplicate is found.
2537 
2538   If CheckPackage is NULL, then ASSERT.
2539 
2540   @param[in] CheckPackage       The package of parsed command line arguments.
2541   @param[out] Param             Upon finding one, a pointer to the duplicated parameter.
2542 
2543   @retval EFI_SUCCESS           No parameters were duplicated.
2544   @retval EFI_DEVICE_ERROR      A duplicate was found.
2545   **/
2546 EFI_STATUS
2547 EFIAPI
ShellCommandLineCheckDuplicate(IN CONST LIST_ENTRY * CheckPackage,OUT CHAR16 ** Param)2548 ShellCommandLineCheckDuplicate (
2549   IN CONST LIST_ENTRY              *CheckPackage,
2550   OUT CHAR16                       **Param
2551   )
2552 {
2553   LIST_ENTRY                    *Node1;
2554   LIST_ENTRY                    *Node2;
2555 
2556   ASSERT(CheckPackage != NULL);
2557 
2558   for ( Node1 = GetFirstNode(CheckPackage)
2559       ; !IsNull (CheckPackage, Node1)
2560       ; Node1 = GetNextNode(CheckPackage, Node1)
2561      ){
2562     for ( Node2 = GetNextNode(CheckPackage, Node1)
2563         ; !IsNull (CheckPackage, Node2)
2564         ; Node2 = GetNextNode(CheckPackage, Node2)
2565        ){
2566       if ((((SHELL_PARAM_PACKAGE*)Node1)->Name != NULL) && (((SHELL_PARAM_PACKAGE*)Node2)->Name != NULL) && StrCmp(((SHELL_PARAM_PACKAGE*)Node1)->Name, ((SHELL_PARAM_PACKAGE*)Node2)->Name) == 0) {
2567         if (Param != NULL) {
2568           *Param = NULL;
2569           *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0);
2570         }
2571         return (EFI_DEVICE_ERROR);
2572       }
2573     }
2574   }
2575   return (EFI_SUCCESS);
2576 }
2577 
2578 /**
2579   This is a find and replace function.  Upon successful return the NewString is a copy of
2580   SourceString with each instance of FindTarget replaced with ReplaceWith.
2581 
2582   If SourceString and NewString overlap the behavior is undefined.
2583 
2584   If the string would grow bigger than NewSize it will halt and return error.
2585 
2586   @param[in] SourceString              The string with source buffer.
2587   @param[in, out] NewString            The string with resultant buffer.
2588   @param[in] NewSize                   The size in bytes of NewString.
2589   @param[in] FindTarget                The string to look for.
2590   @param[in] ReplaceWith               The string to replace FindTarget with.
2591   @param[in] SkipPreCarrot             If TRUE will skip a FindTarget that has a '^'
2592                                        immediately before it.
2593   @param[in] ParameterReplacing        If TRUE will add "" around items with spaces.
2594 
2595   @retval EFI_INVALID_PARAMETER       SourceString was NULL.
2596   @retval EFI_INVALID_PARAMETER       NewString was NULL.
2597   @retval EFI_INVALID_PARAMETER       FindTarget was NULL.
2598   @retval EFI_INVALID_PARAMETER       ReplaceWith was NULL.
2599   @retval EFI_INVALID_PARAMETER       FindTarget had length < 1.
2600   @retval EFI_INVALID_PARAMETER       SourceString had length < 1.
2601   @retval EFI_BUFFER_TOO_SMALL        NewSize was less than the minimum size to hold
2602                                       the new string (truncation occurred).
2603   @retval EFI_SUCCESS                 The string was successfully copied with replacement.
2604 **/
2605 EFI_STATUS
2606 EFIAPI
ShellCopySearchAndReplace(IN CHAR16 CONST * SourceString,IN OUT CHAR16 * NewString,IN UINTN NewSize,IN CONST CHAR16 * FindTarget,IN CONST CHAR16 * ReplaceWith,IN CONST BOOLEAN SkipPreCarrot,IN CONST BOOLEAN ParameterReplacing)2607 ShellCopySearchAndReplace(
2608   IN CHAR16 CONST                     *SourceString,
2609   IN OUT CHAR16                       *NewString,
2610   IN UINTN                            NewSize,
2611   IN CONST CHAR16                     *FindTarget,
2612   IN CONST CHAR16                     *ReplaceWith,
2613   IN CONST BOOLEAN                    SkipPreCarrot,
2614   IN CONST BOOLEAN                    ParameterReplacing
2615   )
2616 {
2617   UINTN Size;
2618   CHAR16 *Replace;
2619 
2620   if ( (SourceString == NULL)
2621     || (NewString    == NULL)
2622     || (FindTarget   == NULL)
2623     || (ReplaceWith  == NULL)
2624     || (StrLen(FindTarget) < 1)
2625     || (StrLen(SourceString) < 1)
2626    ){
2627     return (EFI_INVALID_PARAMETER);
2628   }
2629   Replace = NULL;
2630   if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) {
2631     Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0);
2632   } else {
2633     Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16));
2634     if (Replace != NULL) {
2635       UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);
2636     }
2637   }
2638   if (Replace == NULL) {
2639     return (EFI_OUT_OF_RESOURCES);
2640   }
2641   NewString = ZeroMem(NewString, NewSize);
2642   while (*SourceString != CHAR_NULL) {
2643     //
2644     // if we find the FindTarget and either Skip == FALSE or Skip  and we
2645     // dont have a carrot do a replace...
2646     //
2647     if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0
2648       && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot)
2649      ){
2650       SourceString += StrLen(FindTarget);
2651       Size = StrSize(NewString);
2652       if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) {
2653         FreePool(Replace);
2654         return (EFI_BUFFER_TOO_SMALL);
2655       }
2656       StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);
2657     } else {
2658       Size = StrSize(NewString);
2659       if (Size + sizeof(CHAR16) > NewSize) {
2660         FreePool(Replace);
2661         return (EFI_BUFFER_TOO_SMALL);
2662       }
2663       StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);
2664       SourceString++;
2665     }
2666   }
2667   FreePool(Replace);
2668   return (EFI_SUCCESS);
2669 }
2670 
2671 /**
2672   Internal worker function to output a string.
2673 
2674   This function will output a string to the correct StdOut.
2675 
2676   @param[in] String       The string to print out.
2677 
2678   @retval EFI_SUCCESS     The operation was sucessful.
2679   @retval !EFI_SUCCESS    The operation failed.
2680 **/
2681 EFI_STATUS
2682 EFIAPI
InternalPrintTo(IN CONST CHAR16 * String)2683 InternalPrintTo (
2684   IN CONST CHAR16 *String
2685   )
2686 {
2687   UINTN Size;
2688   Size = StrSize(String) - sizeof(CHAR16);
2689   if (Size == 0) {
2690     return (EFI_SUCCESS);
2691   }
2692   if (gEfiShellParametersProtocol != NULL) {
2693     return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));
2694   }
2695   if (mEfiShellInterface          != NULL) {
2696     if (mEfiShellInterface->RedirArgc == 0) {
2697     //
2698     // Divide in half for old shell.  Must be string length not size.
2699       //
2700       Size /=2;  // Divide in half only when no redirection.
2701     }
2702     return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut,          &Size, (VOID*)String));
2703   }
2704   ASSERT(FALSE);
2705   return (EFI_UNSUPPORTED);
2706 }
2707 
2708 /**
2709   Print at a specific location on the screen.
2710 
2711   This function will move the cursor to a given screen location and print the specified string
2712 
2713   If -1 is specified for either the Row or Col the current screen location for BOTH
2714   will be used.
2715 
2716   if either Row or Col is out of range for the current console, then ASSERT
2717   if Format is NULL, then ASSERT
2718 
2719   In addition to the standard %-based flags as supported by UefiLib Print() this supports
2720   the following additional flags:
2721     %N       -   Set output attribute to normal
2722     %H       -   Set output attribute to highlight
2723     %E       -   Set output attribute to error
2724     %B       -   Set output attribute to blue color
2725     %V       -   Set output attribute to green color
2726 
2727   Note: The background color is controlled by the shell command cls.
2728 
2729   @param[in] Col        the column to print at
2730   @param[in] Row        the row to print at
2731   @param[in] Format     the format string
2732   @param[in] Marker     the marker for the variable argument list
2733 
2734   @return EFI_SUCCESS           The operation was successful.
2735   @return EFI_DEVICE_ERROR      The console device reported an error.
2736 **/
2737 EFI_STATUS
2738 EFIAPI
InternalShellPrintWorker(IN INT32 Col OPTIONAL,IN INT32 Row OPTIONAL,IN CONST CHAR16 * Format,IN VA_LIST Marker)2739 InternalShellPrintWorker(
2740   IN INT32                Col OPTIONAL,
2741   IN INT32                Row OPTIONAL,
2742   IN CONST CHAR16         *Format,
2743   IN VA_LIST              Marker
2744   )
2745 {
2746   EFI_STATUS        Status;
2747   CHAR16            *ResumeLocation;
2748   CHAR16            *FormatWalker;
2749   UINTN             OriginalAttribute;
2750   CHAR16            *mPostReplaceFormat;
2751   CHAR16            *mPostReplaceFormat2;
2752 
2753   mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
2754   mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
2755 
2756   if (mPostReplaceFormat == NULL || mPostReplaceFormat2 == NULL) {
2757     SHELL_FREE_NON_NULL(mPostReplaceFormat);
2758     SHELL_FREE_NON_NULL(mPostReplaceFormat2);
2759     return (EFI_OUT_OF_RESOURCES);
2760   }
2761 
2762   Status            = EFI_SUCCESS;
2763   OriginalAttribute = gST->ConOut->Mode->Attribute;
2764 
2765   //
2766   // Back and forth each time fixing up 1 of our flags...
2767   //
2768   Status = ShellCopySearchAndReplace(Format,             mPostReplaceFormat,  PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);
2769   ASSERT_EFI_ERROR(Status);
2770   Status = ShellCopySearchAndReplace(mPostReplaceFormat,  mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);
2771   ASSERT_EFI_ERROR(Status);
2772   Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat,  PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);
2773   ASSERT_EFI_ERROR(Status);
2774   Status = ShellCopySearchAndReplace(mPostReplaceFormat,  mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);
2775   ASSERT_EFI_ERROR(Status);
2776   Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat,  PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);
2777   ASSERT_EFI_ERROR(Status);
2778 
2779   //
2780   // Use the last buffer from replacing to print from...
2781   //
2782   UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);
2783 
2784   if (Col != -1 && Row != -1) {
2785     Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row);
2786   }
2787 
2788   FormatWalker = mPostReplaceFormat2;
2789   while (*FormatWalker != CHAR_NULL) {
2790     //
2791     // Find the next attribute change request
2792     //
2793     ResumeLocation = StrStr(FormatWalker, L"%");
2794     if (ResumeLocation != NULL) {
2795       *ResumeLocation = CHAR_NULL;
2796     }
2797     //
2798     // print the current FormatWalker string
2799     //
2800     if (StrLen(FormatWalker)>0) {
2801       Status = InternalPrintTo(FormatWalker);
2802       if (EFI_ERROR(Status)) {
2803         break;
2804       }
2805     }
2806 
2807     //
2808     // update the attribute
2809     //
2810     if (ResumeLocation != NULL) {
2811       if (*(ResumeLocation-1) == L'^') {
2812         //
2813         // Move cursor back 1 position to overwrite the ^
2814         //
2815         gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
2816 
2817         //
2818         // Print a simple '%' symbol
2819         //
2820         Status = InternalPrintTo(L"%");
2821         ResumeLocation = ResumeLocation - 1;
2822       } else {
2823         switch (*(ResumeLocation+1)) {
2824           case (L'N'):
2825             gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
2826             break;
2827           case (L'E'):
2828             gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2829             break;
2830           case (L'H'):
2831             gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2832             break;
2833           case (L'B'):
2834             gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2835             break;
2836           case (L'V'):
2837             gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2838             break;
2839           default:
2840             //
2841             // Print a simple '%' symbol
2842             //
2843             Status = InternalPrintTo(L"%");
2844             if (EFI_ERROR(Status)) {
2845               break;
2846             }
2847             ResumeLocation = ResumeLocation - 1;
2848             break;
2849         }
2850       }
2851     } else {
2852       //
2853       // reset to normal now...
2854       //
2855       break;
2856     }
2857 
2858     //
2859     // update FormatWalker to Resume + 2 (skip the % and the indicator)
2860     //
2861     FormatWalker = ResumeLocation + 2;
2862   }
2863 
2864   gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
2865 
2866   SHELL_FREE_NON_NULL(mPostReplaceFormat);
2867   SHELL_FREE_NON_NULL(mPostReplaceFormat2);
2868   return (Status);
2869 }
2870 
2871 /**
2872   Print at a specific location on the screen.
2873 
2874   This function will move the cursor to a given screen location and print the specified string.
2875 
2876   If -1 is specified for either the Row or Col the current screen location for BOTH
2877   will be used.
2878 
2879   If either Row or Col is out of range for the current console, then ASSERT.
2880   If Format is NULL, then ASSERT.
2881 
2882   In addition to the standard %-based flags as supported by UefiLib Print() this supports
2883   the following additional flags:
2884     %N       -   Set output attribute to normal
2885     %H       -   Set output attribute to highlight
2886     %E       -   Set output attribute to error
2887     %B       -   Set output attribute to blue color
2888     %V       -   Set output attribute to green color
2889 
2890   Note: The background color is controlled by the shell command cls.
2891 
2892   @param[in] Col        the column to print at
2893   @param[in] Row        the row to print at
2894   @param[in] Format     the format string
2895   @param[in] ...        The variable argument list.
2896 
2897   @return EFI_SUCCESS           The printing was successful.
2898   @return EFI_DEVICE_ERROR      The console device reported an error.
2899 **/
2900 EFI_STATUS
2901 EFIAPI
ShellPrintEx(IN INT32 Col OPTIONAL,IN INT32 Row OPTIONAL,IN CONST CHAR16 * Format,...)2902 ShellPrintEx(
2903   IN INT32                Col OPTIONAL,
2904   IN INT32                Row OPTIONAL,
2905   IN CONST CHAR16         *Format,
2906   ...
2907   )
2908 {
2909   VA_LIST           Marker;
2910   EFI_STATUS        RetVal;
2911   if (Format == NULL) {
2912     return (EFI_INVALID_PARAMETER);
2913   }
2914   VA_START (Marker, Format);
2915   RetVal = InternalShellPrintWorker(Col, Row, Format, Marker);
2916   VA_END(Marker);
2917   return(RetVal);
2918 }
2919 
2920 /**
2921   Print at a specific location on the screen.
2922 
2923   This function will move the cursor to a given screen location and print the specified string.
2924 
2925   If -1 is specified for either the Row or Col the current screen location for BOTH
2926   will be used.
2927 
2928   If either Row or Col is out of range for the current console, then ASSERT.
2929   If Format is NULL, then ASSERT.
2930 
2931   In addition to the standard %-based flags as supported by UefiLib Print() this supports
2932   the following additional flags:
2933     %N       -   Set output attribute to normal.
2934     %H       -   Set output attribute to highlight.
2935     %E       -   Set output attribute to error.
2936     %B       -   Set output attribute to blue color.
2937     %V       -   Set output attribute to green color.
2938 
2939   Note: The background color is controlled by the shell command cls.
2940 
2941   @param[in] Col                The column to print at.
2942   @param[in] Row                The row to print at.
2943   @param[in] Language           The language of the string to retrieve.  If this parameter
2944                                 is NULL, then the current platform language is used.
2945   @param[in] HiiFormatStringId  The format string Id for getting from Hii.
2946   @param[in] HiiFormatHandle    The format string Handle for getting from Hii.
2947   @param[in] ...                The variable argument list.
2948 
2949   @return EFI_SUCCESS           The printing was successful.
2950   @return EFI_DEVICE_ERROR      The console device reported an error.
2951 **/
2952 EFI_STATUS
2953 EFIAPI
ShellPrintHiiEx(IN INT32 Col OPTIONAL,IN INT32 Row OPTIONAL,IN CONST CHAR8 * Language OPTIONAL,IN CONST EFI_STRING_ID HiiFormatStringId,IN CONST EFI_HANDLE HiiFormatHandle,...)2954 ShellPrintHiiEx(
2955   IN INT32                Col OPTIONAL,
2956   IN INT32                Row OPTIONAL,
2957   IN CONST CHAR8          *Language OPTIONAL,
2958   IN CONST EFI_STRING_ID  HiiFormatStringId,
2959   IN CONST EFI_HANDLE     HiiFormatHandle,
2960   ...
2961   )
2962 {
2963   VA_LIST           Marker;
2964   CHAR16            *HiiFormatString;
2965   EFI_STATUS        RetVal;
2966 
2967   VA_START (Marker, HiiFormatHandle);
2968   HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);
2969   ASSERT(HiiFormatString != NULL);
2970 
2971   RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);
2972 
2973   SHELL_FREE_NON_NULL(HiiFormatString);
2974   VA_END(Marker);
2975 
2976   return (RetVal);
2977 }
2978 
2979 /**
2980   Function to determine if a given filename represents a file or a directory.
2981 
2982   @param[in] DirName      Path to directory to test.
2983 
2984   @retval EFI_SUCCESS             The Path represents a directory
2985   @retval EFI_NOT_FOUND           The Path does not represent a directory
2986   @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.
2987   @return                         The path failed to open
2988 **/
2989 EFI_STATUS
2990 EFIAPI
ShellIsDirectory(IN CONST CHAR16 * DirName)2991 ShellIsDirectory(
2992   IN CONST CHAR16 *DirName
2993   )
2994 {
2995   EFI_STATUS        Status;
2996   SHELL_FILE_HANDLE Handle;
2997   CHAR16            *TempLocation;
2998   CHAR16            *TempLocation2;
2999 
3000   ASSERT(DirName != NULL);
3001 
3002   Handle        = NULL;
3003   TempLocation  = NULL;
3004 
3005   Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);
3006   if (EFI_ERROR(Status)) {
3007     //
3008     // try good logic first.
3009     //
3010     if (gEfiShellProtocol != NULL) {
3011       TempLocation  = StrnCatGrow(&TempLocation, NULL, DirName, 0);
3012       if (TempLocation == NULL) {
3013         ShellCloseFile(&Handle);
3014         return (EFI_OUT_OF_RESOURCES);
3015       }
3016       TempLocation2 = StrStr(TempLocation, L":");
3017       if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) {
3018         *(TempLocation2+1) = CHAR_NULL;
3019       }
3020       if (gEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) {
3021         FreePool(TempLocation);
3022         return (EFI_SUCCESS);
3023       }
3024       FreePool(TempLocation);
3025     } else {
3026       //
3027       // probably a map name?!?!!?
3028       //
3029       TempLocation = StrStr(DirName, L"\\");
3030       if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) {
3031         return (EFI_SUCCESS);
3032       }
3033     }
3034     return (Status);
3035   }
3036 
3037   if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {
3038     ShellCloseFile(&Handle);
3039     return (EFI_SUCCESS);
3040   }
3041   ShellCloseFile(&Handle);
3042   return (EFI_NOT_FOUND);
3043 }
3044 
3045 /**
3046   Function to determine if a given filename represents a file.
3047 
3048   @param[in] Name         Path to file to test.
3049 
3050   @retval EFI_SUCCESS     The Path represents a file.
3051   @retval EFI_NOT_FOUND   The Path does not represent a file.
3052   @retval other           The path failed to open.
3053 **/
3054 EFI_STATUS
3055 EFIAPI
ShellIsFile(IN CONST CHAR16 * Name)3056 ShellIsFile(
3057   IN CONST CHAR16 *Name
3058   )
3059 {
3060   EFI_STATUS        Status;
3061   SHELL_FILE_HANDLE            Handle;
3062 
3063   ASSERT(Name != NULL);
3064 
3065   Handle = NULL;
3066 
3067   Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);
3068   if (EFI_ERROR(Status)) {
3069     return (Status);
3070   }
3071 
3072   if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
3073     ShellCloseFile(&Handle);
3074     return (EFI_SUCCESS);
3075   }
3076   ShellCloseFile(&Handle);
3077   return (EFI_NOT_FOUND);
3078 }
3079 
3080 /**
3081   Function to determine if a given filename represents a file.
3082 
3083   This will search the CWD and then the Path.
3084 
3085   If Name is NULL, then ASSERT.
3086 
3087   @param[in] Name         Path to file to test.
3088 
3089   @retval EFI_SUCCESS     The Path represents a file.
3090   @retval EFI_NOT_FOUND   The Path does not represent a file.
3091   @retval other           The path failed to open.
3092 **/
3093 EFI_STATUS
3094 EFIAPI
ShellIsFileInPath(IN CONST CHAR16 * Name)3095 ShellIsFileInPath(
3096   IN CONST CHAR16 *Name
3097   )
3098 {
3099   CHAR16      *NewName;
3100   EFI_STATUS  Status;
3101 
3102   if (!EFI_ERROR(ShellIsFile(Name))) {
3103     return (EFI_SUCCESS);
3104   }
3105 
3106   NewName = ShellFindFilePath(Name);
3107   if (NewName == NULL) {
3108     return (EFI_NOT_FOUND);
3109   }
3110   Status = ShellIsFile(NewName);
3111   FreePool(NewName);
3112   return (Status);
3113 }
3114 
3115 /**
3116   Function return the number converted from a hex representation of a number.
3117 
3118   Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
3119   result.  Use ShellConvertStringToUint64 instead.
3120 
3121   @param[in] String   String representation of a number.
3122 
3123   @return             The unsigned integer result of the conversion.
3124   @retval (UINTN)(-1) An error occured.
3125 **/
3126 UINTN
3127 EFIAPI
ShellHexStrToUintn(IN CONST CHAR16 * String)3128 ShellHexStrToUintn(
3129   IN CONST CHAR16 *String
3130   )
3131 {
3132   UINT64        RetVal;
3133 
3134   if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {
3135     return ((UINTN)RetVal);
3136   }
3137 
3138   return ((UINTN)(-1));
3139 }
3140 
3141 /**
3142   Function to determine whether a string is decimal or hex representation of a number
3143   and return the number converted from the string.  Spaces are always skipped.
3144 
3145   @param[in] String   String representation of a number
3146 
3147   @return             the number
3148   @retval (UINTN)(-1) An error ocurred.
3149 **/
3150 UINTN
3151 EFIAPI
ShellStrToUintn(IN CONST CHAR16 * String)3152 ShellStrToUintn(
3153   IN CONST CHAR16 *String
3154   )
3155 {
3156   UINT64        RetVal;
3157   BOOLEAN       Hex;
3158 
3159   Hex = FALSE;
3160 
3161   if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {
3162     Hex = TRUE;
3163   }
3164 
3165   if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, Hex, TRUE))) {
3166     return ((UINTN)RetVal);
3167   }
3168   return ((UINTN)(-1));
3169 }
3170 
3171 /**
3172   Safely append with automatic string resizing given length of Destination and
3173   desired length of copy from Source.
3174 
3175   append the first D characters of Source to the end of Destination, where D is
3176   the lesser of Count and the StrLen() of Source. If appending those D characters
3177   will fit within Destination (whose Size is given as CurrentSize) and
3178   still leave room for a NULL terminator, then those characters are appended,
3179   starting at the original terminating NULL of Destination, and a new terminating
3180   NULL is appended.
3181 
3182   If appending D characters onto Destination will result in a overflow of the size
3183   given in CurrentSize the string will be grown such that the copy can be performed
3184   and CurrentSize will be updated to the new size.
3185 
3186   If Source is NULL, there is nothing to append, just return the current buffer in
3187   Destination.
3188 
3189   if Destination is NULL, then ASSERT()
3190   if Destination's current length (including NULL terminator) is already more then
3191   CurrentSize, then ASSERT()
3192 
3193   @param[in, out] Destination   The String to append onto
3194   @param[in, out] CurrentSize   on call the number of bytes in Destination.  On
3195                                 return possibly the new size (still in bytes).  if NULL
3196                                 then allocate whatever is needed.
3197   @param[in]      Source        The String to append from
3198   @param[in]      Count         Maximum number of characters to append.  if 0 then
3199                                 all are appended.
3200 
3201   @return Destination           return the resultant string.
3202 **/
3203 CHAR16*
3204 EFIAPI
StrnCatGrow(IN OUT CHAR16 ** Destination,IN OUT UINTN * CurrentSize,IN CONST CHAR16 * Source,IN UINTN Count)3205 StrnCatGrow (
3206   IN OUT CHAR16           **Destination,
3207   IN OUT UINTN            *CurrentSize,
3208   IN     CONST CHAR16     *Source,
3209   IN     UINTN            Count
3210   )
3211 {
3212   UINTN DestinationStartSize;
3213   UINTN NewSize;
3214 
3215   //
3216   // ASSERTs
3217   //
3218   ASSERT(Destination != NULL);
3219 
3220   //
3221   // If there's nothing to do then just return Destination
3222   //
3223   if (Source == NULL) {
3224     return (*Destination);
3225   }
3226 
3227   //
3228   // allow for un-initialized pointers, based on size being 0
3229   //
3230   if (CurrentSize != NULL && *CurrentSize == 0) {
3231     *Destination = NULL;
3232   }
3233 
3234   //
3235   // allow for NULL pointers address as Destination
3236   //
3237   if (*Destination != NULL) {
3238     ASSERT(CurrentSize != 0);
3239     DestinationStartSize = StrSize(*Destination);
3240     ASSERT(DestinationStartSize <= *CurrentSize);
3241   } else {
3242     DestinationStartSize = 0;
3243 //    ASSERT(*CurrentSize == 0);
3244   }
3245 
3246   //
3247   // Append all of Source?
3248   //
3249   if (Count == 0) {
3250     Count = StrLen(Source);
3251   }
3252 
3253   //
3254   // Test and grow if required
3255   //
3256   if (CurrentSize != NULL) {
3257     NewSize = *CurrentSize;
3258     if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) {
3259       while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {
3260         NewSize += 2 * Count * sizeof(CHAR16);
3261       }
3262       *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
3263       *CurrentSize = NewSize;
3264     }
3265   } else {
3266     NewSize = (Count+1)*sizeof(CHAR16);
3267     *Destination = AllocateZeroPool(NewSize);
3268   }
3269 
3270   //
3271   // Now use standard StrnCat on a big enough buffer
3272   //
3273   if (*Destination == NULL) {
3274     return (NULL);
3275   }
3276 
3277   StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);
3278   return *Destination;
3279 }
3280 
3281 /**
3282   Prompt the user and return the resultant answer to the requestor.
3283 
3284   This function will display the requested question on the shell prompt and then
3285   wait for an apropriate answer to be input from the console.
3286 
3287   if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
3288   or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
3289 
3290   if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
3291   CHAR16*.
3292 
3293   In either case *Response must be callee freed if Response was not NULL;
3294 
3295   @param Type                     What type of question is asked.  This is used to filter the input
3296                                   to prevent invalid answers to question.
3297   @param Prompt                   Pointer to string prompt to use to request input.
3298   @param Response                 Pointer to Response which will be populated upon return.
3299 
3300   @retval EFI_SUCCESS             The operation was sucessful.
3301   @retval EFI_UNSUPPORTED         The operation is not supported as requested.
3302   @retval EFI_INVALID_PARAMETER   A parameter was invalid.
3303   @return other                   The operation failed.
3304 **/
3305 EFI_STATUS
3306 EFIAPI
ShellPromptForResponse(IN SHELL_PROMPT_REQUEST_TYPE Type,IN CHAR16 * Prompt OPTIONAL,IN OUT VOID ** Response OPTIONAL)3307 ShellPromptForResponse (
3308   IN SHELL_PROMPT_REQUEST_TYPE   Type,
3309   IN CHAR16         *Prompt OPTIONAL,
3310   IN OUT VOID       **Response OPTIONAL
3311   )
3312 {
3313   EFI_STATUS        Status;
3314   EFI_INPUT_KEY     Key;
3315   UINTN             EventIndex;
3316   SHELL_PROMPT_RESPONSE          *Resp;
3317   UINTN             Size;
3318   CHAR16            *Buffer;
3319 
3320   Status  = EFI_UNSUPPORTED;
3321   Resp    = NULL;
3322   Buffer  = NULL;
3323   Size    = 0;
3324   if (Type != ShellPromptResponseTypeFreeform) {
3325     Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));
3326     if (Resp == NULL) {
3327       return (EFI_OUT_OF_RESOURCES);
3328     }
3329   }
3330 
3331   switch(Type) {
3332     case ShellPromptResponseTypeQuitContinue:
3333       if (Prompt != NULL) {
3334         ShellPrintEx(-1, -1, L"%s", Prompt);
3335       }
3336       //
3337       // wait for valid response
3338       //
3339       gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3340       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3341       if (EFI_ERROR(Status)) {
3342         break;
3343       }
3344       ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3345       if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {
3346         *Resp = ShellPromptResponseQuit;
3347       } else {
3348         *Resp = ShellPromptResponseContinue;
3349       }
3350       break;
3351     case ShellPromptResponseTypeYesNoCancel:
3352        if (Prompt != NULL) {
3353         ShellPrintEx(-1, -1, L"%s", Prompt);
3354       }
3355       //
3356       // wait for valid response
3357       //
3358       *Resp = ShellPromptResponseMax;
3359       while (*Resp == ShellPromptResponseMax) {
3360         if (ShellGetExecutionBreakFlag()) {
3361           Status = EFI_ABORTED;
3362           break;
3363         }
3364         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3365         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3366         if (EFI_ERROR(Status)) {
3367           break;
3368         }
3369         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3370         switch (Key.UnicodeChar) {
3371           case L'Y':
3372           case L'y':
3373             *Resp = ShellPromptResponseYes;
3374             break;
3375           case L'N':
3376           case L'n':
3377             *Resp = ShellPromptResponseNo;
3378             break;
3379           case L'C':
3380           case L'c':
3381             *Resp = ShellPromptResponseCancel;
3382             break;
3383         }
3384       }
3385       break;    case ShellPromptResponseTypeYesNoAllCancel:
3386        if (Prompt != NULL) {
3387         ShellPrintEx(-1, -1, L"%s", Prompt);
3388       }
3389       //
3390       // wait for valid response
3391       //
3392       *Resp = ShellPromptResponseMax;
3393       while (*Resp == ShellPromptResponseMax) {
3394         if (ShellGetExecutionBreakFlag()) {
3395           Status = EFI_ABORTED;
3396           break;
3397         }
3398         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3399         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3400         if (EFI_ERROR(Status)) {
3401           break;
3402         }
3403         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3404         switch (Key.UnicodeChar) {
3405           case L'Y':
3406           case L'y':
3407             *Resp = ShellPromptResponseYes;
3408             break;
3409           case L'N':
3410           case L'n':
3411             *Resp = ShellPromptResponseNo;
3412             break;
3413           case L'A':
3414           case L'a':
3415             *Resp = ShellPromptResponseAll;
3416             break;
3417           case L'C':
3418           case L'c':
3419             *Resp = ShellPromptResponseCancel;
3420             break;
3421         }
3422       }
3423       break;
3424     case ShellPromptResponseTypeEnterContinue:
3425     case ShellPromptResponseTypeAnyKeyContinue:
3426       if (Prompt != NULL) {
3427         ShellPrintEx(-1, -1, L"%s", Prompt);
3428       }
3429       //
3430       // wait for valid response
3431       //
3432       *Resp = ShellPromptResponseMax;
3433       while (*Resp == ShellPromptResponseMax) {
3434         if (ShellGetExecutionBreakFlag()) {
3435           Status = EFI_ABORTED;
3436           break;
3437         }
3438         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3439         if (Type == ShellPromptResponseTypeEnterContinue) {
3440           Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3441           if (EFI_ERROR(Status)) {
3442             break;
3443           }
3444           ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3445           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
3446             *Resp = ShellPromptResponseContinue;
3447             break;
3448           }
3449         }
3450         if (Type == ShellPromptResponseTypeAnyKeyContinue) {
3451           Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3452           ASSERT_EFI_ERROR(Status);
3453           *Resp = ShellPromptResponseContinue;
3454           break;
3455         }
3456       }
3457       break;
3458     case ShellPromptResponseTypeYesNo:
3459        if (Prompt != NULL) {
3460         ShellPrintEx(-1, -1, L"%s", Prompt);
3461       }
3462       //
3463       // wait for valid response
3464       //
3465       *Resp = ShellPromptResponseMax;
3466       while (*Resp == ShellPromptResponseMax) {
3467         if (ShellGetExecutionBreakFlag()) {
3468           Status = EFI_ABORTED;
3469           break;
3470         }
3471         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3472         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3473         if (EFI_ERROR(Status)) {
3474           break;
3475         }
3476         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3477         switch (Key.UnicodeChar) {
3478           case L'Y':
3479           case L'y':
3480             *Resp = ShellPromptResponseYes;
3481             break;
3482           case L'N':
3483           case L'n':
3484             *Resp = ShellPromptResponseNo;
3485             break;
3486         }
3487       }
3488       break;
3489     case ShellPromptResponseTypeFreeform:
3490       if (Prompt != NULL) {
3491         ShellPrintEx(-1, -1, L"%s", Prompt);
3492       }
3493       while(1) {
3494         if (ShellGetExecutionBreakFlag()) {
3495           Status = EFI_ABORTED;
3496           break;
3497         }
3498         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3499         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3500         if (EFI_ERROR(Status)) {
3501           break;
3502         }
3503         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3504         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
3505           break;
3506         }
3507         ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL));
3508         StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1);
3509       }
3510       break;
3511     //
3512     // This is the location to add new prompt types.
3513     // If your new type loops remember to add ExecutionBreak support.
3514     //
3515     default:
3516       ASSERT(FALSE);
3517   }
3518 
3519   if (Response != NULL) {
3520     if (Resp != NULL) {
3521       *Response = Resp;
3522     } else if (Buffer != NULL) {
3523       *Response = Buffer;
3524     }
3525   } else {
3526     if (Resp != NULL) {
3527       FreePool(Resp);
3528     }
3529     if (Buffer != NULL) {
3530       FreePool(Buffer);
3531     }
3532   }
3533 
3534   ShellPrintEx(-1, -1, L"\r\n");
3535   return (Status);
3536 }
3537 
3538 /**
3539   Prompt the user and return the resultant answer to the requestor.
3540 
3541   This function is the same as ShellPromptForResponse, except that the prompt is
3542   automatically pulled from HII.
3543 
3544   @param Type     What type of question is asked.  This is used to filter the input
3545                   to prevent invalid answers to question.
3546   @param[in] HiiFormatStringId  The format string Id for getting from Hii.
3547   @param[in] HiiFormatHandle    The format string Handle for getting from Hii.
3548   @param Response               Pointer to Response which will be populated upon return.
3549 
3550   @retval EFI_SUCCESS the operation was sucessful.
3551   @return other       the operation failed.
3552 
3553   @sa ShellPromptForResponse
3554 **/
3555 EFI_STATUS
3556 EFIAPI
ShellPromptForResponseHii(IN SHELL_PROMPT_REQUEST_TYPE Type,IN CONST EFI_STRING_ID HiiFormatStringId,IN CONST EFI_HANDLE HiiFormatHandle,IN OUT VOID ** Response)3557 ShellPromptForResponseHii (
3558   IN SHELL_PROMPT_REQUEST_TYPE         Type,
3559   IN CONST EFI_STRING_ID  HiiFormatStringId,
3560   IN CONST EFI_HANDLE     HiiFormatHandle,
3561   IN OUT VOID             **Response
3562   )
3563 {
3564   CHAR16      *Prompt;
3565   EFI_STATUS  Status;
3566 
3567   Prompt = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);
3568   Status = ShellPromptForResponse(Type, Prompt, Response);
3569   FreePool(Prompt);
3570   return (Status);
3571 }
3572 
3573 /**
3574   Function to determin if an entire string is a valid number.
3575 
3576   If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
3577 
3578   @param[in] String       The string to evaluate.
3579   @param[in] ForceHex     TRUE - always assume hex.
3580   @param[in] StopAtSpace  TRUE to halt upon finding a space, FALSE to keep going.
3581   @param[in] TimeNumbers        TRUE to allow numbers with ":", FALSE otherwise.
3582 
3583   @retval TRUE        It is all numeric (dec/hex) characters.
3584   @retval FALSE       There is a non-numeric character.
3585 **/
3586 BOOLEAN
3587 EFIAPI
InternalShellIsHexOrDecimalNumber(IN CONST CHAR16 * String,IN CONST BOOLEAN ForceHex,IN CONST BOOLEAN StopAtSpace,IN CONST BOOLEAN TimeNumbers)3588 InternalShellIsHexOrDecimalNumber (
3589   IN CONST CHAR16   *String,
3590   IN CONST BOOLEAN  ForceHex,
3591   IN CONST BOOLEAN  StopAtSpace,
3592   IN CONST BOOLEAN  TimeNumbers
3593   )
3594 {
3595   BOOLEAN Hex;
3596 
3597   //
3598   // chop off a single negative sign
3599   //
3600   if (String != NULL && *String == L'-') {
3601     String++;
3602   }
3603 
3604   if (String == NULL) {
3605     return (FALSE);
3606   }
3607 
3608   //
3609   // chop leading zeroes
3610   //
3611   while(String != NULL && *String == L'0'){
3612     String++;
3613   }
3614   //
3615   // allow '0x' or '0X', but not 'x' or 'X'
3616   //
3617   if (String != NULL && (*String == L'x' || *String == L'X')) {
3618     if (*(String-1) != L'0') {
3619       //
3620       // we got an x without a preceeding 0
3621       //
3622       return (FALSE);
3623     }
3624     String++;
3625     Hex = TRUE;
3626   } else if (ForceHex) {
3627     Hex = TRUE;
3628   } else {
3629     Hex = FALSE;
3630   }
3631 
3632   //
3633   // loop through the remaining characters and use the lib function
3634   //
3635   for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){
3636     if (TimeNumbers && (String[0] == L':')) {
3637       continue;
3638     }
3639     if (Hex) {
3640       if (!ShellIsHexaDecimalDigitCharacter(*String)) {
3641         return (FALSE);
3642       }
3643     } else {
3644       if (!ShellIsDecimalDigitCharacter(*String)) {
3645         return (FALSE);
3646       }
3647     }
3648   }
3649 
3650   return (TRUE);
3651 }
3652 
3653 /**
3654   Function to determine if a given filename exists.
3655 
3656   @param[in] Name         Path to test.
3657 
3658   @retval EFI_SUCCESS     The Path represents a file.
3659   @retval EFI_NOT_FOUND   The Path does not represent a file.
3660   @retval other           The path failed to open.
3661 **/
3662 EFI_STATUS
3663 EFIAPI
ShellFileExists(IN CONST CHAR16 * Name)3664 ShellFileExists(
3665   IN CONST CHAR16 *Name
3666   )
3667 {
3668   EFI_STATUS          Status;
3669   EFI_SHELL_FILE_INFO *List;
3670 
3671   ASSERT(Name != NULL);
3672 
3673   List = NULL;
3674   Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List);
3675   if (EFI_ERROR(Status)) {
3676     return (Status);
3677   }
3678 
3679   ShellCloseFileMetaArg(&List);
3680 
3681   return (EFI_SUCCESS);
3682 }
3683 
3684 /**
3685   Convert a Unicode character to upper case only if
3686   it maps to a valid small-case ASCII character.
3687 
3688   This internal function only deal with Unicode character
3689   which maps to a valid small-case ASCII character, i.e.
3690   L'a' to L'z'. For other Unicode character, the input character
3691   is returned directly.
3692 
3693   @param  Char  The character to convert.
3694 
3695   @retval LowerCharacter   If the Char is with range L'a' to L'z'.
3696   @retval Unchanged        Otherwise.
3697 
3698 **/
3699 CHAR16
3700 EFIAPI
InternalShellCharToUpper(IN CHAR16 Char)3701 InternalShellCharToUpper (
3702   IN      CHAR16                    Char
3703   )
3704 {
3705   if (Char >= L'a' && Char <= L'z') {
3706     return (CHAR16) (Char - (L'a' - L'A'));
3707   }
3708 
3709   return Char;
3710 }
3711 
3712 /**
3713   Convert a Unicode character to numerical value.
3714 
3715   This internal function only deal with Unicode character
3716   which maps to a valid hexadecimal ASII character, i.e.
3717   L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
3718   Unicode character, the value returned does not make sense.
3719 
3720   @param  Char  The character to convert.
3721 
3722   @return The numerical value converted.
3723 
3724 **/
3725 UINTN
3726 EFIAPI
InternalShellHexCharToUintn(IN CHAR16 Char)3727 InternalShellHexCharToUintn (
3728   IN      CHAR16                    Char
3729   )
3730 {
3731   if (ShellIsDecimalDigitCharacter (Char)) {
3732     return Char - L'0';
3733   }
3734 
3735   return (UINTN) (10 + InternalShellCharToUpper (Char) - L'A');
3736 }
3737 
3738 /**
3739   Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
3740 
3741   This function returns a value of type UINT64 by interpreting the contents
3742   of the Unicode string specified by String as a hexadecimal number.
3743   The format of the input Unicode string String is:
3744 
3745                   [spaces][zeros][x][hexadecimal digits].
3746 
3747   The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
3748   The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
3749   If "x" appears in the input string, it must be prefixed with at least one 0.
3750   The function will ignore the pad space, which includes spaces or tab characters,
3751   before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
3752   [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
3753   first valid hexadecimal digit. Then, the function stops at the first character that is
3754   a not a valid hexadecimal character or NULL, whichever one comes first.
3755 
3756   If String has only pad spaces, then zero is returned.
3757   If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
3758   then zero is returned.
3759 
3760   @param[in]  String      A pointer to a Null-terminated Unicode string.
3761   @param[out] Value       Upon a successful return the value of the conversion.
3762   @param[in] StopAtSpace  FALSE to skip spaces.
3763 
3764   @retval EFI_SUCCESS             The conversion was successful.
3765   @retval EFI_INVALID_PARAMETER   A parameter was NULL or invalid.
3766   @retval EFI_DEVICE_ERROR        An overflow occured.
3767 **/
3768 EFI_STATUS
3769 EFIAPI
InternalShellStrHexToUint64(IN CONST CHAR16 * String,OUT UINT64 * Value,IN CONST BOOLEAN StopAtSpace)3770 InternalShellStrHexToUint64 (
3771   IN CONST CHAR16   *String,
3772      OUT   UINT64   *Value,
3773   IN CONST BOOLEAN  StopAtSpace
3774   )
3775 {
3776   UINT64    Result;
3777 
3778   if (String == NULL || StrSize(String) == 0 || Value == NULL) {
3779     return (EFI_INVALID_PARAMETER);
3780   }
3781 
3782   //
3783   // Ignore the pad spaces (space or tab)
3784   //
3785   while ((*String == L' ') || (*String == L'\t')) {
3786     String++;
3787   }
3788 
3789   //
3790   // Ignore leading Zeros after the spaces
3791   //
3792   while (*String == L'0') {
3793     String++;
3794   }
3795 
3796   if (InternalShellCharToUpper (*String) == L'X') {
3797     if (*(String - 1) != L'0') {
3798       return 0;
3799     }
3800     //
3801     // Skip the 'X'
3802     //
3803     String++;
3804   }
3805 
3806   Result = 0;
3807 
3808   //
3809   // there is a space where there should't be
3810   //
3811   if (*String == L' ') {
3812     return (EFI_INVALID_PARAMETER);
3813   }
3814 
3815   while (ShellIsHexaDecimalDigitCharacter (*String)) {
3816     //
3817     // If the Hex Number represented by String overflows according
3818     // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3819     //
3820     if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
3821 //    if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
3822       return (EFI_DEVICE_ERROR);
3823     }
3824 
3825     Result = (LShiftU64(Result, 4));
3826     Result += InternalShellHexCharToUintn (*String);
3827     String++;
3828 
3829     //
3830     // stop at spaces if requested
3831     //
3832     if (StopAtSpace && *String == L' ') {
3833       break;
3834     }
3835   }
3836 
3837   *Value = Result;
3838   return (EFI_SUCCESS);
3839 }
3840 
3841 /**
3842   Convert a Null-terminated Unicode decimal string to a value of
3843   type UINT64.
3844 
3845   This function returns a value of type UINT64 by interpreting the contents
3846   of the Unicode string specified by String as a decimal number. The format
3847   of the input Unicode string String is:
3848 
3849                   [spaces] [decimal digits].
3850 
3851   The valid decimal digit character is in the range [0-9]. The
3852   function will ignore the pad space, which includes spaces or
3853   tab characters, before [decimal digits]. The running zero in the
3854   beginning of [decimal digits] will be ignored. Then, the function
3855   stops at the first character that is a not a valid decimal character
3856   or a Null-terminator, whichever one comes first.
3857 
3858   If String has only pad spaces, then 0 is returned.
3859   If String has no pad spaces or valid decimal digits,
3860   then 0 is returned.
3861 
3862   @param[in]  String      A pointer to a Null-terminated Unicode string.
3863   @param[out] Value       Upon a successful return the value of the conversion.
3864   @param[in] StopAtSpace  FALSE to skip spaces.
3865 
3866   @retval EFI_SUCCESS             The conversion was successful.
3867   @retval EFI_INVALID_PARAMETER   A parameter was NULL or invalid.
3868   @retval EFI_DEVICE_ERROR        An overflow occured.
3869 **/
3870 EFI_STATUS
3871 EFIAPI
InternalShellStrDecimalToUint64(IN CONST CHAR16 * String,OUT UINT64 * Value,IN CONST BOOLEAN StopAtSpace)3872 InternalShellStrDecimalToUint64 (
3873   IN CONST CHAR16 *String,
3874      OUT   UINT64 *Value,
3875   IN CONST BOOLEAN  StopAtSpace
3876   )
3877 {
3878   UINT64     Result;
3879 
3880   if (String == NULL || StrSize (String) == 0 || Value == NULL) {
3881     return (EFI_INVALID_PARAMETER);
3882   }
3883 
3884   //
3885   // Ignore the pad spaces (space or tab)
3886   //
3887   while ((*String == L' ') || (*String == L'\t')) {
3888     String++;
3889   }
3890 
3891   //
3892   // Ignore leading Zeros after the spaces
3893   //
3894   while (*String == L'0') {
3895     String++;
3896   }
3897 
3898   Result = 0;
3899 
3900   //
3901   // Stop upon space if requested
3902   // (if the whole value was 0)
3903   //
3904   if (StopAtSpace && *String == L' ') {
3905     *Value = Result;
3906     return (EFI_SUCCESS);
3907   }
3908 
3909   while (ShellIsDecimalDigitCharacter (*String)) {
3910     //
3911     // If the number represented by String overflows according
3912     // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3913     //
3914 
3915     if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {
3916       return (EFI_DEVICE_ERROR);
3917     }
3918 
3919     Result = MultU64x32(Result, 10) + (*String - L'0');
3920     String++;
3921 
3922     //
3923     // Stop at spaces if requested
3924     //
3925     if (StopAtSpace && *String == L' ') {
3926       break;
3927     }
3928   }
3929 
3930   *Value = Result;
3931 
3932   return (EFI_SUCCESS);
3933 }
3934 
3935 /**
3936   Function to verify and convert a string to its numerical value.
3937 
3938   If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
3939 
3940   @param[in] String       The string to evaluate.
3941   @param[out] Value       Upon a successful return the value of the conversion.
3942   @param[in] ForceHex     TRUE - always assume hex.
3943   @param[in] StopAtSpace  FALSE to skip spaces.
3944 
3945   @retval EFI_SUCCESS             The conversion was successful.
3946   @retval EFI_INVALID_PARAMETER   String contained an invalid character.
3947   @retval EFI_NOT_FOUND           String was a number, but Value was NULL.
3948 **/
3949 EFI_STATUS
3950 EFIAPI
ShellConvertStringToUint64(IN CONST CHAR16 * String,OUT UINT64 * Value,IN CONST BOOLEAN ForceHex,IN CONST BOOLEAN StopAtSpace)3951 ShellConvertStringToUint64(
3952   IN CONST CHAR16   *String,
3953      OUT   UINT64   *Value,
3954   IN CONST BOOLEAN  ForceHex,
3955   IN CONST BOOLEAN  StopAtSpace
3956   )
3957 {
3958   UINT64        RetVal;
3959   CONST CHAR16  *Walker;
3960   EFI_STATUS    Status;
3961   BOOLEAN       Hex;
3962 
3963   Hex = ForceHex;
3964 
3965   if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
3966     if (!Hex) {
3967       Hex = TRUE;
3968       if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
3969         return (EFI_INVALID_PARAMETER);
3970       }
3971     } else {
3972       return (EFI_INVALID_PARAMETER);
3973     }
3974   }
3975 
3976   //
3977   // Chop off leading spaces
3978   //
3979   for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);
3980 
3981   //
3982   // make sure we have something left that is numeric.
3983   //
3984   if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {
3985     return (EFI_INVALID_PARAMETER);
3986   }
3987 
3988   //
3989   // do the conversion.
3990   //
3991   if (Hex || StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){
3992     Status = InternalShellStrHexToUint64(Walker, &RetVal, StopAtSpace);
3993   } else {
3994     Status = InternalShellStrDecimalToUint64(Walker, &RetVal, StopAtSpace);
3995   }
3996 
3997   if (Value == NULL && !EFI_ERROR(Status)) {
3998     return (EFI_NOT_FOUND);
3999   }
4000 
4001   if (Value != NULL) {
4002     *Value = RetVal;
4003   }
4004 
4005   return (Status);
4006 }
4007 
4008 /**
4009   Function to determin if an entire string is a valid number.
4010 
4011   If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
4012 
4013   @param[in] String       The string to evaluate.
4014   @param[in] ForceHex     TRUE - always assume hex.
4015   @param[in] StopAtSpace  TRUE to halt upon finding a space, FALSE to keep going.
4016 
4017   @retval TRUE        It is all numeric (dec/hex) characters.
4018   @retval FALSE       There is a non-numeric character.
4019 **/
4020 BOOLEAN
4021 EFIAPI
ShellIsHexOrDecimalNumber(IN CONST CHAR16 * String,IN CONST BOOLEAN ForceHex,IN CONST BOOLEAN StopAtSpace)4022 ShellIsHexOrDecimalNumber (
4023   IN CONST CHAR16   *String,
4024   IN CONST BOOLEAN  ForceHex,
4025   IN CONST BOOLEAN  StopAtSpace
4026   )
4027 {
4028   if (ShellConvertStringToUint64(String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {
4029     return (TRUE);
4030   }
4031   return (FALSE);
4032 }
4033 
4034 /**
4035   Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
4036   buffer.  The returned buffer must be callee freed.
4037 
4038   If the position upon start is 0, then the Ascii Boolean will be set.  This should be
4039   maintained and not changed for all operations with the same file.
4040 
4041   @param[in]       Handle        SHELL_FILE_HANDLE to read from.
4042   @param[in, out]  Ascii         Boolean value for indicating whether the file is
4043                                  Ascii (TRUE) or UCS2 (FALSE).
4044 
4045   @return                        The line of text from the file.
4046   @retval NULL                   There was not enough memory available.
4047 
4048   @sa ShellFileHandleReadLine
4049 **/
4050 CHAR16*
4051 EFIAPI
ShellFileHandleReturnLine(IN SHELL_FILE_HANDLE Handle,IN OUT BOOLEAN * Ascii)4052 ShellFileHandleReturnLine(
4053   IN SHELL_FILE_HANDLE            Handle,
4054   IN OUT BOOLEAN                *Ascii
4055   )
4056 {
4057   CHAR16          *RetVal;
4058   UINTN           Size;
4059   EFI_STATUS      Status;
4060 
4061   Size = 0;
4062   RetVal = NULL;
4063 
4064   Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
4065   if (Status == EFI_BUFFER_TOO_SMALL) {
4066     RetVal = AllocateZeroPool(Size);
4067     if (RetVal == NULL) {
4068       return (NULL);
4069     }
4070     Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
4071 
4072   }
4073   if (EFI_ERROR(Status) && (RetVal != NULL)) {
4074     FreePool(RetVal);
4075     RetVal = NULL;
4076   }
4077   return (RetVal);
4078 }
4079 
4080 /**
4081   Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
4082 
4083   If the position upon start is 0, then the Ascii Boolean will be set.  This should be
4084   maintained and not changed for all operations with the same file.
4085 
4086   @param[in]       Handle        SHELL_FILE_HANDLE to read from.
4087   @param[in, out]  Buffer        The pointer to buffer to read into.
4088   @param[in, out]  Size          The pointer to number of bytes in Buffer.
4089   @param[in]       Truncate      If the buffer is large enough, this has no effect.
4090                                  If the buffer is is too small and Truncate is TRUE,
4091                                  the line will be truncated.
4092                                  If the buffer is is too small and Truncate is FALSE,
4093                                  then no read will occur.
4094 
4095   @param[in, out]  Ascii         Boolean value for indicating whether the file is
4096                                  Ascii (TRUE) or UCS2 (FALSE).
4097 
4098   @retval EFI_SUCCESS           The operation was successful.  The line is stored in
4099                                 Buffer.
4100   @retval EFI_INVALID_PARAMETER Handle was NULL.
4101   @retval EFI_INVALID_PARAMETER Size was NULL.
4102   @retval EFI_BUFFER_TOO_SMALL  Size was not large enough to store the line.
4103                                 Size was updated to the minimum space required.
4104 **/
4105 EFI_STATUS
4106 EFIAPI
ShellFileHandleReadLine(IN SHELL_FILE_HANDLE Handle,IN OUT CHAR16 * Buffer,IN OUT UINTN * Size,IN BOOLEAN Truncate,IN OUT BOOLEAN * Ascii)4107 ShellFileHandleReadLine(
4108   IN SHELL_FILE_HANDLE          Handle,
4109   IN OUT CHAR16                 *Buffer,
4110   IN OUT UINTN                  *Size,
4111   IN BOOLEAN                    Truncate,
4112   IN OUT BOOLEAN                *Ascii
4113   )
4114 {
4115   EFI_STATUS  Status;
4116   CHAR16      CharBuffer;
4117   UINTN       CharSize;
4118   UINTN       CountSoFar;
4119   UINT64      OriginalFilePosition;
4120 
4121 
4122   if (Handle == NULL
4123     ||Size   == NULL
4124    ){
4125     return (EFI_INVALID_PARAMETER);
4126   }
4127   if (Buffer == NULL) {
4128     ASSERT(*Size == 0);
4129   } else {
4130     *Buffer = CHAR_NULL;
4131   }
4132   gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);
4133   if (OriginalFilePosition == 0) {
4134     CharSize = sizeof(CHAR16);
4135     Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4136     ASSERT_EFI_ERROR(Status);
4137     if (CharBuffer == gUnicodeFileTag) {
4138       *Ascii = FALSE;
4139     } else {
4140       *Ascii = TRUE;
4141       gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4142     }
4143   }
4144 
4145   for (CountSoFar = 0;;CountSoFar++){
4146     CharBuffer = 0;
4147     if (*Ascii) {
4148       CharSize = sizeof(CHAR8);
4149     } else {
4150       CharSize = sizeof(CHAR16);
4151     }
4152     Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4153     if (  EFI_ERROR(Status)
4154        || CharSize == 0
4155        || (CharBuffer == L'\n' && !(*Ascii))
4156        || (CharBuffer ==  '\n' && *Ascii)
4157      ){
4158       break;
4159     }
4160     //
4161     // if we have space save it...
4162     //
4163     if ((CountSoFar+1)*sizeof(CHAR16) < *Size){
4164       ASSERT(Buffer != NULL);
4165       ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
4166       ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
4167     }
4168   }
4169 
4170   //
4171   // if we ran out of space tell when...
4172   //
4173   if ((CountSoFar+1)*sizeof(CHAR16) > *Size){
4174     *Size = (CountSoFar+1)*sizeof(CHAR16);
4175     if (!Truncate) {
4176       gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4177     } else {
4178       DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
4179     }
4180     return (EFI_BUFFER_TOO_SMALL);
4181   }
4182   while(Buffer[StrLen(Buffer)-1] == L'\r') {
4183     Buffer[StrLen(Buffer)-1] = CHAR_NULL;
4184   }
4185 
4186   return (Status);
4187 }
4188 
4189 /**
4190   Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
4191 
4192   @param[in] CommandToGetHelpOn  Pointer to a string containing the command name of help file to be printed.
4193   @param[in] SectionToGetHelpOn  Pointer to the section specifier(s).
4194   @param[in] PrintCommandText    If TRUE, prints the command followed by the help content, otherwise prints
4195                                  the help content only.
4196   @retval EFI_DEVICE_ERROR       The help data format was incorrect.
4197   @retval EFI_NOT_FOUND          The help data could not be found.
4198   @retval EFI_SUCCESS            The operation was successful.
4199 **/
4200 EFI_STATUS
4201 EFIAPI
ShellPrintHelp(IN CONST CHAR16 * CommandToGetHelpOn,IN CONST CHAR16 * SectionToGetHelpOn,IN BOOLEAN PrintCommandText)4202 ShellPrintHelp (
4203   IN CONST CHAR16     *CommandToGetHelpOn,
4204   IN CONST CHAR16     *SectionToGetHelpOn,
4205   IN BOOLEAN          PrintCommandText
4206   )
4207 {
4208 	EFI_STATUS          Status;
4209 	CHAR16              *OutText;
4210 
4211 	OutText = NULL;
4212 
4213   //
4214   // Get the string to print based
4215   //
4216 	Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
4217 
4218   //
4219   // make sure we got a valid string
4220   //
4221   if (EFI_ERROR(Status)){
4222     return Status;
4223 	}
4224   if (OutText == NULL || StrLen(OutText) == 0) {
4225     return EFI_NOT_FOUND;
4226 	}
4227 
4228   //
4229   // Chop off trailing stuff we dont need
4230   //
4231   while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {
4232     OutText[StrLen(OutText)-1] = CHAR_NULL;
4233   }
4234 
4235   //
4236   // Print this out to the console
4237   //
4238   if (PrintCommandText) {
4239     ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
4240   } else {
4241     ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);
4242   }
4243 
4244   SHELL_FREE_NON_NULL(OutText);
4245 
4246 	return EFI_SUCCESS;
4247 }
4248 
4249 /**
4250   Function to delete a file by name
4251 
4252   @param[in]       FileName       Pointer to file name to delete.
4253 
4254   @retval EFI_SUCCESS             the file was deleted sucessfully
4255   @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
4256                                   deleted
4257   @retval EFI_INVALID_PARAMETER   One of the parameters has an invalid value.
4258   @retval EFI_NOT_FOUND           The specified file could not be found on the
4259                                   device or the file system could not be found
4260                                   on the device.
4261   @retval EFI_NO_MEDIA            The device has no medium.
4262   @retval EFI_MEDIA_CHANGED       The device has a different medium in it or the
4263                                   medium is no longer supported.
4264   @retval EFI_DEVICE_ERROR        The device reported an error.
4265   @retval EFI_VOLUME_CORRUPTED    The file system structures are corrupted.
4266   @retval EFI_WRITE_PROTECTED     The file or medium is write protected.
4267   @retval EFI_ACCESS_DENIED       The file was opened read only.
4268   @retval EFI_OUT_OF_RESOURCES    Not enough resources were available to open the
4269                                   file.
4270   @retval other                   The file failed to open
4271 **/
4272 EFI_STATUS
4273 EFIAPI
ShellDeleteFileByName(IN CONST CHAR16 * FileName)4274 ShellDeleteFileByName(
4275   IN CONST CHAR16               *FileName
4276   )
4277 {
4278   EFI_STATUS                Status;
4279   SHELL_FILE_HANDLE         FileHandle;
4280 
4281   Status = ShellFileExists(FileName);
4282 
4283   if (Status == EFI_SUCCESS){
4284     Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
4285     if (Status == EFI_SUCCESS){
4286       Status = ShellDeleteFile(&FileHandle);
4287     }
4288   }
4289 
4290   return(Status);
4291 
4292 }
4293 
4294 /**
4295   Cleans off all the quotes in the string.
4296 
4297   @param[in]     OriginalString   pointer to the string to be cleaned.
4298   @param[out]   CleanString      The new string with all quotes removed.
4299                                                   Memory allocated in the function and free
4300                                                   by caller.
4301 
4302   @retval EFI_SUCCESS   The operation was successful.
4303 **/
4304 EFI_STATUS
4305 EFIAPI
InternalShellStripQuotes(IN CONST CHAR16 * OriginalString,OUT CHAR16 ** CleanString)4306 InternalShellStripQuotes (
4307   IN  CONST CHAR16     *OriginalString,
4308   OUT CHAR16           **CleanString
4309   )
4310 {
4311   CHAR16            *Walker;
4312 
4313   if (OriginalString == NULL || CleanString == NULL) {
4314     return EFI_INVALID_PARAMETER;
4315   }
4316 
4317   *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
4318   if (*CleanString == NULL) {
4319     return EFI_OUT_OF_RESOURCES;
4320   }
4321 
4322   for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
4323     if (*Walker == L'\"') {
4324       CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
4325     }
4326   }
4327 
4328   return EFI_SUCCESS;
4329 }
4330 
4331