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