2 EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
3 StdIn, StdOut, StdErr, etc...).
5 Copyright 2016 Dell Inc.
6 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 (C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
13 #include "FileHandleInternal.h"
15 #define MEM_WRITE_REALLOC_OVERHEAD 1024
18 File style interface for console (Open).
20 @param[in] This Ignored.
21 @param[out] NewHandle Ignored.
22 @param[in] FileName Ignored.
23 @param[in] OpenMode Ignored.
24 @param[in] Attributes Ignored.
30 FileInterfaceOpenNotFound(
31 IN EFI_FILE_PROTOCOL
*This
,
32 OUT EFI_FILE_PROTOCOL
**NewHandle
,
38 return (EFI_NOT_FOUND
);
42 File style interface for console (Close, Delete, & Flush)
44 @param[in] This Ignored.
50 FileInterfaceNopGeneric(
51 IN EFI_FILE_PROTOCOL
*This
58 File style interface for console (GetPosition).
60 @param[in] This Ignored.
61 @param[out] Position Ignored.
63 @retval EFI_UNSUPPORTED
67 FileInterfaceNopGetPosition(
68 IN EFI_FILE_PROTOCOL
*This
,
72 return (EFI_UNSUPPORTED
);
76 File style interface for console (SetPosition).
78 @param[in] This Ignored.
79 @param[in] Position Ignored.
81 @retval EFI_UNSUPPORTED
85 FileInterfaceNopSetPosition(
86 IN EFI_FILE_PROTOCOL
*This
,
90 return (EFI_UNSUPPORTED
);
94 File style interface for console (GetInfo).
96 @param[in] This Ignored.
97 @param[in] InformationType Ignored.
98 @param[in, out] BufferSize Ignored.
99 @param[out] Buffer Ignored.
101 @retval EFI_UNSUPPORTED
105 FileInterfaceNopGetInfo(
106 IN EFI_FILE_PROTOCOL
*This
,
107 IN EFI_GUID
*InformationType
,
108 IN OUT UINTN
*BufferSize
,
112 return (EFI_UNSUPPORTED
);
116 File style interface for console (SetInfo).
118 @param[in] This Ignored.
119 @param[in] InformationType Ignored.
120 @param[in] BufferSize Ignored.
121 @param[in] Buffer Ignored.
123 @retval EFI_UNSUPPORTED
127 FileInterfaceNopSetInfo(
128 IN EFI_FILE_PROTOCOL
*This
,
129 IN EFI_GUID
*InformationType
,
134 return (EFI_UNSUPPORTED
);
138 File style interface for StdOut (Write).
140 Writes data to the screen.
142 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
143 @param[in, out] BufferSize Size in bytes of Buffer.
144 @param[in] Buffer The pointer to the buffer to write.
146 @retval EFI_UNSUPPORTED No output console is supported.
147 @return A return value from gST->ConOut->OutputString.
151 FileInterfaceStdOutWrite(
152 IN EFI_FILE_PROTOCOL
*This
,
153 IN OUT UINTN
*BufferSize
,
157 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoConsoleOut
) {
158 return (EFI_UNSUPPORTED
);
160 if (*((CHAR16
*)Buffer
) == gUnicodeFileTag
) {
161 return (gST
->ConOut
->OutputString(gST
->ConOut
, (CHAR16
*)Buffer
+ 1));
163 return (gST
->ConOut
->OutputString(gST
->ConOut
, Buffer
));
167 File style interface for StdIn (Write).
169 @param[in] This Ignored.
170 @param[in, out] BufferSize Ignored.
171 @param[in] Buffer Ignored.
173 @retval EFI_UNSUPPORTED
177 FileInterfaceStdInWrite(
178 IN EFI_FILE_PROTOCOL
*This
,
179 IN OUT UINTN
*BufferSize
,
183 return (EFI_UNSUPPORTED
);
187 File style interface for console StdErr (Write).
189 Writes error to the error output.
191 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
192 @param[in, out] BufferSize Size in bytes of Buffer.
193 @param[in] Buffer The pointer to the buffer to write.
195 @return A return value from gST->StdErr->OutputString.
199 FileInterfaceStdErrWrite(
200 IN EFI_FILE_PROTOCOL
*This
,
201 IN OUT UINTN
*BufferSize
,
205 return (gST
->StdErr
->OutputString(gST
->StdErr
, Buffer
));
209 File style interface for console StdOut (Read).
211 @param[in] This Ignored.
212 @param[in, out] BufferSize Ignored.
213 @param[out] Buffer Ignored.
215 @retval EFI_UNSUPPORTED
219 FileInterfaceStdOutRead(
220 IN EFI_FILE_PROTOCOL
*This
,
221 IN OUT UINTN
*BufferSize
,
225 return (EFI_UNSUPPORTED
);
229 File style interface for console StdErr (Read).
231 @param[in] This Ignored.
232 @param[in, out] BufferSize Ignored.
233 @param[out] Buffer Ignored.
235 @retval EFI_UNSUPPORTED Always.
239 FileInterfaceStdErrRead(
240 IN EFI_FILE_PROTOCOL
*This
,
241 IN OUT UINTN
*BufferSize
,
245 return (EFI_UNSUPPORTED
);
249 File style interface for NUL file (Read).
251 @param[in] This Ignored.
252 @param[in, out] BufferSize Poiner to 0 upon return.
253 @param[out] Buffer Ignored.
255 @retval EFI_SUCCESS Always.
259 FileInterfaceNulRead(
260 IN EFI_FILE_PROTOCOL
*This
,
261 IN OUT UINTN
*BufferSize
,
266 return (EFI_SUCCESS
);
270 File style interface for NUL file (Write).
272 @param[in] This Ignored.
273 @param[in, out] BufferSize Ignored.
274 @param[in] Buffer Ignored.
280 FileInterfaceNulWrite(
281 IN EFI_FILE_PROTOCOL
*This
,
282 IN OUT UINTN
*BufferSize
,
286 return (EFI_SUCCESS
);
290 Create the TAB completion list.
292 @param[in] InputString The command line to expand.
293 @param[in] StringLen Length of the command line.
294 @param[in] BufferSize Buffer size.
295 @param[in, out] TabCompletionList Return the TAB completion list.
296 @param[in, out] TabUpdatePos Return the TAB update position.
299 CreateTabCompletionList (
300 IN CONST CHAR16
*InputString
,
301 IN CONST UINTN StringLen
,
302 IN CONST UINTN BufferSize
,
303 IN OUT EFI_SHELL_FILE_INFO
**TabCompletionList
,
304 IN OUT UINTN
*TabUpdatePos
313 EFI_SHELL_FILE_INFO
*FileList
;
314 EFI_SHELL_FILE_INFO
*FileInfo
;
315 EFI_SHELL_FILE_INFO
*TempFileInfo
;
320 TabStr
= AllocateZeroPool (BufferSize
);
321 if (TabStr
== NULL
) {
322 return EFI_OUT_OF_RESOURCES
;
326 // handle auto complete of file and directory names...
327 // E.g.: cd fs0:\EFI\Bo<TAB>
329 // TabPos TabUpdatePos
335 for (Index
= 0; Index
< StringLen
; Index
++) {
336 switch (InputString
[Index
]) {
338 InQuotation
= (BOOLEAN
) (!InQuotation
);
344 *TabUpdatePos
= TabPos
;
350 // handle the case "fs0:<TAB>"
351 // Update the TabUpdatePos as well.
354 *TabUpdatePos
= Index
+ 1;
362 if (StrStr (InputString
+ TabPos
, L
":") == NULL
) {
364 // If file path doesn't contain ":", ...
366 Cwd
= ShellInfoObject
.NewEfiShellProtocol
->GetCurDir (NULL
);
368 if (InputString
[TabPos
] != L
'\\') {
370 // and it doesn't begin with "\\", it's a path relative to current directory.
371 // TabStr = "<cwd>\\"
373 StrnCpyS (TabStr
, BufferSize
/ sizeof (CHAR16
), Cwd
, (BufferSize
) / sizeof (CHAR16
) - 1);
374 StrCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), L
"\\");
377 // and it begins with "\\", it's a path pointing to root directory of current map.
380 Index
= StrStr (Cwd
, L
":") - Cwd
+ 1;
381 StrnCpyS (TabStr
, BufferSize
/ sizeof (CHAR16
), Cwd
, Index
);
385 StrnCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), InputString
+ TabPos
, StringLen
- TabPos
);
386 StrnCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), L
"*", (BufferSize
) / sizeof (CHAR16
) - 1 - StrLen (TabStr
));
387 Status
= ShellInfoObject
.NewEfiShellProtocol
->FindFiles(TabStr
, &FileList
);
390 // Filter out the non-directory for "CD" command
391 // Filter "." and ".." for all
393 if (!EFI_ERROR (Status
) && FileList
!= NULL
) {
395 // Skip the spaces in the beginning
397 while (*InputString
== L
' ') {
401 for (FileInfo
= (EFI_SHELL_FILE_INFO
*) GetFirstNode (&FileList
->Link
); !IsNull (&FileList
->Link
, &FileInfo
->Link
); ) {
402 if (((StrCmp (FileInfo
->FileName
, L
".") == 0) || (StrCmp (FileInfo
->FileName
, L
"..") == 0)) ||
403 (((InputString
[0] == L
'c' || InputString
[0] == L
'C') && (InputString
[1] == L
'd' || InputString
[1] == L
'D')) &&
404 (ShellIsDirectory (FileInfo
->FullName
) != EFI_SUCCESS
))) {
405 TempFileInfo
= FileInfo
;
406 FileInfo
= (EFI_SHELL_FILE_INFO
*) RemoveEntryList (&FileInfo
->Link
);
407 InternalFreeShellFileInfoNode (TempFileInfo
);
409 FileInfo
= (EFI_SHELL_FILE_INFO
*) GetNextNode (&FileList
->Link
, &FileInfo
->Link
);
414 if (FileList
!= NULL
&& !IsListEmpty (&FileList
->Link
)) {
415 Status
= EFI_SUCCESS
;
417 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&FileList
);
418 Status
= EFI_NOT_FOUND
;
423 *TabCompletionList
= FileList
;
428 File style interface for console (Read).
430 This will return a single line of input from the console.
432 @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
433 file handle to read data from. Not used.
434 @param BufferSize On input, the size of the Buffer. On output, the amount
435 of data returned in Buffer. In both cases, the size is
437 @param Buffer The buffer into which the data is read.
440 @retval EFI_SUCCESS The data was read.
441 @retval EFI_NO_MEDIA The device has no medium.
442 @retval EFI_DEVICE_ERROR The device reported an error.
443 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
444 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
445 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
446 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
447 entry. BufferSize has been updated with the size
448 needed to complete the request.
449 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
453 FileInterfaceStdInRead(
454 IN EFI_FILE_PROTOCOL
*This
,
455 IN OUT UINTN
*BufferSize
,
459 CHAR16
*CurrentString
;
461 UINTN TabUpdatePos
; // Start index of the string updated by TAB stroke
462 UINTN Column
; // Column of current cursor
463 UINTN Row
; // Row of current cursor
464 UINTN StartColumn
; // Column at the beginning of the line
465 UINTN Update
; // Line index for update
466 UINTN Delete
; // Num of chars to delete from console after update
467 UINTN StringLen
; // Total length of the line
468 UINTN StringCurPos
; // Line index corresponding to the cursor
469 UINTN MaxStr
; // Maximum possible line length
470 UINTN TotalColumn
; // Num of columns in the console
471 UINTN TotalRow
; // Num of rows in the console
473 UINTN OutputLength
; // Length of the update string
474 UINTN TailRow
; // Row of end of line
475 UINTN TailColumn
; // Column of end of line
478 BUFFER_LIST
*LinePos
;
482 BOOLEAN InTabScrolling
; // Whether in TAB-completion state
483 EFI_SHELL_FILE_INFO
*TabCompleteList
;
484 EFI_SHELL_FILE_INFO
*TabCurrent
;
486 CHAR16
*TabOutputStr
;
489 // If buffer is not large enough to hold a CHAR16, return minimum buffer size
491 if (*BufferSize
< sizeof (CHAR16
) * 2) {
492 *BufferSize
= sizeof (CHAR16
) * 2;
493 return (EFI_BUFFER_TOO_SMALL
);
497 CurrentString
= Buffer
;
503 LinePos
= NewPos
= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
505 InTabScrolling
= FALSE
;
506 Status
= EFI_SUCCESS
;
509 TabCompleteList
= NULL
;
513 // Get the screen setting and the current cursor location
515 Column
= StartColumn
= gST
->ConOut
->Mode
->CursorColumn
;
516 Row
= gST
->ConOut
->Mode
->CursorRow
;
517 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &TotalColumn
, &TotalRow
);
520 // Limit the line length to the buffer size or the minimun size of the
521 // screen. (The smaller takes effect)
523 MaxStr
= TotalColumn
* (TotalRow
- 1) - StartColumn
;
524 if (MaxStr
> *BufferSize
/ sizeof (CHAR16
)) {
525 MaxStr
= *BufferSize
/ sizeof (CHAR16
);
527 ZeroMem (CurrentString
, MaxStr
* sizeof (CHAR16
));
532 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
533 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
534 if (EFI_ERROR (Status
)) {
536 if (Status
== EFI_NOT_READY
)
539 ZeroMem (CurrentString
, MaxStr
* sizeof(CHAR16
));
545 // Press PageUp or PageDown to scroll the history screen up or down.
546 // Press any other key to quit scrolling.
548 if (Key
.UnicodeChar
== 0 && (Key
.ScanCode
== SCAN_PAGE_UP
|| Key
.ScanCode
== SCAN_PAGE_DOWN
)) {
549 if (Key
.ScanCode
== SCAN_PAGE_UP
) {
550 ConsoleLoggerDisplayHistory(FALSE
, 0, ShellInfoObject
.ConsoleInfo
);
551 } else if (Key
.ScanCode
== SCAN_PAGE_DOWN
) {
552 ConsoleLoggerDisplayHistory(TRUE
, 0, ShellInfoObject
.ConsoleInfo
);
558 ConsoleLoggerStopHistory(ShellInfoObject
.ConsoleInfo
);
564 // If we are quitting TAB scrolling...
566 if (InTabScrolling
&& Key
.UnicodeChar
!= CHAR_TAB
) {
567 if (TabCompleteList
!= NULL
) {
568 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&TabCompleteList
);
569 DEBUG_CODE(TabCompleteList
= NULL
;);
571 InTabScrolling
= FALSE
;
574 switch (Key
.UnicodeChar
) {
575 case CHAR_CARRIAGE_RETURN
:
577 // All done, print a newline at the end of the string
579 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
) / TotalColumn
;
580 TailColumn
= (StringLen
- StringCurPos
+ Column
) % TotalColumn
;
581 ShellPrintEx ((INT32
)TailColumn
, (INT32
)TailRow
, L
"%N\n");
586 if (StringCurPos
!= 0) {
588 // If not move back beyond string beginning, move all characters behind
589 // the current position one character forward
592 Update
= StringCurPos
;
594 CopyMem (CurrentString
+ StringCurPos
, CurrentString
+ StringCurPos
+ 1, sizeof (CHAR16
) * (StringLen
- StringCurPos
));
597 // Adjust the current column and row
599 MoveCursorBackward (TotalColumn
, &Column
, &Row
);
604 if (!InTabScrolling
) {
607 // Initialize a tab complete operation.
609 Status
= CreateTabCompletionList (CurrentString
, StringLen
, *BufferSize
, &TabCompleteList
, &TabUpdatePos
);
610 if (!EFI_ERROR(Status
)) {
611 InTabScrolling
= TRUE
;
615 // We do not set up the replacement.
616 // The next section will do that.
620 if (InTabScrolling
) {
622 // We are in a tab complete operation.
623 // set up the next replacement.
625 ASSERT(TabCompleteList
!= NULL
);
626 if (TabCurrent
== NULL
) {
627 TabCurrent
= (EFI_SHELL_FILE_INFO
*) GetFirstNode (&TabCompleteList
->Link
);
629 TabCurrent
= (EFI_SHELL_FILE_INFO
*) GetNextNode (&TabCompleteList
->Link
, &TabCurrent
->Link
);
633 // Skip over the empty list beginning node
635 if (IsNull(&TabCompleteList
->Link
, &TabCurrent
->Link
)) {
636 TabCurrent
= (EFI_SHELL_FILE_INFO
*) GetNextNode (&TabCompleteList
->Link
, &TabCurrent
->Link
);
642 if (Key
.UnicodeChar
>= ' ') {
644 // If we are at the buffer's end, drop the key
646 if (StringLen
== MaxStr
- 1 && (ShellInfoObject
.ViewingSettings
.InsertMode
|| StringCurPos
== StringLen
)) {
650 // If in insert mode, make space by moving each other character 1
651 // space higher in the array
653 if (ShellInfoObject
.ViewingSettings
.InsertMode
) {
654 CopyMem(CurrentString
+ StringCurPos
+ 1, CurrentString
+ StringCurPos
, (StringLen
- StringCurPos
)*sizeof(CurrentString
[0]));
657 CurrentString
[StringCurPos
] = Key
.UnicodeChar
;
658 Update
= StringCurPos
;
666 switch (Key
.ScanCode
) {
669 // Move characters behind current position one character forward
671 if (StringLen
!= 0) {
672 Update
= StringCurPos
;
674 CopyMem (CurrentString
+ StringCurPos
, CurrentString
+ StringCurPos
+ 1, sizeof (CHAR16
) * (StringLen
- StringCurPos
));
680 // Prepare to print the previous command
682 NewPos
= (BUFFER_LIST
*)GetPreviousNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
683 if (IsNull(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
)) {
684 NewPos
= (BUFFER_LIST
*)GetPreviousNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
690 // Prepare to print the next command
692 NewPos
= (BUFFER_LIST
*)GetNextNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
693 if (NewPos
== (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
)) {
694 NewPos
= (BUFFER_LIST
*)GetNextNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
700 // Adjust current cursor position
702 if (StringCurPos
!= 0) {
704 MoveCursorBackward (TotalColumn
, &Column
, &Row
);
710 // Adjust current cursor position
712 if (StringCurPos
< StringLen
) {
714 MoveCursorForward (TotalColumn
, TotalRow
, &Column
, &Row
);
720 // Move current cursor position to the beginning of the command line
722 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
723 Column
= StartColumn
;
729 // Move current cursor position to the end of the command line
731 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
) / TotalColumn
;
732 TailColumn
= (StringLen
- StringCurPos
+ Column
) % TotalColumn
;
735 StringCurPos
= StringLen
;
740 // Prepare to clear the current command line
742 CurrentString
[0] = 0;
745 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
746 Column
= StartColumn
;
752 // Toggle the SEnvInsertMode flag
754 ShellInfoObject
.ViewingSettings
.InsertMode
= (BOOLEAN
)!ShellInfoObject
.ViewingSettings
.InsertMode
;
759 // Print command history
761 PrintCommandHistory (TotalColumn
, TotalRow
, 4);
762 *CurrentString
= CHAR_NULL
;
773 // If we are in auto-complete mode, we are preparing to print
774 // the next file or directory name
776 if (InTabScrolling
) {
777 TabOutputStr
= AllocateZeroPool (*BufferSize
);
778 if (TabOutputStr
== NULL
) {
779 Status
= EFI_OUT_OF_RESOURCES
;
783 if (InTabScrolling
&& TabOutputStr
!= NULL
) {
786 // Adjust the column and row to the start of TAB-completion string.
788 Column
= (StartColumn
+ TabUpdatePos
) % TotalColumn
;
789 Row
-= (StartColumn
+ StringCurPos
) / TotalColumn
- (StartColumn
+ TabUpdatePos
) / TotalColumn
;
790 OutputLength
= StrLen (TabCurrent
->FileName
);
792 // if the output string contains blank space, quotation marks L'\"'
793 // should be added to the output.
795 if (StrStr(TabCurrent
->FileName
, L
" ") != NULL
){
796 TabOutputStr
[0] = L
'\"';
797 CopyMem (TabOutputStr
+ 1, TabCurrent
->FileName
, OutputLength
* sizeof (CHAR16
));
798 TabOutputStr
[OutputLength
+ 1] = L
'\"';
799 TabOutputStr
[OutputLength
+ 2] = CHAR_NULL
;
801 CopyMem (TabOutputStr
, TabCurrent
->FileName
, OutputLength
* sizeof (CHAR16
));
802 TabOutputStr
[OutputLength
] = CHAR_NULL
;
804 OutputLength
= StrLen (TabOutputStr
) < MaxStr
- 1 ? StrLen (TabOutputStr
) : MaxStr
- 1;
805 CopyMem (CurrentString
+ TabUpdatePos
, TabOutputStr
, OutputLength
* sizeof (CHAR16
));
806 CurrentString
[TabUpdatePos
+ OutputLength
] = CHAR_NULL
;
807 StringCurPos
= TabUpdatePos
+ OutputLength
;
808 Update
= TabUpdatePos
;
809 if (StringLen
> TabUpdatePos
+ OutputLength
) {
810 Delete
= StringLen
- TabUpdatePos
- OutputLength
;
813 FreePool(TabOutputStr
);
817 // If we have a new position, we are preparing to print a previous or
820 if (NewPos
!= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
)) {
821 Column
= StartColumn
;
822 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
825 NewPos
= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
827 OutputLength
= StrLen (LinePos
->Buffer
) < MaxStr
- 1 ? StrLen (LinePos
->Buffer
) : MaxStr
- 1;
828 CopyMem (CurrentString
, LinePos
->Buffer
, OutputLength
* sizeof (CHAR16
));
829 CurrentString
[OutputLength
] = CHAR_NULL
;
831 StringCurPos
= OutputLength
;
834 // Draw new input string
837 if (StringLen
> OutputLength
) {
839 // If old string was longer, blank its tail
841 Delete
= StringLen
- OutputLength
;
845 // If we need to update the output do so now
847 if (Update
!= (UINTN
) -1) {
848 ShellPrintEx ((INT32
)Column
, (INT32
)Row
, L
"%s%.*s", CurrentString
+ Update
, Delete
, L
"");
849 StringLen
= StrLen (CurrentString
);
852 SetMem (CurrentString
+ StringLen
, Delete
* sizeof (CHAR16
), CHAR_NULL
);
855 if (StringCurPos
> StringLen
) {
856 StringCurPos
= StringLen
;
862 // After using print to reflect newly updates, if we're not using
863 // BACKSPACE and DELETE, we need to move the cursor position forward,
864 // so adjust row and column here.
866 if (Key
.UnicodeChar
!= CHAR_BACKSPACE
&& !(Key
.UnicodeChar
== 0 && Key
.ScanCode
== SCAN_DELETE
)) {
868 // Calulate row and column of the tail of current string
870 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
+ OutputLength
) / TotalColumn
;
871 TailColumn
= (StringLen
- StringCurPos
+ Column
+ OutputLength
) % TotalColumn
;
874 // If the tail of string reaches screen end, screen rolls up, so if
875 // Row does not equal TailRow, Row should be decremented
877 // (if we are recalling commands using UPPER and DOWN key, and if the
878 // old command is too long to fit the screen, TailColumn must be 79.
880 if (TailColumn
== 0 && TailRow
>= TotalRow
&& Row
!= TailRow
) {
884 // Calculate the cursor position after current operation. If cursor
885 // reaches line end, update both row and column, otherwise, only
886 // column will be changed.
888 if (Column
+ OutputLength
>= TotalColumn
) {
889 SkipLength
= OutputLength
- (TotalColumn
- Column
);
891 Row
+= SkipLength
/ TotalColumn
+ 1;
892 if (Row
> TotalRow
- 1) {
896 Column
= SkipLength
% TotalColumn
;
898 Column
+= OutputLength
;
905 // Set the cursor position for this key
907 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Column
, Row
);
910 if (CurrentString
!= NULL
&& StrLen(CurrentString
) > 0) {
912 // add the line to the history buffer
914 AddLineToCommandHistory(CurrentString
);
918 // Return the data to the caller
920 *BufferSize
= StringLen
* sizeof (CHAR16
);
923 // if this was used it should be deallocated by now...
924 // prevent memory leaks...
926 if (TabCompleteList
!= NULL
) {
927 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&TabCompleteList
);
929 ASSERT(TabCompleteList
== NULL
);
935 // FILE sytle interfaces for StdIn/StdOut/StdErr
937 EFI_FILE_PROTOCOL FileInterfaceStdIn
= {
939 FileInterfaceOpenNotFound
,
940 FileInterfaceNopGeneric
,
941 FileInterfaceNopGeneric
,
942 FileInterfaceStdInRead
,
943 FileInterfaceStdInWrite
,
944 FileInterfaceNopGetPosition
,
945 FileInterfaceNopSetPosition
,
946 FileInterfaceNopGetInfo
,
947 FileInterfaceNopSetInfo
,
948 FileInterfaceNopGeneric
951 EFI_FILE_PROTOCOL FileInterfaceStdOut
= {
953 FileInterfaceOpenNotFound
,
954 FileInterfaceNopGeneric
,
955 FileInterfaceNopGeneric
,
956 FileInterfaceStdOutRead
,
957 FileInterfaceStdOutWrite
,
958 FileInterfaceNopGetPosition
,
959 FileInterfaceNopSetPosition
,
960 FileInterfaceNopGetInfo
,
961 FileInterfaceNopSetInfo
,
962 FileInterfaceNopGeneric
965 EFI_FILE_PROTOCOL FileInterfaceStdErr
= {
967 FileInterfaceOpenNotFound
,
968 FileInterfaceNopGeneric
,
969 FileInterfaceNopGeneric
,
970 FileInterfaceStdErrRead
,
971 FileInterfaceStdErrWrite
,
972 FileInterfaceNopGetPosition
,
973 FileInterfaceNopSetPosition
,
974 FileInterfaceNopGetInfo
,
975 FileInterfaceNopSetInfo
,
976 FileInterfaceNopGeneric
979 EFI_FILE_PROTOCOL FileInterfaceNulFile
= {
981 FileInterfaceOpenNotFound
,
982 FileInterfaceNopGeneric
,
983 FileInterfaceNopGeneric
,
984 FileInterfaceNulRead
,
985 FileInterfaceNulWrite
,
986 FileInterfaceNopGetPosition
,
987 FileInterfaceNopSetPosition
,
988 FileInterfaceNopGetInfo
,
989 FileInterfaceNopSetInfo
,
990 FileInterfaceNopGeneric
997 // This is identical to EFI_FILE_PROTOCOL except for the additional member
1004 EFI_FILE_CLOSE Close
;
1005 EFI_FILE_DELETE Delete
;
1007 EFI_FILE_WRITE Write
;
1008 EFI_FILE_GET_POSITION GetPosition
;
1009 EFI_FILE_SET_POSITION SetPosition
;
1010 EFI_FILE_GET_INFO GetInfo
;
1011 EFI_FILE_SET_INFO SetInfo
;
1012 EFI_FILE_FLUSH Flush
;
1014 } EFI_FILE_PROTOCOL_ENVIRONMENT
;
1015 //ANSI compliance helper to get size of the struct.
1016 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
1019 File style interface for Environment Variable (Close).
1021 Frees the memory for this object.
1023 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1029 FileInterfaceEnvClose(
1030 IN EFI_FILE_PROTOCOL
*This
1040 // Most if not all UEFI commands will have an '\r\n' at the end of any output.
1041 // Since the output was redirected to a variable, it does not make sense to
1042 // keep this. So, before closing, strip the trailing '\r\n' from the variable
1049 Status
= IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &Volatile
);
1050 if (EFI_ERROR (Status
)) {
1054 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1055 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1056 TotalSize
= NewSize
+ sizeof (CHAR16
);
1057 NewBuffer
= AllocateZeroPool (TotalSize
);
1058 if (NewBuffer
== NULL
) {
1059 return EFI_OUT_OF_RESOURCES
;
1061 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1064 if (!EFI_ERROR(Status
) && NewBuffer
!= NULL
) {
1066 if (TotalSize
/ sizeof (CHAR16
) >= 3) {
1067 if ( (((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 2] == CHAR_LINEFEED
) &&
1068 (((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 3] == CHAR_CARRIAGE_RETURN
)
1070 ((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 3] = CHAR_NULL
;
1072 // If the NewBuffer end with \r\n\0, We will repace '\r' by '\0' and then update TotalSize.
1074 TotalSize
-= sizeof(CHAR16
) * 2;
1078 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_V (
1079 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1080 TotalSize
- sizeof (CHAR16
),
1084 if (!EFI_ERROR(Status
)) {
1085 Status
= ShellAddEnvVarToList (
1086 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1089 EFI_VARIABLE_BOOTSERVICE_ACCESS
1093 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1094 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1095 TotalSize
- sizeof (CHAR16
),
1099 if (!EFI_ERROR(Status
)) {
1100 Status
= ShellAddEnvVarToList (
1101 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1104 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1111 SHELL_FREE_NON_NULL(NewBuffer
);
1112 FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
);
1117 File style interface for Environment Variable (Delete).
1119 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1121 @retval The return value from FileInterfaceEnvClose().
1125 FileInterfaceEnvDelete(
1126 IN EFI_FILE_PROTOCOL
*This
1129 SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1130 return (FileInterfaceEnvClose(This
));
1134 File style interface for Environment Variable (Read).
1136 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1137 @param[in, out] BufferSize Size in bytes of Buffer.
1138 @param[out] Buffer The pointer to the buffer to fill.
1140 @retval EFI_SUCCESS The data was read.
1144 FileInterfaceEnvRead(
1145 IN EFI_FILE_PROTOCOL
*This
,
1146 IN OUT UINTN
*BufferSize
,
1152 *BufferSize
= *BufferSize
/ sizeof (CHAR16
) * sizeof (CHAR16
);
1153 if (*BufferSize
!= 0) {
1155 // Make sure the first unicode character is \xFEFF
1157 *(CHAR16
*)Buffer
= gUnicodeFileTag
;
1158 Buffer
= (CHAR16
*)Buffer
+ 1;
1159 *BufferSize
-= sizeof (gUnicodeFileTag
);
1162 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (
1163 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1167 if (!EFI_ERROR (Status
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
1169 // BufferSize is valid and needs update when Status is Success or BufferTooSmall.
1171 *BufferSize
+= sizeof (gUnicodeFileTag
);
1177 File style interface for Volatile Environment Variable (Write).
1178 This function also caches the environment variable into gShellEnvVarList.
1180 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1181 @param[in, out] BufferSize Size in bytes of Buffer.
1182 @param[in] Buffer The pointer to the buffer to write.
1184 @retval EFI_SUCCESS The data was successfully write to variable.
1185 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1189 FileInterfaceEnvVolWrite(
1190 IN EFI_FILE_PROTOCOL
*This
,
1191 IN OUT UINTN
*BufferSize
,
1204 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1205 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1206 TotalSize
= NewSize
+ *BufferSize
+ sizeof (CHAR16
);
1207 } else if (Status
== EFI_NOT_FOUND
) {
1208 TotalSize
= *BufferSize
+ sizeof(CHAR16
);
1213 NewBuffer
= AllocateZeroPool (TotalSize
);
1214 if (NewBuffer
== NULL
) {
1215 return EFI_OUT_OF_RESOURCES
;
1218 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1219 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1222 if (EFI_ERROR (Status
) && Status
!= EFI_NOT_FOUND
) {
1223 FreePool (NewBuffer
);
1227 CopyMem ((UINT8
*)NewBuffer
+ NewSize
, Buffer
, *BufferSize
);
1228 Status
= ShellAddEnvVarToList (
1229 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1232 EFI_VARIABLE_BOOTSERVICE_ACCESS
1234 if (EFI_ERROR(Status
)) {
1235 FreePool (NewBuffer
);
1239 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_V (
1240 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1241 TotalSize
- sizeof (CHAR16
),
1244 if (EFI_ERROR(Status
)) {
1245 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1248 FreePool (NewBuffer
);
1254 File style interface for Non Volatile Environment Variable (Write).
1255 This function also caches the environment variable into gShellEnvVarList.
1257 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1258 @param[in, out] BufferSize Size in bytes of Buffer.
1259 @param[in] Buffer The pointer to the buffer to write.
1261 @retval EFI_SUCCESS The data was successfully write to variable.
1262 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1266 FileInterfaceEnvNonVolWrite(
1267 IN EFI_FILE_PROTOCOL
*This
,
1268 IN OUT UINTN
*BufferSize
,
1281 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1282 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1283 TotalSize
= NewSize
+ *BufferSize
+ sizeof (CHAR16
);
1284 } else if (Status
== EFI_NOT_FOUND
) {
1285 TotalSize
= *BufferSize
+ sizeof (CHAR16
);
1290 NewBuffer
= AllocateZeroPool (TotalSize
);
1291 if (NewBuffer
== NULL
) {
1292 return EFI_OUT_OF_RESOURCES
;
1295 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1296 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1299 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {
1300 FreePool (NewBuffer
);
1304 CopyMem ((UINT8
*) NewBuffer
+ NewSize
, Buffer
, *BufferSize
);
1305 Status
= ShellAddEnvVarToList (
1306 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1309 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1311 if (EFI_ERROR (Status
)) {
1312 FreePool (NewBuffer
);
1316 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1317 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1318 TotalSize
- sizeof (CHAR16
),
1321 if (EFI_ERROR (Status
)) {
1322 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1325 FreePool (NewBuffer
);
1330 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1331 environment variables through file operations.
1333 @param EnvName The name of the Environment Variable to be operated on.
1335 @retval NULL Memory could not be allocated.
1336 @return other a pointer to an EFI_FILE_PROTOCOL structure
1339 CreateFileInterfaceEnv(
1340 IN CONST CHAR16
*EnvName
1344 EFI_FILE_PROTOCOL_ENVIRONMENT
*EnvFileInterface
;
1348 if (EnvName
== NULL
) {
1352 Status
= IsVolatileEnv (EnvName
, &Volatile
);
1353 if (EFI_ERROR (Status
)) {
1360 EnvNameSize
= StrSize(EnvName
);
1361 EnvFileInterface
= AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT
)+EnvNameSize
);
1362 if (EnvFileInterface
== NULL
){
1367 // Assign the generic members
1369 EnvFileInterface
->Revision
= EFI_FILE_REVISION
;
1370 EnvFileInterface
->Open
= FileInterfaceOpenNotFound
;
1371 EnvFileInterface
->Close
= FileInterfaceEnvClose
;
1372 EnvFileInterface
->GetPosition
= FileInterfaceNopGetPosition
;
1373 EnvFileInterface
->SetPosition
= FileInterfaceNopSetPosition
;
1374 EnvFileInterface
->GetInfo
= FileInterfaceNopGetInfo
;
1375 EnvFileInterface
->SetInfo
= FileInterfaceNopSetInfo
;
1376 EnvFileInterface
->Flush
= FileInterfaceNopGeneric
;
1377 EnvFileInterface
->Delete
= FileInterfaceEnvDelete
;
1378 EnvFileInterface
->Read
= FileInterfaceEnvRead
;
1380 CopyMem(EnvFileInterface
->Name
, EnvName
, EnvNameSize
);
1383 // Assign the different members for Volatile and Non-Volatile variables
1386 EnvFileInterface
->Write
= FileInterfaceEnvVolWrite
;
1388 EnvFileInterface
->Write
= FileInterfaceEnvNonVolWrite
;
1390 return ((EFI_FILE_PROTOCOL
*)EnvFileInterface
);
1394 Move the cursor position one character backward.
1396 @param[in] LineLength Length of a line. Get it by calling QueryMode
1397 @param[in, out] Column Current column of the cursor position
1398 @param[in, out] Row Current row of the cursor position
1401 MoveCursorBackward (
1402 IN UINTN LineLength
,
1403 IN OUT UINTN
*Column
,
1408 // If current column is 0, move to the last column of the previous line,
1409 // otherwise, just decrement column.
1412 *Column
= LineLength
- 1;
1422 Move the cursor position one character forward.
1424 @param[in] LineLength Length of a line.
1425 @param[in] TotalRow Total row of a screen
1426 @param[in, out] Column Current column of the cursor position
1427 @param[in, out] Row Current row of the cursor position
1431 IN UINTN LineLength
,
1433 IN OUT UINTN
*Column
,
1438 // Increment Column.
1439 // If this puts column past the end of the line, move to first column
1443 if (*Column
>= LineLength
) {
1445 if ((*Row
) < TotalRow
- 1) {
1452 Prints out each previously typed command in the command list history log.
1454 When each screen is full it will pause for a key before continuing.
1456 @param[in] TotalCols How many columns are on the screen
1457 @param[in] TotalRows How many rows are on the screen
1458 @param[in] StartColumn which column to start at
1461 PrintCommandHistory (
1462 IN CONST UINTN TotalCols
,
1463 IN CONST UINTN TotalRows
,
1464 IN CONST UINTN StartColumn
1472 ShellPrintEx (-1, -1, L
"\n");
1476 // go through history list...
1478 for ( Node
= (BUFFER_LIST
*)GetFirstNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
)
1479 ; !IsNull(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
)
1480 ; Node
= (BUFFER_LIST
*)GetNextNode(&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
)
1483 LineCount
= ((StrLen (Node
->Buffer
) + StartColumn
+ 1) / TotalCols
) + 1;
1485 if (LineNumber
+ LineCount
>= TotalRows
) {
1486 ShellPromptForResponseHii(
1487 ShellPromptResponseTypeEnterContinue
,
1488 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT
),
1489 ShellInfoObject
.HiiHandle
,
1494 ShellPrintEx (-1, -1, L
"%2d. %s\n", Index
, Node
->Buffer
);
1495 LineNumber
+= LineCount
;
1505 // This is identical to EFI_FILE_PROTOCOL except for the additional members
1506 // for the buffer, size, and position.
1512 EFI_FILE_CLOSE Close
;
1513 EFI_FILE_DELETE Delete
;
1515 EFI_FILE_WRITE Write
;
1516 EFI_FILE_GET_POSITION GetPosition
;
1517 EFI_FILE_SET_POSITION SetPosition
;
1518 EFI_FILE_GET_INFO GetInfo
;
1519 EFI_FILE_SET_INFO SetInfo
;
1520 EFI_FILE_FLUSH Flush
;
1526 } EFI_FILE_PROTOCOL_MEM
;
1529 File style interface for Mem (SetPosition).
1531 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1532 @param[out] Position The position to set.
1534 @retval EFI_SUCCESS The position was successfully changed.
1535 @retval EFI_INVALID_PARAMETER The Position was invalid.
1539 FileInterfaceMemSetPosition(
1540 IN EFI_FILE_PROTOCOL
*This
,
1544 if (Position
<= ((EFI_FILE_PROTOCOL_MEM
*)This
)->FileSize
) {
1545 ((EFI_FILE_PROTOCOL_MEM
*)This
)->Position
= Position
;
1546 return (EFI_SUCCESS
);
1548 return (EFI_INVALID_PARAMETER
);
1553 File style interface for Mem (GetPosition).
1555 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1556 @param[out] Position The pointer to the position.
1558 @retval EFI_SUCCESS The position was retrieved.
1562 FileInterfaceMemGetPosition(
1563 IN EFI_FILE_PROTOCOL
*This
,
1564 OUT UINT64
*Position
1567 *Position
= ((EFI_FILE_PROTOCOL_MEM
*)This
)->Position
;
1568 return (EFI_SUCCESS
);
1572 File style interface for Mem (GetInfo).
1574 @param This Protocol instance pointer.
1575 @param InformationType Type of information to return in Buffer.
1576 @param BufferSize On input size of buffer, on output amount of data in buffer.
1577 @param Buffer The buffer to return data.
1579 @retval EFI_SUCCESS Data was returned.
1580 @retval EFI_UNSUPPORT InformationType is not supported.
1581 @retval EFI_NO_MEDIA The device has no media.
1582 @retval EFI_DEVICE_ERROR The device reported an error.
1583 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1584 @retval EFI_WRITE_PROTECTED The device is write protected.
1585 @retval EFI_ACCESS_DENIED The file was open for read only.
1586 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1591 FileInterfaceMemGetInfo(
1592 IN EFI_FILE_PROTOCOL
*This
,
1593 IN EFI_GUID
*InformationType
,
1594 IN OUT UINTN
*BufferSize
,
1598 EFI_FILE_INFO
*FileInfo
;
1600 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1601 if (*BufferSize
< sizeof (EFI_FILE_INFO
)) {
1602 *BufferSize
= sizeof (EFI_FILE_INFO
);
1603 return EFI_BUFFER_TOO_SMALL
;
1605 if (Buffer
== NULL
) {
1606 return EFI_INVALID_PARAMETER
;
1608 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
1609 FileInfo
->Size
= sizeof (*FileInfo
);
1610 ZeroMem (FileInfo
, sizeof (*FileInfo
));
1611 FileInfo
->FileSize
= ((EFI_FILE_PROTOCOL_MEM
*)This
)->FileSize
;
1612 FileInfo
->PhysicalSize
= FileInfo
->FileSize
;
1616 return EFI_UNSUPPORTED
;
1620 File style interface for Mem (Write).
1622 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1623 @param[in, out] BufferSize Size in bytes of Buffer.
1624 @param[in] Buffer The pointer to the buffer to write.
1626 @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
1627 @retval EFI_SUCCESS The data was written.
1631 FileInterfaceMemWrite(
1632 IN EFI_FILE_PROTOCOL
*This
,
1633 IN OUT UINTN
*BufferSize
,
1638 EFI_FILE_PROTOCOL_MEM
*MemFile
;
1640 MemFile
= (EFI_FILE_PROTOCOL_MEM
*) This
;
1641 if (MemFile
->Unicode
) {
1645 if ((UINTN
)(MemFile
->Position
+ (*BufferSize
)) > (UINTN
)(MemFile
->BufferSize
)) {
1646 MemFile
->Buffer
= ReallocatePool((UINTN
)(MemFile
->BufferSize
), (UINTN
)(MemFile
->BufferSize
) + (*BufferSize
) + MEM_WRITE_REALLOC_OVERHEAD
, MemFile
->Buffer
);
1647 if (MemFile
->Buffer
== NULL
){
1648 return EFI_OUT_OF_RESOURCES
;
1650 MemFile
->BufferSize
+= (*BufferSize
) + MEM_WRITE_REALLOC_OVERHEAD
;
1652 CopyMem(((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, Buffer
, *BufferSize
);
1653 MemFile
->Position
+= (*BufferSize
);
1654 MemFile
->FileSize
= MemFile
->Position
;
1655 return (EFI_SUCCESS
);
1660 AsciiBuffer
= AllocateZeroPool(*BufferSize
);
1661 if (AsciiBuffer
== NULL
) {
1662 return (EFI_OUT_OF_RESOURCES
);
1664 AsciiSPrint(AsciiBuffer
, *BufferSize
, "%S", Buffer
);
1665 if ((UINTN
)(MemFile
->Position
+ AsciiStrSize(AsciiBuffer
)) > (UINTN
)(MemFile
->BufferSize
)) {
1666 MemFile
->Buffer
= ReallocatePool((UINTN
)(MemFile
->BufferSize
), (UINTN
)(MemFile
->BufferSize
) + AsciiStrSize(AsciiBuffer
) + MEM_WRITE_REALLOC_OVERHEAD
, MemFile
->Buffer
);
1667 if (MemFile
->Buffer
== NULL
){
1668 FreePool(AsciiBuffer
);
1669 return EFI_OUT_OF_RESOURCES
;
1671 MemFile
->BufferSize
+= AsciiStrSize(AsciiBuffer
) + MEM_WRITE_REALLOC_OVERHEAD
;
1673 CopyMem(((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, AsciiBuffer
, AsciiStrSize(AsciiBuffer
));
1674 MemFile
->Position
+= (*BufferSize
/ sizeof(CHAR16
));
1675 MemFile
->FileSize
= MemFile
->Position
;
1676 FreePool(AsciiBuffer
);
1677 return (EFI_SUCCESS
);
1682 File style interface for Mem (Read).
1684 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1685 @param[in, out] BufferSize Size in bytes of Buffer.
1686 @param[in] Buffer The pointer to the buffer to fill.
1688 @retval EFI_SUCCESS The data was read.
1692 FileInterfaceMemRead(
1693 IN EFI_FILE_PROTOCOL
*This
,
1694 IN OUT UINTN
*BufferSize
,
1698 EFI_FILE_PROTOCOL_MEM
*MemFile
;
1700 MemFile
= (EFI_FILE_PROTOCOL_MEM
*) This
;
1701 if (*BufferSize
> (UINTN
)((MemFile
->FileSize
) - (UINTN
)(MemFile
->Position
))) {
1702 (*BufferSize
) = (UINTN
)((MemFile
->FileSize
) - (UINTN
)(MemFile
->Position
));
1704 CopyMem(Buffer
, ((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, (*BufferSize
));
1705 MemFile
->Position
= MemFile
->Position
+ (*BufferSize
);
1706 return (EFI_SUCCESS
);
1710 File style interface for Mem (Close).
1712 Frees all memory associated with this object.
1714 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1716 @retval EFI_SUCCESS The 'file' was closed.
1720 FileInterfaceMemClose(
1721 IN EFI_FILE_PROTOCOL
*This
1724 SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM
*)This
)->Buffer
);
1725 SHELL_FREE_NON_NULL(This
);
1726 return (EFI_SUCCESS
);
1730 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1731 a file entirely in memory through file operations.
1733 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1735 @retval NULL Memory could not be allocated.
1736 @return other A pointer to an EFI_FILE_PROTOCOL structure.
1739 CreateFileInterfaceMem(
1740 IN CONST BOOLEAN Unicode
1743 EFI_FILE_PROTOCOL_MEM
*FileInterface
;
1748 FileInterface
= AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM
));
1749 if (FileInterface
== NULL
){
1754 // Assign the generic members
1756 FileInterface
->Revision
= EFI_FILE_REVISION
;
1757 FileInterface
->Open
= FileInterfaceOpenNotFound
;
1758 FileInterface
->Close
= FileInterfaceMemClose
;
1759 FileInterface
->GetPosition
= FileInterfaceMemGetPosition
;
1760 FileInterface
->SetPosition
= FileInterfaceMemSetPosition
;
1761 FileInterface
->GetInfo
= FileInterfaceMemGetInfo
;
1762 FileInterface
->SetInfo
= FileInterfaceNopSetInfo
;
1763 FileInterface
->Flush
= FileInterfaceNopGeneric
;
1764 FileInterface
->Delete
= FileInterfaceNopGeneric
;
1765 FileInterface
->Read
= FileInterfaceMemRead
;
1766 FileInterface
->Write
= FileInterfaceMemWrite
;
1767 FileInterface
->Unicode
= Unicode
;
1769 ASSERT(FileInterface
->Buffer
== NULL
);
1770 ASSERT(FileInterface
->BufferSize
== 0);
1771 ASSERT(FileInterface
->Position
== 0);
1774 FileInterface
->Buffer
= AllocateZeroPool(sizeof(gUnicodeFileTag
));
1775 if (FileInterface
->Buffer
== NULL
) {
1776 FreePool (FileInterface
);
1779 *((CHAR16
*) (FileInterface
->Buffer
)) = EFI_UNICODE_BYTE_ORDER_MARK
;
1780 FileInterface
->BufferSize
= 2;
1781 FileInterface
->Position
= 2;
1784 return ((EFI_FILE_PROTOCOL
*)FileInterface
);
1790 EFI_FILE_CLOSE Close
;
1791 EFI_FILE_DELETE Delete
;
1793 EFI_FILE_WRITE Write
;
1794 EFI_FILE_GET_POSITION GetPosition
;
1795 EFI_FILE_SET_POSITION SetPosition
;
1796 EFI_FILE_GET_INFO GetInfo
;
1797 EFI_FILE_SET_INFO SetInfo
;
1798 EFI_FILE_FLUSH Flush
;
1800 EFI_FILE_PROTOCOL
*Orig
;
1801 } EFI_FILE_PROTOCOL_FILE
;
1804 Set a files current position
1806 @param This Protocol instance pointer.
1807 @param Position Byte position from the start of the file.
1809 @retval EFI_SUCCESS Data was written.
1810 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
1815 FileInterfaceFileSetPosition(
1816 IN EFI_FILE_PROTOCOL
*This
,
1820 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->SetPosition(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, Position
);
1824 Get a file's current position
1826 @param This Protocol instance pointer.
1827 @param Position Byte position from the start of the file.
1829 @retval EFI_SUCCESS Data was written.
1830 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
1835 FileInterfaceFileGetPosition(
1836 IN EFI_FILE_PROTOCOL
*This
,
1837 OUT UINT64
*Position
1840 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetPosition(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, Position
);
1844 Get information about a file.
1846 @param This Protocol instance pointer.
1847 @param InformationType Type of information to return in Buffer.
1848 @param BufferSize On input size of buffer, on output amount of data in buffer.
1849 @param Buffer The buffer to return data.
1851 @retval EFI_SUCCESS Data was returned.
1852 @retval EFI_UNSUPPORT InformationType is not supported.
1853 @retval EFI_NO_MEDIA The device has no media.
1854 @retval EFI_DEVICE_ERROR The device reported an error.
1855 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1856 @retval EFI_WRITE_PROTECTED The device is write protected.
1857 @retval EFI_ACCESS_DENIED The file was open for read only.
1858 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1863 FileInterfaceFileGetInfo(
1864 IN EFI_FILE_PROTOCOL
*This
,
1865 IN EFI_GUID
*InformationType
,
1866 IN OUT UINTN
*BufferSize
,
1870 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetInfo(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, InformationType
, BufferSize
, Buffer
);
1874 Set information about a file
1876 @param This Protocol instance pointer.
1877 @param InformationType Type of information in Buffer.
1878 @param BufferSize Size of buffer.
1879 @param Buffer The data to write.
1881 @retval EFI_SUCCESS Data was returned.
1882 @retval EFI_UNSUPPORT InformationType is not supported.
1883 @retval EFI_NO_MEDIA The device has no media.
1884 @retval EFI_DEVICE_ERROR The device reported an error.
1885 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1886 @retval EFI_WRITE_PROTECTED The device is write protected.
1887 @retval EFI_ACCESS_DENIED The file was open for read only.
1892 FileInterfaceFileSetInfo(
1893 IN EFI_FILE_PROTOCOL
*This
,
1894 IN EFI_GUID
*InformationType
,
1895 IN UINTN BufferSize
,
1899 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->SetInfo(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, InformationType
, BufferSize
, Buffer
);
1903 Flush data back for the file handle.
1905 @param This Protocol instance pointer.
1907 @retval EFI_SUCCESS Data was written.
1908 @retval EFI_UNSUPPORT Writes to Open directory are not supported.
1909 @retval EFI_NO_MEDIA The device has no media.
1910 @retval EFI_DEVICE_ERROR The device reported an error.
1911 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1912 @retval EFI_WRITE_PROTECTED The device is write protected.
1913 @retval EFI_ACCESS_DENIED The file was open for read only.
1914 @retval EFI_VOLUME_FULL The volume is full.
1919 FileInterfaceFileFlush(
1920 IN EFI_FILE_PROTOCOL
*This
1923 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Flush(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
1927 Read data from the file.
1929 @param This Protocol instance pointer.
1930 @param BufferSize On input size of buffer, on output amount of data in buffer.
1931 @param Buffer The buffer in which data is read.
1933 @retval EFI_SUCCESS Data was read.
1934 @retval EFI_NO_MEDIA The device has no media.
1935 @retval EFI_DEVICE_ERROR The device reported an error.
1936 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1937 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
1942 FileInterfaceFileRead(
1943 IN EFI_FILE_PROTOCOL
*This
,
1944 IN OUT UINTN
*BufferSize
,
1950 CHAR8
*AsciiStrBuffer
;
1951 CHAR16
*UscStrBuffer
;
1953 if (((EFI_FILE_PROTOCOL_FILE
*)This
)->Unicode
) {
1956 // There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF.
1957 // So we choose to leave the file content as is.
1959 return (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Read(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, BufferSize
, Buffer
));
1964 *BufferSize
= *BufferSize
/ sizeof (CHAR16
) * sizeof (CHAR16
);
1965 if (*BufferSize
== 0) {
1968 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetPosition (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Position
);
1969 if (EFI_ERROR (Status
)) {
1972 if (Position
== 0) {
1974 // First two bytes in Buffer is for the Unicode file tag.
1976 *(CHAR16
*)Buffer
= gUnicodeFileTag
;
1977 Buffer
= (CHAR16
*)Buffer
+ 1;
1978 Size
= *BufferSize
/ sizeof (CHAR16
) - 1;
1980 Size
= *BufferSize
/ sizeof (CHAR16
);
1982 AsciiStrBuffer
= AllocateZeroPool (Size
+ 1);
1983 if (AsciiStrBuffer
== NULL
) {
1984 return EFI_OUT_OF_RESOURCES
;
1986 UscStrBuffer
= AllocateZeroPool ((Size
+ 1) * sizeof(CHAR16
));
1987 if (UscStrBuffer
== NULL
) {
1988 SHELL_FREE_NON_NULL(AsciiStrBuffer
);
1989 return EFI_OUT_OF_RESOURCES
;
1991 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Read (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Size
, AsciiStrBuffer
);
1992 if (!EFI_ERROR(Status
)) {
1993 AsciiStrToUnicodeStrS (AsciiStrBuffer
, UscStrBuffer
, Size
+ 1);
1994 *BufferSize
= Size
* sizeof (CHAR16
);
1995 CopyMem (Buffer
, UscStrBuffer
, *BufferSize
);
1997 SHELL_FREE_NON_NULL (AsciiStrBuffer
);
1998 SHELL_FREE_NON_NULL (UscStrBuffer
);
2004 Opens a new file relative to the source file's location.
2006 @param[in] This The protocol instance pointer.
2007 @param[out] NewHandle Returns File Handle for FileName.
2008 @param[in] FileName Null terminated string. "\", ".", and ".." are supported.
2009 @param[in] OpenMode Open mode for file.
2010 @param[in] Attributes Only used for EFI_FILE_MODE_CREATE.
2012 @retval EFI_SUCCESS The device was opened.
2013 @retval EFI_NOT_FOUND The specified file could not be found on the device.
2014 @retval EFI_NO_MEDIA The device has no media.
2015 @retval EFI_MEDIA_CHANGED The media has changed.
2016 @retval EFI_DEVICE_ERROR The device reported an error.
2017 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2018 @retval EFI_ACCESS_DENIED The service denied access to the file.
2019 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
2020 @retval EFI_VOLUME_FULL The volume is full.
2024 FileInterfaceFileOpen (
2025 IN EFI_FILE_PROTOCOL
*This
,
2026 OUT EFI_FILE_PROTOCOL
**NewHandle
,
2027 IN CHAR16
*FileName
,
2029 IN UINT64 Attributes
2032 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Open(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, NewHandle
, FileName
, OpenMode
, Attributes
);
2036 Close and delete the file handle.
2038 @param This Protocol instance pointer.
2040 @retval EFI_SUCCESS The device was opened.
2041 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
2046 FileInterfaceFileDelete(
2047 IN EFI_FILE_PROTOCOL
*This
2051 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Delete(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
2057 File style interface for File (Close).
2059 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
2061 @retval EFI_SUCCESS The file was closed.
2065 FileInterfaceFileClose(
2066 IN EFI_FILE_PROTOCOL
*This
2070 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Close(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
2076 File style interface for File (Write).
2078 If the file was opened with ASCII mode the data will be processed through
2079 AsciiSPrint before writing.
2081 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
2082 @param[in, out] BufferSize Size in bytes of Buffer.
2083 @param[in] Buffer The pointer to the buffer to write.
2085 @retval EFI_SUCCESS The data was written.
2089 FileInterfaceFileWrite(
2090 IN EFI_FILE_PROTOCOL
*This
,
2091 IN OUT UINTN
*BufferSize
,
2098 if (((EFI_FILE_PROTOCOL_FILE
*)This
)->Unicode
) {
2102 return (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Write(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, BufferSize
, Buffer
));
2107 AsciiBuffer
= AllocateZeroPool(*BufferSize
);
2108 AsciiSPrint(AsciiBuffer
, *BufferSize
, "%S", Buffer
);
2109 Size
= AsciiStrSize(AsciiBuffer
) - 1; // (we dont need the null terminator)
2110 Status
= (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Write(((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Size
, AsciiBuffer
));
2111 FreePool(AsciiBuffer
);
2117 Create a file interface with unicode information.
2119 This will create a new EFI_FILE_PROTOCOL identical to the Templace
2120 except that the new one has Unicode and Ascii knowledge.
2122 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.
2123 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.
2125 @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
2128 CreateFileInterfaceFile(
2129 IN CONST EFI_FILE_PROTOCOL
*Template
,
2130 IN CONST BOOLEAN Unicode
2133 EFI_FILE_PROTOCOL_FILE
*NewOne
;
2135 NewOne
= AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE
));
2136 if (NewOne
== NULL
) {
2139 CopyMem(NewOne
, Template
, sizeof(EFI_FILE_PROTOCOL_FILE
));
2140 NewOne
->Orig
= (EFI_FILE_PROTOCOL
*)Template
;
2141 NewOne
->Unicode
= Unicode
;
2142 NewOne
->Open
= FileInterfaceFileOpen
;
2143 NewOne
->Close
= FileInterfaceFileClose
;
2144 NewOne
->Delete
= FileInterfaceFileDelete
;
2145 NewOne
->Read
= FileInterfaceFileRead
;
2146 NewOne
->Write
= FileInterfaceFileWrite
;
2147 NewOne
->GetPosition
= FileInterfaceFileGetPosition
;
2148 NewOne
->SetPosition
= FileInterfaceFileSetPosition
;
2149 NewOne
->GetInfo
= FileInterfaceFileGetInfo
;
2150 NewOne
->SetInfo
= FileInterfaceFileSetInfo
;
2151 NewOne
->Flush
= FileInterfaceFileFlush
;
2153 return ((EFI_FILE_PROTOCOL
*)NewOne
);