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