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