]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
ShellPkg: Updates to 'smbiosview' command
[mirror_edk2.git] / ShellPkg / Library / UefiShellCommandLib / UefiShellCommandLib.c
CommitLineData
a405b86d 1/** @file\r
2 Provides interface to shell internal functions for shell commands.\r
3\r
1a63ec8f 4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
a405b86d 5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "UefiShellCommandLib.h"\r
16\r
17/// The tag for use in identifying UNICODE files.\r
18/// If the file is UNICODE, the first 16 bits of the file will equal this value.\r
19enum {\r
1a63ec8f 20 gUnicodeFileTag = 0xFEFF\r
a405b86d 21};\r
22\r
23// STATIC local variables\r
24STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList;\r
25STATIC SCRIPT_FILE_LIST mScriptList;\r
26STATIC ALIAS_LIST mAliasList;\r
27STATIC BOOLEAN mEchoState;\r
28STATIC BOOLEAN mExitRequested;\r
b6b22b13 29STATIC UINT64 mExitCode;\r
a405b86d 30STATIC BOOLEAN mExitScript;\r
31STATIC CHAR16 *mProfileList;\r
32STATIC UINTN mProfileListSize;\r
33STATIC UINTN mFsMaxCount = 0;\r
34STATIC UINTN mBlkMaxCount = 0;\r
35STATIC BUFFER_LIST mFileHandleList;\r
36\r
37// global variables required by library class.\r
a405b86d 38EFI_UNICODE_COLLATION_PROTOCOL *gUnicodeCollation = NULL;\r
39EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *gDevPathToText = NULL;\r
40SHELL_MAP_LIST gShellMapList;\r
41SHELL_MAP_LIST *gShellCurDir = NULL;\r
42\r
43CONST CHAR16* SupportLevel[] = {\r
44 L"Minimal",\r
45 L"Scripting",\r
46 L"Basic",\r
47 L"Interactive"\r
48};\r
49\r
50/**\r
51 Function to make sure that the global protocol pointers are valid.\r
52 must be called after constructor before accessing the pointers.\r
53**/\r
54EFI_STATUS\r
55EFIAPI\r
56CommandInit(\r
57 VOID\r
58 )\r
59{\r
60 EFI_STATUS Status;\r
a405b86d 61 if (gUnicodeCollation == NULL) {\r
62 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
63 if (EFI_ERROR(Status)) {\r
64 return (EFI_DEVICE_ERROR);\r
65 }\r
66 }\r
67 if (gDevPathToText == NULL) {\r
68 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID**)&gDevPathToText);\r
69 if (EFI_ERROR(Status)) {\r
70 return (EFI_DEVICE_ERROR);\r
71 }\r
72 }\r
73 return (EFI_SUCCESS);\r
74}\r
75\r
76/**\r
77 Constructor for the Shell Command library.\r
78\r
79 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.\r
80\r
81 @param ImageHandle the image handle of the process\r
82 @param SystemTable the EFI System Table pointer\r
83\r
84 @retval EFI_SUCCESS the initialization was complete sucessfully\r
85**/\r
86RETURN_STATUS\r
87EFIAPI\r
88ShellCommandLibConstructor (\r
89 IN EFI_HANDLE ImageHandle,\r
90 IN EFI_SYSTEM_TABLE *SystemTable\r
91 )\r
92{\r
93 EFI_STATUS Status;\r
94 InitializeListHead(&gShellMapList.Link);\r
95 InitializeListHead(&mCommandList.Link);\r
96 InitializeListHead(&mAliasList.Link);\r
97 InitializeListHead(&mScriptList.Link);\r
98 InitializeListHead(&mFileHandleList.Link);\r
99 mEchoState = TRUE;\r
100\r
101 mExitRequested = FALSE;\r
102 mExitScript = FALSE;\r
103 mProfileListSize = 0;\r
104 mProfileList = NULL;\r
105\r
106 if (gUnicodeCollation == NULL) {\r
107 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID**)&gUnicodeCollation);\r
108 if (EFI_ERROR(Status)) {\r
109 return (EFI_DEVICE_ERROR);\r
110 }\r
111 }\r
112\r
113 return (RETURN_SUCCESS);\r
114}\r
115\r
116/**\r
117 Destructor for the library. free any resources.\r
118\r
119 @param ImageHandle the image handle of the process\r
120 @param SystemTable the EFI System Table pointer\r
121\r
122 @retval RETURN_SUCCESS this function always returns success\r
123**/\r
124RETURN_STATUS\r
125EFIAPI\r
126ShellCommandLibDestructor (\r
127 IN EFI_HANDLE ImageHandle,\r
128 IN EFI_SYSTEM_TABLE *SystemTable\r
129 )\r
130{\r
131 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
3f869579 132 ALIAS_LIST *Node2;\r
a405b86d 133 SCRIPT_FILE_LIST *Node3;\r
134 SHELL_MAP_LIST *MapNode;\r
135 //\r
136 // enumerate throught the list and free all the memory\r
137 //\r
138 while (!IsListEmpty (&mCommandList.Link)) {\r
139 Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link);\r
140 RemoveEntryList(&Node->Link);\r
141 SHELL_FREE_NON_NULL(Node->CommandString);\r
142 FreePool(Node);\r
143 DEBUG_CODE(Node = NULL;);\r
144 }\r
145\r
146 //\r
3f869579 147 // enumerate through the alias list and free all memory\r
a405b86d 148 //\r
149 while (!IsListEmpty (&mAliasList.Link)) {\r
3f869579 150 Node2 = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link);\r
a405b86d 151 RemoveEntryList(&Node2->Link);\r
152 SHELL_FREE_NON_NULL(Node2->CommandString);\r
3f869579 153 SHELL_FREE_NON_NULL(Node2->Alias);\r
154 SHELL_FREE_NON_NULL(Node2);\r
a405b86d 155 DEBUG_CODE(Node2 = NULL;);\r
156 }\r
157\r
158 //\r
159 // enumerate throught the list and free all the memory\r
160 //\r
161 while (!IsListEmpty (&mScriptList.Link)) {\r
162 Node3 = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
163 RemoveEntryList(&Node3->Link);\r
164 DeleteScriptFileStruct(Node3->Data);\r
165 FreePool(Node3);\r
166 }\r
167\r
168 //\r
169 // enumerate throught the mappings list and free all the memory\r
170 //\r
171 if (!IsListEmpty(&gShellMapList.Link)) {\r
172 for (MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
173 ; !IsListEmpty (&gShellMapList.Link)\r
174 ; MapNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
175 ){\r
176 ASSERT(MapNode != NULL);\r
177 RemoveEntryList(&MapNode->Link);\r
178 SHELL_FREE_NON_NULL(MapNode->DevicePath);\r
179 SHELL_FREE_NON_NULL(MapNode->MapName);\r
180 SHELL_FREE_NON_NULL(MapNode->CurrentDirectoryPath);\r
181 FreePool(MapNode);\r
182 }\r
183 }\r
184 if (!IsListEmpty(&mFileHandleList.Link)){\r
185 FreeBufferList(&mFileHandleList);\r
186 }\r
187\r
188 if (mProfileList != NULL) {\r
189 FreePool(mProfileList);\r
190 }\r
191\r
1a63ec8f 192 gUnicodeCollation = NULL;\r
193 gDevPathToText = NULL;\r
194 gShellCurDir = NULL;\r
195\r
a405b86d 196 return (RETURN_SUCCESS);\r
197}\r
198\r
199/**\r
200 Checks if a command is already on the list.\r
201\r
202 @param[in] CommandString The command string to check for on the list.\r
203**/\r
204BOOLEAN\r
205EFIAPI\r
206ShellCommandIsCommandOnList (\r
207 IN CONST CHAR16 *CommandString\r
208 )\r
209{\r
210 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
211\r
212 //\r
213 // assert for NULL parameter\r
214 //\r
215 ASSERT(CommandString != NULL);\r
216\r
217 //\r
218 // check for the command\r
219 //\r
220 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
221 ; !IsNull(&mCommandList.Link, &Node->Link)\r
222 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
223 ){\r
224 ASSERT(Node->CommandString != NULL);\r
225 if (gUnicodeCollation->StriColl(\r
226 gUnicodeCollation,\r
227 (CHAR16*)CommandString,\r
228 Node->CommandString) == 0\r
229 ){\r
230 return (TRUE);\r
231 }\r
232 }\r
233 return (FALSE);\r
234}\r
235\r
236/**\r
237 Get the help text for a command.\r
238\r
239 @param[in] CommandString The command name.\r
240\r
241 @retval NULL No help text was found.\r
242 @return String of help text. Caller reuiqred to free.\r
243**/\r
244CHAR16*\r
245EFIAPI\r
246ShellCommandGetCommandHelp (\r
247 IN CONST CHAR16 *CommandString\r
248 )\r
249{\r
250 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
251\r
252 //\r
253 // assert for NULL parameter\r
254 //\r
255 ASSERT(CommandString != NULL);\r
256\r
257 //\r
258 // check for the command\r
259 //\r
260 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
261 ; !IsNull(&mCommandList.Link, &Node->Link)\r
262 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
263 ){\r
264 ASSERT(Node->CommandString != NULL);\r
265 if (gUnicodeCollation->StriColl(\r
266 gUnicodeCollation,\r
267 (CHAR16*)CommandString,\r
268 Node->CommandString) == 0\r
269 ){\r
270 return (HiiGetString(Node->HiiHandle, Node->ManFormatHelp, NULL));\r
271 }\r
272 }\r
273 return (NULL);\r
274}\r
275\r
276/**\r
277 Registers handlers of type SHELL_RUN_COMMAND and\r
278 SHELL_GET_MAN_FILENAME for each shell command.\r
279\r
280 If the ShellSupportLevel is greater than the value of the\r
281 PcdShellSupportLevel then return RETURN_UNSUPPORTED.\r
282\r
283 Registers the handlers specified by GetHelpInfoHandler and CommandHandler\r
284 with the command specified by CommandString. If the command named by\r
285 CommandString has already been registered, then return\r
286 RETURN_ALREADY_STARTED.\r
287\r
288 If there are not enough resources available to register the handlers then\r
289 RETURN_OUT_OF_RESOURCES is returned.\r
290\r
291 If CommandString is NULL, then ASSERT().\r
292 If GetHelpInfoHandler is NULL, then ASSERT().\r
293 If CommandHandler is NULL, then ASSERT().\r
294 If ProfileName is NULL, then ASSERT().\r
295\r
296 @param[in] CommandString Pointer to the command name. This is the\r
297 name to look for on the command line in\r
298 the shell.\r
299 @param[in] CommandHandler Pointer to a function that runs the\r
300 specified command.\r
301 @param[in] GetManFileName Pointer to a function that provides man\r
302 filename.\r
303 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this\r
304 function.\r
305 @param[in] ProfileName profile name to require for support of this\r
306 function.\r
307 @param[in] CanAffectLE indicates whether this command's return value\r
308 can change the LASTERROR environment variable.\r
309 @param[in] HiiHandle Handle of this command's HII entry.\r
310 @param[in] ManFormatHelp HII locator for the help text.\r
311\r
312 @retval RETURN_SUCCESS The handlers were registered.\r
313 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
314 register the shell command.\r
315 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the\r
316 currently allowed support level.\r
317 @retval RETURN_ALREADY_STARTED The CommandString represents a command that\r
318 is already registered. Only 1 handler set for\r
319 a given command is allowed.\r
320 @sa SHELL_GET_MAN_FILENAME\r
321 @sa SHELL_RUN_COMMAND\r
322**/\r
323RETURN_STATUS\r
324EFIAPI\r
325ShellCommandRegisterCommandName (\r
326 IN CONST CHAR16 *CommandString,\r
327 IN SHELL_RUN_COMMAND CommandHandler,\r
328 IN SHELL_GET_MAN_FILENAME GetManFileName,\r
329 IN UINT32 ShellMinSupportLevel,\r
330 IN CONST CHAR16 *ProfileName,\r
331 IN CONST BOOLEAN CanAffectLE,\r
332 IN CONST EFI_HANDLE HiiHandle,\r
333 IN CONST EFI_STRING_ID ManFormatHelp\r
334 )\r
335{\r
336 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
337\r
338 //\r
339 // ASSERTs for NULL parameters\r
340 //\r
341 ASSERT(CommandString != NULL);\r
342 ASSERT(GetManFileName != NULL);\r
343 ASSERT(CommandHandler != NULL);\r
344 ASSERT(ProfileName != NULL);\r
345\r
346 //\r
347 // check for shell support level\r
348 //\r
349 if (PcdGet8(PcdShellSupportLevel) < ShellMinSupportLevel) {\r
350 return (RETURN_UNSUPPORTED);\r
351 }\r
352\r
353 //\r
354 // check for already on the list\r
355 //\r
356 if (ShellCommandIsCommandOnList(CommandString)) {\r
357 return (RETURN_ALREADY_STARTED);\r
358 }\r
359\r
360 //\r
361 // allocate memory for new struct\r
362 //\r
1a63ec8f 363 Node = AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY));\r
a405b86d 364 ASSERT(Node != NULL);\r
1a63ec8f 365 Node->CommandString = AllocateZeroPool(StrSize(CommandString));\r
a405b86d 366 ASSERT(Node->CommandString != NULL);\r
367\r
368 //\r
369 // populate the new struct\r
370 //\r
371 StrCpy(Node->CommandString, CommandString);\r
372\r
373 Node->GetManFileName = GetManFileName;\r
374 Node->CommandHandler = CommandHandler;\r
375 Node->LastError = CanAffectLE;\r
376 Node->HiiHandle = HiiHandle;\r
377 Node->ManFormatHelp = ManFormatHelp;\r
378\r
379 if ( StrLen(ProfileName)>0\r
380 && ((mProfileList != NULL\r
381 && StrStr(mProfileList, ProfileName) == NULL) || mProfileList == NULL)\r
382 ){\r
383 ASSERT((mProfileList == NULL && mProfileListSize == 0) || (mProfileList != NULL));\r
384 if (mProfileList == NULL) {\r
385 //\r
386 // If this is the first make a leading ';'\r
387 //\r
388 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
389 }\r
390 StrnCatGrow(&mProfileList, &mProfileListSize, ProfileName, 0);\r
391 StrnCatGrow(&mProfileList, &mProfileListSize, L";", 0);\r
392 }\r
393\r
394 //\r
395 // add the new struct to the list\r
396 //\r
397 InsertTailList (&mCommandList.Link, &Node->Link);\r
398\r
399 return (RETURN_SUCCESS);\r
400}\r
401\r
402/**\r
403 Function to get the current Profile string.\r
404\r
405 @retval NULL There are no installed profiles.\r
406 @return A semi-colon delimited list of profiles.\r
407**/\r
408CONST CHAR16 *\r
409EFIAPI\r
410ShellCommandGetProfileList (\r
411 VOID\r
412 )\r
413{\r
414 return (mProfileList);\r
415}\r
416\r
417/**\r
418 Checks if a command string has been registered for CommandString and if so it runs\r
419 the previously registered handler for that command with the command line.\r
420\r
421 If CommandString is NULL, then ASSERT().\r
422\r
423 If Sections is specified, then each section name listed will be compared in a casesensitive\r
424 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,\r
425 it will be appended to the returned help text. If the section does not exist, no\r
426 information will be returned. If Sections is NULL, then all help text information\r
427 available will be returned.\r
428\r
4ff7e37b
ED
429 @param[in] CommandString Pointer to the command name. This is the name\r
430 found on the command line in the shell.\r
431 @param[in, out] RetVal Pointer to the return vaule from the command handler.\r
a405b86d 432\r
4ff7e37b
ED
433 @param[in, out] CanAffectLE indicates whether this command's return value\r
434 needs to be placed into LASTERROR environment variable.\r
a405b86d 435\r
436 @retval RETURN_SUCCESS The handler was run.\r
437 @retval RETURN_NOT_FOUND The CommandString did not match a registered\r
438 command name.\r
439 @sa SHELL_RUN_COMMAND\r
440**/\r
441RETURN_STATUS\r
442EFIAPI\r
443ShellCommandRunCommandHandler (\r
444 IN CONST CHAR16 *CommandString,\r
445 IN OUT SHELL_STATUS *RetVal,\r
446 IN OUT BOOLEAN *CanAffectLE OPTIONAL\r
447 )\r
448{\r
449 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
450\r
451 //\r
452 // assert for NULL parameters\r
453 //\r
454 ASSERT(CommandString != NULL);\r
455\r
456 //\r
457 // check for the command\r
458 //\r
459 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
460 ; !IsNull(&mCommandList.Link, &Node->Link)\r
461 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
462 ){\r
463 ASSERT(Node->CommandString != NULL);\r
464 if (gUnicodeCollation->StriColl(\r
465 gUnicodeCollation,\r
466 (CHAR16*)CommandString,\r
467 Node->CommandString) == 0\r
468 ){\r
469 if (CanAffectLE != NULL) {\r
470 *CanAffectLE = Node->LastError;\r
471 }\r
472 if (RetVal != NULL) {\r
473 *RetVal = Node->CommandHandler(NULL, gST);\r
474 } else {\r
475 Node->CommandHandler(NULL, gST);\r
476 }\r
477 return (RETURN_SUCCESS);\r
478 }\r
479 }\r
480 return (RETURN_NOT_FOUND);\r
481}\r
482\r
483/**\r
484 Checks if a command string has been registered for CommandString and if so it\r
485 returns the MAN filename specified for that command.\r
486\r
487 If CommandString is NULL, then ASSERT().\r
488\r
489 @param[in] CommandString Pointer to the command name. This is the name\r
490 found on the command line in the shell.\\r
491\r
492 @retval NULL the commandString was not a registered command.\r
493 @return other the name of the MAN file.\r
494 @sa SHELL_GET_MAN_FILENAME\r
495**/\r
496CONST CHAR16*\r
497EFIAPI\r
498ShellCommandGetManFileNameHandler (\r
499 IN CONST CHAR16 *CommandString\r
500 )\r
501{\r
502 SHELL_COMMAND_INTERNAL_LIST_ENTRY *Node;\r
503\r
504 //\r
505 // assert for NULL parameters\r
506 //\r
507 ASSERT(CommandString != NULL);\r
508\r
509 //\r
510 // check for the command\r
511 //\r
512 for ( Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetFirstNode(&mCommandList.Link)\r
513 ; !IsNull(&mCommandList.Link, &Node->Link)\r
514 ; Node = (SHELL_COMMAND_INTERNAL_LIST_ENTRY *)GetNextNode(&mCommandList.Link, &Node->Link)\r
515 ){\r
516 ASSERT(Node->CommandString != NULL);\r
517 if (gUnicodeCollation->StriColl(\r
518 gUnicodeCollation,\r
519 (CHAR16*)CommandString,\r
520 Node->CommandString) == 0\r
521 ){\r
522 return (Node->GetManFileName());\r
523 }\r
524 }\r
525 return (NULL);\r
526}\r
527\r
528/**\r
529 Get the list of all available shell internal commands. This is a linked list\r
530 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
531 list functions. do not modify the values.\r
532\r
1a63ec8f 533 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.\r
534\r
a405b86d 535 @return a Linked list of all available shell commands.\r
536**/\r
537CONST COMMAND_LIST*\r
538EFIAPI\r
539ShellCommandGetCommandList (\r
1a63ec8f 540 IN CONST BOOLEAN Sort\r
a405b86d 541 )\r
542{\r
1a63ec8f 543// if (!Sort) {\r
544// return ((COMMAND_LIST*)(&mCommandList));\r
545// }\r
a405b86d 546 return ((COMMAND_LIST*)(&mCommandList));\r
547}\r
548\r
549/**\r
550 Registers aliases to be set as part of the initialization of the shell application.\r
551\r
552 If Command is NULL, then ASSERT().\r
553 If Alias is NULL, then ASSERT().\r
554\r
555 @param[in] Command Pointer to the Command\r
556 @param[in] Alias Pointer to Alias\r
557\r
558 @retval RETURN_SUCCESS The handlers were registered.\r
559 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to\r
560 register the shell command.\r
561**/\r
562RETURN_STATUS\r
563EFIAPI\r
564ShellCommandRegisterAlias (\r
565 IN CONST CHAR16 *Command,\r
566 IN CONST CHAR16 *Alias\r
567 )\r
568{\r
569 ALIAS_LIST *Node;\r
570\r
571 //\r
572 // Asserts for NULL\r
573 //\r
574 ASSERT(Command != NULL);\r
575 ASSERT(Alias != NULL);\r
576\r
577 //\r
578 // allocate memory for new struct\r
579 //\r
1a63ec8f 580 Node = AllocateZeroPool(sizeof(ALIAS_LIST));\r
a405b86d 581 ASSERT(Node != NULL);\r
1a63ec8f 582 Node->CommandString = AllocateZeroPool(StrSize(Command));\r
583 Node->Alias = AllocateZeroPool(StrSize(Alias));\r
a405b86d 584 ASSERT(Node->CommandString != NULL);\r
585 ASSERT(Node->Alias != NULL);\r
586\r
587 //\r
588 // populate the new struct\r
589 //\r
590 StrCpy(Node->CommandString, Command);\r
591 StrCpy(Node->Alias , Alias );\r
592\r
593 //\r
594 // add the new struct to the list\r
595 //\r
596 InsertTailList (&mAliasList.Link, &Node->Link);\r
597\r
598 return (RETURN_SUCCESS);\r
599}\r
600\r
601/**\r
602 Get the list of all shell alias commands. This is a linked list\r
603 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked\r
604 list functions. do not modify the values.\r
605\r
606 @return a Linked list of all requested shell alias'.\r
607**/\r
608CONST ALIAS_LIST*\r
609EFIAPI\r
610ShellCommandGetInitAliasList (\r
611 VOID\r
612 )\r
613{\r
614 return (&mAliasList);\r
615}\r
616\r
617/**\r
1a63ec8f 618 Determine if a given alias is on the list of built in alias'.\r
a405b86d 619\r
620 @param[in] Alias The alias to test for\r
621\r
622 @retval TRUE The alias is a built in alias\r
623 @retval FALSE The alias is not a built in alias\r
624**/\r
625BOOLEAN\r
626EFIAPI\r
627ShellCommandIsOnAliasList(\r
628 IN CONST CHAR16 *Alias\r
629 )\r
630{\r
631 ALIAS_LIST *Node;\r
632\r
633 //\r
634 // assert for NULL parameter\r
635 //\r
636 ASSERT(Alias != NULL);\r
637\r
638 //\r
639 // check for the Alias\r
640 //\r
641 for ( Node = (ALIAS_LIST *)GetFirstNode(&mAliasList.Link)\r
642 ; !IsNull(&mAliasList.Link, &Node->Link)\r
643 ; Node = (ALIAS_LIST *)GetNextNode(&mAliasList.Link, &Node->Link)\r
644 ){\r
645 ASSERT(Node->CommandString != NULL);\r
646 ASSERT(Node->Alias != NULL);\r
647 if (gUnicodeCollation->StriColl(\r
648 gUnicodeCollation,\r
649 (CHAR16*)Alias,\r
650 Node->CommandString) == 0\r
651 ){\r
652 return (TRUE);\r
653 }\r
654 if (gUnicodeCollation->StriColl(\r
655 gUnicodeCollation,\r
656 (CHAR16*)Alias,\r
657 Node->Alias) == 0\r
658 ){\r
659 return (TRUE);\r
660 }\r
661 }\r
662 return (FALSE);\r
663}\r
664\r
665/**\r
666 Function to determine current state of ECHO. Echo determins if lines from scripts\r
667 and ECHO commands are enabled.\r
668\r
669 @retval TRUE Echo is currently enabled\r
670 @retval FALSE Echo is currently disabled\r
671**/\r
672BOOLEAN\r
673EFIAPI\r
674ShellCommandGetEchoState(\r
675 VOID\r
676 )\r
677{\r
678 return (mEchoState);\r
679}\r
680\r
681/**\r
682 Function to set current state of ECHO. Echo determins if lines from scripts\r
683 and ECHO commands are enabled.\r
684\r
685 If State is TRUE, Echo will be enabled.\r
686 If State is FALSE, Echo will be disabled.\r
1a63ec8f 687\r
688 @param[in] State How to set echo.\r
a405b86d 689**/\r
690VOID\r
691EFIAPI\r
692ShellCommandSetEchoState(\r
693 IN BOOLEAN State\r
694 )\r
695{\r
696 mEchoState = State;\r
697}\r
698\r
699/**\r
700 Indicate that the current shell or script should exit.\r
701\r
b6b22b13 702 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.\r
703 @param[in] ErrorCode The 64 bit error code to return.\r
a405b86d 704**/\r
705VOID\r
706EFIAPI\r
707ShellCommandRegisterExit (\r
b6b22b13 708 IN BOOLEAN ScriptOnly,\r
709 IN CONST UINT64 ErrorCode\r
a405b86d 710 )\r
711{\r
712 mExitRequested = (BOOLEAN)(!mExitRequested);\r
713 if (mExitRequested) {\r
714 mExitScript = ScriptOnly;\r
715 } else {\r
716 mExitScript = FALSE;\r
717 }\r
b6b22b13 718 mExitCode = ErrorCode;\r
a405b86d 719}\r
720\r
721/**\r
722 Retrieve the Exit indicator.\r
723\r
724 @retval TRUE Exit was indicated.\r
725 @retval FALSE Exis was not indicated.\r
726**/\r
727BOOLEAN\r
728EFIAPI\r
729ShellCommandGetExit (\r
730 VOID\r
731 )\r
732{\r
733 return (mExitRequested);\r
734}\r
735\r
b6b22b13 736/**\r
737 Retrieve the Exit code.\r
738\r
739 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
740\r
741 @return the value passed into RegisterExit.\r
742**/\r
743UINT64\r
744EFIAPI\r
745ShellCommandGetExitCode (\r
746 VOID\r
747 )\r
748{\r
749 return (mExitCode);\r
750}\r
a405b86d 751/**\r
752 Retrieve the Exit script indicator.\r
753\r
754 If ShellCommandGetExit returns FALSE than the return from this is undefined.\r
755\r
756 @retval TRUE ScriptOnly was indicated.\r
757 @retval FALSE ScriptOnly was not indicated.\r
758**/\r
759BOOLEAN\r
760EFIAPI\r
761ShellCommandGetScriptExit (\r
762 VOID\r
763 )\r
764{\r
765 return (mExitScript);\r
766}\r
767\r
768/**\r
769 Function to cleanup all memory from a SCRIPT_FILE structure.\r
770\r
771 @param[in] Script The pointer to the structure to cleanup.\r
772**/\r
773VOID\r
774EFIAPI\r
775DeleteScriptFileStruct (\r
776 IN SCRIPT_FILE *Script\r
777 )\r
778{\r
779 UINT8 LoopVar;\r
0ab85bef 780\r
781 if (Script == NULL) {\r
782 return;\r
783 }\r
784\r
a405b86d 785 for (LoopVar = 0 ; LoopVar < Script->Argc ; LoopVar++) {\r
0ab85bef 786 SHELL_FREE_NON_NULL(Script->Argv[LoopVar]);\r
a405b86d 787 }\r
788 if (Script->Argv != NULL) {\r
0ab85bef 789 SHELL_FREE_NON_NULL(Script->Argv);\r
a405b86d 790 }\r
791 Script->CurrentCommand = NULL;\r
792 while (!IsListEmpty (&Script->CommandList)) {\r
793 Script->CurrentCommand = (SCRIPT_COMMAND_LIST *)GetFirstNode(&Script->CommandList);\r
794 if (Script->CurrentCommand != NULL) {\r
795 RemoveEntryList(&Script->CurrentCommand->Link);\r
796 if (Script->CurrentCommand->Cl != NULL) {\r
0ab85bef 797 SHELL_FREE_NON_NULL(Script->CurrentCommand->Cl);\r
a405b86d 798 }\r
799 if (Script->CurrentCommand->Data != NULL) {\r
0ab85bef 800 SHELL_FREE_NON_NULL(Script->CurrentCommand->Data);\r
a405b86d 801 }\r
0ab85bef 802 SHELL_FREE_NON_NULL(Script->CurrentCommand);\r
a405b86d 803 }\r
804 }\r
0ab85bef 805 SHELL_FREE_NON_NULL(Script->ScriptName);\r
806 SHELL_FREE_NON_NULL(Script);\r
a405b86d 807}\r
808\r
809/**\r
810 Function to return a pointer to the currently running script file object.\r
811\r
812 @retval NULL A script file is not currently running.\r
813 @return A pointer to the current script file object.\r
814**/\r
815SCRIPT_FILE*\r
816EFIAPI\r
817ShellCommandGetCurrentScriptFile (\r
818 VOID\r
819 )\r
820{\r
821 SCRIPT_FILE_LIST *List;\r
822 if (IsListEmpty (&mScriptList.Link)) {\r
823 return (NULL);\r
824 }\r
825 List = ((SCRIPT_FILE_LIST*)GetFirstNode(&mScriptList.Link));\r
826 return (List->Data);\r
827}\r
828\r
829/**\r
830 Function to set a new script as the currently running one.\r
831\r
832 This function will correctly stack and unstack nested scripts.\r
833\r
834 @param[in] Script Pointer to new script information structure. if NULL\r
835 will remove and de-allocate the top-most Script structure.\r
836\r
837 @return A pointer to the current running script file after this\r
838 change. NULL if removing the final script.\r
839**/\r
840SCRIPT_FILE*\r
841EFIAPI\r
842ShellCommandSetNewScript (\r
843 IN SCRIPT_FILE *Script OPTIONAL\r
844 )\r
845{\r
846 SCRIPT_FILE_LIST *Node;\r
847 if (Script == NULL) {\r
848 if (IsListEmpty (&mScriptList.Link)) {\r
a405b86d 849 return (NULL);\r
850 }\r
851 Node = (SCRIPT_FILE_LIST *)GetFirstNode(&mScriptList.Link);\r
852 RemoveEntryList(&Node->Link);\r
853 DeleteScriptFileStruct(Node->Data);\r
854 FreePool(Node);\r
855 } else {\r
856 Node = AllocateZeroPool(sizeof(SCRIPT_FILE_LIST));\r
0ab85bef 857 if (Node == NULL) {\r
858 return (NULL);\r
859 }\r
a405b86d 860 Node->Data = Script;\r
861 InsertHeadList(&mScriptList.Link, &Node->Link);\r
862 }\r
863 return (ShellCommandGetCurrentScriptFile());\r
864}\r
865\r
866/**\r
867 Function to generate the next default mapping name.\r
868\r
869 If the return value is not NULL then it must be callee freed.\r
870\r
871 @param Type What kind of mapping name to make.\r
872\r
873 @retval NULL a memory allocation failed.\r
874 @return a new map name string\r
875**/\r
876CHAR16*\r
877EFIAPI\r
878ShellCommandCreateNewMappingName(\r
879 IN CONST SHELL_MAPPING_TYPE Type\r
880 )\r
881{\r
882 CHAR16 *String;\r
883 ASSERT(Type < MappingTypeMax);\r
884\r
885 String = NULL;\r
886\r
887 String = AllocateZeroPool(PcdGet8(PcdShellMapNameLength) * sizeof(String[0]));\r
888 UnicodeSPrint(\r
889 String,\r
890 PcdGet8(PcdShellMapNameLength) * sizeof(String[0]),\r
891 Type == MappingTypeFileSystem?L"FS%d:":L"BLK%d:",\r
892 Type == MappingTypeFileSystem?mFsMaxCount++:mBlkMaxCount++);\r
893\r
894 return (String);\r
895}\r
896\r
897/**\r
898 Function to add a map node to the list of map items and update the "path" environment variable (optionally).\r
899\r
900 If Path is TRUE (during initialization only), the path environment variable will also be updated to include\r
901 default paths on the new map name...\r
902\r
903 Path should be FALSE when this function is called from the protocol SetMap function.\r
904\r
905 @param[in] Name The human readable mapped name.\r
906 @param[in] DevicePath The Device Path for this map.\r
907 @param[in] Flags The Flags attribute for this map item.\r
908 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).\r
909\r
910 @retval EFI_SUCCESS The addition was sucessful.\r
911 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
912 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
913**/\r
914EFI_STATUS\r
915EFIAPI\r
916ShellCommandAddMapItemAndUpdatePath(\r
917 IN CONST CHAR16 *Name,\r
918 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
919 IN CONST UINT64 Flags,\r
920 IN CONST BOOLEAN Path\r
921 )\r
922{\r
923 EFI_STATUS Status;\r
924 SHELL_MAP_LIST *MapListNode;\r
925 CONST CHAR16 *OriginalPath;\r
926 CHAR16 *NewPath;\r
927 UINTN NewPathSize;\r
928\r
929 NewPathSize = 0;\r
930 NewPath = NULL;\r
931 OriginalPath = NULL;\r
932 Status = EFI_SUCCESS;\r
933\r
934 MapListNode = AllocateZeroPool(sizeof(SHELL_MAP_LIST));\r
935 if (MapListNode == NULL) {\r
936 Status = EFI_OUT_OF_RESOURCES;\r
937 } else {\r
938 MapListNode->Flags = Flags;\r
939 MapListNode->MapName = AllocateZeroPool(StrSize(Name));\r
940 MapListNode->DevicePath = DuplicateDevicePath(DevicePath);\r
941 if ((MapListNode->MapName == NULL) || (MapListNode->DevicePath == NULL)){\r
942 Status = EFI_OUT_OF_RESOURCES;\r
943 } else {\r
944 StrCpy(MapListNode->MapName, Name);\r
945 InsertTailList(&gShellMapList.Link, &MapListNode->Link);\r
946 }\r
947 }\r
948 if (EFI_ERROR(Status)) {\r
949 if (MapListNode != NULL) {\r
950 if (MapListNode->DevicePath != NULL) {\r
951 FreePool(MapListNode->DevicePath);\r
952 }\r
953 if (MapListNode->MapName != NULL) {\r
954 FreePool(MapListNode->MapName);\r
955 }\r
956 FreePool(MapListNode);\r
957 }\r
958 } else if (Path) {\r
959 //\r
960 // Since there was no error and Path was TRUE\r
961 // Now add the correct path for that mapping\r
962 //\r
963 OriginalPath = gEfiShellProtocol->GetEnv(L"path");\r
964 ASSERT((NewPath == NULL && NewPathSize == 0) || (NewPath != NULL));\r
965 if (OriginalPath != NULL) {\r
966 StrnCatGrow(&NewPath, &NewPathSize, OriginalPath, 0);\r
967 } else {\r
968 StrnCatGrow(&NewPath, &NewPathSize, L".\\", 0);\r
969 }\r
970 StrnCatGrow(&NewPath, &NewPathSize, L";", 0);\r
971 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
972 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\tools\\;", 0);\r
973 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
974 StrnCatGrow(&NewPath, &NewPathSize, L"\\efi\\boot\\;", 0);\r
975 StrnCatGrow(&NewPath, &NewPathSize, Name, 0);\r
976 StrnCatGrow(&NewPath, &NewPathSize, L"\\", 0);\r
977\r
978 Status = gEfiShellProtocol->SetEnv(L"path", NewPath, TRUE);\r
979 ASSERT_EFI_ERROR(Status);\r
980 FreePool(NewPath);\r
981 }\r
982 return (Status);\r
983}\r
984\r
985/**\r
986 Creates the default map names for each device path in the system with\r
987 a protocol depending on the Type.\r
988\r
989 Creates the consistent map names for each device path in the system with\r
990 a protocol depending on the Type.\r
991\r
992 Note: This will reset all mappings in the system("map -r").\r
993\r
994 Also sets up the default path environment variable if Type is FileSystem.\r
995\r
996 @retval EFI_SUCCESS All map names were created sucessfully.\r
997 @retval EFI_NOT_FOUND No protocols were found in the system.\r
998 @return Error returned from gBS->LocateHandle().\r
999\r
1000 @sa LocateHandle\r
1001**/\r
1002EFI_STATUS\r
1003EFIAPI\r
1004ShellCommandCreateInitialMappingsAndPaths(\r
1005 VOID\r
1006 )\r
1007{\r
1008 EFI_STATUS Status;\r
1009 EFI_HANDLE *HandleList;\r
1010 UINTN Count;\r
1011 EFI_DEVICE_PATH_PROTOCOL **DevicePathList;\r
1012 CHAR16 *NewDefaultName;\r
1013 CHAR16 *NewConsistName;\r
1014 EFI_DEVICE_PATH_PROTOCOL **ConsistMappingTable;\r
1015 SHELL_MAP_LIST *MapListNode;\r
1016\r
1017 HandleList = NULL;\r
1018\r
1019 //\r
1020 // Reset the static members back to zero\r
1021 //\r
1022 mFsMaxCount = 0;\r
1023 mBlkMaxCount = 0;\r
1024\r
1025 gEfiShellProtocol->SetEnv(L"path", L"", TRUE);\r
1026\r
1027 //\r
1028 // First empty out the existing list.\r
1029 //\r
1030 if (!IsListEmpty(&gShellMapList.Link)) {\r
1031 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1032 ; !IsListEmpty(&gShellMapList.Link)\r
1033 ; MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
1034 ){\r
1035 RemoveEntryList(&MapListNode->Link);\r
1036 FreePool(MapListNode);\r
1037 } // for loop\r
1038 }\r
1039\r
1040 //\r
1041 // Find each handle with Simple File System\r
1042 //\r
0ab85bef 1043 HandleList = GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid);\r
a405b86d 1044 if (HandleList != NULL) {\r
1045 //\r
1046 // Do a count of the handles\r
1047 //\r
1048 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1049\r
1050 //\r
1051 // Get all Device Paths\r
1052 //\r
1a63ec8f 1053 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
a405b86d 1054 ASSERT(DevicePathList != NULL);\r
1055\r
1056 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1057 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1058 }\r
1059\r
1060 //\r
1061 // Sort all DevicePaths\r
1062 //\r
1063 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1064\r
1065 ShellCommandConsistMappingInitialize(&ConsistMappingTable);\r
1066 //\r
1067 // Assign new Mappings to all...\r
1068 //\r
1069 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1070 //\r
1071 // Get default name first\r
1072 //\r
1073 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeFileSystem);\r
1074 ASSERT(NewDefaultName != NULL);\r
1075 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, TRUE);\r
1076 ASSERT_EFI_ERROR(Status);\r
1077 FreePool(NewDefaultName);\r
1078\r
1079 //\r
1080 // Now do consistent name\r
1081 //\r
1082 NewConsistName = ShellCommandConsistMappingGenMappingName(DevicePathList[Count], ConsistMappingTable);\r
1083 if (NewConsistName != NULL) {\r
1084 Status = ShellCommandAddMapItemAndUpdatePath(NewConsistName, DevicePathList[Count], 0, FALSE);\r
1085 ASSERT_EFI_ERROR(Status);\r
1086 FreePool(NewConsistName);\r
1087 }\r
1088 }\r
1089\r
1090 ShellCommandConsistMappingUnInitialize(ConsistMappingTable);\r
1091\r
1092 SHELL_FREE_NON_NULL(HandleList);\r
1093 SHELL_FREE_NON_NULL(DevicePathList);\r
1094\r
1095 HandleList = NULL;\r
1096 } else {\r
1097 Count = (UINTN)-1;\r
1098 }\r
1099\r
1100 //\r
1101 // Find each handle with Block Io\r
1102 //\r
0ab85bef 1103 HandleList = GetHandleListByProtocol(&gEfiBlockIoProtocolGuid);\r
a405b86d 1104 if (HandleList != NULL) {\r
1105 for (Count = 0 ; HandleList[Count] != NULL ; Count++);\r
1106\r
1107 //\r
1108 // Get all Device Paths\r
1109 //\r
1a63ec8f 1110 DevicePathList = AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL*) * Count);\r
a405b86d 1111 ASSERT(DevicePathList != NULL);\r
1112\r
1113 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1114 DevicePathList[Count] = DevicePathFromHandle(HandleList[Count]);\r
1115 }\r
1116\r
1117 //\r
1118 // Sort all DevicePaths\r
1119 //\r
1120 PerformQuickSort(DevicePathList, Count, sizeof(EFI_DEVICE_PATH_PROTOCOL*), DevicePathCompare);\r
1121\r
1122 //\r
1123 // Assign new Mappings to all...\r
1124 //\r
1125 for (Count = 0 ; HandleList[Count] != NULL ; Count++) {\r
1126 //\r
1127 // Get default name first\r
1128 //\r
1129 NewDefaultName = ShellCommandCreateNewMappingName(MappingTypeBlockIo);\r
1130 ASSERT(NewDefaultName != NULL);\r
1131 Status = ShellCommandAddMapItemAndUpdatePath(NewDefaultName, DevicePathList[Count], 0, FALSE);\r
1132 ASSERT_EFI_ERROR(Status);\r
1133 FreePool(NewDefaultName);\r
1134 }\r
1135\r
1136 SHELL_FREE_NON_NULL(HandleList);\r
1137 SHELL_FREE_NON_NULL(DevicePathList);\r
1138 } else if (Count == (UINTN)-1) {\r
1139 return (EFI_NOT_FOUND);\r
1140 }\r
1141\r
1142 return (EFI_SUCCESS);\r
1143}\r
1144\r
a405b86d 1145/**\r
1146 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.\r
1147\r
1148 @param[in] Handle The SHELL_FILE_HANDLE to convert.\r
1149\r
1150 @return a EFI_FILE_PROTOCOL* representing the same file.\r
1151**/\r
1152EFI_FILE_PROTOCOL*\r
1153EFIAPI\r
1154ConvertShellHandleToEfiFileProtocol(\r
1155 IN CONST SHELL_FILE_HANDLE Handle\r
1156 )\r
1157{\r
1158 return ((EFI_FILE_PROTOCOL*)(Handle));\r
1159}\r
1160\r
1161/**\r
1162 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.\r
1163\r
1164 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.\r
1165 @param[in] Path The path to the file for verification.\r
1166\r
ff51746b 1167 @return A SHELL_FILE_HANDLE representing the same file.\r
1168 @retval NULL There was not enough memory.\r
a405b86d 1169**/\r
1170SHELL_FILE_HANDLE\r
1171EFIAPI\r
1172ConvertEfiFileProtocolToShellHandle(\r
1173 IN CONST EFI_FILE_PROTOCOL *Handle,\r
1174 IN CONST CHAR16 *Path\r
1175 )\r
1176{\r
1177 SHELL_COMMAND_FILE_HANDLE *Buffer;\r
1178 BUFFER_LIST *NewNode;\r
1179\r
1180 if (Path != NULL) {\r
1181 Buffer = AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE));\r
ff51746b 1182 if (Buffer == NULL) {\r
1183 return (NULL);\r
1184 }\r
1a63ec8f 1185 NewNode = AllocateZeroPool(sizeof(BUFFER_LIST));\r
ff51746b 1186 if (NewNode == NULL) {\r
1187 return (NULL);\r
1188 }\r
a405b86d 1189 Buffer->FileHandle = (EFI_FILE_PROTOCOL*)Handle;\r
1190 Buffer->Path = StrnCatGrow(&Buffer->Path, NULL, Path, 0);\r
ff51746b 1191 if (Buffer->Path == NULL) {\r
1192 return (NULL);\r
1193 }\r
a405b86d 1194 NewNode->Buffer = Buffer;\r
1195\r
1196 InsertHeadList(&mFileHandleList.Link, &NewNode->Link);\r
1197 }\r
1198 return ((SHELL_FILE_HANDLE)(Handle));\r
1199}\r
1200\r
1201/**\r
1202 Find the path that was logged with the specified SHELL_FILE_HANDLE.\r
1203\r
1204 @param[in] Handle The SHELL_FILE_HANDLE to query on.\r
1205\r
1206 @return A pointer to the path for the file.\r
1207**/\r
1208CONST CHAR16*\r
1209EFIAPI\r
1210ShellFileHandleGetPath(\r
1211 IN CONST SHELL_FILE_HANDLE Handle\r
1212 )\r
1213{\r
1214 BUFFER_LIST *Node;\r
1215\r
1216 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1217 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1218 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1219 ){\r
1220 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
1221 return (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1222 }\r
1223 }\r
1224 return (NULL);\r
1225}\r
1226\r
1227/**\r
1a63ec8f 1228 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.\r
a405b86d 1229\r
1230 @param[in] Handle The SHELL_FILE_HANDLE to remove.\r
1231\r
1232 @retval TRUE The item was removed.\r
1233 @retval FALSE The item was not found.\r
1234**/\r
1235BOOLEAN\r
1236EFIAPI\r
1237ShellFileHandleRemove(\r
1238 IN CONST SHELL_FILE_HANDLE Handle\r
1239 )\r
1240{\r
1241 BUFFER_LIST *Node;\r
1242\r
1243 for (Node = (BUFFER_LIST*)GetFirstNode(&mFileHandleList.Link)\r
1244 ; !IsNull(&mFileHandleList.Link, &Node->Link)\r
1245 ; Node = (BUFFER_LIST*)GetNextNode(&mFileHandleList.Link, &Node->Link)\r
1246 ){\r
1247 if ((Node->Buffer) && (((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->FileHandle == Handle)){\r
a405b86d 1248 RemoveEntryList(&Node->Link);\r
ff51746b 1249 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE *)Node->Buffer)->Path);\r
1250 SHELL_FREE_NON_NULL(Node->Buffer);\r
1251 SHELL_FREE_NON_NULL(Node);\r
a405b86d 1252 return (TRUE);\r
1253 }\r
1254 }\r
1255 return (FALSE);\r
1256}\r
1257\r
1258/**\r
1259 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.\r
1260\r
1261 This will NOT work on directories.\r
1262\r
1263 If Handle is NULL, then ASSERT.\r
1264\r
1265 @param[in] Handle the file handle\r
1266\r
1267 @retval TRUE the position is at the end of the file\r
1268 @retval FALSE the position is not at the end of the file\r
1269**/\r
1270BOOLEAN\r
1271EFIAPI\r
1272ShellFileHandleEof(\r
1273 IN SHELL_FILE_HANDLE Handle\r
1274 )\r
1275{\r
1276 EFI_FILE_INFO *Info;\r
1277 UINT64 Pos;\r
1278 BOOLEAN RetVal;\r
1279\r
1280 //\r
1281 // ASSERT if Handle is NULL\r
1282 //\r
1283 ASSERT(Handle != NULL);\r
1284\r
1285 gEfiShellProtocol->GetFilePosition(Handle, &Pos);\r
1286 Info = gEfiShellProtocol->GetFileInfo (Handle);\r
1287 ASSERT(Info != NULL);\r
1288 gEfiShellProtocol->SetFilePosition(Handle, Pos);\r
1289\r
1290 if (Info == NULL) {\r
1291 return (FALSE);\r
1292 }\r
1293\r
1294 if (Pos == Info->FileSize) {\r
1295 RetVal = TRUE;\r
1296 } else {\r
1297 RetVal = FALSE;\r
1298 }\r
1299\r
1300 FreePool (Info);\r
1301\r
1302 return (RetVal);\r
1303}\r
1304\r
a405b86d 1305/**\r
1306 Frees any BUFFER_LIST defined type.\r
1a63ec8f 1307\r
1308 @param[in] List The BUFFER_LIST object to free.\r
a405b86d 1309**/\r
1310VOID\r
1311EFIAPI\r
1312FreeBufferList (\r
1313 IN BUFFER_LIST *List\r
1314 )\r
1315{\r
1316 BUFFER_LIST *BufferListEntry;\r
1317\r
1318 if (List == NULL){\r
1319 return;\r
1320 }\r
1321 //\r
1322 // enumerate through the buffer list and free all memory\r
1323 //\r
1324 for ( BufferListEntry = ( BUFFER_LIST *)GetFirstNode(&List->Link)\r
1325 ; !IsListEmpty (&List->Link)\r
1326 ; BufferListEntry = (BUFFER_LIST *)GetFirstNode(&List->Link)\r
1327 ){\r
1328 RemoveEntryList(&BufferListEntry->Link);\r
1329 ASSERT(BufferListEntry->Buffer != NULL);\r
1330 if (BufferListEntry->Buffer != NULL) {\r
1331 FreePool(BufferListEntry->Buffer);\r
1332 }\r
1333 FreePool(BufferListEntry);\r
1334 }\r
1335}\r
1336\r