]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/ShellProtocol.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
CommitLineData
a405b86d 1/** @file\r
2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
4\r
c011b6c9 5 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
583448b4 6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
ba0014b9 7 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
56ba3746 8 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a405b86d 9\r
10**/\r
11\r
12#include "Shell.h"\r
a405b86d 13\r
654a012b
QS
14#define INIT_NAME_BUFFER_SIZE 128\r
15\r
a405b86d 16/**\r
17 Close an open file handle.\r
18\r
19 This function closes a specified file handle. All "dirty" cached file data is\r
20 flushed to the device, and the file is closed. In all cases the handle is\r
21 closed.\r
22\r
23 @param[in] FileHandle The file handle to close.\r
24\r
25 @retval EFI_SUCCESS The file handle was closed successfully.\r
26**/\r
27EFI_STATUS\r
28EFIAPI\r
29EfiShellClose (\r
47d20b54 30 IN SHELL_FILE_HANDLE FileHandle\r
a405b86d 31 )\r
32{\r
47d20b54
MK
33 ShellFileHandleRemove (FileHandle);\r
34 return (FileHandleClose (ConvertShellHandleToEfiFileProtocol (FileHandle)));\r
a405b86d 35}\r
36\r
733f138d 37/**\r
38 Internal worker to determine whether there is a BlockIo somewhere\r
39 upon the device path specified.\r
40\r
41 @param[in] DevicePath The device path to test.\r
42\r
43 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path\r
44 @retval FALSE gEfiBlockIoProtocolGuid was not found.\r
45**/\r
46BOOLEAN\r
47d20b54
MK
47InternalShellProtocolIsBlockIoPresent (\r
48 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
733f138d 49 )\r
50{\r
51 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
52 EFI_STATUS Status;\r
53 EFI_HANDLE Handle;\r
54\r
55 Handle = NULL;\r
56\r
47d20b54
MK
57 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
58 Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);\r
733f138d 59\r
47d20b54 60 if ((Handle != NULL) && (!EFI_ERROR (Status))) {\r
733f138d 61 return (TRUE);\r
62 }\r
47d20b54 63\r
733f138d 64 return (FALSE);\r
65}\r
66\r
a405b86d 67/**\r
68 Internal worker to determine whether there is a file system somewhere\r
69 upon the device path specified.\r
70\r
71 @param[in] DevicePath The device path to test.\r
72\r
73 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path\r
74 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.\r
75**/\r
76BOOLEAN\r
47d20b54
MK
77InternalShellProtocolIsSimpleFileSystemPresent (\r
78 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
a405b86d 79 )\r
80{\r
81 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
82 EFI_STATUS Status;\r
83 EFI_HANDLE Handle;\r
84\r
85 Handle = NULL;\r
86\r
47d20b54
MK
87 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;\r
88 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
a405b86d 89\r
47d20b54 90 if ((Handle != NULL) && (!EFI_ERROR (Status))) {\r
a405b86d 91 return (TRUE);\r
92 }\r
47d20b54 93\r
a405b86d 94 return (FALSE);\r
95}\r
96\r
a405b86d 97/**\r
98 This function creates a mapping for a device path.\r
99\r
6a5033ca 100 If both DevicePath and Mapping are NULL, this will reset the mapping to default values.\r
a405b86d 101\r
102 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,\r
103 then the mapping will be deleted.\r
104 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'\r
105\r
106 @retval EFI_SUCCESS Mapping created or deleted successfully.\r
107 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the\r
108 boot service function LocateDevicePath().\r
109 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.\r
110 @retval EFI_INVALID_PARAMETER Mapping was NULL\r
111 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'\r
112 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.\r
113 @retval EFI_NOT_FOUND There was no mapping found to delete\r
114 @retval EFI_OUT_OF_RESOURCES Memory allocation failed\r
115**/\r
116EFI_STATUS\r
117EFIAPI\r
47d20b54
MK
118EfiShellSetMap (\r
119 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,\r
120 IN CONST CHAR16 *Mapping\r
a405b86d 121 )\r
122{\r
123 EFI_STATUS Status;\r
124 SHELL_MAP_LIST *MapListNode;\r
125\r
47d20b54 126 if (Mapping == NULL) {\r
a405b86d 127 return (EFI_INVALID_PARAMETER);\r
128 }\r
129\r
47d20b54 130 if (Mapping[StrLen (Mapping)-1] != ':') {\r
a405b86d 131 return (EFI_INVALID_PARAMETER);\r
132 }\r
133\r
134 //\r
135 // Delete the mapping\r
136 //\r
137 if (DevicePath == NULL) {\r
47d20b54 138 if (IsListEmpty (&gShellMapList.Link)) {\r
a405b86d 139 return (EFI_NOT_FOUND);\r
140 }\r
47d20b54
MK
141\r
142 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
143 ; !IsNull (&gShellMapList.Link, &MapListNode->Link)\r
144 ; MapListNode = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &MapListNode->Link)\r
145 )\r
146 {\r
147 if (StringNoCaseCompare (&MapListNode->MapName, &Mapping) == 0) {\r
148 RemoveEntryList (&MapListNode->Link);\r
149 SHELL_FREE_NON_NULL (MapListNode->DevicePath);\r
150 SHELL_FREE_NON_NULL (MapListNode->MapName);\r
151 SHELL_FREE_NON_NULL (MapListNode->CurrentDirectoryPath);\r
152 FreePool (MapListNode);\r
153 return (EFI_SUCCESS);\r
154 }\r
a405b86d 155 } // for loop\r
156\r
157 //\r
6a5033ca 158 // We didn't find one to delete\r
a405b86d 159 //\r
160 return (EFI_NOT_FOUND);\r
161 }\r
162\r
163 //\r
164 // make sure this is a valid to add device path\r
165 //\r
47d20b54
MK
166 /// @todo add BlockIo to this test...\r
167 if ( !InternalShellProtocolIsSimpleFileSystemPresent (DevicePath)\r
168 && !InternalShellProtocolIsBlockIoPresent (DevicePath))\r
169 {\r
a405b86d 170 return (EFI_INVALID_PARAMETER);\r
171 }\r
172\r
173 //\r
174 // First make sure there is no old mapping\r
175 //\r
47d20b54 176 Status = EfiShellSetMap (NULL, Mapping);\r
a405b86d 177 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) {\r
178 return (Status);\r
179 }\r
180\r
181 //\r
182 // now add the new one.\r
183 //\r
47d20b54 184 Status = ShellCommandAddMapItemAndUpdatePath (Mapping, DevicePath, 0, FALSE);\r
a405b86d 185\r
47d20b54 186 return (Status);\r
a405b86d 187}\r
188\r
189/**\r
190 Gets the device path from the mapping.\r
191\r
192 This function gets the device path associated with a mapping.\r
193\r
194 @param Mapping A pointer to the mapping\r
195\r
196 @retval !=NULL Pointer to the device path that corresponds to the\r
197 device mapping. The returned pointer does not need\r
198 to be freed.\r
199 @retval NULL There is no device path associated with the\r
200 specified mapping.\r
201**/\r
202CONST EFI_DEVICE_PATH_PROTOCOL *\r
203EFIAPI\r
47d20b54
MK
204EfiShellGetDevicePathFromMap (\r
205 IN CONST CHAR16 *Mapping\r
a405b86d 206 )\r
207{\r
208 SHELL_MAP_LIST *MapListItem;\r
209 CHAR16 *NewName;\r
210 UINTN Size;\r
211\r
212 NewName = NULL;\r
213 Size = 0;\r
214\r
47d20b54
MK
215 StrnCatGrow (&NewName, &Size, Mapping, 0);\r
216 if (Mapping[StrLen (Mapping)-1] != L':') {\r
217 StrnCatGrow (&NewName, &Size, L":", 0);\r
a405b86d 218 }\r
219\r
47d20b54 220 MapListItem = ShellCommandFindMapItem (NewName);\r
a405b86d 221\r
47d20b54 222 FreePool (NewName);\r
a405b86d 223\r
224 if (MapListItem != NULL) {\r
225 return (MapListItem->DevicePath);\r
226 }\r
47d20b54
MK
227\r
228 return (NULL);\r
a405b86d 229}\r
230\r
231/**\r
232 Gets the mapping(s) that most closely matches the device path.\r
233\r
234 This function gets the mapping which corresponds to the device path *DevicePath. If\r
235 there is no exact match, then the mapping which most closely matches *DevicePath\r
236 is returned, and *DevicePath is updated to point to the remaining portion of the\r
237 device path. If there is an exact match, the mapping is returned and *DevicePath\r
238 points to the end-of-device-path node.\r
239\r
6a5033ca 240 If there are multiple map names they will be semi-colon separated in the\r
a405b86d 241 NULL-terminated string.\r
242\r
243 @param DevicePath On entry, points to a device path pointer. On\r
244 exit, updates the pointer to point to the\r
245 portion of the device path after the mapping.\r
246\r
247 @retval NULL No mapping was found.\r
248 @return !=NULL Pointer to NULL-terminated mapping. The buffer\r
249 is callee allocated and should be freed by the caller.\r
250**/\r
251CONST CHAR16 *\r
252EFIAPI\r
47d20b54
MK
253EfiShellGetMapFromDevicePath (\r
254 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
a405b86d 255 )\r
256{\r
47d20b54
MK
257 SHELL_MAP_LIST *Node;\r
258 CHAR16 *PathForReturn;\r
259 UINTN PathSize;\r
260\r
261 // EFI_HANDLE PathHandle;\r
262 // EFI_HANDLE MapHandle;\r
263 // EFI_STATUS Status;\r
264 // EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
265 // EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
266\r
267 if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
a405b86d 268 return (NULL);\r
269 }\r
270\r
271 PathForReturn = NULL;\r
272 PathSize = 0;\r
273\r
47d20b54
MK
274 for ( Node = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
275 ; !IsNull (&gShellMapList.Link, &Node->Link)\r
276 ; Node = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &Node->Link)\r
277 )\r
278 {\r
a405b86d 279 //\r
280 // check for exact match\r
281 //\r
47d20b54
MK
282 if (DevicePathCompare (DevicePath, &Node->DevicePath) == 0) {\r
283 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
a405b86d 284 if (PathSize != 0) {\r
47d20b54 285 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L";", 0);\r
a405b86d 286 }\r
47d20b54
MK
287\r
288 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, Node->MapName, 0);\r
a405b86d 289 }\r
290 }\r
47d20b54 291\r
a405b86d 292 if (PathForReturn != NULL) {\r
293 while (!IsDevicePathEndType (*DevicePath)) {\r
294 *DevicePath = NextDevicePathNode (*DevicePath);\r
295 }\r
47d20b54 296\r
592bf33a
MK
297 //\r
298 // Do not call SetDevicePathEndNode() if the device path node is already the\r
299 // end of an entire device path.\r
300 //\r
301 if (!IsDevicePathEnd (*DevicePath)) {\r
302 SetDevicePathEndNode (*DevicePath);\r
303 }\r
a405b86d 304 }\r
a405b86d 305\r
47d20b54
MK
306 /*\r
307 ///@todo finish code for inexact matches.\r
308 if (PathForReturn == NULL) {\r
309 PathSize = 0;\r
310\r
311 DevicePathCopy = DuplicateDevicePath(*DevicePath);\r
312 ASSERT(DevicePathCopy != NULL);\r
313 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
314 ASSERT_EFI_ERROR(Status);\r
315 //\r
316 // check each of the device paths we have to get the root of the path for consist mappings\r
317 //\r
318 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
319 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
320 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
321 ){\r
322 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {\r
323 continue;\r
324 }\r
325 MapPathCopy = DuplicateDevicePath(Node->DevicePath);\r
326 ASSERT(MapPathCopy != NULL);\r
327 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
328 if (MapHandle == PathHandle) {\r
a405b86d 329\r
47d20b54 330 *DevicePath = DevicePathCopy;\r
a405b86d 331\r
47d20b54
MK
332 MapPathCopy = NULL;\r
333 DevicePathCopy = NULL;\r
334 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
335 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
336 break;\r
337 }\r
a405b86d 338 }\r
47d20b54
MK
339 //\r
340 // now add on the non-consistent mappings\r
341 //\r
342 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
343 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
344 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
345 ){\r
346 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {\r
347 continue;\r
348 }\r
349 MapPathCopy = Node->DevicePath;\r
350 ASSERT(MapPathCopy != NULL);\r
351 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
352 if (MapHandle == PathHandle) {\r
353 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
354 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
355 break;\r
356 }\r
a405b86d 357 }\r
358 }\r
47d20b54 359 */\r
a405b86d 360\r
47d20b54 361 return (AddBufferToFreeList (PathForReturn));\r
a405b86d 362}\r
363\r
364/**\r
365 Converts a device path to a file system-style path.\r
366\r
367 This function converts a device path to a file system path by replacing part, or all, of\r
368 the device path with the file-system mapping. If there are more than one application\r
369 file system mappings, the one that most closely matches Path will be used.\r
370\r
371 @param Path The pointer to the device path\r
372\r
373 @retval NULL the device path could not be found.\r
374 @return all The pointer of the NULL-terminated file path. The path\r
375 is callee-allocated and should be freed by the caller.\r
376**/\r
377CHAR16 *\r
378EFIAPI\r
47d20b54
MK
379EfiShellGetFilePathFromDevicePath (\r
380 IN CONST EFI_DEVICE_PATH_PROTOCOL *Path\r
a405b86d 381 )\r
382{\r
383 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
47d20b54
MK
384 EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
385 SHELL_MAP_LIST *MapListItem;\r
386 CHAR16 *PathForReturn;\r
387 UINTN PathSize;\r
388 EFI_HANDLE PathHandle;\r
389 EFI_HANDLE MapHandle;\r
390 EFI_STATUS Status;\r
391 FILEPATH_DEVICE_PATH *FilePath;\r
392 FILEPATH_DEVICE_PATH *AlignedNode;\r
a405b86d 393\r
394 PathForReturn = NULL;\r
47d20b54 395 PathSize = 0;\r
a405b86d 396\r
47d20b54
MK
397 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL *)Path;\r
398 ASSERT (DevicePathCopy != NULL);\r
a405b86d 399 if (DevicePathCopy == NULL) {\r
400 return (NULL);\r
401 }\r
a405b86d 402\r
47d20b54
MK
403 /// @todo BlockIo?\r
404 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
405\r
406 if (EFI_ERROR (Status)) {\r
a405b86d 407 return (NULL);\r
408 }\r
47d20b54 409\r
a405b86d 410 //\r
411 // check each of the device paths we have to get the root of the path\r
412 //\r
47d20b54
MK
413 for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode (&gShellMapList.Link)\r
414 ; !IsNull (&gShellMapList.Link, &MapListItem->Link)\r
415 ; MapListItem = (SHELL_MAP_LIST *)GetNextNode (&gShellMapList.Link, &MapListItem->Link)\r
416 )\r
417 {\r
418 MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL *)MapListItem->DevicePath;\r
419 ASSERT (MapPathCopy != NULL);\r
420 /// @todo BlockIo?\r
421 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
a405b86d 422 if (MapHandle == PathHandle) {\r
47d20b54
MK
423 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
424 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, MapListItem->MapName, 0);\r
a405b86d 425 //\r
426 // go through all the remaining nodes in the device path\r
427 //\r
47d20b54
MK
428 for ( FilePath = (FILEPATH_DEVICE_PATH *)DevicePathCopy\r
429 ; !IsDevicePathEnd (&FilePath->Header)\r
430 ; FilePath = (FILEPATH_DEVICE_PATH *)NextDevicePathNode (&FilePath->Header)\r
431 )\r
432 {\r
a405b86d 433 //\r
898378c2 434 // If any node is not a file path node, then the conversion can not be completed\r
a405b86d 435 //\r
47d20b54
MK
436 if ((DevicePathType (&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
437 (DevicePathSubType (&FilePath->Header) != MEDIA_FILEPATH_DP))\r
438 {\r
439 FreePool (PathForReturn);\r
898378c2
MK
440 return NULL;\r
441 }\r
6ddc2ff3 442\r
898378c2
MK
443 //\r
444 // append the path part onto the filepath.\r
445 //\r
47d20b54 446 ASSERT ((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
898378c2 447\r
47d20b54 448 AlignedNode = AllocateCopyPool (DevicePathNodeLength (FilePath), FilePath);\r
9168df3d
RN
449 if (AlignedNode == NULL) {\r
450 FreePool (PathForReturn);\r
451 return NULL;\r
452 }\r
898378c2
MK
453\r
454 // File Path Device Path Nodes 'can optionally add a "\" separator to\r
455 // the beginning and/or the end of the Path Name string.'\r
456 // (UEFI Spec 2.4 section 9.3.6.4).\r
457 // If necessary, add a "\", but otherwise don't\r
458 // (This is specified in the above section, and also implied by the\r
459 // UEFI Shell spec section 3.7)\r
460 if ((PathSize != 0) &&\r
461 (PathForReturn != NULL) &&\r
4f046505 462 (PathForReturn[PathSize / sizeof (CHAR16) - 1] != L'\\') &&\r
47d20b54
MK
463 (AlignedNode->PathName[0] != L'\\'))\r
464 {\r
898378c2 465 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
a405b86d 466 }\r
898378c2 467\r
47d20b54
MK
468 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
469 FreePool (AlignedNode);\r
a405b86d 470 } // for loop of remaining nodes\r
471 }\r
47d20b54 472\r
a405b86d 473 if (PathForReturn != NULL) {\r
474 break;\r
475 }\r
476 } // for loop of paths to check\r
47d20b54
MK
477\r
478 return (PathForReturn);\r
a405b86d 479}\r
480\r
481/**\r
482 Converts a file system style name to a device path.\r
483\r
484 This function converts a file system style name to a device path, by replacing any\r
485 mapping references to the associated device path.\r
486\r
532691c8 487 @param[in] Path The pointer to the path.\r
a405b86d 488\r
532691c8 489 @return The pointer of the file path. The file path is callee\r
a405b86d 490 allocated and should be freed by the caller.\r
532691c8 491 @retval NULL The path could not be found.\r
492 @retval NULL There was not enough available memory.\r
a405b86d 493**/\r
494EFI_DEVICE_PATH_PROTOCOL *\r
495EFIAPI\r
47d20b54
MK
496EfiShellGetDevicePathFromFilePath (\r
497 IN CONST CHAR16 *Path\r
a405b86d 498 )\r
499{\r
500 CHAR16 *MapName;\r
501 CHAR16 *NewPath;\r
502 CONST CHAR16 *Cwd;\r
503 UINTN Size;\r
504 CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
505 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
506 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree;\r
507 EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn;\r
508 EFI_HANDLE Handle;\r
509 EFI_STATUS Status;\r
510\r
8be0ba36 511 if (Path == NULL) {\r
512 return (NULL);\r
513 }\r
514\r
a405b86d 515 MapName = NULL;\r
8be0ba36 516 NewPath = NULL;\r
a405b86d 517\r
47d20b54
MK
518 if (StrStr (Path, L":") == NULL) {\r
519 Cwd = EfiShellGetCurDir (NULL);\r
a405b86d 520 if (Cwd == NULL) {\r
521 return (NULL);\r
522 }\r
47d20b54
MK
523\r
524 Size = StrSize (Cwd) + StrSize (Path);\r
525 NewPath = AllocateZeroPool (Size);\r
532691c8 526 if (NewPath == NULL) {\r
527 return (NULL);\r
528 }\r
47d20b54
MK
529\r
530 StrCpyS (NewPath, Size/sizeof (CHAR16), Cwd);\r
531 StrCatS (NewPath, Size/sizeof (CHAR16), L"\\");\r
733f138d 532 if (*Path == L'\\') {\r
533 Path++;\r
47d20b54
MK
534 while (PathRemoveLastItem (NewPath)) {\r
535 }\r
a405b86d 536 }\r
47d20b54
MK
537\r
538 StrCatS (NewPath, Size/sizeof (CHAR16), Path);\r
539 DevicePathForReturn = EfiShellGetDevicePathFromFilePath (NewPath);\r
540 FreePool (NewPath);\r
a405b86d 541 return (DevicePathForReturn);\r
542 }\r
543\r
544 Size = 0;\r
545 //\r
546 // find the part before (but including) the : for the map name\r
547 //\r
47d20b54
MK
548 ASSERT ((MapName == NULL && Size == 0) || (MapName != NULL));\r
549 MapName = StrnCatGrow (&MapName, &Size, Path, (StrStr (Path, L":")-Path+1));\r
550 if ((MapName == NULL) || (MapName[StrLen (MapName)-1] != L':')) {\r
a405b86d 551 return (NULL);\r
552 }\r
553\r
554 //\r
555 // look up the device path in the map\r
556 //\r
47d20b54 557 DevicePath = EfiShellGetDevicePathFromMap (MapName);\r
a405b86d 558 if (DevicePath == NULL) {\r
559 //\r
560 // Must have been a bad Mapname\r
561 //\r
562 return (NULL);\r
563 }\r
564\r
565 //\r
566 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)\r
567 //\r
47d20b54 568 DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath (DevicePath);\r
a405b86d 569 if (DevicePathCopy == NULL) {\r
47d20b54 570 FreePool (MapName);\r
a405b86d 571 return (NULL);\r
572 }\r
573\r
574 //\r
575 // get the handle\r
576 //\r
47d20b54
MK
577 /// @todo BlockIo?\r
578 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
579 if (EFI_ERROR (Status)) {\r
a405b86d 580 if (DevicePathCopyForFree != NULL) {\r
47d20b54 581 FreePool (DevicePathCopyForFree);\r
a405b86d 582 }\r
47d20b54
MK
583\r
584 FreePool (MapName);\r
a405b86d 585 return (NULL);\r
586 }\r
587\r
588 //\r
589 // build the full device path\r
590 //\r
47d20b54
MK
591 if ((*(Path+StrLen (MapName)) != CHAR_NULL) &&\r
592 (*(Path+StrLen (MapName)+1) == CHAR_NULL))\r
593 {\r
594 DevicePathForReturn = FileDevicePath (Handle, L"\\");\r
e35b5317 595 } else {\r
47d20b54 596 DevicePathForReturn = FileDevicePath (Handle, Path+StrLen (MapName));\r
e35b5317 597 }\r
a405b86d 598\r
47d20b54 599 FreePool (MapName);\r
a405b86d 600 if (DevicePathCopyForFree != NULL) {\r
47d20b54 601 FreePool (DevicePathCopyForFree);\r
a405b86d 602 }\r
603\r
604 return (DevicePathForReturn);\r
605}\r
606\r
607/**\r
608 Gets the name of the device specified by the device handle.\r
609\r
610 This function gets the user-readable name of the device specified by the device\r
611 handle. If no user-readable name could be generated, then *BestDeviceName will be\r
612 NULL and EFI_NOT_FOUND will be returned.\r
613\r
614 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the\r
615 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on\r
616 DeviceHandle.\r
617\r
618 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the\r
619 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.\r
620 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and\r
621 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then\r
622 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.\r
623\r
624 @param DeviceHandle The handle of the device.\r
625 @param Flags Determines the possible sources of component names.\r
626 Valid bits are:\r
627 EFI_DEVICE_NAME_USE_COMPONENT_NAME\r
628 EFI_DEVICE_NAME_USE_DEVICE_PATH\r
629 @param Language A pointer to the language specified for the device\r
630 name, in the same format as described in the UEFI\r
631 specification, Appendix M\r
632 @param BestDeviceName On return, points to the callee-allocated NULL-\r
633 terminated name of the device. If no device name\r
634 could be found, points to NULL. The name must be\r
635 freed by the caller...\r
636\r
637 @retval EFI_SUCCESS Get the name successfully.\r
638 @retval EFI_NOT_FOUND Fail to get the device name.\r
639 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.\r
640 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL\r
641 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL\r
642**/\r
643EFI_STATUS\r
644EFIAPI\r
47d20b54
MK
645EfiShellGetDeviceName (\r
646 IN EFI_HANDLE DeviceHandle,\r
647 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags,\r
648 IN CHAR8 *Language,\r
649 OUT CHAR16 **BestDeviceName\r
a405b86d 650 )\r
651{\r
47d20b54
MK
652 EFI_STATUS Status;\r
653 EFI_COMPONENT_NAME2_PROTOCOL *CompName2;\r
654 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
655 EFI_HANDLE *HandleList;\r
656 UINTN HandleCount;\r
657 UINTN LoopVar;\r
658 CHAR16 *DeviceNameToReturn;\r
659 CHAR8 *Lang;\r
660 UINTN ParentControllerCount;\r
661 EFI_HANDLE *ParentControllerBuffer;\r
662 UINTN ParentDriverCount;\r
663 EFI_HANDLE *ParentDriverBuffer;\r
664\r
665 if ((BestDeviceName == NULL) ||\r
666 (DeviceHandle == NULL)\r
667 )\r
668 {\r
a405b86d 669 return (EFI_INVALID_PARAMETER);\r
670 }\r
671\r
672 //\r
673 // make sure one of the 2 supported bits is on\r
674 //\r
675 if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) &&\r
47d20b54
MK
676 ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0))\r
677 {\r
a405b86d 678 return (EFI_INVALID_PARAMETER);\r
679 }\r
680\r
47d20b54
MK
681 DeviceNameToReturn = NULL;\r
682 *BestDeviceName = NULL;\r
683 HandleList = NULL;\r
684 HandleCount = 0;\r
685 Lang = NULL;\r
a405b86d 686\r
687 if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) {\r
47d20b54
MK
688 Status = ParseHandleDatabaseByRelationship (\r
689 NULL,\r
690 DeviceHandle,\r
691 HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER,\r
692 &HandleCount,\r
693 &HandleList\r
694 );\r
695 for (LoopVar = 0; LoopVar < HandleCount; LoopVar++) {\r
a405b86d 696 //\r
697 // Go through those handles until we get one that passes for GetComponentName\r
698 //\r
47d20b54
MK
699 Status = gBS->OpenProtocol (\r
700 HandleList[LoopVar],\r
701 &gEfiComponentName2ProtocolGuid,\r
702 (VOID **)&CompName2,\r
703 gImageHandle,\r
704 NULL,\r
705 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
706 );\r
707 if (EFI_ERROR (Status)) {\r
708 Status = gBS->OpenProtocol (\r
709 HandleList[LoopVar],\r
710 &gEfiComponentNameProtocolGuid,\r
711 (VOID **)&CompName2,\r
712 gImageHandle,\r
713 NULL,\r
714 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
715 );\r
a405b86d 716 }\r
717\r
47d20b54 718 if (EFI_ERROR (Status)) {\r
a405b86d 719 continue;\r
720 }\r
47d20b54
MK
721\r
722 Lang = GetBestLanguageForDriver (CompName2->SupportedLanguages, Language, FALSE);\r
723 Status = CompName2->GetControllerName (CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
724 FreePool (Lang);\r
a405b86d 725 Lang = NULL;\r
47d20b54 726 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
a405b86d 727 break;\r
728 }\r
729 }\r
47d20b54 730\r
a405b86d 731 if (HandleList != NULL) {\r
47d20b54 732 FreePool (HandleList);\r
a405b86d 733 }\r
733f138d 734\r
735 //\r
736 // Now check the parent controller using this as the child.\r
737 //\r
47d20b54
MK
738 if (DeviceNameToReturn == NULL) {\r
739 PARSE_HANDLE_DATABASE_PARENTS (DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);\r
740 for (LoopVar = 0; LoopVar < ParentControllerCount; LoopVar++) {\r
741 PARSE_HANDLE_DATABASE_UEFI_DRIVERS (ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);\r
742 for (HandleCount = 0; HandleCount < ParentDriverCount; HandleCount++) {\r
733f138d 743 //\r
744 // try using that driver's component name with controller and our driver as the child.\r
745 //\r
47d20b54
MK
746 Status = gBS->OpenProtocol (\r
747 ParentDriverBuffer[HandleCount],\r
748 &gEfiComponentName2ProtocolGuid,\r
749 (VOID **)&CompName2,\r
750 gImageHandle,\r
751 NULL,\r
752 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
753 );\r
754 if (EFI_ERROR (Status)) {\r
755 Status = gBS->OpenProtocol (\r
756 ParentDriverBuffer[HandleCount],\r
757 &gEfiComponentNameProtocolGuid,\r
758 (VOID **)&CompName2,\r
759 gImageHandle,\r
760 NULL,\r
761 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
762 );\r
733f138d 763 }\r
764\r
47d20b54 765 if (EFI_ERROR (Status)) {\r
733f138d 766 continue;\r
767 }\r
47d20b54
MK
768\r
769 Lang = GetBestLanguageForDriver (CompName2->SupportedLanguages, Language, FALSE);\r
770 Status = CompName2->GetControllerName (CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
771 FreePool (Lang);\r
733f138d 772 Lang = NULL;\r
47d20b54 773 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
733f138d 774 break;\r
775 }\r
733f138d 776 }\r
47d20b54
MK
777\r
778 SHELL_FREE_NON_NULL (ParentDriverBuffer);\r
779 if (!EFI_ERROR (Status) && (DeviceNameToReturn != NULL)) {\r
733f138d 780 break;\r
781 }\r
782 }\r
47d20b54
MK
783\r
784 SHELL_FREE_NON_NULL (ParentControllerBuffer);\r
733f138d 785 }\r
47d20b54 786\r
733f138d 787 //\r
788 // dont return on fail since we will try device path if that bit is on\r
789 //\r
47d20b54
MK
790 if (DeviceNameToReturn != NULL) {\r
791 ASSERT (BestDeviceName != NULL);\r
792 StrnCatGrow (BestDeviceName, NULL, DeviceNameToReturn, 0);\r
a405b86d 793 return (EFI_SUCCESS);\r
794 }\r
a405b86d 795 }\r
47d20b54 796\r
a405b86d 797 if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
47d20b54
MK
798 Status = gBS->OpenProtocol (\r
799 DeviceHandle,\r
800 &gEfiDevicePathProtocolGuid,\r
801 (VOID **)&DevicePath,\r
802 gImageHandle,\r
803 NULL,\r
804 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
805 );\r
806 if (!EFI_ERROR (Status)) {\r
863986b3
RN
807 //\r
808 // use device path to text on the device path\r
809 //\r
47d20b54 810 *BestDeviceName = ConvertDevicePathToText (DevicePath, TRUE, TRUE);\r
863986b3 811 return (EFI_SUCCESS);\r
a405b86d 812 }\r
813 }\r
47d20b54 814\r
a405b86d 815 //\r
816 // none of the selected bits worked.\r
817 //\r
818 return (EFI_NOT_FOUND);\r
819}\r
820\r
821/**\r
822 Opens the root directory of a device on a handle\r
823\r
824 This function opens the root directory of a device and returns a file handle to it.\r
825\r
826 @param DeviceHandle The handle of the device that contains the volume.\r
827 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
828 device.\r
829\r
830 @retval EFI_SUCCESS Root opened successfully.\r
831 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
832 could not be opened.\r
833 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
996bd353
HW
834 @retval EFI_DEVICE_ERROR The device had an error.\r
835 @retval Others Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume().\r
a405b86d 836**/\r
837EFI_STATUS\r
838EFIAPI\r
47d20b54
MK
839EfiShellOpenRootByHandle (\r
840 IN EFI_HANDLE DeviceHandle,\r
841 OUT SHELL_FILE_HANDLE *FileHandle\r
a405b86d 842 )\r
843{\r
47d20b54
MK
844 EFI_STATUS Status;\r
845 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
846 EFI_FILE_PROTOCOL *RealFileHandle;\r
847 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
a405b86d 848\r
849 //\r
850 // get the simple file system interface\r
851 //\r
47d20b54
MK
852 Status = gBS->OpenProtocol (\r
853 DeviceHandle,\r
854 &gEfiSimpleFileSystemProtocolGuid,\r
855 (VOID **)&SimpleFileSystem,\r
856 gImageHandle,\r
857 NULL,\r
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
859 );\r
860 if (EFI_ERROR (Status)) {\r
a405b86d 861 return (EFI_NOT_FOUND);\r
862 }\r
863\r
47d20b54
MK
864 Status = gBS->OpenProtocol (\r
865 DeviceHandle,\r
866 &gEfiDevicePathProtocolGuid,\r
867 (VOID **)&DevPath,\r
868 gImageHandle,\r
869 NULL,\r
870 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
871 );\r
872 if (EFI_ERROR (Status)) {\r
a405b86d 873 return (EFI_NOT_FOUND);\r
874 }\r
47d20b54 875\r
a405b86d 876 //\r
877 // Open the root volume now...\r
878 //\r
47d20b54
MK
879 Status = SimpleFileSystem->OpenVolume (SimpleFileSystem, &RealFileHandle);\r
880 if (EFI_ERROR (Status)) {\r
996bd353
HW
881 return Status;\r
882 }\r
883\r
47d20b54 884 *FileHandle = ConvertEfiFileProtocolToShellHandle (RealFileHandle, EfiShellGetMapFromDevicePath (&DevPath));\r
996bd353 885 return (EFI_SUCCESS);\r
a405b86d 886}\r
887\r
888/**\r
889 Opens the root directory of a device.\r
890\r
891 This function opens the root directory of a device and returns a file handle to it.\r
892\r
893 @param DevicePath Points to the device path corresponding to the device where the\r
894 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.\r
895 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
896 device.\r
897\r
898 @retval EFI_SUCCESS Root opened successfully.\r
899 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
900 could not be opened.\r
901 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
902 @retval EFI_DEVICE_ERROR The device had an error\r
8be0ba36 903 @retval EFI_INVALID_PARAMETER FileHandle is NULL.\r
a405b86d 904**/\r
905EFI_STATUS\r
906EFIAPI\r
47d20b54
MK
907EfiShellOpenRoot (\r
908 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
909 OUT SHELL_FILE_HANDLE *FileHandle\r
a405b86d 910 )\r
911{\r
47d20b54
MK
912 EFI_STATUS Status;\r
913 EFI_HANDLE Handle;\r
a405b86d 914\r
8be0ba36 915 if (FileHandle == NULL) {\r
916 return (EFI_INVALID_PARAMETER);\r
917 }\r
918\r
a405b86d 919 //\r
920 // find the handle of the device with that device handle and the file system\r
921 //\r
47d20b54
MK
922 /// @todo BlockIo?\r
923 Status = gBS->LocateDevicePath (\r
924 &gEfiSimpleFileSystemProtocolGuid,\r
925 &DevicePath,\r
926 &Handle\r
927 );\r
928 if (EFI_ERROR (Status)) {\r
a405b86d 929 return (EFI_NOT_FOUND);\r
930 }\r
931\r
47d20b54 932 return (EfiShellOpenRootByHandle (Handle, FileHandle));\r
a405b86d 933}\r
934\r
935/**\r
936 Returns whether any script files are currently being processed.\r
937\r
938 @retval TRUE There is at least one script file active.\r
939 @retval FALSE No script files are active now.\r
940\r
941**/\r
942BOOLEAN\r
943EFIAPI\r
944EfiShellBatchIsActive (\r
945 VOID\r
946 )\r
947{\r
47d20b54 948 if (ShellCommandGetCurrentScriptFile () == NULL) {\r
a405b86d 949 return (FALSE);\r
950 }\r
47d20b54 951\r
a405b86d 952 return (TRUE);\r
953}\r
954\r
955/**\r
956 Worker function to open a file based on a device path. this will open the root\r
957 of the volume and then traverse down to the file itself.\r
958\r
959 @param DevicePath Device Path of the file.\r
960 @param FileHandle Pointer to the file upon a successful return.\r
961 @param OpenMode mode to open file in.\r
962 @param Attributes the File Attributes to use when creating a new file.\r
963\r
964 @retval EFI_SUCCESS the file is open and FileHandle is valid\r
6a5033ca
AC
965 @retval EFI_UNSUPPORTED the device path contained non-path elements\r
966 @retval other an error occurred.\r
a405b86d 967**/\r
968EFI_STATUS\r
47d20b54
MK
969InternalOpenFileDevicePath (\r
970 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
971 OUT SHELL_FILE_HANDLE *FileHandle,\r
972 IN UINT64 OpenMode,\r
973 IN UINT64 Attributes OPTIONAL\r
a405b86d 974 )\r
975{\r
47d20b54
MK
976 EFI_STATUS Status;\r
977 FILEPATH_DEVICE_PATH *FilePathNode;\r
978 EFI_HANDLE Handle;\r
979 SHELL_FILE_HANDLE ShellHandle;\r
980 EFI_FILE_PROTOCOL *Handle1;\r
981 EFI_FILE_PROTOCOL *Handle2;\r
982 FILEPATH_DEVICE_PATH *AlignedNode;\r
a405b86d 983\r
8be0ba36 984 if (FileHandle == NULL) {\r
985 return (EFI_INVALID_PARAMETER);\r
986 }\r
a405b86d 987\r
47d20b54
MK
988 *FileHandle = NULL;\r
989 Handle1 = NULL;\r
990 Handle2 = NULL;\r
991 Handle = NULL;\r
992 ShellHandle = NULL;\r
993 FilePathNode = NULL;\r
994 AlignedNode = NULL;\r
a405b86d 995\r
47d20b54
MK
996 Status = EfiShellOpenRoot (DevicePath, &ShellHandle);\r
997\r
998 if (!EFI_ERROR (Status)) {\r
999 Handle1 = ConvertShellHandleToEfiFileProtocol (ShellHandle);\r
c154b997 1000 if (Handle1 != NULL) {\r
a405b86d 1001 //\r
6a5033ca 1002 // chop off the beginning part before the file system part...\r
a405b86d 1003 //\r
47d20b54
MK
1004 /// @todo BlockIo?\r
1005 Status = gBS->LocateDevicePath (\r
1006 &gEfiSimpleFileSystemProtocolGuid,\r
1007 &DevicePath,\r
1008 &Handle\r
1009 );\r
1010 if (!EFI_ERROR (Status)) {\r
a405b86d 1011 //\r
c154b997 1012 // To access as a file system, the file path should only\r
1013 // contain file path components. Follow the file path nodes\r
1014 // and find the target file\r
a405b86d 1015 //\r
c154b997 1016 for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
47d20b54
MK
1017 ; !IsDevicePathEnd (&FilePathNode->Header)\r
1018 ; FilePathNode = (FILEPATH_DEVICE_PATH *)NextDevicePathNode (&FilePathNode->Header)\r
1019 )\r
1020 {\r
1021 SHELL_FREE_NON_NULL (AlignedNode);\r
1022 AlignedNode = AllocateCopyPool (DevicePathNodeLength (FilePathNode), FilePathNode);\r
a405b86d 1023 //\r
c154b997 1024 // For file system access each node should be a file path component\r
a405b86d 1025 //\r
47d20b54
MK
1026 if ((DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH) ||\r
1027 (DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP)\r
1028 )\r
1029 {\r
c154b997 1030 Status = EFI_UNSUPPORTED;\r
1031 break;\r
1032 }\r
a405b86d 1033\r
1034 //\r
c154b997 1035 // Open this file path node\r
a405b86d 1036 //\r
c154b997 1037 Handle2 = Handle1;\r
1038 Handle1 = NULL;\r
1039\r
a405b86d 1040 //\r
c154b997 1041 // if this is the last node in the DevicePath always create (if that was requested).\r
a405b86d 1042 //\r
c154b997 1043 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
a405b86d 1044 Status = Handle2->Open (\r
47d20b54
MK
1045 Handle2,\r
1046 &Handle1,\r
1047 AlignedNode->PathName,\r
1048 OpenMode,\r
1049 Attributes\r
1050 );\r
c154b997 1051 } else {\r
c154b997 1052 //\r
1053 // This is not the last node and we dont want to 'create' existing\r
1054 // directory entries...\r
1055 //\r
1056\r
1057 //\r
1058 // open without letting it create\r
1059 // prevents error on existing files/directories\r
1060 //\r
1061 Status = Handle2->Open (\r
47d20b54
MK
1062 Handle2,\r
1063 &Handle1,\r
1064 AlignedNode->PathName,\r
1065 OpenMode &~EFI_FILE_MODE_CREATE,\r
1066 Attributes\r
1067 );\r
c154b997 1068 //\r
1069 // if above failed now open and create the 'item'\r
1070 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
1071 //\r
1072 if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
1073 Status = Handle2->Open (\r
47d20b54
MK
1074 Handle2,\r
1075 &Handle1,\r
1076 AlignedNode->PathName,\r
1077 OpenMode,\r
1078 Attributes\r
1079 );\r
c154b997 1080 }\r
a405b86d 1081 }\r
47d20b54 1082\r
c154b997 1083 //\r
1084 // Close the last node\r
1085 //\r
1086 ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
a405b86d 1087\r
c154b997 1088 //\r
1089 // If there's been an error, stop\r
1090 //\r
1091 if (EFI_ERROR (Status)) {\r
1092 break;\r
1093 }\r
1094 } // for loop\r
1095 }\r
a405b86d 1096 }\r
1097 }\r
47d20b54
MK
1098\r
1099 SHELL_FREE_NON_NULL (AlignedNode);\r
1100 if (EFI_ERROR (Status)) {\r
a405b86d 1101 if (Handle1 != NULL) {\r
47d20b54 1102 ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle1);\r
a405b86d 1103 }\r
1104 } else {\r
47d20b54 1105 *FileHandle = ConvertEfiFileProtocolToShellHandle (Handle1, ShellFileHandleGetPath (ShellHandle));\r
a405b86d 1106 }\r
47d20b54 1107\r
a405b86d 1108 return (Status);\r
1109}\r
1110\r
1111/**\r
1112 Creates a file or directory by name.\r
1113\r
1114 This function creates an empty new file or directory with the specified attributes and\r
1115 returns the new file's handle. If the file already exists and is read-only, then\r
1116 EFI_INVALID_PARAMETER will be returned.\r
1117\r
1118 If the file already existed, it is truncated and its attributes updated. If the file is\r
1119 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.\r
1120\r
1121 If the file name begins with >v, then the file handle which is returned refers to the\r
1122 shell environment variable with the specified name. If the shell environment variable\r
1123 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.\r
1124\r
1125 @param FileName Pointer to NULL-terminated file path\r
6a5033ca 1126 @param FileAttribs The new file's attributes. the different attributes are\r
a405b86d 1127 described in EFI_FILE_PROTOCOL.Open().\r
1128 @param FileHandle On return, points to the created file handle or directory's handle\r
1129\r
1130 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.\r
1131 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1132 @retval EFI_UNSUPPORTED could not open the file path\r
6a5033ca 1133 @retval EFI_NOT_FOUND the specified file could not be found on the device, or could not\r
a405b86d 1134 file the file system on the device.\r
1135 @retval EFI_NO_MEDIA the device has no medium.\r
1136 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1137 longer supported.\r
1138 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1139 the DirName.\r
1140 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1141 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1142 when the media is write-protected.\r
1143 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
1144 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
1145 @retval EFI_VOLUME_FULL The volume is full.\r
1146**/\r
1147EFI_STATUS\r
1148EFIAPI\r
47d20b54
MK
1149EfiShellCreateFile (\r
1150 IN CONST CHAR16 *FileName,\r
1151 IN UINT64 FileAttribs,\r
1152 OUT SHELL_FILE_HANDLE *FileHandle\r
a405b86d 1153 )\r
1154{\r
1155 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1156 EFI_STATUS Status;\r
31e5b912 1157 BOOLEAN Volatile;\r
a405b86d 1158\r
1159 //\r
1160 // Is this for an environment variable\r
1161 // do we start with >v\r
1162 //\r
47d20b54 1163 if (StrStr (FileName, L">v") == FileName) {\r
31e5b912
RN
1164 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1165 if (EFI_ERROR (Status)) {\r
1166 return Status;\r
1167 }\r
47d20b54 1168\r
31e5b912 1169 if (!Volatile) {\r
a405b86d 1170 return (EFI_INVALID_PARAMETER);\r
1171 }\r
47d20b54
MK
1172\r
1173 *FileHandle = CreateFileInterfaceEnv (FileName+2);\r
a405b86d 1174 return (EFI_SUCCESS);\r
1175 }\r
1176\r
1177 //\r
1178 // We are opening a regular file.\r
1179 //\r
47d20b54 1180 DevicePath = EfiShellGetDevicePathFromFilePath (FileName);\r
a405b86d 1181 if (DevicePath == NULL) {\r
1182 return (EFI_NOT_FOUND);\r
1183 }\r
1184\r
47d20b54
MK
1185 Status = InternalOpenFileDevicePath (DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);\r
1186 FreePool (DevicePath);\r
a405b86d 1187\r
47d20b54 1188 return (Status);\r
a405b86d 1189}\r
1190\r
09fd5328
JC
1191/**\r
1192 Register a GUID and a localized human readable name for it.\r
1193\r
1194 If Guid is not assigned a name, then assign GuidName to Guid. This list of GUID\r
1195 names must be used whenever a shell command outputs GUID information.\r
1196\r
1197 This function is only available when the major and minor versions in the\r
1198 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
1199\r
1200 @param[in] Guid A pointer to the GUID being registered.\r
1201 @param[in] GuidName A pointer to the localized name for the GUID being registered.\r
1202\r
1203 @retval EFI_SUCCESS The operation was successful.\r
1204 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
1205 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
1206 @retval EFI_ACCESS_DENIED Guid already is assigned a name.\r
1207**/\r
1208EFI_STATUS\r
c20bd8e1 1209EFIAPI\r
47d20b54
MK
1210EfiShellRegisterGuidName (\r
1211 IN CONST EFI_GUID *Guid,\r
1212 IN CONST CHAR16 *GuidName\r
09fd5328
JC
1213 )\r
1214{\r
47d20b54 1215 return (AddNewGuidNameMapping (Guid, GuidName, NULL));\r
09fd5328
JC
1216}\r
1217\r
a405b86d 1218/**\r
1219 Opens a file or a directory by file name.\r
1220\r
1221 This function opens the specified file in the specified OpenMode and returns a file\r
1222 handle.\r
1223 If the file name begins with >v, then the file handle which is returned refers to the\r
1224 shell environment variable with the specified name. If the shell environment variable\r
1225 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then\r
1226 EFI_INVALID_PARAMETER is returned.\r
1227\r
1228 If the file name is >i, then the file handle which is returned refers to the standard\r
1229 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER\r
1230 is returned.\r
1231\r
1232 If the file name is >o, then the file handle which is returned refers to the standard\r
1233 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1234 is returned.\r
1235\r
1236 If the file name is >e, then the file handle which is returned refers to the standard\r
1237 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1238 is returned.\r
1239\r
1240 If the file name is NUL, then the file handle that is returned refers to the standard NUL\r
1241 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is\r
1242 returned.\r
1243\r
1244 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the\r
1245 FileHandle is NULL.\r
1246\r
1247 @param FileName Points to the NULL-terminated UCS-2 encoded file name.\r
1248 @param FileHandle On return, points to the file handle.\r
1249 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or\r
1250 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI\r
1251 Specification.\r
1252 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.\r
1253 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.\r
1254 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.\r
1255 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file\r
1256 system could not be found on the device. FileHandle is NULL.\r
1257 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.\r
1258 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1259 longer supported. FileHandle is NULL.\r
1260 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1261 the FileName. FileHandle is NULL.\r
1262 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.\r
1263 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1264 when the media is write-protected. FileHandle is NULL.\r
1265 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.\r
1266 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle\r
1267 is NULL.\r
1268 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.\r
1269**/\r
1270EFI_STATUS\r
1271EFIAPI\r
47d20b54
MK
1272EfiShellOpenFileByName (\r
1273 IN CONST CHAR16 *FileName,\r
1274 OUT SHELL_FILE_HANDLE *FileHandle,\r
1275 IN UINT64 OpenMode\r
a405b86d 1276 )\r
1277{\r
47d20b54
MK
1278 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1279 EFI_STATUS Status;\r
1280 BOOLEAN Volatile;\r
a405b86d 1281\r
1282 *FileHandle = NULL;\r
1283\r
1284 //\r
1285 // Is this for StdIn\r
1286 //\r
47d20b54 1287 if (StrCmp (FileName, L">i") == 0) {\r
a405b86d 1288 //\r
1289 // make sure not writing to StdIn\r
1290 //\r
1291 if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) {\r
1292 return (EFI_INVALID_PARAMETER);\r
1293 }\r
47d20b54 1294\r
a405b86d 1295 *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
47d20b54 1296 ASSERT (*FileHandle != NULL);\r
a405b86d 1297 return (EFI_SUCCESS);\r
1298 }\r
1299\r
1300 //\r
1301 // Is this for StdOut\r
1302 //\r
47d20b54 1303 if (StrCmp (FileName, L">o") == 0) {\r
a405b86d 1304 //\r
1305 // make sure not writing to StdIn\r
1306 //\r
1307 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1308 return (EFI_INVALID_PARAMETER);\r
1309 }\r
47d20b54 1310\r
a405b86d 1311 *FileHandle = &FileInterfaceStdOut;\r
1312 return (EFI_SUCCESS);\r
1313 }\r
1314\r
1315 //\r
583448b4 1316 // Is this for NUL / NULL file\r
a405b86d 1317 //\r
47d20b54
MK
1318 if ((gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NUL") == 0) ||\r
1319 (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)FileName, L"NULL") == 0))\r
1320 {\r
a405b86d 1321 *FileHandle = &FileInterfaceNulFile;\r
1322 return (EFI_SUCCESS);\r
1323 }\r
1324\r
1325 //\r
1326 // Is this for StdErr\r
1327 //\r
47d20b54 1328 if (StrCmp (FileName, L">e") == 0) {\r
a405b86d 1329 //\r
1330 // make sure not writing to StdIn\r
1331 //\r
1332 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1333 return (EFI_INVALID_PARAMETER);\r
1334 }\r
47d20b54 1335\r
a405b86d 1336 *FileHandle = &FileInterfaceStdErr;\r
1337 return (EFI_SUCCESS);\r
1338 }\r
1339\r
1340 //\r
1341 // Is this for an environment variable\r
1342 // do we start with >v\r
1343 //\r
47d20b54 1344 if (StrStr (FileName, L">v") == FileName) {\r
31e5b912
RN
1345 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1346 if (EFI_ERROR (Status)) {\r
1347 return Status;\r
1348 }\r
47d20b54 1349\r
31e5b912 1350 if (!Volatile &&\r
47d20b54
MK
1351 ((OpenMode & EFI_FILE_MODE_WRITE) != 0))\r
1352 {\r
a405b86d 1353 return (EFI_INVALID_PARAMETER);\r
1354 }\r
47d20b54
MK
1355\r
1356 *FileHandle = CreateFileInterfaceEnv (FileName+2);\r
a405b86d 1357 return (EFI_SUCCESS);\r
1358 }\r
1359\r
1360 //\r
1361 // We are opening a regular file.\r
1362 //\r
47d20b54 1363 DevicePath = EfiShellGetDevicePathFromFilePath (FileName);\r
22cf747f 1364\r
a405b86d 1365 if (DevicePath == NULL) {\r
1366 return (EFI_NOT_FOUND);\r
1367 }\r
1368\r
1369 //\r
1370 // Copy the device path, open the file, then free the memory\r
1371 //\r
47d20b54
MK
1372 Status = InternalOpenFileDevicePath (DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes\r
1373 FreePool (DevicePath);\r
a405b86d 1374\r
47d20b54 1375 return (Status);\r
a405b86d 1376}\r
1377\r
1378/**\r
1379 Deletes the file specified by the file name.\r
1380\r
1381 This function deletes a file.\r
1382\r
1383 @param FileName Points to the NULL-terminated file name.\r
1384\r
1385 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.\r
1386 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
1387 @sa EfiShellCreateFile\r
1388**/\r
1389EFI_STATUS\r
1390EFIAPI\r
47d20b54
MK
1391EfiShellDeleteFileByName (\r
1392 IN CONST CHAR16 *FileName\r
a405b86d 1393 )\r
1394{\r
47d20b54
MK
1395 SHELL_FILE_HANDLE FileHandle;\r
1396 EFI_STATUS Status;\r
a405b86d 1397\r
0d807dae
ED
1398 FileHandle = NULL;\r
1399\r
a405b86d 1400 //\r
1401 // get a handle to the file\r
1402 //\r
47d20b54
MK
1403 Status = EfiShellCreateFile (\r
1404 FileName,\r
1405 0,\r
1406 &FileHandle\r
1407 );\r
1408 if (EFI_ERROR (Status)) {\r
a405b86d 1409 return (Status);\r
1410 }\r
47d20b54 1411\r
a405b86d 1412 //\r
1413 // now delete the file\r
1414 //\r
47d20b54
MK
1415 ShellFileHandleRemove (FileHandle);\r
1416 return (ShellInfoObject.NewEfiShellProtocol->DeleteFile (FileHandle));\r
a405b86d 1417}\r
1418\r
1419/**\r
1420 Disables the page break output mode.\r
1421**/\r
1422VOID\r
1423EFIAPI\r
1424EfiShellDisablePageBreak (\r
1425 VOID\r
1426 )\r
1427{\r
1428 ShellInfoObject.PageBreakEnabled = FALSE;\r
1429}\r
1430\r
1431/**\r
1432 Enables the page break output mode.\r
1433**/\r
1434VOID\r
1435EFIAPI\r
1436EfiShellEnablePageBreak (\r
1437 VOID\r
1438 )\r
1439{\r
1440 ShellInfoObject.PageBreakEnabled = TRUE;\r
1441}\r
1442\r
1443/**\r
1444 internal worker function to load and run an image via device path.\r
1445\r
b5ce69c3
QS
1446 @param ParentImageHandle A handle of the image that is executing the specified\r
1447 command line.\r
1448 @param DevicePath device path of the file to execute\r
1449 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1450 containing the command line. If NULL then the command-\r
1451 line will be empty.\r
1452 @param Environment Points to a NULL-terminated array of environment\r
1453 variables with the format 'x=y', where x is the\r
1454 environment variable name and y is the value. If this\r
1455 is NULL, then the current shell environment is used.\r
ba0014b9 1456\r
b5ce69c3 1457 @param[out] StartImageStatus Returned status from gBS->StartImage.\r
5223c121 1458\r
a405b86d 1459 @retval EFI_SUCCESS The command executed successfully. The status code\r
1460 returned by the command is pointed to by StatusCode.\r
1461 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1462 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1463 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1464**/\r
1465EFI_STATUS\r
47d20b54
MK
1466InternalShellExecuteDevicePath (\r
1467 IN CONST EFI_HANDLE *ParentImageHandle,\r
1468 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1469 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1470 IN CONST CHAR16 **Environment OPTIONAL,\r
1471 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
a405b86d 1472 )\r
1473{\r
47d20b54
MK
1474 EFI_STATUS Status;\r
1475 EFI_STATUS StartStatus;\r
1476 EFI_STATUS CleanupStatus;\r
1477 EFI_HANDLE NewHandle;\r
1478 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
1479 LIST_ENTRY OrigEnvs;\r
1480 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
1481 CHAR16 *ImagePath;\r
1482 UINTN Index;\r
1483 CHAR16 *Walker;\r
1484 CHAR16 *NewCmdLine;\r
5223c121 1485\r
a405b86d 1486 if (ParentImageHandle == NULL) {\r
1487 return (EFI_INVALID_PARAMETER);\r
1488 }\r
1489\r
47d20b54
MK
1490 InitializeListHead (&OrigEnvs);\r
1491 ZeroMem (&ShellParamsProtocol, sizeof (EFI_SHELL_PARAMETERS_PROTOCOL));\r
a405b86d 1492\r
1493 NewHandle = NULL;\r
ba0014b9 1494\r
4b6b543e
QS
1495 NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);\r
1496 if (NewCmdLine == NULL) {\r
1497 return EFI_OUT_OF_RESOURCES;\r
1498 }\r
1499\r
47d20b54
MK
1500 for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL; Walker++) {\r
1501 if ((*Walker == L'^') && (*(Walker+1) == L'#')) {\r
1502 CopyMem (Walker, Walker+1, StrSize (Walker) - sizeof (Walker[0]));\r
4b6b543e
QS
1503 }\r
1504 }\r
a405b86d 1505\r
1506 //\r
1507 // Load the image with:\r
1508 // FALSE - not from boot manager and NULL, 0 being not already in memory\r
1509 //\r
47d20b54
MK
1510 Status = gBS->LoadImage (\r
1511 FALSE,\r
1512 *ParentImageHandle,\r
1513 (EFI_DEVICE_PATH_PROTOCOL *)DevicePath,\r
1514 NULL,\r
1515 0,\r
1516 &NewHandle\r
1517 );\r
a405b86d 1518\r
47d20b54 1519 if (EFI_ERROR (Status)) {\r
a405b86d 1520 if (NewHandle != NULL) {\r
47d20b54 1521 gBS->UnloadImage (NewHandle);\r
a405b86d 1522 }\r
47d20b54 1523\r
a5bc2ff8 1524 FreePool (NewCmdLine);\r
a405b86d 1525 return (Status);\r
1526 }\r
a405b86d 1527\r
47d20b54
MK
1528 Status = gBS->OpenProtocol (\r
1529 NewHandle,\r
1530 &gEfiLoadedImageProtocolGuid,\r
1531 (VOID **)&LoadedImage,\r
1532 gImageHandle,\r
1533 NULL,\r
1534 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
1535 );\r
1536\r
1537 if (!EFI_ERROR (Status)) {\r
91a92220
QS
1538 //\r
1539 // If the image is not an app abort it.\r
1540 //\r
47d20b54
MK
1541 if (LoadedImage->ImageCodeType != EfiLoaderCode) {\r
1542 ShellPrintHiiEx (\r
ba0014b9
LG
1543 -1,\r
1544 -1,\r
91a92220
QS
1545 NULL,\r
1546 STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP),\r
1547 ShellInfoObject.HiiHandle\r
47d20b54 1548 );\r
91a92220
QS
1549 goto UnloadImage;\r
1550 }\r
1551\r
47d20b54 1552 ASSERT (LoadedImage->LoadOptionsSize == 0);\r
4b6b543e 1553 if (NewCmdLine != NULL) {\r
47d20b54
MK
1554 LoadedImage->LoadOptionsSize = (UINT32)StrSize (NewCmdLine);\r
1555 LoadedImage->LoadOptions = (VOID *)NewCmdLine;\r
a405b86d 1556 }\r
1557\r
1558 //\r
1559 // Save our current environment settings for later restoration if necessary\r
1560 //\r
1561 if (Environment != NULL) {\r
47d20b54
MK
1562 Status = GetEnvironmentVariableList (&OrigEnvs);\r
1563 if (!EFI_ERROR (Status)) {\r
1564 Status = SetEnvironmentVariables (Environment);\r
a405b86d 1565 }\r
1566 }\r
1567\r
1568 //\r
1569 // Initialize and install a shell parameters protocol on the image.\r
1570 //\r
47d20b54
MK
1571 ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
1572 ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
1573 ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
1574 Status = UpdateArgcArgv (&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL);\r
95bb2038
ZG
1575 if (EFI_ERROR (Status)) {\r
1576 goto UnloadImage;\r
1577 }\r
1578\r
3e2b20a1
BJ
1579 //\r
1580 // Replace Argv[0] with the full path of the binary we're executing:\r
1581 // If the command line was "foo", the binary might be called "foo.efi".\r
1582 // "The first entry in [Argv] is always the full file path of the\r
1583 // executable" - UEFI Shell Spec section 2.3\r
1584 //\r
1585 ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);\r
1586 // The image we're executing isn't necessarily in a filesystem - it might\r
1587 // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will\r
1588 // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.\r
1589 if (ImagePath != NULL) {\r
1590 if (ShellParamsProtocol.Argv == NULL) {\r
1591 // Command line was empty or null.\r
1592 // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)\r
1593 ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));\r
1594 if (ShellParamsProtocol.Argv == NULL) {\r
1595 Status = EFI_OUT_OF_RESOURCES;\r
fe6c94d2 1596 goto UnloadImage;\r
3e2b20a1 1597 }\r
47d20b54 1598\r
3e2b20a1
BJ
1599 ShellParamsProtocol.Argc = 1;\r
1600 } else {\r
1601 // Free the string UpdateArgcArgv put in Argv[0];\r
1602 FreePool (ShellParamsProtocol.Argv[0]);\r
1603 }\r
47d20b54 1604\r
3e2b20a1
BJ
1605 ShellParamsProtocol.Argv[0] = ImagePath;\r
1606 }\r
1607\r
47d20b54
MK
1608 Status = gBS->InstallProtocolInterface (&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
1609 ASSERT_EFI_ERROR (Status);\r
a405b86d 1610\r
47d20b54 1611 /// @todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
a405b86d 1612\r
1613 //\r
a308e058 1614 // now start the image and if the caller wanted the return code pass it to them...\r
a405b86d 1615 //\r
47d20b54
MK
1616 if (!EFI_ERROR (Status)) {\r
1617 StartStatus = gBS->StartImage (\r
1618 NewHandle,\r
1619 0,\r
1620 NULL\r
1621 );\r
cd39fe08
OM
1622 if (StartImageStatus != NULL) {\r
1623 *StartImageStatus = StartStatus;\r
1624 }\r
a405b86d 1625\r
47d20b54
MK
1626 CleanupStatus = gBS->UninstallProtocolInterface (\r
1627 NewHandle,\r
1628 &gEfiShellParametersProtocolGuid,\r
1629 &ShellParamsProtocol\r
1630 );\r
1631 ASSERT_EFI_ERROR (CleanupStatus);\r
fe6c94d2
BJ
1632\r
1633 goto FreeAlloc;\r
1634 }\r
1635\r
1636UnloadImage:\r
1637 // Unload image - We should only get here if we didn't call StartImage\r
1638 gBS->UnloadImage (NewHandle);\r
1639\r
1640FreeAlloc:\r
1641 // Free Argv (Allocated in UpdateArgcArgv)\r
1642 if (ShellParamsProtocol.Argv != NULL) {\r
1643 for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) {\r
1644 if (ShellParamsProtocol.Argv[Index] != NULL) {\r
1645 FreePool (ShellParamsProtocol.Argv[Index]);\r
1646 }\r
1647 }\r
47d20b54 1648\r
fe6c94d2 1649 FreePool (ShellParamsProtocol.Argv);\r
a405b86d 1650 }\r
1651 }\r
1652\r
fe6c94d2 1653 // Restore environment variables\r
47d20b54
MK
1654 if (!IsListEmpty (&OrigEnvs)) {\r
1655 CleanupStatus = SetEnvironmentVariableList (&OrigEnvs);\r
fe6c94d2 1656 ASSERT_EFI_ERROR (CleanupStatus);\r
a405b86d 1657 }\r
1658\r
4b6b543e
QS
1659 FreePool (NewCmdLine);\r
1660\r
47d20b54 1661 return (Status);\r
a405b86d 1662}\r
dcbdb8bf
QS
1663\r
1664/**\r
1665 internal worker function to load and run an image in the current shell.\r
1666\r
1667 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1668 containing the command line. If NULL then the command-\r
1669 line will be empty.\r
1670 @param Environment Points to a NULL-terminated array of environment\r
1671 variables with the format 'x=y', where x is the\r
1672 environment variable name and y is the value. If this\r
1673 is NULL, then the current shell environment is used.\r
ba0014b9 1674\r
dcbdb8bf
QS
1675 @param[out] StartImageStatus Returned status from the command line.\r
1676\r
1677 @retval EFI_SUCCESS The command executed successfully. The status code\r
1678 returned by the command is pointed to by StatusCode.\r
1679 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1680 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1681 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1682**/\r
1683EFI_STATUS\r
47d20b54
MK
1684InternalShellExecute (\r
1685 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1686 IN CONST CHAR16 **Environment OPTIONAL,\r
1687 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
dcbdb8bf
QS
1688 )\r
1689{\r
47d20b54
MK
1690 EFI_STATUS Status;\r
1691 EFI_STATUS CleanupStatus;\r
1692 LIST_ENTRY OrigEnvs;\r
dcbdb8bf 1693\r
47d20b54 1694 InitializeListHead (&OrigEnvs);\r
dcbdb8bf
QS
1695\r
1696 //\r
1697 // Save our current environment settings for later restoration if necessary\r
1698 //\r
1699 if (Environment != NULL) {\r
47d20b54
MK
1700 Status = GetEnvironmentVariableList (&OrigEnvs);\r
1701 if (!EFI_ERROR (Status)) {\r
1702 Status = SetEnvironmentVariables (Environment);\r
dcbdb8bf
QS
1703 } else {\r
1704 return Status;\r
1705 }\r
1706 }\r
1707\r
47d20b54 1708 Status = RunShellCommand (CommandLine, StartImageStatus);\r
dcbdb8bf
QS
1709\r
1710 // Restore environment variables\r
47d20b54
MK
1711 if (!IsListEmpty (&OrigEnvs)) {\r
1712 CleanupStatus = SetEnvironmentVariableList (&OrigEnvs);\r
dcbdb8bf
QS
1713 ASSERT_EFI_ERROR (CleanupStatus);\r
1714 }\r
1715\r
47d20b54 1716 return (Status);\r
dcbdb8bf
QS
1717}\r
1718\r
1719/**\r
1720 Determine if the UEFI Shell is currently running with nesting enabled or disabled.\r
1721\r
1722 @retval FALSE nesting is required\r
1723 @retval other nesting is enabled\r
1724**/\r
1725STATIC\r
1726BOOLEAN\r
47d20b54 1727NestingEnabled (\r
e7275d3f 1728 VOID\r
47d20b54 1729 )\r
dcbdb8bf
QS
1730{\r
1731 EFI_STATUS Status;\r
1732 CHAR16 *Temp;\r
1733 CHAR16 *Temp2;\r
1734 UINTN TempSize;\r
1735 BOOLEAN RetVal;\r
1736\r
1737 RetVal = TRUE;\r
1738 Temp = NULL;\r
1739 Temp2 = NULL;\r
1740\r
1741 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
1742 TempSize = 0;\r
1743 Temp = NULL;\r
47d20b54 1744 Status = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);\r
dcbdb8bf 1745 if (Status == EFI_BUFFER_TOO_SMALL) {\r
47d20b54 1746 Temp = AllocateZeroPool (TempSize + sizeof (CHAR16));\r
dcbdb8bf 1747 if (Temp != NULL) {\r
47d20b54 1748 Status = SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName, &TempSize, Temp);\r
dcbdb8bf
QS
1749 }\r
1750 }\r
47d20b54
MK
1751\r
1752 Temp2 = StrnCatGrow (&Temp2, NULL, mNoNestingTrue, 0);\r
1753 if ((Temp != NULL) && (Temp2 != NULL) && (StringNoCaseCompare (&Temp, &Temp2) == 0)) {\r
dcbdb8bf
QS
1754 //\r
1755 // Use the no nesting method.\r
1756 //\r
1757 RetVal = FALSE;\r
1758 }\r
1759 }\r
1760\r
47d20b54
MK
1761 SHELL_FREE_NON_NULL (Temp);\r
1762 SHELL_FREE_NON_NULL (Temp2);\r
dcbdb8bf
QS
1763 return (RetVal);\r
1764}\r
1765\r
a405b86d 1766/**\r
1767 Execute the command line.\r
1768\r
1769 This function creates a nested instance of the shell and executes the specified\r
1770 command (CommandLine) with the specified environment (Environment). Upon return,\r
1771 the status code returned by the specified command is placed in StatusCode.\r
1772\r
1773 If Environment is NULL, then the current environment is used and all changes made\r
1774 by the commands executed will be reflected in the current environment. If the\r
1775 Environment is non-NULL, then the changes made will be discarded.\r
1776\r
1777 The CommandLine is executed from the current working directory on the current\r
1778 device.\r
1779\r
1780 @param ParentImageHandle A handle of the image that is executing the specified\r
1781 command line.\r
1782 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1783 containing the command line. If NULL then the command-\r
1784 line will be empty.\r
1785 @param Environment Points to a NULL-terminated array of environment\r
1786 variables with the format 'x=y', where x is the\r
1787 environment variable name and y is the value. If this\r
1788 is NULL, then the current shell environment is used.\r
dcbdb8bf 1789 @param StatusCode Points to the status code returned by the CommandLine.\r
a405b86d 1790\r
1791 @retval EFI_SUCCESS The command executed successfully. The status code\r
1792 returned by the command is pointed to by StatusCode.\r
1793 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1794 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1795 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1796 @retval EFI_UNSUPPORTED The support level required for this function is not present.\r
1797\r
1798 @sa InternalShellExecuteDevicePath\r
1799**/\r
1800EFI_STATUS\r
1801EFIAPI\r
47d20b54
MK
1802EfiShellExecute (\r
1803 IN EFI_HANDLE *ParentImageHandle,\r
1804 IN CHAR16 *CommandLine OPTIONAL,\r
1805 IN CHAR16 **Environment OPTIONAL,\r
1806 OUT EFI_STATUS *StatusCode OPTIONAL\r
a405b86d 1807 )\r
1808{\r
1809 EFI_STATUS Status;\r
1810 CHAR16 *Temp;\r
1811 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1812 UINTN Size;\r
c6173804 1813\r
47d20b54 1814 if ((PcdGet8 (PcdShellSupportLevel) < 1)) {\r
a405b86d 1815 return (EFI_UNSUPPORTED);\r
1816 }\r
1817\r
47d20b54 1818 if (NestingEnabled ()) {\r
490ce43d 1819 DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
dcbdb8bf 1820\r
47d20b54
MK
1821 DEBUG_CODE_BEGIN ();\r
1822 Temp = ConvertDevicePathToText (ShellInfoObject.FileDevPath, TRUE, TRUE);\r
1823 FreePool (Temp);\r
1824 Temp = ConvertDevicePathToText (ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
1825 FreePool (Temp);\r
1826 Temp = ConvertDevicePathToText (DevPath, TRUE, TRUE);\r
1827 FreePool (Temp);\r
1828 DEBUG_CODE_END ();\r
490ce43d
QS
1829\r
1830 Temp = NULL;\r
1831 Size = 0;\r
47d20b54
MK
1832 ASSERT ((Temp == NULL && Size == 0) || (Temp != NULL));\r
1833 StrnCatGrow (&Temp, &Size, L"Shell.efi -exit ", 0);\r
1834 StrnCatGrow (&Temp, &Size, CommandLine, 0);\r
1835\r
1836 Status = InternalShellExecuteDevicePath (\r
1837 ParentImageHandle,\r
1838 DevPath,\r
1839 Temp,\r
1840 (CONST CHAR16 **)Environment,\r
1841 StatusCode\r
1842 );\r
a405b86d 1843\r
490ce43d
QS
1844 //\r
1845 // de-allocate and return\r
1846 //\r
47d20b54
MK
1847 FreePool (DevPath);\r
1848 FreePool (Temp);\r
490ce43d 1849 } else {\r
47d20b54
MK
1850 Status = InternalShellExecute (\r
1851 (CONST CHAR16 *)CommandLine,\r
1852 (CONST CHAR16 **)Environment,\r
1853 StatusCode\r
1854 );\r
490ce43d 1855 }\r
a405b86d 1856\r
47d20b54 1857 return (Status);\r
a405b86d 1858}\r
1859\r
1860/**\r
1861 Utility cleanup function for EFI_SHELL_FILE_INFO objects.\r
1862\r
1863 1) frees all pointers (non-NULL)\r
1864 2) Closes the SHELL_FILE_HANDLE\r
1865\r
1866 @param FileListNode pointer to the list node to free\r
1867**/\r
1868VOID\r
47d20b54
MK
1869InternalFreeShellFileInfoNode (\r
1870 IN EFI_SHELL_FILE_INFO *FileListNode\r
a405b86d 1871 )\r
1872{\r
1873 if (FileListNode->Info != NULL) {\r
47d20b54 1874 FreePool ((VOID *)FileListNode->Info);\r
a405b86d 1875 }\r
47d20b54 1876\r
a405b86d 1877 if (FileListNode->FileName != NULL) {\r
47d20b54 1878 FreePool ((VOID *)FileListNode->FileName);\r
a405b86d 1879 }\r
47d20b54 1880\r
a405b86d 1881 if (FileListNode->FullName != NULL) {\r
47d20b54 1882 FreePool ((VOID *)FileListNode->FullName);\r
a405b86d 1883 }\r
47d20b54 1884\r
a405b86d 1885 if (FileListNode->Handle != NULL) {\r
47d20b54 1886 ShellInfoObject.NewEfiShellProtocol->CloseFile (FileListNode->Handle);\r
a405b86d 1887 }\r
47d20b54
MK
1888\r
1889 FreePool (FileListNode);\r
a405b86d 1890}\r
47d20b54 1891\r
a405b86d 1892/**\r
1893 Frees the file list.\r
1894\r
1895 This function cleans up the file list and any related data structures. It has no\r
1896 impact on the files themselves.\r
1897\r
1898 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is\r
1899 defined in OpenFileList()\r
1900\r
1901 @retval EFI_SUCCESS Free the file list successfully.\r
1902 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1903**/\r
1904EFI_STATUS\r
1905EFIAPI\r
47d20b54
MK
1906EfiShellFreeFileList (\r
1907 IN EFI_SHELL_FILE_INFO **FileList\r
a405b86d 1908 )\r
1909{\r
47d20b54 1910 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
a405b86d 1911\r
47d20b54 1912 if ((FileList == NULL) || (*FileList == NULL)) {\r
a405b86d 1913 return (EFI_INVALID_PARAMETER);\r
1914 }\r
1915\r
47d20b54
MK
1916 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1917 ; !IsListEmpty (&(*FileList)->Link)\r
1918 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1919 )\r
1920 {\r
1921 RemoveEntryList (&ShellFileListItem->Link);\r
1922 InternalFreeShellFileInfoNode (ShellFileListItem);\r
a405b86d 1923 }\r
47d20b54
MK
1924\r
1925 InternalFreeShellFileInfoNode (*FileList);\r
8844288c 1926 *FileList = NULL;\r
47d20b54 1927 return (EFI_SUCCESS);\r
a405b86d 1928}\r
1929\r
1930/**\r
1931 Deletes the duplicate file names files in the given file list.\r
1932\r
1933 This function deletes the reduplicate files in the given file list.\r
1934\r
1935 @param FileList A pointer to the first entry in the file list.\r
1936\r
1937 @retval EFI_SUCCESS Always success.\r
1938 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1939**/\r
1940EFI_STATUS\r
1941EFIAPI\r
47d20b54
MK
1942EfiShellRemoveDupInFileList (\r
1943 IN EFI_SHELL_FILE_INFO **FileList\r
a405b86d 1944 )\r
1945{\r
47d20b54
MK
1946 EFI_STATUS Status;\r
1947 EFI_SHELL_FILE_INFO *Duplicates;\r
1948 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
1949 EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
1950 EFI_SHELL_FILE_INFO *TempNode;\r
a405b86d 1951\r
47d20b54 1952 if ((FileList == NULL) || (*FileList == NULL)) {\r
a405b86d 1953 return (EFI_INVALID_PARAMETER);\r
1954 }\r
c8ce60eb
LE
1955\r
1956 Status = ShellSortFileList (\r
1957 FileList,\r
1958 &Duplicates,\r
1959 ShellSortFileListByFullName\r
1960 );\r
1961 if (!EFI_ERROR (Status)) {\r
1962 EfiShellFreeFileList (&Duplicates);\r
1963 return EFI_SUCCESS;\r
1964 }\r
47d20b54 1965\r
c8ce60eb
LE
1966 //\r
1967 // Fall back to the slow method that needs no extra memory, and so cannot\r
1968 // fail.\r
1969 //\r
47d20b54
MK
1970 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
1971 ; !IsNull (&(*FileList)->Link, &ShellFileListItem->Link)\r
1972 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
1973 )\r
1974 {\r
1975 for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
1976 ; !IsNull (&(*FileList)->Link, &ShellFileListItem2->Link)\r
1977 ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem2->Link)\r
1978 )\r
1979 {\r
1980 if (gUnicodeCollation->StriColl (\r
1981 gUnicodeCollation,\r
1982 (CHAR16 *)ShellFileListItem->FullName,\r
1983 (CHAR16 *)ShellFileListItem2->FullName\r
1984 ) == 0\r
1985 )\r
1986 {\r
1987 TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode (\r
3e2b20a1
BJ
1988 &(*FileList)->Link,\r
1989 &ShellFileListItem2->Link\r
1990 );\r
47d20b54
MK
1991 RemoveEntryList (&ShellFileListItem2->Link);\r
1992 InternalFreeShellFileInfoNode (ShellFileListItem2);\r
3e2b20a1
BJ
1993 // Set ShellFileListItem2 to PreviousNode so we don't access Freed\r
1994 // memory in GetNextNode in the loop expression above.\r
1995 ShellFileListItem2 = TempNode;\r
a405b86d 1996 }\r
1997 }\r
1998 }\r
47d20b54 1999\r
a405b86d 2000 return (EFI_SUCCESS);\r
2001}\r
4b5168d8
JC
2002\r
2003//\r
2004// This is the same structure as the external version, but it has no CONST qualifiers.\r
2005//\r
2006typedef struct {\r
47d20b54
MK
2007 LIST_ENTRY Link; ///< Linked list members.\r
2008 EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL.\r
2009 CHAR16 *FullName; ///< Fully qualified filename.\r
2010 CHAR16 *FileName; ///< name of this file.\r
2011 SHELL_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed.\r
2012 EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL.\r
4b5168d8
JC
2013} EFI_SHELL_FILE_INFO_NO_CONST;\r
2014\r
a405b86d 2015/**\r
2016 Allocates and duplicates a EFI_SHELL_FILE_INFO node.\r
2017\r
2018 @param[in] Node The node to copy from.\r
2019 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.\r
2020\r
6a5033ca 2021 @retval NULL a memory allocation error occurred\r
a405b86d 2022 @return != NULL a pointer to the new node\r
2023**/\r
47d20b54
MK
2024EFI_SHELL_FILE_INFO *\r
2025InternalDuplicateShellFileInfo (\r
2026 IN EFI_SHELL_FILE_INFO *Node,\r
2027 IN BOOLEAN Save\r
a405b86d 2028 )\r
2029{\r
47d20b54 2030 EFI_SHELL_FILE_INFO_NO_CONST *NewNode;\r
4b5168d8
JC
2031\r
2032 //\r
2033 // try to confirm that the objects are in sync\r
2034 //\r
47d20b54 2035 ASSERT (sizeof (EFI_SHELL_FILE_INFO_NO_CONST) == sizeof (EFI_SHELL_FILE_INFO));\r
a405b86d 2036\r
47d20b54 2037 NewNode = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
a405b86d 2038 if (NewNode == NULL) {\r
2039 return (NULL);\r
2040 }\r
47d20b54
MK
2041\r
2042 NewNode->FullName = AllocateCopyPool (StrSize (Node->FullName), Node->FullName);\r
2043 NewNode->FileName = AllocateCopyPool (StrSize (Node->FileName), Node->FileName);\r
2044 NewNode->Info = AllocateCopyPool ((UINTN)Node->Info->Size, Node->Info);\r
2045 if ( (NewNode->FullName == NULL)\r
2046 || (NewNode->FileName == NULL)\r
2047 || (NewNode->Info == NULL)\r
2048 )\r
2049 {\r
2050 SHELL_FREE_NON_NULL (NewNode->FullName);\r
2051 SHELL_FREE_NON_NULL (NewNode->FileName);\r
2052 SHELL_FREE_NON_NULL (NewNode->Info);\r
2053 SHELL_FREE_NON_NULL (NewNode);\r
2054 return (NULL);\r
a405b86d 2055 }\r
47d20b54 2056\r
a405b86d 2057 NewNode->Status = Node->Status;\r
2058 NewNode->Handle = Node->Handle;\r
2059 if (!Save) {\r
2060 Node->Handle = NULL;\r
2061 }\r
a405b86d 2062\r
47d20b54 2063 return ((EFI_SHELL_FILE_INFO *)NewNode);\r
a405b86d 2064}\r
2065\r
2066/**\r
2067 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation\r
2068 failed it will return NULL.\r
2069\r
2070 @param[in] BasePath the Path to prepend onto filename for FullPath\r
2071 @param[in] Status Status member initial value.\r
a405b86d 2072 @param[in] FileName FileName member initial value.\r
2073 @param[in] Handle Handle member initial value.\r
2074 @param[in] Info Info struct to copy.\r
2075\r
6a5033ca 2076 @retval NULL An error occurred.\r
a405b86d 2077 @return a pointer to the newly allocated structure.\r
2078**/\r
2079EFI_SHELL_FILE_INFO *\r
47d20b54
MK
2080CreateAndPopulateShellFileInfo (\r
2081 IN CONST CHAR16 *BasePath,\r
2082 IN CONST EFI_STATUS Status,\r
2083 IN CONST CHAR16 *FileName,\r
2084 IN CONST SHELL_FILE_HANDLE Handle,\r
2085 IN CONST EFI_FILE_INFO *Info\r
a405b86d 2086 )\r
2087{\r
47d20b54
MK
2088 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2089 CHAR16 *TempString;\r
2090 UINTN Size;\r
a405b86d 2091\r
2092 TempString = NULL;\r
47d20b54 2093 Size = 0;\r
a405b86d 2094\r
47d20b54 2095 ShellFileListItem = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
a405b86d 2096 if (ShellFileListItem == NULL) {\r
2097 return (NULL);\r
2098 }\r
47d20b54
MK
2099\r
2100 if ((Info != NULL) && (Info->Size != 0)) {\r
2101 ShellFileListItem->Info = AllocateZeroPool ((UINTN)Info->Size);\r
a405b86d 2102 if (ShellFileListItem->Info == NULL) {\r
47d20b54 2103 FreePool (ShellFileListItem);\r
a405b86d 2104 return (NULL);\r
2105 }\r
47d20b54
MK
2106\r
2107 CopyMem (ShellFileListItem->Info, Info, (UINTN)Info->Size);\r
a405b86d 2108 } else {\r
2109 ShellFileListItem->Info = NULL;\r
2110 }\r
47d20b54 2111\r
a405b86d 2112 if (FileName != NULL) {\r
47d20b54
MK
2113 ASSERT (TempString == NULL);\r
2114 ShellFileListItem->FileName = StrnCatGrow (&TempString, 0, FileName, 0);\r
a405b86d 2115 if (ShellFileListItem->FileName == NULL) {\r
47d20b54
MK
2116 FreePool (ShellFileListItem->Info);\r
2117 FreePool (ShellFileListItem);\r
a405b86d 2118 return (NULL);\r
2119 }\r
2120 } else {\r
2121 ShellFileListItem->FileName = NULL;\r
2122 }\r
47d20b54
MK
2123\r
2124 Size = 0;\r
a405b86d 2125 TempString = NULL;\r
2126 if (BasePath != NULL) {\r
47d20b54
MK
2127 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
2128 TempString = StrnCatGrow (&TempString, &Size, BasePath, 0);\r
a405b86d 2129 if (TempString == NULL) {\r
47d20b54
MK
2130 FreePool ((VOID *)ShellFileListItem->FileName);\r
2131 SHELL_FREE_NON_NULL (ShellFileListItem->Info);\r
2132 FreePool (ShellFileListItem);\r
a405b86d 2133 return (NULL);\r
2134 }\r
2135 }\r
47d20b54 2136\r
a405b86d 2137 if (ShellFileListItem->FileName != NULL) {\r
47d20b54
MK
2138 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
2139 TempString = StrnCatGrow (&TempString, &Size, ShellFileListItem->FileName, 0);\r
a405b86d 2140 if (TempString == NULL) {\r
47d20b54
MK
2141 FreePool ((VOID *)ShellFileListItem->FileName);\r
2142 FreePool (ShellFileListItem->Info);\r
2143 FreePool (ShellFileListItem);\r
a405b86d 2144 return (NULL);\r
2145 }\r
2146 }\r
2147\r
47d20b54 2148 TempString = PathCleanUpDirectories (TempString);\r
bbf904d1 2149\r
a405b86d 2150 ShellFileListItem->FullName = TempString;\r
2151 ShellFileListItem->Status = Status;\r
2152 ShellFileListItem->Handle = Handle;\r
2153\r
2154 return (ShellFileListItem);\r
2155}\r
2156\r
2157/**\r
2158 Find all files in a specified directory.\r
2159\r
2160 @param FileDirHandle Handle of the directory to search.\r
2161 @param FileList On return, points to the list of files in the directory\r
2162 or NULL if there are no files in the directory.\r
2163\r
2164 @retval EFI_SUCCESS File information was returned successfully.\r
2165 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.\r
2166 @retval EFI_DEVICE_ERROR The device reported an error.\r
2167 @retval EFI_NO_MEDIA The device media is not present.\r
2168 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.\r
2169 @return An error from FileHandleGetFileName().\r
2170**/\r
2171EFI_STATUS\r
2172EFIAPI\r
47d20b54
MK
2173EfiShellFindFilesInDir (\r
2174 IN SHELL_FILE_HANDLE FileDirHandle,\r
2175 OUT EFI_SHELL_FILE_INFO **FileList\r
a405b86d 2176 )\r
2177{\r
47d20b54
MK
2178 EFI_SHELL_FILE_INFO *ShellFileList;\r
2179 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2180 EFI_FILE_INFO *FileInfo;\r
2181 EFI_STATUS Status;\r
2182 BOOLEAN NoFile;\r
2183 CHAR16 *TempString;\r
2184 CHAR16 *BasePath;\r
2185 UINTN Size;\r
2186 CHAR16 *TempSpot;\r
a405b86d 2187\r
0d807dae 2188 BasePath = NULL;\r
47d20b54
MK
2189 Status = FileHandleGetFileName (FileDirHandle, &BasePath);\r
2190 if (EFI_ERROR (Status)) {\r
a405b86d 2191 return (Status);\r
2192 }\r
2193\r
47d20b54
MK
2194 if (ShellFileHandleGetPath (FileDirHandle) != NULL) {\r
2195 TempString = NULL;\r
2196 Size = 0;\r
2197 TempString = StrnCatGrow (&TempString, &Size, ShellFileHandleGetPath (FileDirHandle), 0);\r
532691c8 2198 if (TempString == NULL) {\r
47d20b54 2199 SHELL_FREE_NON_NULL (BasePath);\r
532691c8 2200 return (EFI_OUT_OF_RESOURCES);\r
2201 }\r
47d20b54
MK
2202\r
2203 TempSpot = StrStr (TempString, L";");\r
a405b86d 2204\r
2205 if (TempSpot != NULL) {\r
2206 *TempSpot = CHAR_NULL;\r
2207 }\r
2208\r
47d20b54 2209 TempString = StrnCatGrow (&TempString, &Size, BasePath, 0);\r
532691c8 2210 if (TempString == NULL) {\r
47d20b54 2211 SHELL_FREE_NON_NULL (BasePath);\r
532691c8 2212 return (EFI_OUT_OF_RESOURCES);\r
2213 }\r
47d20b54
MK
2214\r
2215 SHELL_FREE_NON_NULL (BasePath);\r
2216 BasePath = TempString;\r
a405b86d 2217 }\r
2218\r
2219 NoFile = FALSE;\r
2220 ShellFileList = NULL;\r
2221 ShellFileListItem = NULL;\r
2222 FileInfo = NULL;\r
2223 Status = EFI_SUCCESS;\r
2224\r
47d20b54
MK
2225 for ( Status = FileHandleFindFirstFile (FileDirHandle, &FileInfo)\r
2226 ; !EFI_ERROR (Status) && !NoFile\r
2227 ; Status = FileHandleFindNextFile (FileDirHandle, FileInfo, &NoFile)\r
2228 )\r
2229 {\r
9168df3d 2230 if (ShellFileList == NULL) {\r
47d20b54 2231 ShellFileList = (EFI_SHELL_FILE_INFO *)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
9168df3d
RN
2232 if (ShellFileList == NULL) {\r
2233 SHELL_FREE_NON_NULL (BasePath);\r
2234 return EFI_OUT_OF_RESOURCES;\r
2235 }\r
47d20b54
MK
2236\r
2237 InitializeListHead (&ShellFileList->Link);\r
9168df3d 2238 }\r
47d20b54 2239\r
a405b86d 2240 //\r
2241 // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
2242 //\r
47d20b54
MK
2243 ShellFileListItem = CreateAndPopulateShellFileInfo (\r
2244 BasePath,\r
2245 EFI_SUCCESS, // success since we didn't fail to open it...\r
2246 FileInfo->FileName,\r
2247 NULL, // no handle since not open\r
2248 FileInfo\r
2249 );\r
9168df3d
RN
2250 if (ShellFileListItem == NULL) {\r
2251 Status = EFI_OUT_OF_RESOURCES;\r
2252 //\r
2253 // Free resources outside the loop.\r
2254 //\r
2255 break;\r
a405b86d 2256 }\r
47d20b54
MK
2257\r
2258 InsertTailList (&ShellFileList->Link, &ShellFileListItem->Link);\r
a405b86d 2259 }\r
47d20b54
MK
2260\r
2261 if (EFI_ERROR (Status)) {\r
2262 EfiShellFreeFileList (&ShellFileList);\r
a405b86d 2263 *FileList = NULL;\r
2264 } else {\r
2265 *FileList = ShellFileList;\r
2266 }\r
47d20b54
MK
2267\r
2268 SHELL_FREE_NON_NULL (BasePath);\r
2269 return (Status);\r
33fe8308 2270}\r
09fd5328
JC
2271\r
2272/**\r
2273 Get the GUID value from a human readable name.\r
2274\r
2275 If GuidName is a known GUID name, then update Guid to have the correct value for\r
2276 that GUID.\r
2277\r
2278 This function is only available when the major and minor versions in the\r
2279 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2280\r
2281 @param[in] GuidName A pointer to the localized name for the GUID being queried.\r
2282 @param[out] Guid A pointer to the GUID structure to be filled in.\r
2283\r
2284 @retval EFI_SUCCESS The operation was successful.\r
2285 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2286 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2287 @retval EFI_NOT_FOUND GuidName is not a known GUID Name.\r
2288**/\r
2289EFI_STATUS\r
c20bd8e1 2290EFIAPI\r
47d20b54
MK
2291EfiShellGetGuidFromName (\r
2292 IN CONST CHAR16 *GuidName,\r
2293 OUT EFI_GUID *Guid\r
09fd5328
JC
2294 )\r
2295{\r
2296 EFI_GUID *NewGuid;\r
2297 EFI_STATUS Status;\r
2298\r
47d20b54 2299 if ((Guid == NULL) || (GuidName == NULL)) {\r
09fd5328
JC
2300 return (EFI_INVALID_PARAMETER);\r
2301 }\r
ba0014b9 2302\r
47d20b54 2303 Status = GetGuidFromStringName (GuidName, NULL, &NewGuid);\r
09fd5328 2304\r
47d20b54
MK
2305 if (!EFI_ERROR (Status)) {\r
2306 CopyGuid (Guid, NewGuid);\r
09fd5328
JC
2307 }\r
2308\r
2309 return (Status);\r
2310}\r
2311\r
2312/**\r
2313 Get the human readable name for a GUID from the value.\r
2314\r
2315 If Guid is assigned a name, then update *GuidName to point to the name. The callee\r
2316 should not modify the value.\r
2317\r
2318 This function is only available when the major and minor versions in the\r
2319 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2320\r
2321 @param[in] Guid A pointer to the GUID being queried.\r
2322 @param[out] GuidName A pointer to a pointer the localized to name for the GUID being requested\r
2323\r
2324 @retval EFI_SUCCESS The operation was successful.\r
2325 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2326 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2327 @retval EFI_NOT_FOUND Guid is not assigned a name.\r
2328**/\r
2329EFI_STATUS\r
c20bd8e1 2330EFIAPI\r
47d20b54
MK
2331EfiShellGetGuidName (\r
2332 IN CONST EFI_GUID *Guid,\r
2333 OUT CONST CHAR16 **GuidName\r
09fd5328
JC
2334 )\r
2335{\r
47d20b54 2336 CHAR16 *Name;\r
09fd5328 2337\r
47d20b54 2338 if ((Guid == NULL) || (GuidName == NULL)) {\r
09fd5328
JC
2339 return (EFI_INVALID_PARAMETER);\r
2340 }\r
2341\r
47d20b54
MK
2342 Name = GetStringNameFromGuid (Guid, NULL);\r
2343 if ((Name == NULL) || (StrLen (Name) == 0)) {\r
2344 SHELL_FREE_NON_NULL (Name);\r
09fd5328
JC
2345 return (EFI_NOT_FOUND);\r
2346 }\r
2347\r
47d20b54 2348 *GuidName = AddBufferToFreeList (Name);\r
09fd5328
JC
2349\r
2350 return (EFI_SUCCESS);\r
a405b86d 2351}\r
2352\r
a405b86d 2353/**\r
2354 If FileHandle is a directory then the function reads from FileHandle and reads in\r
2355 each of the FileInfo structures. If one of them matches the Pattern's first\r
2356 "level" then it opens that handle and calls itself on that handle.\r
2357\r
2358 If FileHandle is a file and matches all of the remaining Pattern (which would be\r
2359 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.\r
2360\r
a405b86d 2361 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
2362 FreeFileList with FileList.\r
2363\r
4ff7e37b
ED
2364 @param[in] FilePattern The FilePattern to check against.\r
2365 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
2366 @param[in] FileHandle The FileHandle to start with\r
2367 @param[in, out] FileList pointer to pointer to list of found files.\r
2368 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.\r
2369 @param[in] MapName The file system name this file is on.\r
a405b86d 2370\r
2371 @retval EFI_SUCCESS all files were found and the FileList contains a list.\r
2372 @retval EFI_NOT_FOUND no files were found\r
2373 @retval EFI_OUT_OF_RESOURCES a memory allocation failed\r
2374**/\r
2375EFI_STATUS\r
47d20b54
MK
2376ShellSearchHandle (\r
2377 IN CONST CHAR16 *FilePattern,\r
2378 IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
2379 IN SHELL_FILE_HANDLE FileHandle,\r
2380 IN OUT EFI_SHELL_FILE_INFO **FileList,\r
2381 IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL,\r
2382 IN CONST CHAR16 *MapName\r
a405b86d 2383 )\r
2384{\r
47d20b54
MK
2385 EFI_STATUS Status;\r
2386 CONST CHAR16 *NextFilePatternStart;\r
2387 CHAR16 *CurrentFilePattern;\r
2388 EFI_SHELL_FILE_INFO *ShellInfo;\r
2389 EFI_SHELL_FILE_INFO *ShellInfoNode;\r
2390 EFI_SHELL_FILE_INFO *NewShellNode;\r
2391 EFI_FILE_INFO *FileInfo;\r
2392 BOOLEAN Directory;\r
2393 CHAR16 *NewFullName;\r
2394 UINTN Size;\r
2395\r
2396 if ( (FilePattern == NULL)\r
2397 || (UnicodeCollation == NULL)\r
2398 || (FileList == NULL)\r
2399 )\r
2400 {\r
a405b86d 2401 return (EFI_INVALID_PARAMETER);\r
2402 }\r
47d20b54
MK
2403\r
2404 ShellInfo = NULL;\r
a405b86d 2405 CurrentFilePattern = NULL;\r
2406\r
2407 if (*FilePattern == L'\\') {\r
2408 FilePattern++;\r
2409 }\r
2410\r
47d20b54
MK
2411 for ( NextFilePatternStart = FilePattern\r
2412 ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\'\r
2413 ; NextFilePatternStart++)\r
2414 {\r
2415 }\r
a405b86d 2416\r
47d20b54 2417 CurrentFilePattern = AllocateZeroPool ((NextFilePatternStart-FilePattern+1)*sizeof (CHAR16));\r
9168df3d
RN
2418 if (CurrentFilePattern == NULL) {\r
2419 return EFI_OUT_OF_RESOURCES;\r
2420 }\r
2421\r
47d20b54 2422 StrnCpyS (CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
a405b86d 2423\r
47d20b54
MK
2424 if ( (CurrentFilePattern[0] == CHAR_NULL)\r
2425 && (NextFilePatternStart[0] == CHAR_NULL)\r
2426 )\r
2427 {\r
a405b86d 2428 //\r
d0a5723f 2429 // we want the parent or root node (if no parent)\r
a405b86d 2430 //\r
2431 if (ParentNode == NULL) {\r
d0a5723f
JC
2432 //\r
2433 // We want the root node. create the node.\r
2434 //\r
47d20b54
MK
2435 FileInfo = FileHandleGetInfo (FileHandle);\r
2436 NewShellNode = CreateAndPopulateShellFileInfo (\r
2437 MapName,\r
2438 EFI_SUCCESS,\r
2439 L"\\",\r
2440 FileHandle,\r
2441 FileInfo\r
2442 );\r
2443 SHELL_FREE_NON_NULL (FileInfo);\r
a405b86d 2444 } else {\r
d0a5723f
JC
2445 //\r
2446 // Add the current parameter FileHandle to the list, then end...\r
2447 //\r
47d20b54 2448 NewShellNode = InternalDuplicateShellFileInfo ((EFI_SHELL_FILE_INFO *)ParentNode, TRUE);\r
d0a5723f 2449 }\r
47d20b54 2450\r
d0a5723f
JC
2451 if (NewShellNode == NULL) {\r
2452 Status = EFI_OUT_OF_RESOURCES;\r
2453 } else {\r
2454 NewShellNode->Handle = NULL;\r
2455 if (*FileList == NULL) {\r
47d20b54
MK
2456 *FileList = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2457 InitializeListHead (&((*FileList)->Link));\r
d0a5723f 2458 }\r
a405b86d 2459\r
d0a5723f
JC
2460 //\r
2461 // Add to the returning to use list\r
2462 //\r
47d20b54 2463 InsertTailList (&(*FileList)->Link, &NewShellNode->Link);\r
a405b86d 2464\r
d0a5723f 2465 Status = EFI_SUCCESS;\r
a405b86d 2466 }\r
2467 } else {\r
47d20b54 2468 Status = EfiShellFindFilesInDir (FileHandle, &ShellInfo);\r
a405b86d 2469\r
47d20b54
MK
2470 if (!EFI_ERROR (Status)) {\r
2471 if (StrStr (NextFilePatternStart, L"\\") != NULL) {\r
a405b86d 2472 Directory = TRUE;\r
2473 } else {\r
2474 Directory = FALSE;\r
2475 }\r
47d20b54
MK
2476\r
2477 for ( ShellInfoNode = (EFI_SHELL_FILE_INFO *)GetFirstNode (&ShellInfo->Link)\r
2478 ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link)\r
2479 ; ShellInfoNode = (EFI_SHELL_FILE_INFO *)GetNextNode (&ShellInfo->Link, &ShellInfoNode->Link)\r
2480 )\r
2481 {\r
2482 if (UnicodeCollation->MetaiMatch (UnicodeCollation, (CHAR16 *)ShellInfoNode->FileName, CurrentFilePattern)) {\r
2483 if ((ShellInfoNode->FullName != NULL) && (StrStr (ShellInfoNode->FullName, L":") == NULL)) {\r
2484 Size = StrSize (ShellInfoNode->FullName) + StrSize (MapName);\r
2485 NewFullName = AllocateZeroPool (Size);\r
8be0ba36 2486 if (NewFullName == NULL) {\r
2487 Status = EFI_OUT_OF_RESOURCES;\r
2488 } else {\r
47d20b54
MK
2489 StrCpyS (NewFullName, Size / sizeof (CHAR16), MapName);\r
2490 StrCatS (NewFullName, Size / sizeof (CHAR16), ShellInfoNode->FullName);\r
2491 FreePool ((VOID *)ShellInfoNode->FullName);\r
8be0ba36 2492 ShellInfoNode->FullName = NewFullName;\r
2493 }\r
2494 }\r
47d20b54
MK
2495\r
2496 if (Directory && !EFI_ERROR (Status) && (ShellInfoNode->FullName != NULL) && (ShellInfoNode->FileName != NULL)) {\r
a405b86d 2497 //\r
2498 // should be a directory\r
2499 //\r
2500\r
2501 //\r
2502 // don't open the . and .. directories\r
2503 //\r
47d20b54
MK
2504 if ( (StrCmp (ShellInfoNode->FileName, L".") != 0)\r
2505 && (StrCmp (ShellInfoNode->FileName, L"..") != 0)\r
2506 )\r
2507 {\r
a405b86d 2508 //\r
2509 //\r
2510 //\r
47d20b54 2511 if (EFI_ERROR (Status)) {\r
a405b86d 2512 break;\r
2513 }\r
47d20b54 2514\r
a405b86d 2515 //\r
2516 // Open the directory since we need that handle in the next recursion.\r
2517 //\r
2518 ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ);\r
2519\r
2520 //\r
2521 // recurse with the next part of the pattern\r
2522 //\r
47d20b54
MK
2523 Status = ShellSearchHandle (NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);\r
2524 EfiShellClose (ShellInfoNode->Handle);\r
06e5ae77 2525 ShellInfoNode->Handle = NULL;\r
a405b86d 2526 }\r
47d20b54 2527 } else if (!EFI_ERROR (Status)) {\r
a405b86d 2528 //\r
2529 // should be a file\r
2530 //\r
2531\r
2532 //\r
2533 // copy the information we need into a new Node\r
2534 //\r
47d20b54 2535 NewShellNode = InternalDuplicateShellFileInfo (ShellInfoNode, FALSE);\r
a405b86d 2536 if (NewShellNode == NULL) {\r
2537 Status = EFI_OUT_OF_RESOURCES;\r
2538 }\r
47d20b54 2539\r
a405b86d 2540 if (*FileList == NULL) {\r
47d20b54
MK
2541 *FileList = AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO));\r
2542 InitializeListHead (&((*FileList)->Link));\r
a405b86d 2543 }\r
2544\r
2545 //\r
2546 // Add to the returning to use list\r
2547 //\r
47d20b54 2548 InsertTailList (&(*FileList)->Link, &NewShellNode->Link);\r
a405b86d 2549 }\r
2550 }\r
47d20b54
MK
2551\r
2552 if (EFI_ERROR (Status)) {\r
a405b86d 2553 break;\r
2554 }\r
2555 }\r
47d20b54
MK
2556\r
2557 if (EFI_ERROR (Status)) {\r
2558 EfiShellFreeFileList (&ShellInfo);\r
a405b86d 2559 } else {\r
47d20b54 2560 Status = EfiShellFreeFileList (&ShellInfo);\r
a405b86d 2561 }\r
2562 }\r
2563 }\r
2564\r
47d20b54 2565 if ((*FileList == NULL) || ((*FileList != NULL) && IsListEmpty (&(*FileList)->Link))) {\r
00afc8f8
DB
2566 Status = EFI_NOT_FOUND;\r
2567 }\r
2568\r
47d20b54 2569 FreePool (CurrentFilePattern);\r
a405b86d 2570 return (Status);\r
2571}\r
2572\r
2573/**\r
2574 Find files that match a specified pattern.\r
2575\r
2576 This function searches for all files and directories that match the specified\r
2577 FilePattern. The FilePattern can contain wild-card characters. The resulting file\r
2578 information is placed in the file list FileList.\r
2579\r
2580 Wildcards are processed\r
2581 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.\r
2582\r
2583 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo\r
2584 field is set to NULL.\r
2585\r
2586 if *FileList is not NULL then it must be a pre-existing and properly initialized list.\r
2587\r
2588 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.\r
2589 @param FileList On return, points to the start of a file list containing the names\r
2590 of all matching files or else points to NULL if no matching files\r
2591 were found. only on a EFI_SUCCESS return will; this be non-NULL.\r
2592\r
2593 @retval EFI_SUCCESS Files found. FileList is a valid list.\r
2594 @retval EFI_NOT_FOUND No files found.\r
2595 @retval EFI_NO_MEDIA The device has no media\r
2596 @retval EFI_DEVICE_ERROR The device reported an error\r
2597 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted\r
2598**/\r
2599EFI_STATUS\r
2600EFIAPI\r
47d20b54
MK
2601EfiShellFindFiles (\r
2602 IN CONST CHAR16 *FilePattern,\r
2603 OUT EFI_SHELL_FILE_INFO **FileList\r
a405b86d 2604 )\r
2605{\r
47d20b54
MK
2606 EFI_STATUS Status;\r
2607 CHAR16 *PatternCopy;\r
2608 CHAR16 *PatternCurrentLocation;\r
2609 EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
2610 SHELL_FILE_HANDLE RootFileHandle;\r
2611 CHAR16 *MapName;\r
2612 UINTN Count;\r
2613\r
2614 if ( (FilePattern == NULL)\r
2615 || (FileList == NULL)\r
2616 || (StrStr (FilePattern, L":") == NULL)\r
2617 )\r
2618 {\r
a405b86d 2619 return (EFI_INVALID_PARAMETER);\r
2620 }\r
47d20b54
MK
2621\r
2622 Status = EFI_SUCCESS;\r
a405b86d 2623 RootDevicePath = NULL;\r
2624 RootFileHandle = NULL;\r
2625 MapName = NULL;\r
47d20b54 2626 PatternCopy = AllocateCopyPool (StrSize (FilePattern), FilePattern);\r
a405b86d 2627 if (PatternCopy == NULL) {\r
2628 return (EFI_OUT_OF_RESOURCES);\r
2629 }\r
a405b86d 2630\r
47d20b54 2631 PatternCopy = PathCleanUpDirectories (PatternCopy);\r
a405b86d 2632\r
47d20b54 2633 Count = StrStr (PatternCopy, L":") - PatternCopy + 1;\r
d25d59cb 2634 ASSERT (Count <= StrLen (PatternCopy));\r
a405b86d 2635\r
47d20b54
MK
2636 ASSERT (MapName == NULL);\r
2637 MapName = StrnCatGrow (&MapName, NULL, PatternCopy, Count);\r
532691c8 2638 if (MapName == NULL) {\r
2639 Status = EFI_OUT_OF_RESOURCES;\r
c8c22591 2640 } else {\r
47d20b54 2641 RootDevicePath = EfiShellGetDevicePathFromFilePath (PatternCopy);\r
a405b86d 2642 if (RootDevicePath == NULL) {\r
2643 Status = EFI_INVALID_PARAMETER;\r
2644 } else {\r
47d20b54
MK
2645 Status = EfiShellOpenRoot (RootDevicePath, &RootFileHandle);\r
2646 if (!EFI_ERROR (Status)) {\r
a405b86d 2647 for ( PatternCurrentLocation = PatternCopy\r
47d20b54
MK
2648 ; *PatternCurrentLocation != ':'\r
2649 ; PatternCurrentLocation++)\r
2650 {\r
2651 }\r
2652\r
a405b86d 2653 PatternCurrentLocation++;\r
47d20b54
MK
2654 Status = ShellSearchHandle (PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
2655 EfiShellClose (RootFileHandle);\r
a405b86d 2656 }\r
47d20b54
MK
2657\r
2658 FreePool (RootDevicePath);\r
a405b86d 2659 }\r
2660 }\r
2661\r
47d20b54
MK
2662 SHELL_FREE_NON_NULL (PatternCopy);\r
2663 SHELL_FREE_NON_NULL (MapName);\r
a405b86d 2664\r
47d20b54 2665 return (Status);\r
a405b86d 2666}\r
2667\r
2668/**\r
2669 Opens the files that match the path specified.\r
2670\r
2671 This function opens all of the files specified by Path. Wildcards are processed\r
2672 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each\r
2673 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.\r
2674\r
2675 @param Path A pointer to the path string.\r
2676 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or\r
2677 EFI_FILE_MODE_WRITE.\r
2678 @param FileList Points to the start of a list of files opened.\r
2679\r
2680 @retval EFI_SUCCESS Create the file list successfully.\r
2681 @return Others Can't create the file list.\r
2682**/\r
2683EFI_STATUS\r
2684EFIAPI\r
47d20b54
MK
2685EfiShellOpenFileList (\r
2686 IN CHAR16 *Path,\r
2687 IN UINT64 OpenMode,\r
2688 IN OUT EFI_SHELL_FILE_INFO **FileList\r
a405b86d 2689 )\r
2690{\r
47d20b54
MK
2691 EFI_STATUS Status;\r
2692 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2693 CHAR16 *Path2;\r
2694 UINTN Path2Size;\r
2695 CONST CHAR16 *CurDir;\r
2696 BOOLEAN Found;\r
a405b86d 2697\r
47d20b54 2698 PathCleanUpDirectories (Path);\r
a405b86d 2699\r
47d20b54
MK
2700 Path2Size = 0;\r
2701 Path2 = NULL;\r
a405b86d 2702\r
47d20b54 2703 if ((FileList == NULL) || (*FileList == NULL)) {\r
733f138d 2704 return (EFI_INVALID_PARAMETER);\r
2705 }\r
a405b86d 2706\r
47d20b54
MK
2707 if ((*Path == L'.') && (*(Path+1) == L'\\')) {\r
2708 Path += 2;\r
a405b86d 2709 }\r
2710\r
2711 //\r
2712 // convert a local path to an absolute path\r
2713 //\r
47d20b54
MK
2714 if (StrStr (Path, L":") == NULL) {\r
2715 CurDir = EfiShellGetCurDir (NULL);\r
2716 ASSERT ((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2717 StrnCatGrow (&Path2, &Path2Size, CurDir, 0);\r
2718 StrnCatGrow (&Path2, &Path2Size, L"\\", 0);\r
a405b86d 2719 if (*Path == L'\\') {\r
2720 Path++;\r
47d20b54
MK
2721 while (PathRemoveLastItem (Path2)) {\r
2722 }\r
a405b86d 2723 }\r
47d20b54
MK
2724\r
2725 ASSERT ((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2726 StrnCatGrow (&Path2, &Path2Size, Path, 0);\r
a405b86d 2727 } else {\r
47d20b54
MK
2728 ASSERT (Path2 == NULL);\r
2729 StrnCatGrow (&Path2, NULL, Path, 0);\r
a405b86d 2730 }\r
2731\r
ab94587a 2732 PathCleanUpDirectories (Path2);\r
a405b86d 2733\r
2734 //\r
2735 // do the search\r
2736 //\r
47d20b54 2737 Status = EfiShellFindFiles (Path2, FileList);\r
a405b86d 2738\r
47d20b54 2739 FreePool (Path2);\r
a405b86d 2740\r
47d20b54 2741 if (EFI_ERROR (Status)) {\r
a405b86d 2742 return (Status);\r
2743 }\r
2744\r
733f138d 2745 Found = FALSE;\r
a405b86d 2746 //\r
2747 // We had no errors so open all the files (that are not already opened...)\r
2748 //\r
47d20b54
MK
2749 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetFirstNode (&(*FileList)->Link)\r
2750 ; !IsNull (&(*FileList)->Link, &ShellFileListItem->Link)\r
2751 ; ShellFileListItem = (EFI_SHELL_FILE_INFO *)GetNextNode (&(*FileList)->Link, &ShellFileListItem->Link)\r
2752 )\r
2753 {\r
2754 if ((ShellFileListItem->Status == 0) && (ShellFileListItem->Handle == NULL)) {\r
a405b86d 2755 ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
47d20b54 2756 Found = TRUE;\r
a405b86d 2757 }\r
2758 }\r
2759\r
733f138d 2760 if (!Found) {\r
2761 return (EFI_NOT_FOUND);\r
2762 }\r
47d20b54
MK
2763\r
2764 return (EFI_SUCCESS);\r
a405b86d 2765}\r
2766\r
2767/**\r
09fd5328
JC
2768 Gets the environment variable and Attributes, or list of environment variables. Can be\r
2769 used instead of GetEnv().\r
2770\r
2771 This function returns the current value of the specified environment variable and\r
2772 the Attributes. If no variable name was specified, then all of the known\r
2773 variables will be returned.\r
2774\r
2775 @param[in] Name A pointer to the environment variable name. If Name is NULL,\r
2776 then the function will return all of the defined shell\r
2777 environment variables. In the case where multiple environment\r
2778 variables are being returned, each variable will be terminated\r
2779 by a NULL, and the list will be terminated by a double NULL.\r
2780 @param[out] Attributes If not NULL, a pointer to the returned attributes bitmask for\r
2781 the environment variable. In the case where Name is NULL, and\r
2782 multiple environment variables are being returned, Attributes\r
2783 is undefined.\r
2784\r
f5ba4007
QS
2785 @retval NULL The environment variable doesn't exist.\r
2786 @return A non-NULL value points to the variable's value. The returned\r
09fd5328 2787 pointer does not need to be freed by the caller.\r
a405b86d 2788**/\r
2789CONST CHAR16 *\r
c20bd8e1 2790EFIAPI\r
47d20b54
MK
2791EfiShellGetEnvEx (\r
2792 IN CONST CHAR16 *Name,\r
2793 OUT UINT32 *Attributes OPTIONAL\r
a405b86d 2794 )\r
2795{\r
47d20b54
MK
2796 EFI_STATUS Status;\r
2797 VOID *Buffer;\r
2798 UINTN Size;\r
2799 ENV_VAR_LIST *Node;\r
2800 CHAR16 *CurrentWriteLocation;\r
a405b86d 2801\r
47d20b54 2802 Size = 0;\r
a405b86d 2803 Buffer = NULL;\r
2804\r
2805 if (Name == NULL) {\r
a405b86d 2806 //\r
2807 // Build the semi-colon delimited list. (2 passes)\r
2808 //\r
47d20b54
MK
2809 for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)\r
2810 ; !IsNull (&gShellEnvVarList.Link, &Node->Link)\r
2811 ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)\r
2812 )\r
2813 {\r
2814 ASSERT (Node->Key != NULL);\r
2815 Size += StrSize (Node->Key);\r
a405b86d 2816 }\r
2817\r
47d20b54 2818 Size += 2*sizeof (CHAR16);\r
a405b86d 2819\r
47d20b54 2820 Buffer = AllocateZeroPool (Size);\r
3c865f20 2821 if (Buffer == NULL) {\r
3c865f20 2822 return (NULL);\r
2823 }\r
a405b86d 2824\r
47d20b54 2825 CurrentWriteLocation = (CHAR16 *)Buffer;\r
a405b86d 2826\r
47d20b54
MK
2827 for ( Node = (ENV_VAR_LIST *)GetFirstNode (&gShellEnvVarList.Link)\r
2828 ; !IsNull (&gShellEnvVarList.Link, &Node->Link)\r
2829 ; Node = (ENV_VAR_LIST *)GetNextNode (&gShellEnvVarList.Link, &Node->Link)\r
2830 )\r
2831 {\r
2832 ASSERT (Node->Key != NULL);\r
2833 StrCpyS (\r
2834 CurrentWriteLocation,\r
2835 (Size)/sizeof (CHAR16) - (CurrentWriteLocation - ((CHAR16 *)Buffer)),\r
2836 Node->Key\r
2837 );\r
2838 CurrentWriteLocation += StrLen (CurrentWriteLocation) + 1;\r
2839 }\r
a405b86d 2840 } else {\r
2841 //\r
2842 // We are doing a specific environment variable\r
2843 //\r
47d20b54 2844 Status = ShellFindEnvVarInList (Name, (CHAR16 **)&Buffer, &Size, Attributes);\r
a405b86d 2845\r
47d20b54 2846 if (EFI_ERROR (Status)) {\r
a405b86d 2847 //\r
b62bb885 2848 // get the size we need for this EnvVariable\r
a405b86d 2849 //\r
47d20b54 2850 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name, Attributes, &Size, Buffer);\r
b62bb885
QS
2851 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2852 //\r
2853 // Allocate the space and recall the get function\r
2854 //\r
47d20b54
MK
2855 Buffer = AllocateZeroPool (Size);\r
2856 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name, Attributes, &Size, Buffer);\r
b62bb885 2857 }\r
47d20b54 2858\r
b62bb885 2859 //\r
6a5033ca 2860 // we didn't get it (might not exist)\r
b62bb885
QS
2861 // free the memory if we allocated any and return NULL\r
2862 //\r
47d20b54 2863 if (EFI_ERROR (Status)) {\r
b62bb885 2864 if (Buffer != NULL) {\r
47d20b54 2865 FreePool (Buffer);\r
b62bb885 2866 }\r
47d20b54 2867\r
b62bb885
QS
2868 return (NULL);\r
2869 } else {\r
2870 //\r
2871 // If we did not find the environment variable in the gShellEnvVarList\r
2872 // but get it from UEFI variable storage successfully then we need update\r
2873 // the gShellEnvVarList.\r
2874 //\r
2875 ShellFreeEnvVarList ();\r
2876 Status = ShellInitEnvVarList ();\r
2877 ASSERT (Status == EFI_SUCCESS);\r
a405b86d 2878 }\r
a405b86d 2879 }\r
2880 }\r
2881\r
2882 //\r
2883 // return the buffer\r
2884 //\r
47d20b54 2885 return (AddBufferToFreeList (Buffer));\r
a405b86d 2886}\r
2887\r
09fd5328
JC
2888/**\r
2889 Gets either a single or list of environment variables.\r
2890\r
2891 If name is not NULL then this function returns the current value of the specified\r
2892 environment variable.\r
2893\r
2894 If Name is NULL, then a list of all environment variable names is returned. Each is a\r
2895 NULL terminated string with a double NULL terminating the list.\r
2896\r
2897 @param Name A pointer to the environment variable name. If\r
2898 Name is NULL, then the function will return all\r
2899 of the defined shell environment variables. In\r
2900 the case where multiple environment variables are\r
2901 being returned, each variable will be terminated by\r
2902 a NULL, and the list will be terminated by a double\r
2903 NULL.\r
2904\r
2905 @retval !=NULL A pointer to the returned string.\r
2906 The returned pointer does not need to be freed by the caller.\r
2907\r
2908 @retval NULL The environment variable doesn't exist or there are\r
2909 no environment variables.\r
2910**/\r
2911CONST CHAR16 *\r
2912EFIAPI\r
47d20b54
MK
2913EfiShellGetEnv (\r
2914 IN CONST CHAR16 *Name\r
09fd5328
JC
2915 )\r
2916{\r
47d20b54 2917 return (EfiShellGetEnvEx (Name, NULL));\r
09fd5328
JC
2918}\r
2919\r
a405b86d 2920/**\r
2921 Internal variable setting function. Allows for setting of the read only variables.\r
2922\r
2923 @param Name Points to the NULL-terminated environment variable name.\r
2924 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2925 empty string then the environment variable is deleted.\r
2926 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2927\r
2928 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2929**/\r
2930EFI_STATUS\r
47d20b54
MK
2931InternalEfiShellSetEnv (\r
2932 IN CONST CHAR16 *Name,\r
2933 IN CONST CHAR16 *Value,\r
2934 IN BOOLEAN Volatile\r
a405b86d 2935 )\r
2936{\r
47d20b54 2937 EFI_STATUS Status;\r
b62bb885 2938\r
47d20b54
MK
2939 if ((Value == NULL) || (StrLen (Value) == 0)) {\r
2940 Status = SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);\r
2941 if (!EFI_ERROR (Status)) {\r
2942 ShellRemvoeEnvVarFromList (Name);\r
b62bb885 2943 }\r
a405b86d 2944 } else {\r
47d20b54
MK
2945 SHELL_DELETE_ENVIRONMENT_VARIABLE (Name);\r
2946 Status = ShellAddEnvVarToList (\r
2947 Name,\r
2948 Value,\r
2949 StrSize (Value),\r
ffbc60a0
RN
2950 EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE)\r
2951 );\r
2952 if (!EFI_ERROR (Status)) {\r
2953 Status = Volatile\r
c5c994c5
CC
2954 ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name, StrSize (Value) - sizeof (CHAR16), Value)\r
2955 : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name, StrSize (Value) - sizeof (CHAR16), Value);\r
ffbc60a0 2956 if (EFI_ERROR (Status)) {\r
47d20b54 2957 ShellRemvoeEnvVarFromList (Name);\r
b62bb885 2958 }\r
a405b86d 2959 }\r
2960 }\r
47d20b54 2961\r
ffbc60a0 2962 return Status;\r
a405b86d 2963}\r
2964\r
2965/**\r
2966 Sets the environment variable.\r
2967\r
2968 This function changes the current value of the specified environment variable. If the\r
2969 environment variable exists and the Value is an empty string, then the environment\r
2970 variable is deleted. If the environment variable exists and the Value is not an empty\r
2971 string, then the value of the environment variable is changed. If the environment\r
2972 variable does not exist and the Value is an empty string, there is no action. If the\r
2973 environment variable does not exist and the Value is a non-empty string, then the\r
2974 environment variable is created and assigned the specified value.\r
2975\r
2976 For a description of volatile and non-volatile environment variables, see UEFI Shell\r
2977 2.0 specification section 3.6.1.\r
2978\r
2979 @param Name Points to the NULL-terminated environment variable name.\r
2980 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2981 empty string then the environment variable is deleted.\r
2982 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2983\r
2984 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2985**/\r
2986EFI_STATUS\r
2987EFIAPI\r
47d20b54
MK
2988EfiShellSetEnv (\r
2989 IN CONST CHAR16 *Name,\r
2990 IN CONST CHAR16 *Value,\r
2991 IN BOOLEAN Volatile\r
a405b86d 2992 )\r
2993{\r
47d20b54 2994 if ((Name == NULL) || (*Name == CHAR_NULL)) {\r
a405b86d 2995 return (EFI_INVALID_PARAMETER);\r
2996 }\r
47d20b54 2997\r
a405b86d 2998 //\r
2999 // Make sure we dont 'set' a predefined read only variable\r
3000 //\r
0e967dff
RN
3001 if ((StrCmp (Name, L"cwd") == 0) ||\r
3002 (StrCmp (Name, L"lasterror") == 0) ||\r
3003 (StrCmp (Name, L"profiles") == 0) ||\r
3004 (StrCmp (Name, L"uefishellsupport") == 0) ||\r
3005 (StrCmp (Name, L"uefishellversion") == 0) ||\r
3006 (StrCmp (Name, L"uefiversion") == 0) ||\r
3007 (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
47d20b54
MK
3008 (StrCmp (Name, mNoNestingEnvVarName) == 0))\r
3009 )\r
3010 {\r
a405b86d 3011 return (EFI_INVALID_PARAMETER);\r
3012 }\r
47d20b54
MK
3013\r
3014 return (InternalEfiShellSetEnv (Name, Value, Volatile));\r
a405b86d 3015}\r
3016\r
3017/**\r
3018 Returns the current directory on the specified device.\r
3019\r
3020 If FileSystemMapping is NULL, it returns the current working directory. If the\r
3021 FileSystemMapping is not NULL, it returns the current directory associated with the\r
3022 FileSystemMapping. In both cases, the returned name includes the file system\r
3023 mapping (i.e. fs0:\current-dir).\r
dcbdb8bf 3024\r
fbd2dfad 3025 Note that the current directory string should exclude the tailing backslash character.\r
a405b86d 3026\r
3027 @param FileSystemMapping A pointer to the file system mapping. If NULL,\r
3028 then the current working directory is returned.\r
3029\r
3030 @retval !=NULL The current directory.\r
3031 @retval NULL Current directory does not exist.\r
3032**/\r
3033CONST CHAR16 *\r
3034EFIAPI\r
47d20b54
MK
3035EfiShellGetCurDir (\r
3036 IN CONST CHAR16 *FileSystemMapping OPTIONAL\r
a405b86d 3037 )\r
3038{\r
47d20b54
MK
3039 CHAR16 *PathToReturn;\r
3040 UINTN Size;\r
3041 SHELL_MAP_LIST *MapListItem;\r
3042\r
3043 if (!IsListEmpty (&gShellMapList.Link)) {\r
a405b86d 3044 //\r
3045 // if parameter is NULL, use current\r
3046 //\r
3047 if (FileSystemMapping == NULL) {\r
47d20b54 3048 return (EfiShellGetEnv (L"cwd"));\r
a405b86d 3049 } else {\r
47d20b54 3050 Size = 0;\r
a405b86d 3051 PathToReturn = NULL;\r
47d20b54 3052 MapListItem = ShellCommandFindMapItem (FileSystemMapping);\r
a405b86d 3053 if (MapListItem != NULL) {\r
47d20b54
MK
3054 ASSERT ((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));\r
3055 PathToReturn = StrnCatGrow (&PathToReturn, &Size, MapListItem->MapName, 0);\r
3056 PathToReturn = StrnCatGrow (&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0);\r
a405b86d 3057 }\r
3058 }\r
47d20b54
MK
3059\r
3060 return (AddBufferToFreeList (PathToReturn));\r
a405b86d 3061 } else {\r
3062 return (NULL);\r
3063 }\r
3064}\r
3065\r
3066/**\r
3067 Changes the current directory on the specified device.\r
3068\r
3069 If the FileSystem is NULL, and the directory Dir does not contain a file system's\r
3070 mapped name, this function changes the current working directory.\r
3071\r
3072 If the FileSystem is NULL and the directory Dir contains a mapped name, then the\r
3073 current file system and the current directory on that file system are changed.\r
3074\r
3075 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file\r
3076 system.\r
3077\r
3078 If FileSystem is not NULL and Dir is not NULL, then this function changes the current\r
3079 directory on the specified file system.\r
3080\r
3081 If the current working directory or the current working file system is changed then the\r
3082 %cwd% environment variable will be updated\r
3083\r
fbd2dfad
QS
3084 Note that the current directory string should exclude the tailing backslash character.\r
3085\r
a405b86d 3086 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working\r
3087 directory is changed.\r
3088 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.\r
3089\r
6a5033ca 3090 @retval EFI_SUCCESS The operation was successful\r
a405b86d 3091 @retval EFI_NOT_FOUND The file system could not be found\r
3092**/\r
3093EFI_STATUS\r
3094EFIAPI\r
47d20b54
MK
3095EfiShellSetCurDir (\r
3096 IN CONST CHAR16 *FileSystem OPTIONAL,\r
3097 IN CONST CHAR16 *Dir\r
a405b86d 3098 )\r
3099{\r
3100 CHAR16 *MapName;\r
3101 SHELL_MAP_LIST *MapListItem;\r
3102 UINTN Size;\r
3103 EFI_STATUS Status;\r
3104 CHAR16 *TempString;\r
3105 CHAR16 *DirectoryName;\r
3106 UINTN TempLen;\r
3107\r
3108 Size = 0;\r
3109 MapName = NULL;\r
3110 MapListItem = NULL;\r
3111 TempString = NULL;\r
3112 DirectoryName = NULL;\r
3113\r
47d20b54 3114 if (((FileSystem == NULL) && (Dir == NULL)) || (Dir == NULL)) {\r
a405b86d 3115 return (EFI_INVALID_PARAMETER);\r
3116 }\r
3117\r
47d20b54 3118 if (IsListEmpty (&gShellMapList.Link)) {\r
a405b86d 3119 return (EFI_NOT_FOUND);\r
3120 }\r
3121\r
47d20b54
MK
3122 DirectoryName = StrnCatGrow (&DirectoryName, NULL, Dir, 0);\r
3123 ASSERT (DirectoryName != NULL);\r
a405b86d 3124\r
47d20b54 3125 PathCleanUpDirectories (DirectoryName);\r
a405b86d 3126\r
3127 if (FileSystem == NULL) {\r
3128 //\r
3129 // determine the file system mapping to use\r
3130 //\r
47d20b54
MK
3131 if (StrStr (DirectoryName, L":") != NULL) {\r
3132 ASSERT (MapName == NULL);\r
3133 MapName = StrnCatGrow (&MapName, NULL, DirectoryName, (StrStr (DirectoryName, L":")-DirectoryName+1));\r
a405b86d 3134 }\r
47d20b54 3135\r
a405b86d 3136 //\r
3137 // find the file system mapping's entry in the list\r
3138 // or use current\r
3139 //\r
3140 if (MapName != NULL) {\r
47d20b54 3141 MapListItem = ShellCommandFindMapItem (MapName);\r
a405b86d 3142\r
3143 //\r
3144 // make that the current file system mapping\r
3145 //\r
3146 if (MapListItem != NULL) {\r
9cf45187 3147 gShellCurMapping = MapListItem;\r
a405b86d 3148 }\r
3149 } else {\r
9cf45187 3150 MapListItem = gShellCurMapping;\r
a405b86d 3151 }\r
3152\r
3153 if (MapListItem == NULL) {\r
4aec9fe3 3154 FreePool (DirectoryName);\r
47d20b54 3155 SHELL_FREE_NON_NULL (MapName);\r
a405b86d 3156 return (EFI_NOT_FOUND);\r
3157 }\r
3158\r
3159 //\r
3160 // now update the MapListItem's current directory\r
3161 //\r
47d20b54
MK
3162 if ((MapListItem->CurrentDirectoryPath != NULL) && (DirectoryName[StrLen (DirectoryName) - 1] != L':')) {\r
3163 FreePool (MapListItem->CurrentDirectoryPath);\r
a405b86d 3164 MapListItem->CurrentDirectoryPath = NULL;\r
3165 }\r
47d20b54 3166\r
a405b86d 3167 if (MapName != NULL) {\r
47d20b54
MK
3168 TempLen = StrLen (MapName);\r
3169 if (TempLen != StrLen (DirectoryName)) {\r
3170 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3171 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen (MapName), 0);\r
a405b86d 3172 }\r
47d20b54 3173\r
4aec9fe3 3174 FreePool (MapName);\r
a405b86d 3175 } else {\r
47d20b54
MK
3176 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3177 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
a405b86d 3178 }\r
47d20b54
MK
3179\r
3180 if (((MapListItem->CurrentDirectoryPath != NULL) && (MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] == L'\\')) || (MapListItem->CurrentDirectoryPath == NULL)) {\r
3181 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
fbd2dfad 3182 if (MapListItem->CurrentDirectoryPath != NULL) {\r
47d20b54
MK
3183 MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
3184 }\r
a405b86d 3185 }\r
3186 } else {\r
3187 //\r
3188 // cant have a mapping in the directory...\r
3189 //\r
47d20b54 3190 if (StrStr (DirectoryName, L":") != NULL) {\r
4aec9fe3 3191 FreePool (DirectoryName);\r
a405b86d 3192 return (EFI_INVALID_PARAMETER);\r
3193 }\r
47d20b54 3194\r
a405b86d 3195 //\r
3196 // FileSystem != NULL\r
3197 //\r
47d20b54 3198 MapListItem = ShellCommandFindMapItem (FileSystem);\r
a405b86d 3199 if (MapListItem == NULL) {\r
4aec9fe3 3200 FreePool (DirectoryName);\r
a405b86d 3201 return (EFI_INVALID_PARAMETER);\r
3202 }\r
47d20b54
MK
3203\r
3204 // gShellCurMapping = MapListItem;\r
a405b86d 3205 if (DirectoryName != NULL) {\r
3206 //\r
3207 // change current dir on that file system\r
3208 //\r
3209\r
3210 if (MapListItem->CurrentDirectoryPath != NULL) {\r
47d20b54
MK
3211 FreePool (MapListItem->CurrentDirectoryPath);\r
3212 DEBUG_CODE (\r
3213 MapListItem->CurrentDirectoryPath = NULL;\r
3214 );\r
a405b86d 3215 }\r
47d20b54
MK
3216\r
3217 // ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3218 // MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);\r
3219 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3220 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
3221 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3222 MapListItem->CurrentDirectoryPath = StrnCatGrow (&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
3223 if ((MapListItem->CurrentDirectoryPath != NULL) && (MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] == L'\\')) {\r
3224 ASSERT ((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3225 MapListItem->CurrentDirectoryPath[StrLen (MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
a405b86d 3226 }\r
3227 }\r
3228 }\r
47d20b54 3229\r
4aec9fe3 3230 FreePool (DirectoryName);\r
a405b86d 3231 //\r
3232 // if updated the current directory then update the environment variable\r
3233 //\r
9cf45187 3234 if (MapListItem == gShellCurMapping) {\r
a405b86d 3235 Size = 0;\r
47d20b54
MK
3236 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
3237 StrnCatGrow (&TempString, &Size, MapListItem->MapName, 0);\r
3238 ASSERT ((TempString == NULL && Size == 0) || (TempString != NULL));\r
3239 StrnCatGrow (&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);\r
3240 Status = InternalEfiShellSetEnv (L"cwd", TempString, TRUE);\r
3241 FreePool (TempString);\r
a405b86d 3242 return (Status);\r
3243 }\r
47d20b54
MK
3244\r
3245 return (EFI_SUCCESS);\r
a405b86d 3246}\r
3247\r
3248/**\r
3249 Return help information about a specific command.\r
3250\r
3251 This function returns the help information for the specified command. The help text\r
3252 can be internal to the shell or can be from a UEFI Shell manual page.\r
3253\r
3254 If Sections is specified, then each section name listed will be compared in a casesensitive\r
3255 manner, to the section names described in Appendix B. If the section exists,\r
3256 it will be appended to the returned help text. If the section does not exist, no\r
3257 information will be returned. If Sections is NULL, then all help text information\r
3258 available will be returned.\r
3259\r
3260 @param Command Points to the NULL-terminated UEFI Shell command name.\r
3261 @param Sections Points to the NULL-terminated comma-delimited\r
3262 section names to return. If NULL, then all\r
3263 sections will be returned.\r
3264 @param HelpText On return, points to a callee-allocated buffer\r
3265 containing all specified help text.\r
3266\r
3267 @retval EFI_SUCCESS The help text was returned.\r
3268 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the\r
3269 returned help text.\r
3270 @retval EFI_INVALID_PARAMETER HelpText is NULL\r
3271 @retval EFI_NOT_FOUND There is no help text available for Command.\r
3272**/\r
3273EFI_STATUS\r
3274EFIAPI\r
47d20b54
MK
3275EfiShellGetHelpText (\r
3276 IN CONST CHAR16 *Command,\r
3277 IN CONST CHAR16 *Sections OPTIONAL,\r
3278 OUT CHAR16 **HelpText\r
a405b86d 3279 )\r
3280{\r
3281 CONST CHAR16 *ManFileName;\r
42f75495
SQ
3282 CHAR16 *FixCommand;\r
3283 EFI_STATUS Status;\r
a405b86d 3284\r
47d20b54 3285 ASSERT (HelpText != NULL);\r
42f75495 3286 FixCommand = NULL;\r
a405b86d 3287\r
47d20b54 3288 ManFileName = ShellCommandGetManFileNameHandler (Command);\r
a405b86d 3289\r
3290 if (ManFileName != NULL) {\r
47d20b54 3291 return (ProcessManFile (ManFileName, Command, Sections, NULL, HelpText));\r
a405b86d 3292 } else {\r
47d20b54
MK
3293 if ( (StrLen (Command) > 4)\r
3294 && ((Command[StrLen (Command)-1] == L'i') || (Command[StrLen (Command)-1] == L'I'))\r
3295 && ((Command[StrLen (Command)-2] == L'f') || (Command[StrLen (Command)-2] == L'F'))\r
3296 && ((Command[StrLen (Command)-3] == L'e') || (Command[StrLen (Command)-3] == L'E'))\r
3297 && (Command[StrLen (Command)-4] == L'.')\r
3298 )\r
3299 {\r
3300 FixCommand = AllocateZeroPool (StrSize (Command) - 4 * sizeof (CHAR16));\r
9168df3d
RN
3301 if (FixCommand == NULL) {\r
3302 return EFI_OUT_OF_RESOURCES;\r
3303 }\r
42f75495 3304\r
47d20b54
MK
3305 StrnCpyS (\r
3306 FixCommand,\r
3307 (StrSize (Command) - 4 * sizeof (CHAR16))/sizeof (CHAR16),\r
3308 Command,\r
3309 StrLen (Command)-4\r
3310 );\r
3311 Status = ProcessManFile (FixCommand, FixCommand, Sections, NULL, HelpText);\r
3312 FreePool (FixCommand);\r
42f75495
SQ
3313 return Status;\r
3314 } else {\r
47d20b54 3315 return (ProcessManFile (Command, Command, Sections, NULL, HelpText));\r
42f75495 3316 }\r
a405b86d 3317 }\r
3318}\r
3319\r
3320/**\r
3321 Gets the enable status of the page break output mode.\r
3322\r
3323 User can use this function to determine current page break mode.\r
3324\r
3325 @retval TRUE The page break output mode is enabled.\r
3326 @retval FALSE The page break output mode is disabled.\r
3327**/\r
3328BOOLEAN\r
3329EFIAPI\r
47d20b54 3330EfiShellGetPageBreak (\r
a405b86d 3331 VOID\r
3332 )\r
3333{\r
47d20b54 3334 return (ShellInfoObject.PageBreakEnabled);\r
a405b86d 3335}\r
3336\r
3337/**\r
3338 Judges whether the active shell is the root shell.\r
3339\r
3340 This function makes the user to know that whether the active Shell is the root shell.\r
3341\r
3342 @retval TRUE The active Shell is the root Shell.\r
3343 @retval FALSE The active Shell is NOT the root Shell.\r
3344**/\r
3345BOOLEAN\r
3346EFIAPI\r
47d20b54 3347EfiShellIsRootShell (\r
a405b86d 3348 VOID\r
3349 )\r
3350{\r
47d20b54 3351 return (ShellInfoObject.RootShellInstance);\r
a405b86d 3352}\r
3353\r
3354/**\r
6a5033ca 3355 function to return a semi-colon delimited list of all alias' in the current shell\r
a405b86d 3356\r
3357 up to caller to free the memory.\r
3358\r
3359 @retval NULL No alias' were found\r
6a5033ca 3360 @retval NULL An error occurred getting alias'\r
a405b86d 3361 @return !NULL a list of all alias'\r
3362**/\r
3363CHAR16 *\r
47d20b54 3364InternalEfiShellGetListAlias (\r
e7275d3f 3365 VOID\r
a405b86d 3366 )\r
3367{\r
47d20b54
MK
3368 EFI_STATUS Status;\r
3369 EFI_GUID Guid;\r
3370 CHAR16 *VariableName;\r
3371 UINTN NameSize;\r
3372 UINTN NameBufferSize;\r
3373 CHAR16 *RetVal;\r
3374 UINTN RetSize;\r
a405b86d 3375\r
654a012b 3376 NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
47d20b54
MK
3377 VariableName = AllocateZeroPool (NameBufferSize);\r
3378 RetSize = 0;\r
3379 RetVal = NULL;\r
a405b86d 3380\r
3c865f20 3381 if (VariableName == NULL) {\r
3382 return (NULL);\r
3383 }\r
3384\r
a405b86d 3385 VariableName[0] = CHAR_NULL;\r
3386\r
3387 while (TRUE) {\r
654a012b 3388 NameSize = NameBufferSize;\r
47d20b54
MK
3389 Status = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);\r
3390 if (Status == EFI_NOT_FOUND) {\r
a405b86d 3391 break;\r
654a012b
QS
3392 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
3393 NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
47d20b54
MK
3394 SHELL_FREE_NON_NULL (VariableName);\r
3395 VariableName = AllocateZeroPool (NameBufferSize);\r
654a012b
QS
3396 if (VariableName == NULL) {\r
3397 Status = EFI_OUT_OF_RESOURCES;\r
47d20b54 3398 SHELL_FREE_NON_NULL (RetVal);\r
654a012b
QS
3399 RetVal = NULL;\r
3400 break;\r
3401 }\r
ba0014b9 3402\r
654a012b 3403 NameSize = NameBufferSize;\r
47d20b54 3404 Status = gRT->GetNextVariableName (&NameSize, VariableName, &Guid);\r
654a012b 3405 }\r
ba0014b9 3406\r
654a012b 3407 if (EFI_ERROR (Status)) {\r
47d20b54 3408 SHELL_FREE_NON_NULL (RetVal);\r
654a012b 3409 RetVal = NULL;\r
a405b86d 3410 break;\r
3411 }\r
ba0014b9 3412\r
47d20b54
MK
3413 if (CompareGuid (&Guid, &gShellAliasGuid)) {\r
3414 ASSERT ((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
3415 RetVal = StrnCatGrow (&RetVal, &RetSize, VariableName, 0);\r
3416 RetVal = StrnCatGrow (&RetVal, &RetSize, L";", 0);\r
a405b86d 3417 } // compare guid\r
3418 } // while\r
47d20b54
MK
3419\r
3420 SHELL_FREE_NON_NULL (VariableName);\r
a405b86d 3421\r
3422 return (RetVal);\r
3423}\r
3424\r
b9b77ab1
BJ
3425/**\r
3426 Convert a null-terminated unicode string, in-place, to all lowercase.\r
3427 Then return it.\r
ba0014b9 3428\r
4f344fff 3429 @param Str The null-terminated string to be converted to all lowercase.\r
ba0014b9
LG
3430\r
3431 @return The null-terminated string converted into all lowercase.\r
b9b77ab1 3432**/\r
de4caceb 3433CHAR16 *\r
b9b77ab1 3434ToLower (\r
47d20b54 3435 CHAR16 *Str\r
b9b77ab1
BJ
3436 )\r
3437{\r
47d20b54 3438 UINTN Index;\r
b9b77ab1
BJ
3439\r
3440 for (Index = 0; Str[Index] != L'\0'; Index++) {\r
47d20b54 3441 if ((Str[Index] >= L'A') && (Str[Index] <= L'Z')) {\r
f716d7b8 3442 Str[Index] -= (CHAR16)(L'A' - L'a');\r
b9b77ab1
BJ
3443 }\r
3444 }\r
47d20b54 3445\r
b9b77ab1
BJ
3446 return Str;\r
3447}\r
3448\r
a405b86d 3449/**\r
3450 This function returns the command associated with a alias or a list of all\r
3451 alias'.\r
3452\r
3453 @param[in] Alias Points to the NULL-terminated shell alias.\r
3454 If this parameter is NULL, then all\r
3455 aliases will be returned in ReturnedData.\r
3456 @param[out] Volatile upon return of a single command if TRUE indicates\r
3457 this is stored in a volatile fashion. FALSE otherwise.\r
3458\r
ba0014b9 3459 @return If Alias is not NULL, it will return a pointer to\r
a405b86d 3460 the NULL-terminated command for that alias.\r
3461 If Alias is NULL, ReturnedData points to a ';'\r
3462 delimited list of alias (e.g.\r
3463 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.\r
6a5033ca 3464 @retval NULL an error occurred\r
a405b86d 3465 @retval NULL Alias was not a valid Alias\r
3466**/\r
3467CONST CHAR16 *\r
3468EFIAPI\r
47d20b54
MK
3469EfiShellGetAlias (\r
3470 IN CONST CHAR16 *Alias,\r
3471 OUT BOOLEAN *Volatile OPTIONAL\r
a405b86d 3472 )\r
3473{\r
3474 CHAR16 *RetVal;\r
3475 UINTN RetSize;\r
3476 UINT32 Attribs;\r
3477 EFI_STATUS Status;\r
b9b77ab1 3478 CHAR16 *AliasLower;\r
4c33aace 3479 CHAR16 *AliasVal;\r
a405b86d 3480\r
b9b77ab1 3481 // Convert to lowercase to make aliases case-insensitive\r
a405b86d 3482 if (Alias != NULL) {\r
b9b77ab1 3483 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
9168df3d
RN
3484 if (AliasLower == NULL) {\r
3485 return NULL;\r
3486 }\r
47d20b54 3487\r
b9b77ab1
BJ
3488 ToLower (AliasLower);\r
3489\r
a405b86d 3490 if (Volatile == NULL) {\r
4c33aace 3491 GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
47d20b54
MK
3492 FreePool (AliasLower);\r
3493 return (AddBufferToFreeList (AliasVal));\r
a405b86d 3494 }\r
47d20b54 3495\r
a405b86d 3496 RetSize = 0;\r
47d20b54
MK
3497 RetVal = NULL;\r
3498 Status = gRT->GetVariable (AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
a405b86d 3499 if (Status == EFI_BUFFER_TOO_SMALL) {\r
47d20b54
MK
3500 RetVal = AllocateZeroPool (RetSize);\r
3501 Status = gRT->GetVariable (AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
a405b86d 3502 }\r
47d20b54
MK
3503\r
3504 if (EFI_ERROR (Status)) {\r
a405b86d 3505 if (RetVal != NULL) {\r
47d20b54 3506 FreePool (RetVal);\r
a405b86d 3507 }\r
47d20b54
MK
3508\r
3509 FreePool (AliasLower);\r
a405b86d 3510 return (NULL);\r
3511 }\r
47d20b54 3512\r
a405b86d 3513 if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {\r
3514 *Volatile = FALSE;\r
3515 } else {\r
3516 *Volatile = TRUE;\r
3517 }\r
3518\r
b9b77ab1 3519 FreePool (AliasLower);\r
47d20b54 3520 return (AddBufferToFreeList (RetVal));\r
a405b86d 3521 }\r
47d20b54
MK
3522\r
3523 return (AddBufferToFreeList (InternalEfiShellGetListAlias ()));\r
a405b86d 3524}\r
3525\r
3526/**\r
3527 Changes a shell command alias.\r
3528\r
3529 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3530\r
3531 this function does not check for built in alias'.\r
3532\r
3533 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3534 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3535 Command refers to an alias, that alias will be deleted.\r
3536 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3537 Alias being set will be stored in a non-volatile fashion.\r
3538\r
3539 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3540 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3541**/\r
3542EFI_STATUS\r
47d20b54
MK
3543InternalSetAlias (\r
3544 IN CONST CHAR16 *Command,\r
3545 IN CONST CHAR16 *Alias,\r
3546 IN BOOLEAN Volatile\r
a405b86d 3547 )\r
3548{\r
b9b77ab1
BJ
3549 EFI_STATUS Status;\r
3550 CHAR16 *AliasLower;\r
7ec69844 3551 BOOLEAN DeleteAlias;\r
b9b77ab1 3552\r
7ec69844 3553 DeleteAlias = FALSE;\r
a405b86d 3554 if (Alias == NULL) {\r
3555 //\r
7ec69844 3556 // We must be trying to remove one if Alias is NULL\r
a405b86d 3557 // remove an alias (but passed in COMMAND parameter)\r
3558 //\r
7ec69844
RN
3559 Alias = Command;\r
3560 DeleteAlias = TRUE;\r
3561 }\r
47d20b54 3562\r
7ec69844 3563 ASSERT (Alias != NULL);\r
a405b86d 3564\r
7ec69844
RN
3565 //\r
3566 // Convert to lowercase to make aliases case-insensitive\r
3567 //\r
3568 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
3569 if (AliasLower == NULL) {\r
3570 return EFI_OUT_OF_RESOURCES;\r
a405b86d 3571 }\r
47d20b54 3572\r
7ec69844 3573 ToLower (AliasLower);\r
b9b77ab1 3574\r
7ec69844
RN
3575 if (DeleteAlias) {\r
3576 Status = gRT->SetVariable (AliasLower, &gShellAliasGuid, 0, 0, NULL);\r
3577 } else {\r
3578 Status = gRT->SetVariable (\r
47d20b54
MK
3579 AliasLower,\r
3580 &gShellAliasGuid,\r
7ec69844 3581 EFI_VARIABLE_BOOTSERVICE_ACCESS | (Volatile ? 0 : EFI_VARIABLE_NON_VOLATILE),\r
47d20b54
MK
3582 StrSize (Command),\r
3583 (VOID *)Command\r
7ec69844 3584 );\r
b9b77ab1 3585 }\r
7ec69844
RN
3586\r
3587 FreePool (AliasLower);\r
3588\r
b9b77ab1 3589 return Status;\r
a405b86d 3590}\r
3591\r
3592/**\r
3593 Changes a shell command alias.\r
3594\r
3595 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3596\r
3597\r
3598 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3599 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3600 Command refers to an alias, that alias will be deleted.\r
3601 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If\r
3602 FALSE and the alias already exists, then the existing alias is unchanged and\r
3603 EFI_ACCESS_DENIED is returned.\r
3604 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3605 Alias being set will be stored in a non-volatile fashion.\r
3606\r
3607 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3608 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3609 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to\r
3610 FALSE.\r
b9b77ab1 3611 @retval EFI_INVALID_PARAMETER Command is null or the empty string.\r
a405b86d 3612**/\r
3613EFI_STATUS\r
3614EFIAPI\r
47d20b54
MK
3615EfiShellSetAlias (\r
3616 IN CONST CHAR16 *Command,\r
3617 IN CONST CHAR16 *Alias,\r
3618 IN BOOLEAN Replace,\r
3619 IN BOOLEAN Volatile\r
a405b86d 3620 )\r
3621{\r
47d20b54 3622 if (ShellCommandIsOnAliasList ((Alias == NULL) ? Command : Alias)) {\r
b9b77ab1
BJ
3623 //\r
3624 // cant set over a built in alias\r
3625 //\r
a405b86d 3626 return (EFI_ACCESS_DENIED);\r
47d20b54 3627 } else if ((Command == NULL) || (*Command == CHAR_NULL) || (StrLen (Command) == 0)) {\r
b9b77ab1
BJ
3628 //\r
3629 // Command is null or empty\r
3630 //\r
a405b86d 3631 return (EFI_INVALID_PARAMETER);\r
47d20b54 3632 } else if ((EfiShellGetAlias (Command, NULL) != NULL) && !Replace) {\r
b9b77ab1
BJ
3633 //\r
3634 // Alias already exists, Replace not set\r
3635 //\r
a405b86d 3636 return (EFI_ACCESS_DENIED);\r
b9b77ab1 3637 } else {\r
47d20b54 3638 return (InternalSetAlias (Command, Alias, Volatile));\r
a405b86d 3639 }\r
a405b86d 3640}\r
3641\r
3642// Pure FILE_HANDLE operations are passed to FileHandleLib\r
3643// these functions are indicated by the *\r
47d20b54 3644EFI_SHELL_PROTOCOL mShellProtocol = {\r
a405b86d 3645 EfiShellExecute,\r
3646 EfiShellGetEnv,\r
3647 EfiShellSetEnv,\r
3648 EfiShellGetAlias,\r
3649 EfiShellSetAlias,\r
3650 EfiShellGetHelpText,\r
3651 EfiShellGetDevicePathFromMap,\r
3652 EfiShellGetMapFromDevicePath,\r
3653 EfiShellGetDevicePathFromFilePath,\r
3654 EfiShellGetFilePathFromDevicePath,\r
3655 EfiShellSetMap,\r
3656 EfiShellGetCurDir,\r
3657 EfiShellSetCurDir,\r
3658 EfiShellOpenFileList,\r
3659 EfiShellFreeFileList,\r
3660 EfiShellRemoveDupInFileList,\r
3661 EfiShellBatchIsActive,\r
3662 EfiShellIsRootShell,\r
3663 EfiShellEnablePageBreak,\r
3664 EfiShellDisablePageBreak,\r
3665 EfiShellGetPageBreak,\r
3666 EfiShellGetDeviceName,\r
47d20b54
MK
3667 (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, // *\r
3668 (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, // *\r
a405b86d 3669 EfiShellOpenFileByName,\r
3670 EfiShellClose,\r
3671 EfiShellCreateFile,\r
47d20b54
MK
3672 (EFI_SHELL_READ_FILE)FileHandleRead, // *\r
3673 (EFI_SHELL_WRITE_FILE)FileHandleWrite, // *\r
3674 (EFI_SHELL_DELETE_FILE)FileHandleDelete, // *\r
a405b86d 3675 EfiShellDeleteFileByName,\r
47d20b54
MK
3676 (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, // *\r
3677 (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, // *\r
3678 (EFI_SHELL_FLUSH_FILE)FileHandleFlush, // *\r
a405b86d 3679 EfiShellFindFiles,\r
3680 EfiShellFindFilesInDir,\r
47d20b54 3681 (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, // *\r
a405b86d 3682 EfiShellOpenRoot,\r
3683 EfiShellOpenRootByHandle,\r
3684 NULL,\r
838b31a6
CP
3685 SHELL_MAJOR_VERSION,\r
3686 SHELL_MINOR_VERSION,\r
09fd5328
JC
3687\r
3688 // New for UEFI Shell 2.1\r
3689 EfiShellRegisterGuidName,\r
3690 EfiShellGetGuidName,\r
3691 EfiShellGetGuidFromName,\r
3692 EfiShellGetEnvEx\r
a405b86d 3693};\r
3694\r
3695/**\r
3696 Function to create and install on the current handle.\r
3697\r
3698 Will overwrite any existing ShellProtocols in the system to be sure that\r
3699 the current shell is in control.\r
3700\r
3701 This must be removed via calling CleanUpShellProtocol().\r
3702\r
4ff7e37b 3703 @param[in, out] NewShell The pointer to the pointer to the structure\r
a405b86d 3704 to install.\r
3705\r
3706 @retval EFI_SUCCESS The operation was successful.\r
3707 @return An error from LocateHandle, CreateEvent, or other core function.\r
3708**/\r
3709EFI_STATUS\r
a405b86d 3710CreatePopulateInstallShellProtocol (\r
838b31a6 3711 IN OUT EFI_SHELL_PROTOCOL **NewShell\r
a405b86d 3712 )\r
3713{\r
3714 EFI_STATUS Status;\r
3715 UINTN BufferSize;\r
3716 EFI_HANDLE *Buffer;\r
3717 UINTN HandleCounter;\r
3718 SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode;\r
9168df3d 3719 EFI_SHELL_PROTOCOL *OldShell;\r
a405b86d 3720\r
8be0ba36 3721 if (NewShell == NULL) {\r
3722 return (EFI_INVALID_PARAMETER);\r
3723 }\r
3724\r
47d20b54
MK
3725 BufferSize = 0;\r
3726 Buffer = NULL;\r
a405b86d 3727 OldProtocolNode = NULL;\r
47d20b54 3728 InitializeListHead (&ShellInfoObject.OldShellList.Link);\r
a405b86d 3729\r
a405b86d 3730 //\r
3731 // Initialize EfiShellProtocol object...\r
3732 //\r
47d20b54
MK
3733 Status = gBS->CreateEvent (\r
3734 0,\r
3735 0,\r
3736 NULL,\r
3737 NULL,\r
3738 &mShellProtocol.ExecutionBreak\r
3739 );\r
3740 if (EFI_ERROR (Status)) {\r
8be0ba36 3741 return (Status);\r
3742 }\r
a405b86d 3743\r
3744 //\r
3745 // Get the size of the buffer we need.\r
3746 //\r
47d20b54
MK
3747 Status = gBS->LocateHandle (\r
3748 ByProtocol,\r
3749 &gEfiShellProtocolGuid,\r
3750 NULL,\r
3751 &BufferSize,\r
3752 Buffer\r
3753 );\r
a405b86d 3754 if (Status == EFI_BUFFER_TOO_SMALL) {\r
3755 //\r
3756 // Allocate and recall with buffer of correct size\r
3757 //\r
47d20b54 3758 Buffer = AllocateZeroPool (BufferSize);\r
8be0ba36 3759 if (Buffer == NULL) {\r
3760 return (EFI_OUT_OF_RESOURCES);\r
3761 }\r
47d20b54
MK
3762\r
3763 Status = gBS->LocateHandle (\r
3764 ByProtocol,\r
3765 &gEfiShellProtocolGuid,\r
3766 NULL,\r
3767 &BufferSize,\r
3768 Buffer\r
3769 );\r
3770 if (EFI_ERROR (Status)) {\r
3771 FreePool (Buffer);\r
8be0ba36 3772 return (Status);\r
3773 }\r
47d20b54 3774\r
a405b86d 3775 //\r
3776 // now overwrite each of them, but save the info to restore when we end.\r
3777 //\r
47d20b54
MK
3778 for (HandleCounter = 0; HandleCounter < (BufferSize/sizeof (EFI_HANDLE)); HandleCounter++) {\r
3779 Status = gBS->OpenProtocol (\r
3780 Buffer[HandleCounter],\r
3781 &gEfiShellProtocolGuid,\r
3782 (VOID **)&OldShell,\r
3783 gImageHandle,\r
3784 NULL,\r
3785 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3786 );\r
3787 if (!EFI_ERROR (Status)) {\r
3788 OldProtocolNode = AllocateZeroPool (sizeof (SHELL_PROTOCOL_HANDLE_LIST));\r
51686a7a
RN
3789 if (OldProtocolNode == NULL) {\r
3790 if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {\r
3791 CleanUpShellProtocol (&mShellProtocol);\r
3792 }\r
47d20b54 3793\r
9168df3d
RN
3794 Status = EFI_OUT_OF_RESOURCES;\r
3795 break;\r
3796 }\r
47d20b54 3797\r
a405b86d 3798 //\r
3799 // reinstall over the old one...\r
3800 //\r
9168df3d
RN
3801 OldProtocolNode->Handle = Buffer[HandleCounter];\r
3802 OldProtocolNode->Interface = OldShell;\r
47d20b54
MK
3803 Status = gBS->ReinstallProtocolInterface (\r
3804 OldProtocolNode->Handle,\r
3805 &gEfiShellProtocolGuid,\r
3806 OldProtocolNode->Interface,\r
3807 (VOID *)(&mShellProtocol)\r
3808 );\r
3809 if (!EFI_ERROR (Status)) {\r
a405b86d 3810 //\r
6a5033ca 3811 // we reinstalled successfully. log this so we can reverse it later.\r
a405b86d 3812 //\r
3813\r
3814 //\r
3815 // add to the list for subsequent...\r
3816 //\r
47d20b54 3817 InsertTailList (&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link);\r
a405b86d 3818 }\r
3819 }\r
3820 }\r
47d20b54
MK
3821\r
3822 FreePool (Buffer);\r
a405b86d 3823 } else if (Status == EFI_NOT_FOUND) {\r
47d20b54 3824 ASSERT (IsListEmpty (&ShellInfoObject.OldShellList.Link));\r
a405b86d 3825 //\r
3826 // no one else published yet. just publish it ourselves.\r
3827 //\r
3828 Status = gBS->InstallProtocolInterface (\r
47d20b54
MK
3829 &gImageHandle,\r
3830 &gEfiShellProtocolGuid,\r
3831 EFI_NATIVE_INTERFACE,\r
3832 (VOID *)(&mShellProtocol)\r
3833 );\r
a405b86d 3834 }\r
3835\r
47d20b54
MK
3836 if (PcdGetBool (PcdShellSupportOldProtocols)) {\r
3837 /// @todo support ShellEnvironment2\r
3838 /// @todo do we need to support ShellEnvironment (not ShellEnvironment2) also?\r
a405b86d 3839 }\r
3840\r
47d20b54 3841 if (!EFI_ERROR (Status)) {\r
8be0ba36 3842 *NewShell = &mShellProtocol;\r
3843 }\r
47d20b54 3844\r
a405b86d 3845 return (Status);\r
3846}\r
3847\r
3848/**\r
e9723321 3849 Opposite of CreatePopulateInstallShellProtocol.\r
a405b86d 3850\r
3851 Free all memory and restore the system to the state it was in before calling\r
3852 CreatePopulateInstallShellProtocol.\r
3853\r
4ff7e37b 3854 @param[in, out] NewShell The pointer to the new shell protocol structure.\r
a405b86d 3855\r
3856 @retval EFI_SUCCESS The operation was successful.\r
3857**/\r
3858EFI_STATUS\r
a405b86d 3859CleanUpShellProtocol (\r
838b31a6 3860 IN OUT EFI_SHELL_PROTOCOL *NewShell\r
a405b86d 3861 )\r
3862{\r
47d20b54 3863 SHELL_PROTOCOL_HANDLE_LIST *Node2;\r
a405b86d 3864\r
3865 //\r
3866 // if we need to restore old protocols...\r
3867 //\r
47d20b54
MK
3868 if (!IsListEmpty (&ShellInfoObject.OldShellList.Link)) {\r
3869 for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
a405b86d 3870 ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)\r
47d20b54
MK
3871 ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode (&ShellInfoObject.OldShellList.Link)\r
3872 )\r
3873 {\r
9168df3d
RN
3874 RemoveEntryList (&Node2->Link);\r
3875 gBS->ReinstallProtocolInterface (Node2->Handle, &gEfiShellProtocolGuid, NewShell, Node2->Interface);\r
3876 FreePool (Node2);\r
a405b86d 3877 }\r
3878 } else {\r
3879 //\r
3880 // no need to restore\r
3881 //\r
9168df3d 3882 gBS->UninstallProtocolInterface (gImageHandle, &gEfiShellProtocolGuid, NewShell);\r
a405b86d 3883 }\r
47d20b54 3884\r
9168df3d
RN
3885 return EFI_SUCCESS;\r
3886}\r
3887\r
3888/**\r
3889 Cleanup the shell environment.\r
3890\r
3891 @param[in, out] NewShell The pointer to the new shell protocol structure.\r
3892\r
3893 @retval EFI_SUCCESS The operation was successful.\r
3894**/\r
3895EFI_STATUS\r
3896CleanUpShellEnvironment (\r
3897 IN OUT EFI_SHELL_PROTOCOL *NewShell\r
3898 )\r
3899{\r
47d20b54
MK
3900 EFI_STATUS Status;\r
3901 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
ba0014b9 3902\r
9168df3d
RN
3903 CleanUpShellProtocol (NewShell);\r
3904\r
47d20b54 3905 Status = gBS->CloseEvent (NewShell->ExecutionBreak);\r
8be0ba36 3906 NewShell->ExecutionBreak = NULL;\r
3907\r
47d20b54
MK
3908 Status = gBS->OpenProtocol (\r
3909 gST->ConsoleInHandle,\r
3910 &gEfiSimpleTextInputExProtocolGuid,\r
3911 (VOID **)&SimpleEx,\r
3912 gImageHandle,\r
3913 NULL,\r
3914 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3915 );\r
8be0ba36 3916\r
a7a394a4 3917 if (!EFI_ERROR (Status)) {\r
47d20b54
MK
3918 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
3919 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
3920 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);\r
3921 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);\r
3922 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);\r
3923 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);\r
3924 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);\r
3925 Status = SimpleEx->UnregisterKeyNotify (SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);\r
a7a394a4 3926 }\r
47d20b54 3927\r
a405b86d 3928 return (Status);\r
3929}\r
3930\r
8be0ba36 3931/**\r
3932 Notification function for keystrokes.\r
3933\r
3934 @param[in] KeyData The key that was pressed.\r
3935\r
3936 @retval EFI_SUCCESS The operation was successful.\r
3937**/\r
3938EFI_STATUS\r
3939EFIAPI\r
47d20b54
MK
3940NotificationFunction (\r
3941 IN EFI_KEY_DATA *KeyData\r
8be0ba36 3942 )\r
3943{\r
47d20b54
MK
3944 if (((KeyData->Key.UnicodeChar == L'c') &&\r
3945 ((KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED)) || (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED)))) ||\r
41cf3e45 3946 (KeyData->Key.UnicodeChar == 3)\r
47d20b54
MK
3947 )\r
3948 {\r
733f138d 3949 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
3950 return (EFI_UNSUPPORTED);\r
3951 }\r
47d20b54
MK
3952\r
3953 return (gBS->SignalEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
3954 } else if ((KeyData->Key.UnicodeChar == L's') &&\r
3955 ((KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED)) || (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED)))\r
3956 )\r
3957 {\r
a49f6a2f 3958 ShellInfoObject.HaltOutput = TRUE;\r
8be0ba36 3959 }\r
47d20b54 3960\r
733f138d 3961 return (EFI_SUCCESS);\r
8be0ba36 3962}\r
3963\r
3964/**\r
ba0014b9 3965 Function to start monitoring for CTRL-C using SimpleTextInputEx. This\r
8be0ba36 3966 feature's enabled state was not known when the shell initially launched.\r
3967\r
3968 @retval EFI_SUCCESS The feature is enabled.\r
6a5033ca 3969 @retval EFI_OUT_OF_RESOURCES There is not enough memory available.\r
8be0ba36 3970**/\r
3971EFI_STATUS\r
47d20b54 3972InernalEfiShellStartMonitor (\r
8be0ba36 3973 VOID\r
3974 )\r
3975{\r
47d20b54
MK
3976 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
3977 EFI_KEY_DATA KeyData;\r
3978 EFI_STATUS Status;\r
3979\r
3980 Status = gBS->OpenProtocol (\r
3981 gST->ConsoleInHandle,\r
3982 &gEfiSimpleTextInputExProtocolGuid,\r
3983 (VOID **)&SimpleEx,\r
3984 gImageHandle,\r
3985 NULL,\r
3986 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3987 );\r
3988 if (EFI_ERROR (Status)) {\r
3989 ShellPrintHiiEx (\r
ba0014b9
LG
3990 -1,\r
3991 -1,\r
8be0ba36 3992 NULL,\r
3993 STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
47d20b54
MK
3994 ShellInfoObject.HiiHandle\r
3995 );\r
8be0ba36 3996 return (EFI_SUCCESS);\r
3997 }\r
a405b86d 3998\r
8be0ba36 3999 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
4000 return (EFI_UNSUPPORTED);\r
4001 }\r
4002\r
4003 KeyData.KeyState.KeyToggleState = 0;\r
4004 KeyData.Key.ScanCode = 0;\r
4005 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
4006 KeyData.Key.UnicodeChar = L'c';\r
4007\r
47d20b54
MK
4008 Status = SimpleEx->RegisterKeyNotify (\r
4009 SimpleEx,\r
4010 &KeyData,\r
4011 NotificationFunction,\r
4012 &ShellInfoObject.CtrlCNotifyHandle1\r
4013 );\r
ba0014b9 4014\r
47d20b54
MK
4015 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
4016 if (!EFI_ERROR (Status)) {\r
4017 Status = SimpleEx->RegisterKeyNotify (\r
4018 SimpleEx,\r
4019 &KeyData,\r
4020 NotificationFunction,\r
4021 &ShellInfoObject.CtrlCNotifyHandle2\r
4022 );\r
8be0ba36 4023 }\r
47d20b54
MK
4024\r
4025 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
4026 KeyData.Key.UnicodeChar = 3;\r
4027 if (!EFI_ERROR (Status)) {\r
4028 Status = SimpleEx->RegisterKeyNotify (\r
4029 SimpleEx,\r
4030 &KeyData,\r
4031 NotificationFunction,\r
4032 &ShellInfoObject.CtrlCNotifyHandle3\r
4033 );\r
4034 }\r
4035\r
4036 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
4037 if (!EFI_ERROR (Status)) {\r
4038 Status = SimpleEx->RegisterKeyNotify (\r
4039 SimpleEx,\r
4040 &KeyData,\r
4041 NotificationFunction,\r
4042 &ShellInfoObject.CtrlCNotifyHandle4\r
4043 );\r
8be0ba36 4044 }\r
47d20b54 4045\r
8be0ba36 4046 return (Status);\r
4047}\r