]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/BaseShellLib/BaseShellLib.c
205974d519168435479176b70e56c7bcfc301436
[mirror_edk2.git] / ShellPkg / Library / BaseShellLib / BaseShellLib.c
1 /** @file
2 Provides interface to shell functionality for shell commands and applications.
3
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Uefi.h>
16 #include <Library/ShellLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/BaseLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/DevicePathLib.h>
23 #include <Protocol/EfiShellEnvironment2.h>
24 #include <Protocol/EfiShellInterface.h>
25 #include <Protocol/EfiShell.h>
26 #include <Protocol/EfiShellParameters.h>
27 #include <Protocol/SimpleFileSystem.h>
28
29 #define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
30 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
31
32 EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
33 EFI_SHELL_INTERFACE *mEfiShellInterface;
34 EFI_SHELL_PROTOCOL *mEfiShellProtocol;
35 EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;
36 EFI_HANDLE mEfiShellEnvironment2Handle;
37 EFI_LIST_ENTRY *mOldStyleFileList;
38
39 /**
40 helper function to find ShellEnvironment2 for constructor
41 **/
42 EFI_STATUS
43 EFIAPI
44 ShellFindSE2 (
45 IN EFI_HANDLE ImageHandle
46 )
47 {
48 EFI_STATUS Status;
49 EFI_HANDLE *Buffer;
50 UINTN BufferSize;
51 UINTN HandleIndex;
52
53 BufferSize = 0;
54 Buffer = NULL;
55 Status = gBS->OpenProtocol(ImageHandle,
56 &gEfiShellEnvironment2Guid,
57 (VOID **)&mEfiShellEnvironment2,
58 ImageHandle,
59 NULL,
60 EFI_OPEN_PROTOCOL_GET_PROTOCOL
61 );
62 //
63 // look for the mEfiShellEnvironment2 protocol at a higher level
64 //
65 if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE &&
66 (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER ||
67 (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER)))) {
68 //
69 // figure out how big of a buffer we need.
70 //
71 Status = gBS->LocateHandle (ByProtocol,
72 &gEfiShellEnvironment2Guid,
73 NULL, // ignored for ByProtocol
74 &BufferSize,
75 Buffer
76 );
77 ASSERT(Status == EFI_BUFFER_TOO_SMALL);
78 Buffer = (EFI_HANDLE*)AllocatePool(BufferSize);
79 ASSERT(Buffer != NULL);
80 Status = gBS->LocateHandle (ByProtocol,
81 &gEfiShellEnvironment2Guid,
82 NULL, // ignored for ByProtocol
83 &BufferSize,
84 Buffer
85 );
86 if (!EFI_ERROR (Status)) {
87 //
88 // now parse the list of returned handles
89 //
90 Status = EFI_NOT_FOUND;
91 for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) {
92 Status = gBS->OpenProtocol(Buffer[HandleIndex],
93 &gEfiShellEnvironment2Guid,
94 (VOID **)&mEfiShellEnvironment2,
95 ImageHandle,
96 NULL,
97 EFI_OPEN_PROTOCOL_GET_PROTOCOL
98 );
99 if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid) != FALSE &&
100 (mEfiShellEnvironment2->MajorVersion > EFI_SHELL_MAJOR_VER ||
101 (mEfiShellEnvironment2->MajorVersion == EFI_SHELL_MAJOR_VER && mEfiShellEnvironment2->MinorVersion >= EFI_SHELL_MINOR_VER))) {
102 mEfiShellEnvironment2Handle = Buffer[HandleIndex];
103 Status = EFI_SUCCESS;
104 break;
105 }
106 }
107 }
108 }
109 if (Buffer != NULL) {
110 FreePool (Buffer);
111 }
112 return (Status);
113 }
114
115 /**
116 Constructor for the Shell library.
117
118 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
119
120 @param ImageHandle the image handle of the process
121 @param SystemTable the EFI System Table pointer
122
123 @retval EFI_SUCCESS the initialization was complete sucessfully
124 @return others an error ocurred during initialization
125 **/
126 EFI_STATUS
127 EFIAPI
128 ShellLibConstructor (
129 IN EFI_HANDLE ImageHandle,
130 IN EFI_SYSTEM_TABLE *SystemTable
131 )
132 {
133 EFI_STATUS Status;
134
135 ASSERT(SystemTable != NULL);
136 ASSERT(gBS != NULL);
137
138 mEfiShellEnvironment2 = NULL;
139 mEfiShellProtocol = NULL;
140 mEfiShellParametersProtocol = NULL;
141 mEfiShellInterface = NULL;
142 mEfiShellEnvironment2Handle = NULL;
143 mOldStyleFileList = NULL;
144
145 //
146 // UEFI 2.0 shell interfaces (used preferentially)
147 //
148 Status = gBS->OpenProtocol(ImageHandle,
149 &gEfiShellProtocolGuid,
150 (VOID **)&mEfiShellProtocol,
151 ImageHandle,
152 NULL,
153 EFI_OPEN_PROTOCOL_GET_PROTOCOL
154 );
155 if (EFI_ERROR(Status)) {
156 mEfiShellProtocol = NULL;
157 }
158 Status = gBS->OpenProtocol(ImageHandle,
159 &gEfiShellParametersProtocolGuid,
160 (VOID **)&mEfiShellParametersProtocol,
161 ImageHandle,
162 NULL,
163 EFI_OPEN_PROTOCOL_GET_PROTOCOL
164 );
165 if (EFI_ERROR(Status)) {
166 mEfiShellParametersProtocol = NULL;
167 }
168
169 if (mEfiShellParametersProtocol == NULL || mEfiShellProtocol == NULL) {
170 //
171 // Moved to seperate function due to complexity
172 //
173 Status = ShellFindSE2(ImageHandle);
174
175 if (EFI_ERROR(Status)) {
176 DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
177 mEfiShellEnvironment2 = NULL;
178 }
179 Status = gBS->OpenProtocol(ImageHandle,
180 &gEfiShellInterfaceGuid,
181 (VOID **)&mEfiShellInterface,
182 ImageHandle,
183 NULL,
184 EFI_OPEN_PROTOCOL_GET_PROTOCOL
185 );
186 if (EFI_ERROR(Status)) {
187 mEfiShellInterface = NULL;
188 }
189 }
190 //
191 // only success getting 2 of either the old or new, but no 1/2 and 1/2
192 //
193 if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||
194 (mEfiShellProtocol != NULL && mEfiShellParametersProtocol != NULL) ) {
195 return (EFI_SUCCESS);
196 }
197 return (EFI_NOT_FOUND);
198 }
199
200 /**
201 Destructory for the library. free any resources.
202 **/
203 EFI_STATUS
204 EFIAPI
205 ShellLibDestructor (
206 IN EFI_HANDLE ImageHandle,
207 IN EFI_SYSTEM_TABLE *SystemTable
208 )
209 {
210 if (mEfiShellEnvironment2 != NULL) {
211 gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
212 &gEfiShellEnvironment2Guid,
213 ImageHandle,
214 NULL);
215 }
216 if (mEfiShellInterface != NULL) {
217 gBS->CloseProtocol(ImageHandle,
218 &gEfiShellInterfaceGuid,
219 ImageHandle,
220 NULL);
221 }
222 if (mEfiShellProtocol != NULL) {
223 gBS->CloseProtocol(ImageHandle,
224 &gEfiShellProtocolGuid,
225 ImageHandle,
226 NULL);
227 }
228 if (mEfiShellParametersProtocol != NULL) {
229 gBS->CloseProtocol(ImageHandle,
230 &gEfiShellParametersProtocolGuid,
231 ImageHandle,
232 NULL);
233 }
234 return (EFI_SUCCESS);
235 }
236 /**
237 This function will retrieve the information about the file for the handle
238 specified and store it in allocated pool memory.
239
240 This function allocates a buffer to store the file\92s information. It is the
241 caller\92s responsibility to free the buffer
242
243 @param FileHandle The file handle of the file for which information is
244 being requested.
245
246 @retval NULL information could not be retrieved.
247
248 @return the information about the file
249 **/
250 EFI_FILE_INFO*
251 EFIAPI
252 ShellGetFileInfo (
253 IN EFI_FILE_HANDLE FileHandle
254 )
255 {
256 EFI_GUID FileInfoGuid;
257 EFI_FILE_INFO *pFileInfo;
258 UINTN FileInfoSize;
259 EFI_STATUS Status;
260
261 //
262 // ASSERT if FileHandle is NULL
263 //
264 ASSERT (FileHandle != NULL);
265
266 //
267 // Get the required size to allocate
268 //
269 FileInfoGuid = gEfiFileInfoGuid;
270 FileInfoSize = 0;
271 pFileInfo = NULL;
272 Status = FileHandle->GetInfo(FileHandle,
273 &FileInfoGuid,
274 &FileInfoSize,
275 pFileInfo);
276 //
277 // error is expected. getting size to allocate
278 //
279 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
280 pFileInfo = AllocateZeroPool(FileInfoSize);
281 ASSERT (pFileInfo != NULL);
282 //
283 // now get the information
284 //
285 Status = FileHandle->GetInfo(FileHandle,
286 &FileInfoGuid,
287 &FileInfoSize,
288 pFileInfo);
289 //
290 // if we got an error free the memory and return NULL
291 //
292 if (EFI_ERROR(Status)) {
293 FreePool(pFileInfo);
294 return NULL;
295 }
296 return (pFileInfo);
297 }
298
299 /**
300 This function will set the information about the file for the opened handle
301 specified.
302
303 @param FileHandle The file handle of the file for which information
304 is being set
305
306 @param FileInfo The infotmation to set.
307
308 @retval EFI_SUCCESS The information was set.
309 @retval EFI_UNSUPPORTED The InformationType is not known.
310 @retval EFI_NO_MEDIA The device has no medium.
311 @retval EFI_DEVICE_ERROR The device reported an error.
312 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
313 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
314 @retval EFI_ACCESS_DENIED The file was opened read only.
315 @retval EFI_VOLUME_FULL The volume is full.
316 **/
317 EFI_STATUS
318 EFIAPI
319 ShellSetFileInfo (
320 IN EFI_FILE_HANDLE FileHandle,
321 IN EFI_FILE_INFO *FileInfo
322 )
323 {
324 EFI_GUID FileInfoGuid;
325
326 //
327 // ASSERT if the FileHandle or FileInfo is NULL
328 //
329 ASSERT (FileHandle != NULL);
330 ASSERT (FileInfo != NULL);
331
332 FileInfoGuid = gEfiFileInfoGuid;
333 //
334 // Set the info
335 //
336 return (FileHandle->SetInfo(FileHandle,
337 &FileInfoGuid,
338 (UINTN)FileInfo->Size,
339 FileInfo));
340 }
341
342 /**
343 This function will open a file or directory referenced by DevicePath.
344
345 This function opens a file with the open mode according to the file path. The
346 Attributes is valid only for EFI_FILE_MODE_CREATE.
347
348 @param FilePath on input the device path to the file. On output
349 the remaining device path.
350 @param DeviceHandle pointer to the system device handle.
351 @param FileHandle pointer to the file handle.
352 @param OpenMode the mode to open the file with.
353 @param Attributes the file's file attributes.
354
355 @retval EFI_SUCCESS The information was set.
356 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
357 @retval EFI_UNSUPPORTED Could not open the file path.
358 @retval EFI_NOT_FOUND The specified file could not be found on the
359 device or the file system could not be found on
360 the device.
361 @retval EFI_NO_MEDIA The device has no medium.
362 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
363 medium is no longer supported.
364 @retval EFI_DEVICE_ERROR The device reported an error.
365 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
366 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
367 @retval EFI_ACCESS_DENIED The file was opened read only.
368 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
369 file.
370 @retval EFI_VOLUME_FULL The volume is full.
371 **/
372 EFI_STATUS
373 EFIAPI
374 ShellOpenFileByDevicePath(
375 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
376 OUT EFI_HANDLE *DeviceHandle,
377 OUT EFI_FILE_HANDLE *FileHandle,
378 IN UINT64 OpenMode,
379 IN UINT64 Attributes
380 )
381 {
382 CHAR16 *FileName;
383 EFI_STATUS Status;
384 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
385 EFI_FILE_HANDLE LastHandle;
386
387 //
388 // ASERT for FileHandle, FilePath, and DeviceHandle being NULL
389 //
390 ASSERT(FilePath != NULL);
391 ASSERT(FileHandle != NULL);
392 ASSERT(DeviceHandle != NULL);
393 //
394 // which shell interface should we use
395 //
396 if (mEfiShellProtocol != NULL) {
397 //
398 // use UEFI Shell 2.0 method.
399 //
400 FileName = mEfiShellProtocol->GetFilePathFromDevicePath(*FilePath);
401 if (FileName == NULL) {
402 return (EFI_INVALID_PARAMETER);
403 }
404 Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes);
405 FreePool(FileName);
406 return (Status);
407 } else {
408 //
409 // use old shell method.
410 //
411 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
412 FilePath,
413 DeviceHandle);
414 if (EFI_ERROR (Status)) {
415 return Status;
416 }
417 Status = gBS->OpenProtocol(*DeviceHandle,
418 &gEfiSimpleFileSystemProtocolGuid,
419 &EfiSimpleFileSystemProtocol,
420 gImageHandle,
421 NULL,
422 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
423 if (EFI_ERROR (Status)) {
424 return Status;
425 }
426 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle);
427 if (EFI_ERROR (Status)) {
428 FileHandle = NULL;
429 return Status;
430 }
431
432 //
433 // go down directories one node at a time.
434 //
435 while (!IsDevicePathEnd (*FilePath)) {
436 //
437 // For file system access each node should be a file path component
438 //
439 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
440 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
441 ) {
442 FileHandle = NULL;
443 return (EFI_INVALID_PARAMETER);
444 }
445 //
446 // Open this file path node
447 //
448 LastHandle = *FileHandle;
449 *FileHandle = NULL;
450
451 //
452 // Try to test opening an existing file
453 //
454 Status = LastHandle->Open (
455 LastHandle,
456 FileHandle,
457 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
458 OpenMode &~EFI_FILE_MODE_CREATE,
459 0
460 );
461
462 //
463 // see if the error was that it needs to be created
464 //
465 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
466 Status = LastHandle->Open (
467 LastHandle,
468 FileHandle,
469 ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
470 OpenMode,
471 Attributes
472 );
473 }
474 //
475 // Close the last node
476 //
477 LastHandle->Close (LastHandle);
478
479 if (EFI_ERROR(Status)) {
480 return (Status);
481 }
482
483 //
484 // Get the next node
485 //
486 *FilePath = NextDevicePathNode (*FilePath);
487 }
488 return (EFI_SUCCESS);
489 }
490 }
491
492 /**
493 This function will open a file or directory referenced by filename.
494
495 If return is EFI_SUCCESS, the Filehandle is the opened file\92s handle;
496 otherwise, the Filehandle is NULL. The Attributes is valid only for
497 EFI_FILE_MODE_CREATE.
498
499 if FileNAme is NULL then ASSERT()
500
501 @param FileName pointer to file name
502 @param FileHandle pointer to the file handle.
503 @param OpenMode the mode to open the file with.
504 @param Attributes the file's file attributes.
505
506 @retval EFI_SUCCESS The information was set.
507 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
508 @retval EFI_UNSUPPORTED Could not open the file path.
509 @retval EFI_NOT_FOUND The specified file could not be found on the
510 device or the file system could not be found
511 on the device.
512 @retval EFI_NO_MEDIA The device has no medium.
513 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
514 medium is no longer supported.
515 @retval EFI_DEVICE_ERROR The device reported an error.
516 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
517 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
518 @retval EFI_ACCESS_DENIED The file was opened read only.
519 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
520 file.
521 @retval EFI_VOLUME_FULL The volume is full.
522 **/
523 EFI_STATUS
524 EFIAPI
525 ShellOpenFileByName(
526 IN CHAR16 *FileName,
527 OUT EFI_FILE_HANDLE *FileHandle,
528 IN UINT64 OpenMode,
529 IN UINT64 Attributes
530 )
531 {
532 EFI_HANDLE DeviceHandle;
533 EFI_DEVICE_PATH_PROTOCOL *FilePath;
534
535 //
536 // ASSERT if FileName is NULL
537 //
538 ASSERT(FileName != NULL);
539
540 if (mEfiShellProtocol != NULL) {
541 //
542 // Use UEFI Shell 2.0 method
543 //
544 return (mEfiShellProtocol->OpenFileByName(FileName,
545 FileHandle,
546 OpenMode));
547 }
548 //
549 // Using EFI Shell version
550 // this means convert name to path and call that function
551 // since this will use EFI method again that will open it.
552 //
553 ASSERT(mEfiShellEnvironment2 != NULL);
554 FilePath = mEfiShellEnvironment2->NameToPath (FileName);
555 if (FileDevicePath != NULL) {
556 return (ShellOpenFileByDevicePath(&FilePath,
557 &DeviceHandle,
558 FileHandle,
559 OpenMode,
560 Attributes ));
561 }
562 return (EFI_DEVICE_ERROR);
563 }
564 /**
565 This function create a directory
566
567 If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
568 otherwise, the Filehandle is NULL. If the directory already existed, this
569 function opens the existing directory.
570
571 @param DirectoryName pointer to directory name
572 @param FileHandle pointer to the file handle.
573
574 @retval EFI_SUCCESS The information was set.
575 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
576 @retval EFI_UNSUPPORTED Could not open the file path.
577 @retval EFI_NOT_FOUND The specified file could not be found on the
578 device or the file system could not be found
579 on the device.
580 @retval EFI_NO_MEDIA The device has no medium.
581 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
582 medium is no longer supported.
583 @retval EFI_DEVICE_ERROR The device reported an error.
584 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
585 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
586 @retval EFI_ACCESS_DENIED The file was opened read only.
587 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
588 file.
589 @retval EFI_VOLUME_FULL The volume is full.
590 @sa ShellOpenFileByName
591 **/
592 EFI_STATUS
593 EFIAPI
594 ShellCreateDirectory(
595 IN CHAR16 *DirectoryName,
596 OUT EFI_FILE_HANDLE *FileHandle
597 )
598 {
599 //
600 // this is a pass thru to the open file function with sepcific open mode and attributes
601 //
602 return (ShellOpenFileByName(DirectoryName,
603 FileHandle,
604 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
605 EFI_FILE_DIRECTORY
606 ));
607 }
608
609 /**
610 This function reads information from an opened file.
611
612 If FileHandle is not a directory, the function reads the requested number of
613 bytes from the file at the file\92s current position and returns them in Buffer.
614 If the read goes beyond the end of the file, the read length is truncated to the
615 end of the file. The file\92s current position is increased by the number of bytes
616 returned. If FileHandle is a directory, the function reads the directory entry
617 at the file\92s current position and returns the entry in Buffer. If the Buffer
618 is not large enough to hold the current directory entry, then
619 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
620 BufferSize is set to be the size of the buffer needed to read the entry. On
621 success, the current position is updated to the next directory entry. If there
622 are no more directory entries, the read returns a zero-length buffer.
623 EFI_FILE_INFO is the structure returned as the directory entry.
624
625 @param FileHandle the opened file handle
626 @param BufferSize on input the size of buffer in bytes. on return
627 the number of bytes written.
628 @param Buffer the buffer to put read data into.
629
630 @retval EFI_SUCCESS Data was read.
631 @retval EFI_NO_MEDIA The device has no media.
632 @retval EFI_DEVICE_ERROR The device reported an error.
633 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
634 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
635 size.
636
637 **/
638 EFI_STATUS
639 EFIAPI
640 ShellReadFile(
641 IN EFI_FILE_HANDLE FileHandle,
642 IN OUT UINTN *BufferSize,
643 OUT VOID *Buffer
644 )
645 {
646 //
647 // ASSERT if FileHandle is NULL
648 //
649 ASSERT (FileHandle != NULL);
650
651 //
652 // Perform the read based on EFI_FILE_PROTOCOL
653 //
654 return (FileHandle->Read(FileHandle, BufferSize, Buffer));
655 }
656
657
658 /**
659 Write data to a file.
660
661 This function writes the specified number of bytes to the file at the current
662 file position. The current file position is advanced the actual number of bytes
663 written, which is returned in BufferSize. Partial writes only occur when there
664 has been a data error during the write attempt (such as \93volume space full\94).
665 The file is automatically grown to hold the data if required. Direct writes to
666 opened directories are not supported.
667
668 @param FileHandle The opened file for writing
669 @param BufferSize on input the number of bytes in Buffer. On output
670 the number of bytes written.
671 @param Buffer the buffer containing data to write is stored.
672
673 @retval EFI_SUCCESS Data was written.
674 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
675 @retval EFI_NO_MEDIA The device has no media.
676 @retval EFI_DEVICE_ERROR The device reported an error.
677 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
678 @retval EFI_WRITE_PROTECTED The device is write-protected.
679 @retval EFI_ACCESS_DENIED The file was open for read only.
680 @retval EFI_VOLUME_FULL The volume is full.
681 **/
682 EFI_STATUS
683 EFIAPI
684 ShellWriteFile(
685 IN EFI_FILE_HANDLE FileHandle,
686 IN OUT UINTN *BufferSize,
687 IN VOID *Buffer
688 )
689 {
690 //
691 // ASSERT if FileHandle is NULL
692 //
693 ASSERT (FileHandle != NULL);
694 //
695 // Perform the write based on EFI_FILE_PROTOCOL
696 //
697 return (FileHandle->Write(FileHandle, BufferSize, Buffer));
698 }
699
700 /**
701 Close an open file handle.
702
703 This function closes a specified file handle. All \93dirty\94 cached file data is
704 flushed to the device, and the file is closed. In all cases the handle is
705 closed.
706
707 @param FileHandle the file handle to close.
708
709 @retval EFI_SUCCESS the file handle was closed sucessfully.
710 **/
711 EFI_STATUS
712 EFIAPI
713 ShellCloseFile (
714 IN EFI_FILE_HANDLE *FileHandle
715 )
716 {
717 EFI_STATUS Status;
718 //
719 // ASSERT if FileHandle is NULL
720 //
721 ASSERT (FileHandle != NULL);
722 ASSERT (*FileHandle != NULL);
723 //
724 // Perform the Close based on EFI_FILE_PROTOCOL
725 //
726 Status = (*FileHandle)->Close(*FileHandle);
727 *FileHandle = NULL;
728 return Status;
729 }
730
731 /**
732 Delete a file and close the handle
733
734 This function closes and deletes a file. In all cases the file handle is closed.
735 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
736 returned, but the handle is still closed.
737
738 @param FileHandle the file handle to delete
739
740 @retval EFI_SUCCESS the file was closed sucessfully
741 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
742 deleted
743 @retval INVALID_PARAMETER One of the parameters has an invalid value.
744 **/
745 EFI_STATUS
746 EFIAPI
747 ShellDeleteFile (
748 IN EFI_FILE_HANDLE *FileHandle
749 )
750 {
751 EFI_STATUS Status;
752 //
753 // ASSERT if FileHandle is NULL
754 //
755 ASSERT (FileHandle != NULL);
756 ASSERT (*FileHandle != NULL);
757 //
758 // Perform the Delete based on EFI_FILE_PROTOCOL
759 //
760 Status = (*FileHandle)->Delete(*FileHandle);
761 *FileHandle = NULL;
762 return Status;
763 }
764
765 /**
766 Set the current position in a file.
767
768 This function sets the current file position for the handle to the position
769 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
770 absolute positioning is supported, and seeking past the end of the file is
771 allowed (a subsequent write would grow the file). Seeking to position
772 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
773 If FileHandle is a directory, the only position that may be set is zero. This
774 has the effect of starting the read process of the directory entries over.
775
776 @param FileHandle The file handle on which the position is being set
777 @param Position Byte position from begining of file
778
779 @retval EFI_SUCCESS Operation completed sucessfully.
780 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
781 directories.
782 @retval INVALID_PARAMETER One of the parameters has an invalid value.
783 **/
784 EFI_STATUS
785 EFIAPI
786 ShellSetFilePosition (
787 IN EFI_FILE_HANDLE FileHandle,
788 IN UINT64 Position
789 )
790 {
791 //
792 // ASSERT if FileHandle is NULL
793 //
794 ASSERT (FileHandle != NULL);
795 //
796 // Perform the SetPosition based on EFI_FILE_PROTOCOL
797 //
798 return (FileHandle->SetPosition(FileHandle, Position));
799 }
800
801 /**
802 Gets a file's current position
803
804 This function retrieves the current file position for the file handle. For
805 directories, the current file position has no meaning outside of the file
806 system driver and as such the operation is not supported. An error is returned
807 if FileHandle is a directory.
808
809 @param FileHandle The open file handle on which to get the position.
810 @param Position Byte position from begining of file.
811
812 @retval EFI_SUCCESS the operation completed sucessfully.
813 @retval INVALID_PARAMETER One of the parameters has an invalid value.
814 @retval EFI_UNSUPPORTED the request is not valid on directories.
815 **/
816 EFI_STATUS
817 EFIAPI
818 ShellGetFilePosition (
819 IN EFI_FILE_HANDLE FileHandle,
820 OUT UINT64 *Position
821 )
822 {
823 //
824 // ASSERT if FileHandle is NULL
825 //
826 ASSERT (FileHandle != NULL);
827 //
828 // Perform the GetPosition based on EFI_FILE_PROTOCOL
829 //
830 return (FileHandle->GetPosition(FileHandle, Position));
831 }
832 /**
833 Flushes data on a file
834
835 This function flushes all modified data associated with a file to a device.
836
837 @param FileHandle The file handle on which to flush data
838
839 @retval EFI_SUCCESS The data was flushed.
840 @retval EFI_NO_MEDIA The device has no media.
841 @retval EFI_DEVICE_ERROR The device reported an error.
842 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
843 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
844 @retval EFI_ACCESS_DENIED The file was opened for read only.
845 **/
846 EFI_STATUS
847 EFIAPI
848 ShellFlushFile (
849 IN EFI_FILE_HANDLE FileHandle
850 )
851 {
852 //
853 // ASSERT if FileHandle is NULL
854 //
855 ASSERT (FileHandle != NULL);
856 //
857 // Perform the Flush based on EFI_FILE_PROTOCOL
858 //
859 return (FileHandle->Flush(FileHandle));
860 }
861
862 /**
863 function to determine if a given handle is a directory handle
864
865 if DirHandle is NULL then ASSERT()
866
867 open the file information on the DirHandle and verify that the Attribute
868 includes EFI_FILE_DIRECTORY bit set.
869
870 @param DirHandle Handle to open file
871
872 @retval EFI_SUCCESS DirHandle is a directory
873 @retval EFI_INVALID_PARAMETER DirHandle did not have EFI_FILE_INFO available
874 @retval EFI_NOT_FOUND DirHandle is not a directory
875 **/
876 EFI_STATUS
877 EFIAPI
878 InternalShellIsDirectory (
879 IN EFI_FILE_HANDLE DirHandle
880 )
881 {
882 EFI_FILE_INFO *DirInfo;
883
884 //
885 // ASSERT if DirHandle is NULL
886 //
887 ASSERT(DirHandle != NULL);
888
889 //
890 // get the file information for DirHandle
891 //
892 DirInfo = ShellGetFileInfo (DirHandle);
893
894 //
895 // Parse DirInfo
896 //
897 if (DirInfo == NULL) {
898 //
899 // We got nothing...
900 //
901 return (EFI_INVALID_PARAMETER);
902 }
903 if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
904 //
905 // Attributes say this is not a directory
906 //
907 FreePool (DirInfo);
908 return (EFI_NOT_FOUND);
909 }
910 //
911 // all good...
912 //
913 FreePool (DirInfo);
914 return (EFI_SUCCESS);
915 }
916
917 /**
918 Retrieves the first file from a directory
919
920 This function opens a directory and gets the first file\92s info in the
921 directory. Caller can use ShellFindNextFile() to get other files. When
922 complete the caller is responsible for calling FreePool() on Buffer.
923
924 @param DirHandle The file handle of the directory to search
925 @param Buffer Pointer to buffer for file's information
926
927 @retval EFI_SUCCESS Found the first file.
928 @retval EFI_NOT_FOUND Cannot find the directory.
929 @retval EFI_NO_MEDIA The device has no media.
930 @retval EFI_DEVICE_ERROR The device reported an error.
931 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
932 @return Others status of ShellGetFileInfo, ShellSetFilePosition,
933 or ShellReadFile
934 **/
935 EFI_STATUS
936 EFIAPI
937 ShellFindFirstFile (
938 IN EFI_FILE_HANDLE DirHandle,
939 OUT EFI_FILE_INFO *Buffer
940 )
941 {
942 EFI_STATUS Status;
943 UINTN BufferSize;
944
945 //
946 // ASSERT if DirHandle is NULL
947 //
948 ASSERT (DirHandle != NULL);
949
950 //
951 // verify that DirHandle is a directory
952 //
953 Status = InternalShellIsDirectory(DirHandle);
954 if (EFI_ERROR(Status)) {
955 return (Status);
956 }
957
958 //
959 // reset to the begining of the directory
960 //
961 Status = ShellSetFilePosition (DirHandle, 0);
962 if (EFI_ERROR(Status)) {
963 return (Status);
964 }
965
966 //
967 // Allocate a buffer sized to struct size + enough for the string at the end
968 //
969 BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;
970 Buffer = AllocateZeroPool(BufferSize);
971 ASSERT (Buffer != NULL);
972
973 //
974 // read in the info about the first file
975 //
976 Status = ShellReadFile (DirHandle, &BufferSize, Buffer);
977 ASSERT(Status != EFI_BUFFER_TOO_SMALL);
978 if (EFI_ERROR(Status)) {
979 return (Status);
980 }
981 return (EFI_SUCCESS);
982 }
983 /**
984 Retrieves the next file in a directory.
985
986 To use this function, caller must call the LibFindFirstFile() to get the
987 first file, and then use this function get other files. This function can be
988 called for several times to get each file's information in the directory. If
989 the call of ShellFindNextFile() got the last file in the directory, the next
990 call of this function has no file to get. *NoFile will be set to TRUE and the
991 Buffer memory will be automatically freed.
992
993 @param DirHandle the file handle of the directory
994 @param Buffer pointer to buffer for file's information
995 @param NoFile pointer to boolean when last file is found
996
997 @retval EFI_SUCCESS Found the next file, or reached last file
998 @retval EFI_NO_MEDIA The device has no media.
999 @retval EFI_DEVICE_ERROR The device reported an error.
1000 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1001 **/
1002 EFI_STATUS
1003 EFIAPI
1004 ShellFindNextFile(
1005 IN EFI_FILE_HANDLE DirHandle,
1006 OUT EFI_FILE_INFO *Buffer,
1007 OUT BOOLEAN *NoFile
1008 )
1009 {
1010 EFI_STATUS Status;
1011 UINTN BufferSize;
1012
1013 //
1014 // ASSERTs for DirHandle or Buffer or NoFile poitners being NULL
1015 //
1016 ASSERT (DirHandle != NULL);
1017 ASSERT (Buffer != NULL);
1018 ASSERT (NoFile != NULL);
1019
1020 //
1021 // verify that DirHandle is a directory
1022 //
1023 Status = InternalShellIsDirectory(DirHandle);
1024 if (EFI_ERROR(Status)) {
1025 return (Status);
1026 }
1027
1028 //
1029 // This BufferSize MUST stay equal to the originally allocated one in GetFirstFile
1030 //
1031 BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;
1032
1033 //
1034 // read in the info about the next file
1035 //
1036 Status = ShellReadFile (DirHandle, &BufferSize, Buffer);
1037 ASSERT(Status != EFI_BUFFER_TOO_SMALL);
1038 if (EFI_ERROR(Status)) {
1039 return (Status);
1040 }
1041
1042 //
1043 // If we read 0 bytes (but did not have erros) we already read in the last file.
1044 //
1045 if (BufferSize == 0) {
1046 FreePool(Buffer);
1047 *NoFile = TRUE;
1048 }
1049
1050 return (EFI_SUCCESS);
1051 }
1052 /**
1053 Retrieve the size of a file.
1054
1055 if FileHandle is NULL then ASSERT()
1056 if Size is NULL then ASSERT()
1057
1058 This function extracts the file size info from the FileHandle\92s EFI_FILE_INFO
1059 data.
1060
1061 @param FileHandle file handle from which size is retrieved
1062 @param Size pointer to size
1063
1064 @retval EFI_SUCCESS operation was completed sucessfully
1065 @retval EFI_DEVICE_ERROR cannot access the file
1066 **/
1067 EFI_STATUS
1068 EFIAPI
1069 ShellGetFileSize (
1070 IN EFI_FILE_HANDLE FileHandle,
1071 OUT UINT64 *Size
1072 )
1073 {
1074 EFI_FILE_INFO *FileInfo;
1075
1076 //
1077 // ASSERT for FileHandle or Size being NULL
1078 //
1079 ASSERT (FileHandle != NULL);
1080 ASSERT (Size != NULL);
1081
1082 //
1083 // get the FileInfo structure
1084 //
1085 FileInfo = ShellGetFileInfo(FileHandle);
1086 if (FileInfo == NULL) {
1087 return (EFI_DEVICE_ERROR);
1088 }
1089
1090 //
1091 // Assign the Size pointer to the correct value
1092 //
1093 *Size = FileInfo->FileSize;
1094
1095 //
1096 // free the FileInfo memory
1097 //
1098 FreePool(FileInfo);
1099
1100 return (EFI_SUCCESS);
1101 }
1102 /**
1103 Retrieves the status of the break execution flag
1104
1105 this function is useful to check whether the application is being asked to halt by the shell.
1106
1107 @retval TRUE the execution break is enabled
1108 @retval FALSE the execution break is not enabled
1109 **/
1110 BOOLEAN
1111 EFIAPI
1112 ShellGetExecutionBreakFlag(
1113 VOID
1114 )
1115 {
1116 //
1117 // Check for UEFI Shell 2.0 protocols
1118 //
1119 if (mEfiShellProtocol != NULL) {
1120
1121 //
1122 // We are using UEFI Shell 2.0; see if the event has been triggered
1123 //
1124 if (gBS->CheckEvent(mEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
1125 return (FALSE);
1126 }
1127 return (TRUE);
1128 }
1129
1130 //
1131 // using EFI Shell; call the function to check
1132 //
1133 ASSERT(mEfiShellEnvironment2 != NULL);
1134 return (mEfiShellEnvironment2->GetExecutionBreak());
1135 }
1136 /**
1137 return the value of an environment variable
1138
1139 this function gets the value of the environment variable set by the
1140 ShellSetEnvironmentVariable function
1141
1142 @param EnvKey The key name of the environment variable.
1143
1144 @retval NULL the named environment variable does not exist.
1145 @return != NULL pointer to the value of the environment variable
1146 **/
1147 CONST CHAR16*
1148 EFIAPI
1149 ShellGetEnvironmentVariable (
1150 IN CHAR16 *EnvKey
1151 )
1152 {
1153 //
1154 // Check for UEFI Shell 2.0 protocols
1155 //
1156 if (mEfiShellProtocol != NULL) {
1157 return (mEfiShellProtocol->GetEnv(EnvKey));
1158 }
1159
1160 //
1161 // ASSERT that we must have EFI shell
1162 //
1163 ASSERT(mEfiShellEnvironment2 != NULL);
1164
1165 //
1166 // using EFI Shell
1167 //
1168 return (mEfiShellEnvironment2->GetEnv(EnvKey));
1169 }
1170 /**
1171 set the value of an environment variable
1172
1173 This function changes the current value of the specified environment variable. If the
1174 environment variable exists and the Value is an empty string, then the environment
1175 variable is deleted. If the environment variable exists and the Value is not an empty
1176 string, then the value of the environment variable is changed. If the environment
1177 variable does not exist and the Value is an empty string, there is no action. If the
1178 environment variable does not exist and the Value is a non-empty string, then the
1179 environment variable is created and assigned the specified value.
1180
1181 This is not supported pre-UEFI Shell 2.0.
1182
1183 @param EnvKey The key name of the environment variable.
1184 @param EnvVal The Value of the environment variable
1185 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1186
1187 @retval EFI_SUCCESS the operation was completed sucessfully
1188 @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
1189 **/
1190 EFI_STATUS
1191 EFIAPI
1192 ShellSetEnvironmentVariable (
1193 IN CONST CHAR16 *EnvKey,
1194 IN CONST CHAR16 *EnvVal,
1195 IN BOOLEAN Volatile
1196 )
1197 {
1198 //
1199 // Check for UEFI Shell 2.0 protocols
1200 //
1201 if (mEfiShellProtocol != NULL) {
1202 return (mEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile));
1203 }
1204
1205 //
1206 // This feature does not exist under EFI shell
1207 //
1208 return (EFI_UNSUPPORTED);
1209 }
1210 /**
1211 cause the shell to parse and execute a command line.
1212
1213 This function creates a nested instance of the shell and executes the specified
1214 command (CommandLine) with the specified environment (Environment). Upon return,
1215 the status code returned by the specified command is placed in StatusCode.
1216 If Environment is NULL, then the current environment is used and all changes made
1217 by the commands executed will be reflected in the current environment. If the
1218 Environment is non-NULL, then the changes made will be discarded.
1219 The CommandLine is executed from the current working directory on the current
1220 device.
1221
1222 EnvironmentVariables and Status are only supported for UEFI Shell 2.0.
1223 Output is only supported for pre-UEFI Shell 2.0
1224
1225 @param ImageHandle Parent image that is starting the operation
1226 @param CommandLine pointer to null terminated command line.
1227 @param Output true to display debug output. false to hide it.
1228 @param EnvironmentVariables optional pointer to array of environment variables
1229 in the form "x=y". if NULL current set is used.
1230 @param Status the status of the run command line.
1231
1232 @retval EFI_SUCCESS the operation completed sucessfully. Status
1233 contains the status code returned.
1234 @retval EFI_INVALID_PARAMETER a parameter contains an invalid value
1235 @retval EFI_OUT_OF_RESOURCES out of resources
1236 @retval EFI_UNSUPPORTED the operation is not allowed.
1237 **/
1238 EFI_STATUS
1239 EFIAPI
1240 ShellExecute (
1241 IN EFI_HANDLE *ParentHandle,
1242 IN CHAR16 *CommandLine OPTIONAL,
1243 IN BOOLEAN Output OPTIONAL,
1244 IN CHAR16 **EnvironmentVariables OPTIONAL,
1245 OUT EFI_STATUS *Status OPTIONAL
1246 )
1247 {
1248 //
1249 // Check for UEFI Shell 2.0 protocols
1250 //
1251 if (mEfiShellProtocol != NULL) {
1252 //
1253 // Call UEFI Shell 2.0 version (not using Output parameter)
1254 //
1255 return (mEfiShellProtocol->Execute(ParentHandle,
1256 CommandLine,
1257 EnvironmentVariables,
1258 Status));
1259 }
1260 //
1261 // ASSERT that we must have EFI shell
1262 //
1263 ASSERT(mEfiShellEnvironment2 != NULL);
1264 //
1265 // Call EFI Shell version (not using EnvironmentVariables or Status parameters)
1266 // Due to oddity in the EFI shell we want to dereference the ParentHandle here
1267 //
1268 return (mEfiShellEnvironment2->Execute(*ParentHandle,
1269 CommandLine,
1270 Output));
1271 }
1272 /**
1273 Retreives the current directory path
1274
1275 If the DeviceName is NULL, it returns the current device\92s current directory
1276 name. If the DeviceName is not NULL, it returns the current directory name
1277 on specified drive.
1278
1279 @param DeviceName the name of the drive to get directory on
1280
1281 @retval NULL the directory does not exist
1282 @return != NULL the directory
1283 **/
1284 CONST CHAR16*
1285 EFIAPI
1286 ShellGetCurrentDir (
1287 IN CHAR16 *DeviceName OPTIONAL
1288 )
1289 {
1290 //
1291 // Check for UEFI Shell 2.0 protocols
1292 //
1293 if (mEfiShellProtocol != NULL) {
1294 return (mEfiShellProtocol->GetCurDir(DeviceName));
1295 }
1296 //
1297 // ASSERT that we must have EFI shell
1298 //
1299 ASSERT(mEfiShellEnvironment2 != NULL);
1300 return (mEfiShellEnvironment2->CurDir(DeviceName));
1301 }
1302 /**
1303 sets (enabled or disabled) the page break mode
1304
1305 when page break mode is enabled the screen will stop scrolling
1306 and wait for operator input before scrolling a subsequent screen.
1307
1308 @param CurrentState TRUE to enable and FALSE to disable
1309 **/
1310 VOID
1311 EFIAPI
1312 ShellSetPageBreakMode (
1313 IN BOOLEAN CurrentState
1314 )
1315 {
1316 //
1317 // check for enabling
1318 //
1319 if (CurrentState != 0x00) {
1320 //
1321 // check for UEFI Shell 2.0
1322 //
1323 if (mEfiShellProtocol != NULL) {
1324 //
1325 // Enable with UEFI 2.0 Shell
1326 //
1327 mEfiShellProtocol->EnablePageBreak();
1328 return;
1329 } else {
1330 //
1331 // ASSERT that must have EFI Shell
1332 //
1333 ASSERT(mEfiShellEnvironment2 != NULL);
1334 //
1335 // Enable with EFI Shell
1336 //
1337 mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
1338 return;
1339 }
1340 } else {
1341 //
1342 // check for UEFI Shell 2.0
1343 //
1344 if (mEfiShellProtocol != NULL) {
1345 //
1346 // Disable with UEFI 2.0 Shell
1347 //
1348 mEfiShellProtocol->DisablePageBreak();
1349 return;
1350 } else {
1351 //
1352 // ASSERT that must have EFI Shell
1353 //
1354 ASSERT(mEfiShellEnvironment2 != NULL);
1355 //
1356 // Disable with EFI Shell
1357 //
1358 mEfiShellEnvironment2->DisablePageBreak ();
1359 return;
1360 }
1361 }
1362 }
1363
1364 ///
1365 /// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1366 /// This allows for the struct to be populated.
1367 ///
1368 typedef struct {
1369 EFI_LIST_ENTRY Link;
1370 EFI_STATUS Status;
1371 CHAR16 *FullName;
1372 CHAR16 *FileName;
1373 EFI_FILE_HANDLE Handle;
1374 EFI_FILE_INFO *Info;
1375 } EFI_SHELL_FILE_INFO_NO_CONST;
1376
1377 /**
1378 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1379
1380 if OldStyleFileList is NULL then ASSERT()
1381
1382 this function will convert a SHELL_FILE_ARG based list into a callee allocated
1383 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
1384 the ShellCloseFileMetaArg function.
1385
1386 @param FileList the EFI shell list type
1387
1388 @retval the resultant head of the double linked new format list;
1389 **/
1390 LIST_ENTRY*
1391 EFIAPI
1392 InternalShellConvertFileListType (
1393 EFI_LIST_ENTRY *FileList
1394 )
1395 {
1396 LIST_ENTRY *ListHead;
1397 SHELL_FILE_ARG *OldInfo;
1398 EFI_LIST_ENTRY *Link;
1399 EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;
1400
1401 //
1402 // ASSERT that FileList is not NULL
1403 //
1404 ASSERT(FileList != NULL);
1405
1406 //
1407 // Allocate our list head and initialize the list
1408 //
1409 ListHead = AllocateZeroPool(sizeof(EFI_LIST_ENTRY));
1410 ASSERT (ListHead != NULL);
1411 ListHead = InitializeListHead (ListHead);
1412
1413 //
1414 // enumerate through each member of the old list and copy
1415 //
1416 for (Link = FileList->Flink; Link != FileList; Link = Link->Flink) {
1417 OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
1418
1419 //
1420 // make sure the old list was valid
1421 //
1422 ASSERT(OldInfo != NULL);
1423 ASSERT(OldInfo->Info != NULL);
1424 ASSERT(OldInfo->FullName != NULL);
1425 ASSERT(OldInfo->FileName != NULL);
1426
1427 //
1428 // allocate a new EFI_SHELL_FILE_INFO object
1429 //
1430 NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1431
1432 //
1433 // copy the simple items
1434 //
1435 NewInfo->Handle = OldInfo->Handle;
1436 NewInfo->Status = OldInfo->Status;
1437
1438 //
1439 // allocate new space to copy strings and structure
1440 //
1441 NewInfo->FullName = AllocateZeroPool(StrSize(OldInfo->FullName));
1442 NewInfo->FileName = AllocateZeroPool(StrSize(OldInfo->FileName));
1443 NewInfo->Info = AllocateZeroPool((UINTN)OldInfo->Info->Size);
1444
1445 //
1446 // make sure all the memory allocations were sucessful
1447 //
1448 ASSERT(NewInfo->FullName != NULL);
1449 ASSERT(NewInfo->FileName != NULL);
1450 ASSERT(NewInfo->Info != NULL);
1451
1452 //
1453 // Copt the strings and structure
1454 //
1455 StrCpy(NewInfo->FullName, OldInfo->FullName);
1456 StrCpy(NewInfo->FileName, OldInfo->FileName);
1457 gBS->CopyMem (NewInfo->Info, OldInfo->Info, (UINTN)OldInfo->Info->Size);
1458
1459 //
1460 // add that to the list
1461 //
1462 InsertTailList(ListHead, (LIST_ENTRY*)NewInfo);
1463 }
1464 return (ListHead);
1465 }
1466 /**
1467 Opens a group of files based on a path.
1468
1469 This function uses the Arg to open all the matching files. Each matched
1470 file has a SHELL_FILE_ARG structure to record the file information. These
1471 structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG
1472 structures from ListHead to access each file. This function supports wildcards
1473 and will process '?' and '*' as such. the list must be freed with a call to
1474 ShellCloseFileMetaArg().
1475
1476 This function will fail if called sequentially without freeing the list in the middle.
1477
1478 @param Arg pointer to path string
1479 @param OpenMode mode to open files with
1480 @param ListHead head of linked list of results
1481
1482 @retval EFI_SUCCESS the operation was sucessful and the list head
1483 contains the list of opened files
1484 #retval EFI_UNSUPPORTED a previous ShellOpenFileMetaArg must be closed first.
1485 *ListHead is set to NULL.
1486 @return != EFI_SUCCESS the operation failed
1487
1488 @sa InternalShellConvertFileListType
1489 **/
1490 EFI_STATUS
1491 EFIAPI
1492 ShellOpenFileMetaArg (
1493 IN CHAR16 *Arg,
1494 IN UINT64 OpenMode,
1495 IN OUT EFI_SHELL_FILE_INFO **ListHead
1496 )
1497 {
1498 EFI_STATUS Status;
1499 LIST_ENTRY *EmptyNode;
1500
1501 //
1502 // make sure we have no outstanding list
1503 //
1504 if (mOldStyleFileList != NULL) {
1505 *ListHead = NULL;
1506 return (EFI_UNSUPPORTED);
1507 }
1508
1509 //
1510 // ASSERT that Arg and ListHead are not NULL
1511 //
1512 ASSERT(Arg != NULL);
1513 ASSERT(ListHead != NULL);
1514
1515 //
1516 // Check for UEFI Shell 2.0 protocols
1517 //
1518 if (mEfiShellProtocol != NULL) {
1519 return (mEfiShellProtocol->OpenFileList(Arg,
1520 OpenMode,
1521 ListHead));
1522 }
1523
1524 //
1525 // ASSERT that we must have EFI shell
1526 //
1527 ASSERT(mEfiShellEnvironment2 != NULL);
1528
1529 //
1530 // allocate memory for old list head
1531 //
1532 mOldStyleFileList = (EFI_LIST_ENTRY*)AllocatePool(sizeof(EFI_LIST_ENTRY));
1533 ASSERT(mOldStyleFileList != NULL);
1534
1535 //
1536 // make sure the list head is initialized
1537 //
1538 InitializeListHead((LIST_ENTRY*)mOldStyleFileList);
1539
1540 //
1541 // Get the EFI Shell list of files
1542 //
1543 Status = mEfiShellEnvironment2->FileMetaArg(Arg, mOldStyleFileList);
1544 if (EFI_ERROR(Status)) {
1545 *ListHead = NULL;
1546 return (Status);
1547 }
1548
1549 //
1550 // Convert that to equivalent of UEFI Shell 2.0 structure
1551 //
1552 EmptyNode = InternalShellConvertFileListType(mOldStyleFileList);
1553
1554 //
1555 // remove the empty head of the list
1556 //
1557 *ListHead = (EFI_SHELL_FILE_INFO*)RemoveEntryList(EmptyNode);
1558 FreePool(EmptyNode);
1559
1560 return (Status);
1561 }
1562 /**
1563 Free the linked list returned from ShellOpenFileMetaArg
1564
1565 if ListHead is NULL then ASSERT()
1566
1567 @param ListHead the pointer to free
1568
1569 @retval EFI_SUCCESS the operation was sucessful
1570 **/
1571 EFI_STATUS
1572 EFIAPI
1573 ShellCloseFileMetaArg (
1574 IN OUT EFI_SHELL_FILE_INFO **ListHead
1575 )
1576 {
1577 LIST_ENTRY *Node;
1578
1579 //
1580 // ASSERT that ListHead is not NULL
1581 //
1582 ASSERT(ListHead != NULL);
1583
1584 //
1585 // Check for UEFI Shell 2.0 protocols
1586 //
1587 if (mEfiShellProtocol != NULL) {
1588 return (mEfiShellProtocol->FreeFileList(ListHead));
1589 } else {
1590 //
1591 // Free the EFI Shell version that was converted.
1592 //
1593 ASSERT_EFI_ERROR(mEfiShellEnvironment2->FreeFileList(mOldStyleFileList));
1594 FreePool(mOldStyleFileList);
1595 mOldStyleFileList = NULL;
1596
1597 //
1598 // Since this is EFI Shell version we need to free our internally made copy
1599 // of the list
1600 //
1601 for (Node = GetFirstNode((LIST_ENTRY*)*ListHead) ; IsListEmpty((LIST_ENTRY*)*ListHead) == FALSE ; Node = GetFirstNode((LIST_ENTRY*)*ListHead)) {
1602 RemoveEntryList(Node);
1603 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);
1604 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);
1605 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);
1606 FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);
1607 }
1608 return EFI_SUCCESS;
1609 }
1610 }
1611
1612 typedef struct {
1613 EFI_LIST_ENTRY List;
1614 CHAR16 *Name;
1615 ParamType Type;
1616 CHAR16 *Value;
1617 UINTN OriginalPosition;
1618 } SHELL_PARAM_PACKAGE;
1619
1620 /**
1621 Checks the list of valid arguments and returns TRUE if the item was found. If the
1622 return value is TRUE then the type parameter is set also.
1623
1624 if CheckList is NULL then ASSERT();
1625 if Name is NULL then ASSERT();
1626 if Type is NULL then ASSERT();
1627
1628 @param Type pointer to type of parameter if it was found
1629 @param Name pointer to Name of parameter found
1630 @param CheckList List to check against
1631
1632 @retval TRUE the Parameter was found. Type is valid.
1633 @retval FALSE the Parameter was not found. Type is not valid.
1634 **/
1635 BOOLEAN
1636 EFIAPI
1637 IsCheckList (
1638 IN CONST CHAR16 *Name,
1639 IN CONST SHELL_PARAM_ITEM *CheckList,
1640 OUT ParamType *Type
1641 )
1642 {
1643 SHELL_PARAM_ITEM *TempListItem;
1644
1645 //
1646 // ASSERT that all 3 pointer parameters aren't NULL
1647 //
1648 ASSERT(CheckList != NULL);
1649 ASSERT(Type != NULL);
1650 ASSERT(Name != NULL);
1651
1652 //
1653 // Enumerate through the list
1654 //
1655 for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {
1656 //
1657 // If the Name matches set the type and return TRUE
1658 //
1659 if (StrCmp(Name, TempListItem->Name) == 0) {
1660 *Type = TempListItem->Type;
1661 return (TRUE);
1662 }
1663 }
1664 return (FALSE);
1665 }
1666 /**
1667 Checks the string for indicators of "flag" status. this is a leading '/' or '-'
1668
1669 @param Name pointer to Name of parameter found
1670
1671 @retval TRUE the Parameter is a flag.
1672 @retval FALSE the Parameter not a flag
1673 **/
1674 BOOLEAN
1675 EFIAPI
1676 IsFlag (
1677 IN CONST CHAR16 *Name
1678 )
1679 {
1680 //
1681 // ASSERT that Name isn't NULL
1682 //
1683 ASSERT(Name != NULL);
1684
1685 //
1686 // If the Name has a / or - as the first character return TRUE
1687 //
1688 if ((Name[0] == L'/') || (Name[0] == L'-') ) {
1689 return (TRUE);
1690 }
1691 return (FALSE);
1692 }
1693
1694 /**
1695 Checks the command line arguments passed against the list of valid ones.
1696
1697 If no initialization is required, then return RETURN_SUCCESS.
1698
1699 @param CheckList pointer to list of parameters to check
1700 @param CheckPackage pointer to pointer to list checked values
1701 @param ProblemParam optional pointer to pointer to unicode string for
1702 the paramater that caused failure.
1703 @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
1704 @param Argc Count of parameters in Argv
1705 @param Argv pointer to array of parameters
1706
1707 @retval EFI_SUCCESS The operation completed sucessfully.
1708 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
1709 @retval EFI_INVALID_PARAMETER A parameter was invalid
1710 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
1711 duplicated. the duplicated command line argument
1712 was returned in ProblemParam if provided.
1713 @retval EFI_NOT_FOUND a argument required a value that was missing.
1714 the invalid command line argument was returned in
1715 ProblemParam if provided.
1716 **/
1717 EFI_STATUS
1718 EFIAPI
1719 InternalCommandLineParse (
1720 IN CONST SHELL_PARAM_ITEM *CheckList,
1721 OUT LIST_ENTRY **CheckPackage,
1722 OUT CHAR16 **ProblemParam OPTIONAL,
1723 IN BOOLEAN AutoPageBreak,
1724 IN CONST CHAR16 **Argv,
1725 IN UINTN Argc
1726 )
1727 {
1728 UINTN LoopCounter;
1729 UINTN Count;
1730 ParamType CurrentItemType;
1731 SHELL_PARAM_PACKAGE *CurrentItemPackage;
1732 BOOLEAN GetItemValue;
1733
1734 CurrentItemPackage = NULL;
1735
1736 //
1737 // ASSERTs
1738 //
1739 ASSERT(CheckList != NULL);
1740 ASSERT(Argv != NULL);
1741
1742 Count = 0;
1743 GetItemValue = FALSE;
1744
1745 //
1746 // If there is only 1 item we dont need to do anything
1747 //
1748 if (Argc <= 1) {
1749 *CheckPackage = NULL;
1750 return (EFI_SUCCESS);
1751 }
1752
1753 //
1754 // initialize the linked list
1755 //
1756 *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));
1757 InitializeListHead(*CheckPackage);
1758
1759 //
1760 // loop through each of the arguments
1761 //
1762 for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) {
1763 if (Argv[LoopCounter] == NULL) {
1764 //
1765 // do nothing for NULL argv
1766 //
1767 } else if (GetItemValue == TRUE) {
1768 ASSERT(CurrentItemPackage != NULL);
1769 //
1770 // get the item VALUE for the previous flag
1771 //
1772 GetItemValue = FALSE;
1773 CurrentItemPackage->Value = AllocateZeroPool(StrSize(Argv[LoopCounter]));
1774 ASSERT(CurrentItemPackage->Value != NULL);
1775 StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);
1776 InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);
1777 } else if (IsFlag(Argv[LoopCounter]) == FALSE) {
1778 //
1779 // add this one as a non-flag
1780 //
1781 CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE));
1782 ASSERT(CurrentItemPackage != NULL);
1783 CurrentItemPackage->Name = NULL;
1784 CurrentItemPackage->Type = TypePosition;
1785 CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter]));
1786 ASSERT(CurrentItemPackage->Value != NULL);
1787 StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);
1788 CurrentItemPackage->OriginalPosition = Count++;
1789 InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);
1790 } else if (IsCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {
1791 //
1792 // this is a flag
1793 //
1794 CurrentItemPackage = AllocatePool(sizeof(SHELL_PARAM_PACKAGE));
1795 ASSERT(CurrentItemPackage != NULL);
1796 CurrentItemPackage->Name = AllocatePool(StrSize(Argv[LoopCounter]));
1797 ASSERT(CurrentItemPackage->Name != NULL);
1798 StrCpy(CurrentItemPackage->Name, Argv[LoopCounter]);
1799 CurrentItemPackage->Type = CurrentItemType;
1800 CurrentItemPackage->OriginalPosition = (UINTN)(-1);
1801
1802 //
1803 // Does this flag require a value
1804 //
1805 if (CurrentItemPackage->Type == TypeValue) {
1806 //
1807 // trigger the next loop to populate the value of this item
1808 //
1809 GetItemValue = TRUE;
1810 } else {
1811 //
1812 // this item has no value expected; we are done
1813 //
1814 CurrentItemPackage->Value = NULL;
1815 InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);
1816 }
1817 } else if (ProblemParam) {
1818 //
1819 // this was a non-recognised flag... error!
1820 //
1821 *ProblemParam = (CHAR16*)Argv[LoopCounter];
1822 ShellCommandLineFreeVarList(*CheckPackage);
1823 *CheckPackage = NULL;
1824 return (EFI_VOLUME_CORRUPTED);
1825 } else {
1826 ShellCommandLineFreeVarList(*CheckPackage);
1827 *CheckPackage = NULL;
1828 return (EFI_VOLUME_CORRUPTED);
1829 }
1830 }
1831 //
1832 // support for AutoPageBreak
1833 //
1834 if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) {
1835 ShellSetPageBreakMode(TRUE);
1836 }
1837 return (EFI_SUCCESS);
1838 }
1839
1840 /**
1841 Checks the command line arguments passed against the list of valid ones.
1842 Optionally removes NULL values first.
1843
1844 If no initialization is required, then return RETURN_SUCCESS.
1845
1846 @param CheckList pointer to list of parameters to check
1847 @param CheckPackage pointer to pointer to list checked values
1848 @param ProblemParam optional pointer to pointer to unicode string for
1849 the paramater that caused failure.
1850 @param AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
1851
1852 @retval EFI_SUCCESS The operation completed sucessfully.
1853 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
1854 @retval EFI_INVALID_PARAMETER A parameter was invalid
1855 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
1856 duplicated. the duplicated command line argument
1857 was returned in ProblemParam if provided.
1858 @retval EFI_DEVICE_ERROR the commands contained 2 opposing arguments. one
1859 of the command line arguments was returned in
1860 ProblemParam if provided.
1861 @retval EFI_NOT_FOUND a argument required a value that was missing.
1862 the invalid command line argument was returned in
1863 ProblemParam if provided.
1864 **/
1865 EFI_STATUS
1866 EFIAPI
1867 ShellCommandLineParse (
1868 IN CONST SHELL_PARAM_ITEM *CheckList,
1869 OUT LIST_ENTRY **CheckPackage,
1870 OUT CHAR16 **ProblemParam OPTIONAL,
1871 IN BOOLEAN AutoPageBreak
1872 )
1873 {
1874 //
1875 // ASSERT that CheckList and CheckPackage aren't NULL
1876 //
1877 ASSERT(CheckList != NULL);
1878 ASSERT(CheckPackage != NULL);
1879
1880 //
1881 // Check for UEFI Shell 2.0 protocols
1882 //
1883 if (mEfiShellParametersProtocol != NULL) {
1884 return (InternalCommandLineParse(CheckList,
1885 CheckPackage,
1886 ProblemParam,
1887 AutoPageBreak,
1888 mEfiShellParametersProtocol->Argv,
1889 mEfiShellParametersProtocol->Argc ));
1890 }
1891
1892 //
1893 // ASSERT That EFI Shell is not required
1894 //
1895 ASSERT (mEfiShellInterface != NULL);
1896 return (InternalCommandLineParse(CheckList,
1897 CheckPackage,
1898 ProblemParam,
1899 AutoPageBreak,
1900 mEfiShellInterface->Argv,
1901 mEfiShellInterface->Argc ));
1902 }
1903
1904 /**
1905 Frees shell variable list that was returned from ShellCommandLineParse.
1906
1907 This function will free all the memory that was used for the CheckPackage
1908 list of postprocessed shell arguments.
1909
1910 this function has no return value.
1911
1912 if CheckPackage is NULL, then return
1913
1914 @param CheckPackage the list to de-allocate
1915 **/
1916 VOID
1917 EFIAPI
1918 ShellCommandLineFreeVarList (
1919 IN LIST_ENTRY *CheckPackage
1920 )
1921 {
1922 LIST_ENTRY *Node;
1923
1924 //
1925 // check for CheckPackage == NULL
1926 //
1927 if (CheckPackage == NULL) {
1928 return;
1929 }
1930
1931 //
1932 // for each node in the list
1933 //
1934 for (Node = GetFirstNode(CheckPackage); Node != CheckPackage ; Node = GetFirstNode(CheckPackage)) {
1935 //
1936 // Remove it from the list
1937 //
1938 RemoveEntryList(Node);
1939
1940 //
1941 // if it has a name free the name
1942 //
1943 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
1944 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name);
1945 }
1946
1947 //
1948 // if it has a value free the value
1949 //
1950 if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) {
1951 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value);
1952 }
1953
1954 //
1955 // free the node structure
1956 //
1957 FreePool((SHELL_PARAM_PACKAGE*)Node);
1958 }
1959 //
1960 // free the list head node
1961 //
1962 FreePool(CheckPackage);
1963 }
1964 /**
1965 Checks for presence of a flag parameter
1966
1967 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
1968
1969 if CheckPackage is NULL then return FALSE.
1970 if KeyString is NULL then ASSERT()
1971
1972 @param CheckPackage The package of parsed command line arguments
1973 @param KeyString the Key of the command line argument to check for
1974
1975 @retval TRUE the flag is on the command line
1976 @retval FALSE the flag is not on the command line
1977 **/
1978 BOOLEAN
1979 EFIAPI
1980 ShellCommandLineGetFlag (
1981 IN CONST LIST_ENTRY *CheckPackage,
1982 IN CHAR16 *KeyString
1983 )
1984 {
1985 LIST_ENTRY *Node;
1986
1987 //
1988 // ASSERT that both CheckPackage and KeyString aren't NULL
1989 //
1990 ASSERT(KeyString != NULL);
1991
1992 //
1993 // return FALSE for no package
1994 //
1995 if (CheckPackage == NULL) {
1996 return (FALSE);
1997 }
1998
1999 //
2000 // enumerate through the list of parametrs
2001 //
2002 for (Node = GetFirstNode(CheckPackage) ; Node != CheckPackage ; Node = GetNextNode(CheckPackage, Node) ) {
2003 //
2004 // If the Name matches, return TRUE (and there may be NULL name)
2005 //
2006 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2007 if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2008 return (TRUE);
2009 }
2010 }
2011 }
2012 return (FALSE);
2013 }
2014 /**
2015 returns value from command line argument
2016
2017 value parameters are in the form of "-<Key> value" or "/<Key> value"
2018
2019 if CheckPackage is NULL, then return NULL;
2020
2021 @param CheckPackage The package of parsed command line arguments
2022 @param KeyString the Key of the command line argument to check for
2023
2024 @retval NULL the flag is not on the command line
2025 @return !=NULL pointer to unicode string of the value
2026 **/
2027 CONST CHAR16*
2028 EFIAPI
2029 ShellCommandLineGetValue (
2030 IN CONST LIST_ENTRY *CheckPackage,
2031 IN CHAR16 *KeyString
2032 )
2033 {
2034 LIST_ENTRY *Node;
2035
2036 //
2037 // check for CheckPackage == NULL
2038 //
2039 if (CheckPackage == NULL) {
2040 return (NULL);
2041 }
2042
2043 //
2044 // enumerate through the list of parametrs
2045 //
2046 for (Node = GetFirstNode(CheckPackage) ; Node != NULL ; Node = GetNextNode(CheckPackage, Node) ) {
2047 //
2048 // If the Name matches, return the value (name can be NULL)
2049 //
2050 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2051 if (StrCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2052 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2053 }
2054 }
2055 }
2056 return (NULL);
2057 }
2058 /**
2059 returns raw value from command line argument
2060
2061 raw value parameters are in the form of "value" in a specific position in the list
2062
2063 if CheckPackage is NULL, then return NULL;
2064
2065 @param CheckPackage The package of parsed command line arguments
2066 @param Position the position of the value
2067
2068 @retval NULL the flag is not on the command line
2069 @return !=NULL pointer to unicode string of the value
2070 **/
2071 CONST CHAR16*
2072 EFIAPI
2073 ShellCommandLineGetRawValue (
2074 IN CONST LIST_ENTRY *CheckPackage,
2075 IN UINT32 Position
2076 )
2077 {
2078 LIST_ENTRY *Node;
2079
2080 //
2081 // check for CheckPackage == NULL
2082 //
2083 if (CheckPackage == NULL) {
2084 return (NULL);
2085 }
2086
2087 //
2088 // enumerate through the list of parametrs
2089 //
2090 for (Node = GetFirstNode(CheckPackage) ; Node != NULL ; Node = GetNextNode(CheckPackage, Node) ) {
2091 //
2092 // If the position matches, return the value
2093 //
2094 if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) {
2095 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2096 }
2097 }
2098 return (NULL);
2099 }