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
);
161 if (*((CHAR16
*)Buffer
) == gUnicodeFileTag
) {
162 return (gST
->ConOut
->OutputString (gST
->ConOut
, (CHAR16
*)Buffer
+ 1));
165 return (gST
->ConOut
->OutputString (gST
->ConOut
, Buffer
));
169 File style interface for StdIn (Write).
171 @param[in] This Ignored.
172 @param[in, out] BufferSize Ignored.
173 @param[in] Buffer Ignored.
175 @retval EFI_UNSUPPORTED
179 FileInterfaceStdInWrite (
180 IN EFI_FILE_PROTOCOL
*This
,
181 IN OUT UINTN
*BufferSize
,
185 return (EFI_UNSUPPORTED
);
189 File style interface for console StdErr (Write).
191 Writes error to the error output.
193 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
194 @param[in, out] BufferSize Size in bytes of Buffer.
195 @param[in] Buffer The pointer to the buffer to write.
197 @return A return value from gST->StdErr->OutputString.
201 FileInterfaceStdErrWrite (
202 IN EFI_FILE_PROTOCOL
*This
,
203 IN OUT UINTN
*BufferSize
,
207 return (gST
->StdErr
->OutputString (gST
->StdErr
, Buffer
));
211 File style interface for console StdOut (Read).
213 @param[in] This Ignored.
214 @param[in, out] BufferSize Ignored.
215 @param[out] Buffer Ignored.
217 @retval EFI_UNSUPPORTED
221 FileInterfaceStdOutRead (
222 IN EFI_FILE_PROTOCOL
*This
,
223 IN OUT UINTN
*BufferSize
,
227 return (EFI_UNSUPPORTED
);
231 File style interface for console StdErr (Read).
233 @param[in] This Ignored.
234 @param[in, out] BufferSize Ignored.
235 @param[out] Buffer Ignored.
237 @retval EFI_UNSUPPORTED Always.
241 FileInterfaceStdErrRead (
242 IN EFI_FILE_PROTOCOL
*This
,
243 IN OUT UINTN
*BufferSize
,
247 return (EFI_UNSUPPORTED
);
251 File style interface for NUL file (Read).
253 @param[in] This Ignored.
254 @param[in, out] BufferSize Poiner to 0 upon return.
255 @param[out] Buffer Ignored.
257 @retval EFI_SUCCESS Always.
261 FileInterfaceNulRead (
262 IN EFI_FILE_PROTOCOL
*This
,
263 IN OUT UINTN
*BufferSize
,
268 return (EFI_SUCCESS
);
272 File style interface for NUL file (Write).
274 @param[in] This Ignored.
275 @param[in, out] BufferSize Ignored.
276 @param[in] Buffer Ignored.
282 FileInterfaceNulWrite (
283 IN EFI_FILE_PROTOCOL
*This
,
284 IN OUT UINTN
*BufferSize
,
288 return (EFI_SUCCESS
);
292 Create the TAB completion list.
294 @param[in] InputString The command line to expand.
295 @param[in] StringLen Length of the command line.
296 @param[in] BufferSize Buffer size.
297 @param[in, out] TabCompletionList Return the TAB completion list.
298 @param[in, out] TabUpdatePos Return the TAB update position.
301 CreateTabCompletionList (
302 IN CONST CHAR16
*InputString
,
303 IN CONST UINTN StringLen
,
304 IN CONST UINTN BufferSize
,
305 IN OUT EFI_SHELL_FILE_INFO
**TabCompletionList
,
306 IN OUT UINTN
*TabUpdatePos
315 EFI_SHELL_FILE_INFO
*FileList
;
316 EFI_SHELL_FILE_INFO
*FileInfo
;
317 EFI_SHELL_FILE_INFO
*TempFileInfo
;
322 TabStr
= AllocateZeroPool (BufferSize
);
323 if (TabStr
== NULL
) {
324 return EFI_OUT_OF_RESOURCES
;
328 // handle auto complete of file and directory names...
329 // E.g.: cd fs0:\EFI\Bo<TAB>
331 // TabPos TabUpdatePos
337 for (Index
= 0; Index
< StringLen
; Index
++) {
338 switch (InputString
[Index
]) {
340 InQuotation
= (BOOLEAN
)(!InQuotation
);
346 *TabUpdatePos
= TabPos
;
353 // handle the case "fs0:<TAB>"
354 // Update the TabUpdatePos as well.
357 *TabUpdatePos
= Index
+ 1;
365 if (StrStr (InputString
+ TabPos
, L
":") == NULL
) {
367 // If file path doesn't contain ":", ...
369 Cwd
= ShellInfoObject
.NewEfiShellProtocol
->GetCurDir (NULL
);
371 if (InputString
[TabPos
] != L
'\\') {
373 // and it doesn't begin with "\\", it's a path relative to current directory.
374 // TabStr = "<cwd>\\"
376 StrnCpyS (TabStr
, BufferSize
/ sizeof (CHAR16
), Cwd
, (BufferSize
) / sizeof (CHAR16
) - 1);
377 StrCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), L
"\\");
380 // and it begins with "\\", it's a path pointing to root directory of current map.
383 Index
= StrStr (Cwd
, L
":") - Cwd
+ 1;
384 StrnCpyS (TabStr
, BufferSize
/ sizeof (CHAR16
), Cwd
, Index
);
389 StrnCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), InputString
+ TabPos
, StringLen
- TabPos
);
390 StrnCatS (TabStr
, (BufferSize
) / sizeof (CHAR16
), L
"*", (BufferSize
) / sizeof (CHAR16
) - 1 - StrLen (TabStr
));
391 Status
= ShellInfoObject
.NewEfiShellProtocol
->FindFiles (TabStr
, &FileList
);
394 // Filter out the non-directory for "CD" command
395 // Filter "." and ".." for all
397 if (!EFI_ERROR (Status
) && (FileList
!= NULL
)) {
399 // Skip the spaces in the beginning
401 while (*InputString
== L
' ') {
405 for (FileInfo
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&FileList
->Link
); !IsNull (&FileList
->Link
, &FileInfo
->Link
); ) {
406 if (((StrCmp (FileInfo
->FileName
, L
".") == 0) || (StrCmp (FileInfo
->FileName
, L
"..") == 0)) ||
407 ((((InputString
[0] == L
'c') || (InputString
[0] == L
'C')) && ((InputString
[1] == L
'd') || (InputString
[1] == L
'D'))) &&
408 (ShellIsDirectory (FileInfo
->FullName
) != EFI_SUCCESS
)))
410 TempFileInfo
= FileInfo
;
411 FileInfo
= (EFI_SHELL_FILE_INFO
*)RemoveEntryList (&FileInfo
->Link
);
412 InternalFreeShellFileInfoNode (TempFileInfo
);
414 FileInfo
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&FileList
->Link
, &FileInfo
->Link
);
419 if ((FileList
!= NULL
) && !IsListEmpty (&FileList
->Link
)) {
420 Status
= EFI_SUCCESS
;
422 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&FileList
);
423 Status
= EFI_NOT_FOUND
;
428 *TabCompletionList
= FileList
;
433 File style interface for console (Read).
435 This will return a single line of input from the console.
437 @param This A pointer to the EFI_FILE_PROTOCOL instance that is the
438 file handle to read data from. Not used.
439 @param BufferSize On input, the size of the Buffer. On output, the amount
440 of data returned in Buffer. In both cases, the size is
442 @param Buffer The buffer into which the data is read.
445 @retval EFI_SUCCESS The data was read.
446 @retval EFI_NO_MEDIA The device has no medium.
447 @retval EFI_DEVICE_ERROR The device reported an error.
448 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file.
449 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file.
450 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
451 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory
452 entry. BufferSize has been updated with the size
453 needed to complete the request.
454 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
458 FileInterfaceStdInRead (
459 IN EFI_FILE_PROTOCOL
*This
,
460 IN OUT UINTN
*BufferSize
,
464 CHAR16
*CurrentString
;
466 UINTN TabUpdatePos
; // Start index of the string updated by TAB stroke
467 UINTN Column
; // Column of current cursor
468 UINTN Row
; // Row of current cursor
469 UINTN StartColumn
; // Column at the beginning of the line
470 UINTN Update
; // Line index for update
471 UINTN Delete
; // Num of chars to delete from console after update
472 UINTN StringLen
; // Total length of the line
473 UINTN StringCurPos
; // Line index corresponding to the cursor
474 UINTN MaxStr
; // Maximum possible line length
475 UINTN TotalColumn
; // Num of columns in the console
476 UINTN TotalRow
; // Num of rows in the console
478 UINTN OutputLength
; // Length of the update string
479 UINTN TailRow
; // Row of end of line
480 UINTN TailColumn
; // Column of end of line
483 BUFFER_LIST
*LinePos
;
487 BOOLEAN InTabScrolling
; // Whether in TAB-completion state
488 EFI_SHELL_FILE_INFO
*TabCompleteList
;
489 EFI_SHELL_FILE_INFO
*TabCurrent
;
491 CHAR16
*TabOutputStr
;
494 // If buffer is not large enough to hold a CHAR16, return minimum buffer size
496 if (*BufferSize
< sizeof (CHAR16
) * 2) {
497 *BufferSize
= sizeof (CHAR16
) * 2;
498 return (EFI_BUFFER_TOO_SMALL
);
502 CurrentString
= Buffer
;
508 LinePos
= NewPos
= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
510 InTabScrolling
= FALSE
;
511 Status
= EFI_SUCCESS
;
514 TabCompleteList
= NULL
;
518 // Get the screen setting and the current cursor location
520 Column
= StartColumn
= gST
->ConOut
->Mode
->CursorColumn
;
521 Row
= gST
->ConOut
->Mode
->CursorRow
;
522 gST
->ConOut
->QueryMode (gST
->ConOut
, gST
->ConOut
->Mode
->Mode
, &TotalColumn
, &TotalRow
);
525 // Limit the line length to the buffer size or the minimum size of the
526 // screen. (The smaller takes effect)
528 MaxStr
= TotalColumn
* (TotalRow
- 1) - StartColumn
;
529 if (MaxStr
> *BufferSize
/ sizeof (CHAR16
)) {
530 MaxStr
= *BufferSize
/ sizeof (CHAR16
);
533 ZeroMem (CurrentString
, MaxStr
* sizeof (CHAR16
));
538 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
539 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
540 if (EFI_ERROR (Status
)) {
541 if (Status
== EFI_NOT_READY
) {
545 ZeroMem (CurrentString
, MaxStr
* sizeof (CHAR16
));
551 // Press PageUp or PageDown to scroll the history screen up or down.
552 // Press any other key to quit scrolling.
554 if ((Key
.UnicodeChar
== 0) && ((Key
.ScanCode
== SCAN_PAGE_UP
) || (Key
.ScanCode
== SCAN_PAGE_DOWN
))) {
555 if (Key
.ScanCode
== SCAN_PAGE_UP
) {
556 ConsoleLoggerDisplayHistory (FALSE
, 0, ShellInfoObject
.ConsoleInfo
);
557 } else if (Key
.ScanCode
== SCAN_PAGE_DOWN
) {
558 ConsoleLoggerDisplayHistory (TRUE
, 0, ShellInfoObject
.ConsoleInfo
);
564 ConsoleLoggerStopHistory (ShellInfoObject
.ConsoleInfo
);
570 // If we are quitting TAB scrolling...
572 if (InTabScrolling
&& (Key
.UnicodeChar
!= CHAR_TAB
)) {
573 if (TabCompleteList
!= NULL
) {
574 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&TabCompleteList
);
576 TabCompleteList
= NULL
;
580 InTabScrolling
= FALSE
;
583 switch (Key
.UnicodeChar
) {
584 case CHAR_CARRIAGE_RETURN
:
586 // All done, print a newline at the end of the string
588 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
) / TotalColumn
;
589 TailColumn
= (StringLen
- StringCurPos
+ Column
) % TotalColumn
;
590 ShellPrintEx ((INT32
)TailColumn
, (INT32
)TailRow
, L
"%N\n");
595 if (StringCurPos
!= 0) {
597 // If not move back beyond string beginning, move all characters behind
598 // the current position one character forward
601 Update
= StringCurPos
;
603 CopyMem (CurrentString
+ StringCurPos
, CurrentString
+ StringCurPos
+ 1, sizeof (CHAR16
) * (StringLen
- StringCurPos
));
606 // Adjust the current column and row
608 MoveCursorBackward (TotalColumn
, &Column
, &Row
);
614 if (!InTabScrolling
) {
617 // Initialize a tab complete operation.
619 Status
= CreateTabCompletionList (CurrentString
, StringLen
, *BufferSize
, &TabCompleteList
, &TabUpdatePos
);
620 if (!EFI_ERROR (Status
)) {
621 InTabScrolling
= TRUE
;
625 // We do not set up the replacement.
626 // The next section will do that.
630 if (InTabScrolling
) {
632 // We are in a tab complete operation.
633 // set up the next replacement.
635 ASSERT (TabCompleteList
!= NULL
);
636 if (TabCurrent
== NULL
) {
637 TabCurrent
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&TabCompleteList
->Link
);
639 TabCurrent
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&TabCompleteList
->Link
, &TabCurrent
->Link
);
643 // Skip over the empty list beginning node
645 if (IsNull (&TabCompleteList
->Link
, &TabCurrent
->Link
)) {
646 TabCurrent
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&TabCompleteList
->Link
, &TabCurrent
->Link
);
653 if (Key
.UnicodeChar
>= ' ') {
655 // If we are at the buffer's end, drop the key
657 if ((StringLen
== MaxStr
- 1) && (ShellInfoObject
.ViewingSettings
.InsertMode
|| (StringCurPos
== StringLen
))) {
662 // If in insert mode, make space by moving each other character 1
663 // space higher in the array
665 if (ShellInfoObject
.ViewingSettings
.InsertMode
) {
666 CopyMem (CurrentString
+ StringCurPos
+ 1, CurrentString
+ StringCurPos
, (StringLen
- StringCurPos
)*sizeof (CurrentString
[0]));
669 CurrentString
[StringCurPos
] = Key
.UnicodeChar
;
670 Update
= StringCurPos
;
679 switch (Key
.ScanCode
) {
682 // Move characters behind current position one character forward
684 if (StringLen
!= 0) {
685 Update
= StringCurPos
;
687 CopyMem (CurrentString
+ StringCurPos
, CurrentString
+ StringCurPos
+ 1, sizeof (CHAR16
) * (StringLen
- StringCurPos
));
694 // Prepare to print the previous command
696 NewPos
= (BUFFER_LIST
*)GetPreviousNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
697 if (IsNull (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
)) {
698 NewPos
= (BUFFER_LIST
*)GetPreviousNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
705 // Prepare to print the next command
707 NewPos
= (BUFFER_LIST
*)GetNextNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
708 if (NewPos
== (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
)) {
709 NewPos
= (BUFFER_LIST
*)GetNextNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &LinePos
->Link
);
716 // Adjust current cursor position
718 if (StringCurPos
!= 0) {
720 MoveCursorBackward (TotalColumn
, &Column
, &Row
);
727 // Adjust current cursor position
729 if (StringCurPos
< StringLen
) {
731 MoveCursorForward (TotalColumn
, TotalRow
, &Column
, &Row
);
738 // Move current cursor position to the beginning of the command line
740 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
741 Column
= StartColumn
;
747 // Move current cursor position to the end of the command line
749 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
) / TotalColumn
;
750 TailColumn
= (StringLen
- StringCurPos
+ Column
) % TotalColumn
;
753 StringCurPos
= StringLen
;
758 // Prepare to clear the current command line
760 CurrentString
[0] = 0;
763 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
764 Column
= StartColumn
;
770 // Toggle the SEnvInsertMode flag
772 ShellInfoObject
.ViewingSettings
.InsertMode
= (BOOLEAN
) !ShellInfoObject
.ViewingSettings
.InsertMode
;
777 // Print command history
779 PrintCommandHistory (TotalColumn
, TotalRow
, 4);
780 *CurrentString
= CHAR_NULL
;
791 // If we are in auto-complete mode, we are preparing to print
792 // the next file or directory name
794 if (InTabScrolling
) {
795 TabOutputStr
= AllocateZeroPool (*BufferSize
);
796 if (TabOutputStr
== NULL
) {
797 Status
= EFI_OUT_OF_RESOURCES
;
801 if (InTabScrolling
&& (TabOutputStr
!= NULL
)) {
803 // Adjust the column and row to the start of TAB-completion string.
805 Column
= (StartColumn
+ TabUpdatePos
) % TotalColumn
;
806 Row
-= (StartColumn
+ StringCurPos
) / TotalColumn
- (StartColumn
+ TabUpdatePos
) / TotalColumn
;
807 OutputLength
= StrLen (TabCurrent
->FileName
);
809 // if the output string contains blank space, quotation marks L'\"'
810 // should be added to the output.
812 if (StrStr (TabCurrent
->FileName
, L
" ") != NULL
) {
813 TabOutputStr
[0] = L
'\"';
814 CopyMem (TabOutputStr
+ 1, TabCurrent
->FileName
, OutputLength
* sizeof (CHAR16
));
815 TabOutputStr
[OutputLength
+ 1] = L
'\"';
816 TabOutputStr
[OutputLength
+ 2] = CHAR_NULL
;
818 CopyMem (TabOutputStr
, TabCurrent
->FileName
, OutputLength
* sizeof (CHAR16
));
819 TabOutputStr
[OutputLength
] = CHAR_NULL
;
822 OutputLength
= StrLen (TabOutputStr
) < MaxStr
- 1 ? StrLen (TabOutputStr
) : MaxStr
- 1;
823 CopyMem (CurrentString
+ TabUpdatePos
, TabOutputStr
, OutputLength
* sizeof (CHAR16
));
824 CurrentString
[TabUpdatePos
+ OutputLength
] = CHAR_NULL
;
825 StringCurPos
= TabUpdatePos
+ OutputLength
;
826 Update
= TabUpdatePos
;
827 if (StringLen
> TabUpdatePos
+ OutputLength
) {
828 Delete
= StringLen
- TabUpdatePos
- OutputLength
;
831 FreePool (TabOutputStr
);
835 // If we have a new position, we are preparing to print a previous or
838 if (NewPos
!= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
)) {
839 Column
= StartColumn
;
840 Row
-= (StringCurPos
+ StartColumn
) / TotalColumn
;
843 NewPos
= (BUFFER_LIST
*)(&ShellInfoObject
.ViewingSettings
.CommandHistory
);
845 OutputLength
= StrLen (LinePos
->Buffer
) < MaxStr
- 1 ? StrLen (LinePos
->Buffer
) : MaxStr
- 1;
846 CopyMem (CurrentString
, LinePos
->Buffer
, OutputLength
* sizeof (CHAR16
));
847 CurrentString
[OutputLength
] = CHAR_NULL
;
849 StringCurPos
= OutputLength
;
852 // Draw new input string
855 if (StringLen
> OutputLength
) {
857 // If old string was longer, blank its tail
859 Delete
= StringLen
- OutputLength
;
864 // If we need to update the output do so now
866 if (Update
!= (UINTN
)-1) {
867 ShellPrintEx ((INT32
)Column
, (INT32
)Row
, L
"%s%.*s", CurrentString
+ Update
, Delete
, L
"");
868 StringLen
= StrLen (CurrentString
);
871 SetMem (CurrentString
+ StringLen
, Delete
* sizeof (CHAR16
), CHAR_NULL
);
874 if (StringCurPos
> StringLen
) {
875 StringCurPos
= StringLen
;
881 // After using print to reflect newly updates, if we're not using
882 // BACKSPACE and DELETE, we need to move the cursor position forward,
883 // so adjust row and column here.
885 if ((Key
.UnicodeChar
!= CHAR_BACKSPACE
) && !((Key
.UnicodeChar
== 0) && (Key
.ScanCode
== SCAN_DELETE
))) {
887 // Calculate row and column of the tail of current string
889 TailRow
= Row
+ (StringLen
- StringCurPos
+ Column
+ OutputLength
) / TotalColumn
;
890 TailColumn
= (StringLen
- StringCurPos
+ Column
+ OutputLength
) % TotalColumn
;
893 // If the tail of string reaches screen end, screen rolls up, so if
894 // Row does not equal TailRow, Row should be decremented
896 // (if we are recalling commands using UPPER and DOWN key, and if the
897 // old command is too long to fit the screen, TailColumn must be 79.
899 if ((TailColumn
== 0) && (TailRow
>= TotalRow
) && (Row
!= TailRow
)) {
904 // Calculate the cursor position after current operation. If cursor
905 // reaches line end, update both row and column, otherwise, only
906 // column will be changed.
908 if (Column
+ OutputLength
>= TotalColumn
) {
909 SkipLength
= OutputLength
- (TotalColumn
- Column
);
911 Row
+= SkipLength
/ TotalColumn
+ 1;
912 if (Row
> TotalRow
- 1) {
916 Column
= SkipLength
% TotalColumn
;
918 Column
+= OutputLength
;
926 // Set the cursor position for this key
928 gST
->ConOut
->SetCursorPosition (gST
->ConOut
, Column
, Row
);
931 if ((CurrentString
!= NULL
) && (StrLen (CurrentString
) > 0)) {
933 // add the line to the history buffer
935 AddLineToCommandHistory (CurrentString
);
939 // Return the data to the caller
941 *BufferSize
= StringLen
* sizeof (CHAR16
);
944 // if this was used it should be deallocated by now...
945 // prevent memory leaks...
947 if (TabCompleteList
!= NULL
) {
948 ShellInfoObject
.NewEfiShellProtocol
->FreeFileList (&TabCompleteList
);
951 ASSERT (TabCompleteList
== NULL
);
957 // FILE style interfaces for StdIn/StdOut/StdErr
959 EFI_FILE_PROTOCOL FileInterfaceStdIn
= {
961 FileInterfaceOpenNotFound
,
962 FileInterfaceNopGeneric
,
963 FileInterfaceNopGeneric
,
964 FileInterfaceStdInRead
,
965 FileInterfaceStdInWrite
,
966 FileInterfaceNopGetPosition
,
967 FileInterfaceNopSetPosition
,
968 FileInterfaceNopGetInfo
,
969 FileInterfaceNopSetInfo
,
970 FileInterfaceNopGeneric
973 EFI_FILE_PROTOCOL FileInterfaceStdOut
= {
975 FileInterfaceOpenNotFound
,
976 FileInterfaceNopGeneric
,
977 FileInterfaceNopGeneric
,
978 FileInterfaceStdOutRead
,
979 FileInterfaceStdOutWrite
,
980 FileInterfaceNopGetPosition
,
981 FileInterfaceNopSetPosition
,
982 FileInterfaceNopGetInfo
,
983 FileInterfaceNopSetInfo
,
984 FileInterfaceNopGeneric
987 EFI_FILE_PROTOCOL FileInterfaceStdErr
= {
989 FileInterfaceOpenNotFound
,
990 FileInterfaceNopGeneric
,
991 FileInterfaceNopGeneric
,
992 FileInterfaceStdErrRead
,
993 FileInterfaceStdErrWrite
,
994 FileInterfaceNopGetPosition
,
995 FileInterfaceNopSetPosition
,
996 FileInterfaceNopGetInfo
,
997 FileInterfaceNopSetInfo
,
998 FileInterfaceNopGeneric
1001 EFI_FILE_PROTOCOL FileInterfaceNulFile
= {
1003 FileInterfaceOpenNotFound
,
1004 FileInterfaceNopGeneric
,
1005 FileInterfaceNopGeneric
,
1006 FileInterfaceNulRead
,
1007 FileInterfaceNulWrite
,
1008 FileInterfaceNopGetPosition
,
1009 FileInterfaceNopSetPosition
,
1010 FileInterfaceNopGetInfo
,
1011 FileInterfaceNopSetInfo
,
1012 FileInterfaceNopGeneric
1016 // This is identical to EFI_FILE_PROTOCOL except for the additional member
1023 EFI_FILE_CLOSE Close
;
1024 EFI_FILE_DELETE Delete
;
1026 EFI_FILE_WRITE Write
;
1027 EFI_FILE_GET_POSITION GetPosition
;
1028 EFI_FILE_SET_POSITION SetPosition
;
1029 EFI_FILE_GET_INFO GetInfo
;
1030 EFI_FILE_SET_INFO SetInfo
;
1031 EFI_FILE_FLUSH Flush
;
1033 } EFI_FILE_PROTOCOL_ENVIRONMENT
;
1034 // ANSI compliance helper to get size of the struct.
1035 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
1038 File style interface for Environment Variable (Close).
1040 Frees the memory for this object.
1042 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1048 FileInterfaceEnvClose (
1049 IN EFI_FILE_PROTOCOL
*This
1059 // Most if not all UEFI commands will have an '\r\n' at the end of any output.
1060 // Since the output was redirected to a variable, it does not make sense to
1061 // keep this. So, before closing, strip the trailing '\r\n' from the variable
1068 Status
= IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &Volatile
);
1069 if (EFI_ERROR (Status
)) {
1073 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1074 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1075 TotalSize
= NewSize
+ sizeof (CHAR16
);
1076 NewBuffer
= AllocateZeroPool (TotalSize
);
1077 if (NewBuffer
== NULL
) {
1078 return EFI_OUT_OF_RESOURCES
;
1081 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1084 if (!EFI_ERROR (Status
) && (NewBuffer
!= NULL
)) {
1085 if (TotalSize
/ sizeof (CHAR16
) >= 3) {
1086 if ((((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 2] == CHAR_LINEFEED
) &&
1087 (((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 3] == CHAR_CARRIAGE_RETURN
)
1090 ((CHAR16
*)NewBuffer
)[TotalSize
/ sizeof (CHAR16
) - 3] = CHAR_NULL
;
1092 // If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize.
1094 TotalSize
-= sizeof (CHAR16
) * 2;
1098 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_V (
1099 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1100 TotalSize
- sizeof (CHAR16
),
1104 if (!EFI_ERROR (Status
)) {
1105 Status
= ShellAddEnvVarToList (
1106 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1109 EFI_VARIABLE_BOOTSERVICE_ACCESS
1113 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1114 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1115 TotalSize
- sizeof (CHAR16
),
1119 if (!EFI_ERROR (Status
)) {
1120 Status
= ShellAddEnvVarToList (
1121 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1124 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1131 SHELL_FREE_NON_NULL (NewBuffer
);
1132 FreePool ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
);
1137 File style interface for Environment Variable (Delete).
1139 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1141 @retval The return value from FileInterfaceEnvClose().
1145 FileInterfaceEnvDelete (
1146 IN EFI_FILE_PROTOCOL
*This
1149 SHELL_DELETE_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1150 return (FileInterfaceEnvClose (This
));
1154 File style interface for Environment Variable (Read).
1156 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1157 @param[in, out] BufferSize Size in bytes of Buffer.
1158 @param[out] Buffer The pointer to the buffer to fill.
1160 @retval EFI_SUCCESS The data was read.
1164 FileInterfaceEnvRead (
1165 IN EFI_FILE_PROTOCOL
*This
,
1166 IN OUT UINTN
*BufferSize
,
1172 *BufferSize
= *BufferSize
/ sizeof (CHAR16
) * sizeof (CHAR16
);
1173 if (*BufferSize
!= 0) {
1175 // Make sure the first unicode character is \xFEFF
1177 *(CHAR16
*)Buffer
= gUnicodeFileTag
;
1178 Buffer
= (CHAR16
*)Buffer
+ 1;
1179 *BufferSize
-= sizeof (gUnicodeFileTag
);
1182 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (
1183 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1187 if (!EFI_ERROR (Status
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
1189 // BufferSize is valid and needs update when Status is Success or BufferTooSmall.
1191 *BufferSize
+= sizeof (gUnicodeFileTag
);
1198 File style interface for Volatile Environment Variable (Write).
1199 This function also caches the environment variable into gShellEnvVarList.
1201 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1202 @param[in, out] BufferSize Size in bytes of Buffer.
1203 @param[in] Buffer The pointer to the buffer to write.
1205 @retval EFI_SUCCESS The data was successfully write to variable.
1206 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1210 FileInterfaceEnvVolWrite (
1211 IN EFI_FILE_PROTOCOL
*This
,
1212 IN OUT UINTN
*BufferSize
,
1225 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1226 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1227 TotalSize
= NewSize
+ *BufferSize
+ sizeof (CHAR16
);
1228 } else if (Status
== EFI_NOT_FOUND
) {
1229 TotalSize
= *BufferSize
+ sizeof (CHAR16
);
1234 NewBuffer
= AllocateZeroPool (TotalSize
);
1235 if (NewBuffer
== NULL
) {
1236 return EFI_OUT_OF_RESOURCES
;
1239 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1240 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1243 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1244 FreePool (NewBuffer
);
1248 CopyMem ((UINT8
*)NewBuffer
+ NewSize
, Buffer
, *BufferSize
);
1249 Status
= ShellAddEnvVarToList (
1250 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1253 EFI_VARIABLE_BOOTSERVICE_ACCESS
1255 if (EFI_ERROR (Status
)) {
1256 FreePool (NewBuffer
);
1260 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_V (
1261 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1262 TotalSize
- sizeof (CHAR16
),
1265 if (EFI_ERROR (Status
)) {
1266 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1269 FreePool (NewBuffer
);
1274 File style interface for Non Volatile Environment Variable (Write).
1275 This function also caches the environment variable into gShellEnvVarList.
1277 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1278 @param[in, out] BufferSize Size in bytes of Buffer.
1279 @param[in] Buffer The pointer to the buffer to write.
1281 @retval EFI_SUCCESS The data was successfully write to variable.
1282 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1286 FileInterfaceEnvNonVolWrite (
1287 IN EFI_FILE_PROTOCOL
*This
,
1288 IN OUT UINTN
*BufferSize
,
1301 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1302 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1303 TotalSize
= NewSize
+ *BufferSize
+ sizeof (CHAR16
);
1304 } else if (Status
== EFI_NOT_FOUND
) {
1305 TotalSize
= *BufferSize
+ sizeof (CHAR16
);
1310 NewBuffer
= AllocateZeroPool (TotalSize
);
1311 if (NewBuffer
== NULL
) {
1312 return EFI_OUT_OF_RESOURCES
;
1315 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1316 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
, &NewSize
, NewBuffer
);
1319 if (EFI_ERROR (Status
) && (Status
!= EFI_NOT_FOUND
)) {
1320 FreePool (NewBuffer
);
1324 CopyMem ((UINT8
*)NewBuffer
+ NewSize
, Buffer
, *BufferSize
);
1325 Status
= ShellAddEnvVarToList (
1326 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1329 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1331 if (EFI_ERROR (Status
)) {
1332 FreePool (NewBuffer
);
1336 Status
= SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1337 ((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
,
1338 TotalSize
- sizeof (CHAR16
),
1341 if (EFI_ERROR (Status
)) {
1342 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT
*)This
)->Name
);
1345 FreePool (NewBuffer
);
1350 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1351 environment variables through file operations.
1353 @param EnvName The name of the Environment Variable to be operated on.
1355 @retval NULL Memory could not be allocated.
1356 @return other a pointer to an EFI_FILE_PROTOCOL structure
1359 CreateFileInterfaceEnv (
1360 IN CONST CHAR16
*EnvName
1364 EFI_FILE_PROTOCOL_ENVIRONMENT
*EnvFileInterface
;
1368 if (EnvName
== NULL
) {
1372 Status
= IsVolatileEnv (EnvName
, &Volatile
);
1373 if (EFI_ERROR (Status
)) {
1380 EnvNameSize
= StrSize (EnvName
);
1381 EnvFileInterface
= AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_ENVIRONMENT
)+EnvNameSize
);
1382 if (EnvFileInterface
== NULL
) {
1387 // Assign the generic members
1389 EnvFileInterface
->Revision
= EFI_FILE_REVISION
;
1390 EnvFileInterface
->Open
= FileInterfaceOpenNotFound
;
1391 EnvFileInterface
->Close
= FileInterfaceEnvClose
;
1392 EnvFileInterface
->GetPosition
= FileInterfaceNopGetPosition
;
1393 EnvFileInterface
->SetPosition
= FileInterfaceNopSetPosition
;
1394 EnvFileInterface
->GetInfo
= FileInterfaceNopGetInfo
;
1395 EnvFileInterface
->SetInfo
= FileInterfaceNopSetInfo
;
1396 EnvFileInterface
->Flush
= FileInterfaceNopGeneric
;
1397 EnvFileInterface
->Delete
= FileInterfaceEnvDelete
;
1398 EnvFileInterface
->Read
= FileInterfaceEnvRead
;
1400 CopyMem (EnvFileInterface
->Name
, EnvName
, EnvNameSize
);
1403 // Assign the different members for Volatile and Non-Volatile variables
1406 EnvFileInterface
->Write
= FileInterfaceEnvVolWrite
;
1408 EnvFileInterface
->Write
= FileInterfaceEnvNonVolWrite
;
1411 return ((EFI_FILE_PROTOCOL
*)EnvFileInterface
);
1415 Move the cursor position one character backward.
1417 @param[in] LineLength Length of a line. Get it by calling QueryMode
1418 @param[in, out] Column Current column of the cursor position
1419 @param[in, out] Row Current row of the cursor position
1422 MoveCursorBackward (
1423 IN UINTN LineLength
,
1424 IN OUT UINTN
*Column
,
1429 // If current column is 0, move to the last column of the previous line,
1430 // otherwise, just decrement column.
1433 *Column
= LineLength
- 1;
1445 Move the cursor position one character forward.
1447 @param[in] LineLength Length of a line.
1448 @param[in] TotalRow Total row of a screen
1449 @param[in, out] Column Current column of the cursor position
1450 @param[in, out] Row Current row of the cursor position
1454 IN UINTN LineLength
,
1456 IN OUT UINTN
*Column
,
1461 // Increment Column.
1462 // If this puts column past the end of the line, move to first column
1466 if (*Column
>= LineLength
) {
1468 if ((*Row
) < TotalRow
- 1) {
1475 Prints out each previously typed command in the command list history log.
1477 When each screen is full it will pause for a key before continuing.
1479 @param[in] TotalCols How many columns are on the screen
1480 @param[in] TotalRows How many rows are on the screen
1481 @param[in] StartColumn which column to start at
1484 PrintCommandHistory (
1485 IN CONST UINTN TotalCols
,
1486 IN CONST UINTN TotalRows
,
1487 IN CONST UINTN StartColumn
1495 ShellPrintEx (-1, -1, L
"\n");
1499 // go through history list...
1501 for ( Node
= (BUFFER_LIST
*)GetFirstNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
)
1502 ; !IsNull (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
)
1503 ; Node
= (BUFFER_LIST
*)GetNextNode (&ShellInfoObject
.ViewingSettings
.CommandHistory
.Link
, &Node
->Link
)
1507 LineCount
= ((StrLen (Node
->Buffer
) + StartColumn
+ 1) / TotalCols
) + 1;
1509 if (LineNumber
+ LineCount
>= TotalRows
) {
1510 ShellPromptForResponseHii (
1511 ShellPromptResponseTypeEnterContinue
,
1512 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT
),
1513 ShellInfoObject
.HiiHandle
,
1519 ShellPrintEx (-1, -1, L
"%2d. %s\n", Index
, Node
->Buffer
);
1520 LineNumber
+= LineCount
;
1525 // This is identical to EFI_FILE_PROTOCOL except for the additional members
1526 // for the buffer, size, and position.
1532 EFI_FILE_CLOSE Close
;
1533 EFI_FILE_DELETE Delete
;
1535 EFI_FILE_WRITE Write
;
1536 EFI_FILE_GET_POSITION GetPosition
;
1537 EFI_FILE_SET_POSITION SetPosition
;
1538 EFI_FILE_GET_INFO GetInfo
;
1539 EFI_FILE_SET_INFO SetInfo
;
1540 EFI_FILE_FLUSH Flush
;
1546 } EFI_FILE_PROTOCOL_MEM
;
1549 File style interface for Mem (SetPosition).
1551 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1552 @param[out] Position The position to set.
1554 @retval EFI_SUCCESS The position was successfully changed.
1555 @retval EFI_INVALID_PARAMETER The Position was invalid.
1559 FileInterfaceMemSetPosition (
1560 IN EFI_FILE_PROTOCOL
*This
,
1564 if (Position
<= ((EFI_FILE_PROTOCOL_MEM
*)This
)->FileSize
) {
1565 ((EFI_FILE_PROTOCOL_MEM
*)This
)->Position
= Position
;
1566 return (EFI_SUCCESS
);
1568 return (EFI_INVALID_PARAMETER
);
1573 File style interface for Mem (GetPosition).
1575 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1576 @param[out] Position The pointer to the position.
1578 @retval EFI_SUCCESS The position was retrieved.
1582 FileInterfaceMemGetPosition (
1583 IN EFI_FILE_PROTOCOL
*This
,
1584 OUT UINT64
*Position
1587 *Position
= ((EFI_FILE_PROTOCOL_MEM
*)This
)->Position
;
1588 return (EFI_SUCCESS
);
1592 File style interface for Mem (GetInfo).
1594 @param This Protocol instance pointer.
1595 @param InformationType Type of information to return in Buffer.
1596 @param BufferSize On input size of buffer, on output amount of data in buffer.
1597 @param Buffer The buffer to return data.
1599 @retval EFI_SUCCESS Data was returned.
1600 @retval EFI_UNSUPPORT InformationType is not supported.
1601 @retval EFI_NO_MEDIA The device has no media.
1602 @retval EFI_DEVICE_ERROR The device reported an error.
1603 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1604 @retval EFI_WRITE_PROTECTED The device is write protected.
1605 @retval EFI_ACCESS_DENIED The file was open for read only.
1606 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1611 FileInterfaceMemGetInfo (
1612 IN EFI_FILE_PROTOCOL
*This
,
1613 IN EFI_GUID
*InformationType
,
1614 IN OUT UINTN
*BufferSize
,
1618 EFI_FILE_INFO
*FileInfo
;
1620 if (CompareGuid (InformationType
, &gEfiFileInfoGuid
)) {
1621 if (*BufferSize
< sizeof (EFI_FILE_INFO
)) {
1622 *BufferSize
= sizeof (EFI_FILE_INFO
);
1623 return EFI_BUFFER_TOO_SMALL
;
1626 if (Buffer
== NULL
) {
1627 return EFI_INVALID_PARAMETER
;
1630 FileInfo
= (EFI_FILE_INFO
*)Buffer
;
1631 FileInfo
->Size
= sizeof (*FileInfo
);
1632 ZeroMem (FileInfo
, sizeof (*FileInfo
));
1633 FileInfo
->FileSize
= ((EFI_FILE_PROTOCOL_MEM
*)This
)->FileSize
;
1634 FileInfo
->PhysicalSize
= FileInfo
->FileSize
;
1638 return EFI_UNSUPPORTED
;
1642 File style interface for Mem (Write).
1644 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1645 @param[in, out] BufferSize Size in bytes of Buffer.
1646 @param[in] Buffer The pointer to the buffer to write.
1648 @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
1649 @retval EFI_SUCCESS The data was written.
1653 FileInterfaceMemWrite (
1654 IN EFI_FILE_PROTOCOL
*This
,
1655 IN OUT UINTN
*BufferSize
,
1660 EFI_FILE_PROTOCOL_MEM
*MemFile
;
1662 MemFile
= (EFI_FILE_PROTOCOL_MEM
*)This
;
1663 if (MemFile
->Unicode
) {
1667 if ((UINTN
)(MemFile
->Position
+ (*BufferSize
)) > (UINTN
)(MemFile
->BufferSize
)) {
1668 MemFile
->Buffer
= ReallocatePool ((UINTN
)(MemFile
->BufferSize
), (UINTN
)(MemFile
->BufferSize
) + (*BufferSize
) + MEM_WRITE_REALLOC_OVERHEAD
, MemFile
->Buffer
);
1669 if (MemFile
->Buffer
== NULL
) {
1670 return EFI_OUT_OF_RESOURCES
;
1673 MemFile
->BufferSize
+= (*BufferSize
) + MEM_WRITE_REALLOC_OVERHEAD
;
1676 CopyMem (((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, Buffer
, *BufferSize
);
1677 MemFile
->Position
+= (*BufferSize
);
1678 MemFile
->FileSize
= MemFile
->Position
;
1679 return (EFI_SUCCESS
);
1684 AsciiBuffer
= AllocateZeroPool (*BufferSize
);
1685 if (AsciiBuffer
== NULL
) {
1686 return (EFI_OUT_OF_RESOURCES
);
1689 AsciiSPrint (AsciiBuffer
, *BufferSize
, "%S", Buffer
);
1690 if ((UINTN
)(MemFile
->Position
+ AsciiStrSize (AsciiBuffer
)) > (UINTN
)(MemFile
->BufferSize
)) {
1691 MemFile
->Buffer
= ReallocatePool ((UINTN
)(MemFile
->BufferSize
), (UINTN
)(MemFile
->BufferSize
) + AsciiStrSize (AsciiBuffer
) + MEM_WRITE_REALLOC_OVERHEAD
, MemFile
->Buffer
);
1692 if (MemFile
->Buffer
== NULL
) {
1693 FreePool (AsciiBuffer
);
1694 return EFI_OUT_OF_RESOURCES
;
1697 MemFile
->BufferSize
+= AsciiStrSize (AsciiBuffer
) + MEM_WRITE_REALLOC_OVERHEAD
;
1700 CopyMem (((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, AsciiBuffer
, AsciiStrSize (AsciiBuffer
));
1701 MemFile
->Position
+= (*BufferSize
/ sizeof (CHAR16
));
1702 MemFile
->FileSize
= MemFile
->Position
;
1703 FreePool (AsciiBuffer
);
1704 return (EFI_SUCCESS
);
1709 File style interface for Mem (Read).
1711 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1712 @param[in, out] BufferSize Size in bytes of Buffer.
1713 @param[in] Buffer The pointer to the buffer to fill.
1715 @retval EFI_SUCCESS The data was read.
1719 FileInterfaceMemRead (
1720 IN EFI_FILE_PROTOCOL
*This
,
1721 IN OUT UINTN
*BufferSize
,
1725 EFI_FILE_PROTOCOL_MEM
*MemFile
;
1727 MemFile
= (EFI_FILE_PROTOCOL_MEM
*)This
;
1728 if (*BufferSize
> (UINTN
)((MemFile
->FileSize
) - (UINTN
)(MemFile
->Position
))) {
1729 (*BufferSize
) = (UINTN
)((MemFile
->FileSize
) - (UINTN
)(MemFile
->Position
));
1732 CopyMem (Buffer
, ((UINT8
*)MemFile
->Buffer
) + MemFile
->Position
, (*BufferSize
));
1733 MemFile
->Position
= MemFile
->Position
+ (*BufferSize
);
1734 return (EFI_SUCCESS
);
1738 File style interface for Mem (Close).
1740 Frees all memory associated with this object.
1742 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1744 @retval EFI_SUCCESS The 'file' was closed.
1748 FileInterfaceMemClose (
1749 IN EFI_FILE_PROTOCOL
*This
1752 SHELL_FREE_NON_NULL (((EFI_FILE_PROTOCOL_MEM
*)This
)->Buffer
);
1753 SHELL_FREE_NON_NULL (This
);
1754 return (EFI_SUCCESS
);
1758 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1759 a file entirely in memory through file operations.
1761 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1763 @retval NULL Memory could not be allocated.
1764 @return other A pointer to an EFI_FILE_PROTOCOL structure.
1767 CreateFileInterfaceMem (
1768 IN CONST BOOLEAN Unicode
1771 EFI_FILE_PROTOCOL_MEM
*FileInterface
;
1776 FileInterface
= AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_MEM
));
1777 if (FileInterface
== NULL
) {
1782 // Assign the generic members
1784 FileInterface
->Revision
= EFI_FILE_REVISION
;
1785 FileInterface
->Open
= FileInterfaceOpenNotFound
;
1786 FileInterface
->Close
= FileInterfaceMemClose
;
1787 FileInterface
->GetPosition
= FileInterfaceMemGetPosition
;
1788 FileInterface
->SetPosition
= FileInterfaceMemSetPosition
;
1789 FileInterface
->GetInfo
= FileInterfaceMemGetInfo
;
1790 FileInterface
->SetInfo
= FileInterfaceNopSetInfo
;
1791 FileInterface
->Flush
= FileInterfaceNopGeneric
;
1792 FileInterface
->Delete
= FileInterfaceNopGeneric
;
1793 FileInterface
->Read
= FileInterfaceMemRead
;
1794 FileInterface
->Write
= FileInterfaceMemWrite
;
1795 FileInterface
->Unicode
= Unicode
;
1797 ASSERT (FileInterface
->Buffer
== NULL
);
1798 ASSERT (FileInterface
->BufferSize
== 0);
1799 ASSERT (FileInterface
->Position
== 0);
1802 FileInterface
->Buffer
= AllocateZeroPool (sizeof (gUnicodeFileTag
));
1803 if (FileInterface
->Buffer
== NULL
) {
1804 FreePool (FileInterface
);
1808 *((CHAR16
*)(FileInterface
->Buffer
)) = EFI_UNICODE_BYTE_ORDER_MARK
;
1809 FileInterface
->BufferSize
= 2;
1810 FileInterface
->Position
= 2;
1813 return ((EFI_FILE_PROTOCOL
*)FileInterface
);
1819 EFI_FILE_CLOSE Close
;
1820 EFI_FILE_DELETE Delete
;
1822 EFI_FILE_WRITE Write
;
1823 EFI_FILE_GET_POSITION GetPosition
;
1824 EFI_FILE_SET_POSITION SetPosition
;
1825 EFI_FILE_GET_INFO GetInfo
;
1826 EFI_FILE_SET_INFO SetInfo
;
1827 EFI_FILE_FLUSH Flush
;
1829 EFI_FILE_PROTOCOL
*Orig
;
1830 } EFI_FILE_PROTOCOL_FILE
;
1833 Set a files current position
1835 @param This Protocol instance pointer.
1836 @param Position Byte position from the start of the file.
1838 @retval EFI_SUCCESS Data was written.
1839 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
1844 FileInterfaceFileSetPosition (
1845 IN EFI_FILE_PROTOCOL
*This
,
1849 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->SetPosition (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, Position
);
1853 Get a file's current position
1855 @param This Protocol instance pointer.
1856 @param Position Byte position from the start of the file.
1858 @retval EFI_SUCCESS Data was written.
1859 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
1864 FileInterfaceFileGetPosition (
1865 IN EFI_FILE_PROTOCOL
*This
,
1866 OUT UINT64
*Position
1869 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetPosition (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, Position
);
1873 Get information about a file.
1875 @param This Protocol instance pointer.
1876 @param InformationType Type of information to return in Buffer.
1877 @param BufferSize On input size of buffer, on output amount of data in buffer.
1878 @param Buffer The buffer to return data.
1880 @retval EFI_SUCCESS Data was returned.
1881 @retval EFI_UNSUPPORT InformationType is not supported.
1882 @retval EFI_NO_MEDIA The device has no media.
1883 @retval EFI_DEVICE_ERROR The device reported an error.
1884 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1885 @retval EFI_WRITE_PROTECTED The device is write protected.
1886 @retval EFI_ACCESS_DENIED The file was open for read only.
1887 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1892 FileInterfaceFileGetInfo (
1893 IN EFI_FILE_PROTOCOL
*This
,
1894 IN EFI_GUID
*InformationType
,
1895 IN OUT UINTN
*BufferSize
,
1899 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetInfo (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, InformationType
, BufferSize
, Buffer
);
1903 Set information about a file
1905 @param This Protocol instance pointer.
1906 @param InformationType Type of information in Buffer.
1907 @param BufferSize Size of buffer.
1908 @param Buffer The data to write.
1910 @retval EFI_SUCCESS Data was returned.
1911 @retval EFI_UNSUPPORT InformationType is not supported.
1912 @retval EFI_NO_MEDIA The device has no media.
1913 @retval EFI_DEVICE_ERROR The device reported an error.
1914 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1915 @retval EFI_WRITE_PROTECTED The device is write protected.
1916 @retval EFI_ACCESS_DENIED The file was open for read only.
1921 FileInterfaceFileSetInfo (
1922 IN EFI_FILE_PROTOCOL
*This
,
1923 IN EFI_GUID
*InformationType
,
1924 IN UINTN BufferSize
,
1928 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->SetInfo (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, InformationType
, BufferSize
, Buffer
);
1932 Flush data back for the file handle.
1934 @param This Protocol instance pointer.
1936 @retval EFI_SUCCESS Data was written.
1937 @retval EFI_UNSUPPORT Writes to Open directory are not supported.
1938 @retval EFI_NO_MEDIA The device has no media.
1939 @retval EFI_DEVICE_ERROR The device reported an error.
1940 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1941 @retval EFI_WRITE_PROTECTED The device is write protected.
1942 @retval EFI_ACCESS_DENIED The file was open for read only.
1943 @retval EFI_VOLUME_FULL The volume is full.
1948 FileInterfaceFileFlush (
1949 IN EFI_FILE_PROTOCOL
*This
1952 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Flush (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
1956 Read data from the file.
1958 @param This Protocol instance pointer.
1959 @param BufferSize On input size of buffer, on output amount of data in buffer.
1960 @param Buffer The buffer in which data is read.
1962 @retval EFI_SUCCESS Data was read.
1963 @retval EFI_NO_MEDIA The device has no media.
1964 @retval EFI_DEVICE_ERROR The device reported an error.
1965 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1966 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size.
1971 FileInterfaceFileRead (
1972 IN EFI_FILE_PROTOCOL
*This
,
1973 IN OUT UINTN
*BufferSize
,
1979 CHAR8
*AsciiStrBuffer
;
1980 CHAR16
*UscStrBuffer
;
1983 if (((EFI_FILE_PROTOCOL_FILE
*)This
)->Unicode
) {
1986 // There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF.
1987 // So we choose to leave the file content as is.
1989 return (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Read (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, BufferSize
, Buffer
));
1994 *BufferSize
= *BufferSize
/ sizeof (CHAR16
) * sizeof (CHAR16
);
1995 if (*BufferSize
== 0) {
1999 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->GetPosition (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Position
);
2000 if (EFI_ERROR (Status
)) {
2004 if (Position
== 0) {
2006 // First two bytes in Buffer is for the Unicode file tag.
2008 *(CHAR16
*)Buffer
= gUnicodeFileTag
;
2009 Buffer
= (CHAR16
*)Buffer
+ 1;
2010 Size
= *BufferSize
/ sizeof (CHAR16
) - 1;
2012 Size
= *BufferSize
/ sizeof (CHAR16
);
2015 AsciiStrBuffer
= AllocateZeroPool (Size
+ 1);
2016 if (AsciiStrBuffer
== NULL
) {
2017 return EFI_OUT_OF_RESOURCES
;
2020 UscStrBuffer
= AllocateZeroPool ((Size
+ 1) * sizeof (CHAR16
));
2021 if (UscStrBuffer
== NULL
) {
2022 SHELL_FREE_NON_NULL (AsciiStrBuffer
);
2023 return EFI_OUT_OF_RESOURCES
;
2026 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Read (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Size
, AsciiStrBuffer
);
2027 if (!EFI_ERROR (Status
)) {
2028 AsciiStrToUnicodeStrS (AsciiStrBuffer
, UscStrBuffer
, Size
+ 1);
2029 *BufferSize
= Size
* sizeof (CHAR16
);
2030 CopyMem (Buffer
, UscStrBuffer
, *BufferSize
);
2033 SHELL_FREE_NON_NULL (AsciiStrBuffer
);
2034 SHELL_FREE_NON_NULL (UscStrBuffer
);
2040 Opens a new file relative to the source file's location.
2042 @param[in] This The protocol instance pointer.
2043 @param[out] NewHandle Returns File Handle for FileName.
2044 @param[in] FileName Null terminated string. "\", ".", and ".." are supported.
2045 @param[in] OpenMode Open mode for file.
2046 @param[in] Attributes Only used for EFI_FILE_MODE_CREATE.
2048 @retval EFI_SUCCESS The device was opened.
2049 @retval EFI_NOT_FOUND The specified file could not be found on the device.
2050 @retval EFI_NO_MEDIA The device has no media.
2051 @retval EFI_MEDIA_CHANGED The media has changed.
2052 @retval EFI_DEVICE_ERROR The device reported an error.
2053 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2054 @retval EFI_ACCESS_DENIED The service denied access to the file.
2055 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
2056 @retval EFI_VOLUME_FULL The volume is full.
2060 FileInterfaceFileOpen (
2061 IN EFI_FILE_PROTOCOL
*This
,
2062 OUT EFI_FILE_PROTOCOL
**NewHandle
,
2063 IN CHAR16
*FileName
,
2065 IN UINT64 Attributes
2068 return ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Open (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, NewHandle
, FileName
, OpenMode
, Attributes
);
2072 Close and delete the file handle.
2074 @param This Protocol instance pointer.
2076 @retval EFI_SUCCESS The device was opened.
2077 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
2082 FileInterfaceFileDelete (
2083 IN EFI_FILE_PROTOCOL
*This
2088 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Delete (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
2094 File style interface for File (Close).
2096 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
2098 @retval EFI_SUCCESS The file was closed.
2102 FileInterfaceFileClose (
2103 IN EFI_FILE_PROTOCOL
*This
2108 Status
= ((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Close (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
);
2114 File style interface for File (Write).
2116 If the file was opened with ASCII mode the data will be processed through
2117 AsciiSPrint before writing.
2119 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
2120 @param[in, out] BufferSize Size in bytes of Buffer.
2121 @param[in] Buffer The pointer to the buffer to write.
2123 @retval EFI_SUCCESS The data was written.
2127 FileInterfaceFileWrite (
2128 IN EFI_FILE_PROTOCOL
*This
,
2129 IN OUT UINTN
*BufferSize
,
2137 if (((EFI_FILE_PROTOCOL_FILE
*)This
)->Unicode
) {
2141 return (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Write (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, BufferSize
, Buffer
));
2146 AsciiBuffer
= AllocateZeroPool (*BufferSize
);
2147 AsciiSPrint (AsciiBuffer
, *BufferSize
, "%S", Buffer
);
2148 Size
= AsciiStrSize (AsciiBuffer
) - 1; // (we dont need the null terminator)
2149 Status
= (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
->Write (((EFI_FILE_PROTOCOL_FILE
*)This
)->Orig
, &Size
, AsciiBuffer
));
2150 FreePool (AsciiBuffer
);
2156 Create a file interface with unicode information.
2158 This will create a new EFI_FILE_PROTOCOL identical to the Templace
2159 except that the new one has Unicode and Ascii knowledge.
2161 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.
2162 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.
2164 @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
2167 CreateFileInterfaceFile (
2168 IN CONST EFI_FILE_PROTOCOL
*Template
,
2169 IN CONST BOOLEAN Unicode
2172 EFI_FILE_PROTOCOL_FILE
*NewOne
;
2174 NewOne
= AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_FILE
));
2175 if (NewOne
== NULL
) {
2179 CopyMem (NewOne
, Template
, sizeof (EFI_FILE_PROTOCOL_FILE
));
2180 NewOne
->Orig
= (EFI_FILE_PROTOCOL
*)Template
;
2181 NewOne
->Unicode
= Unicode
;
2182 NewOne
->Open
= FileInterfaceFileOpen
;
2183 NewOne
->Close
= FileInterfaceFileClose
;
2184 NewOne
->Delete
= FileInterfaceFileDelete
;
2185 NewOne
->Read
= FileInterfaceFileRead
;
2186 NewOne
->Write
= FileInterfaceFileWrite
;
2187 NewOne
->GetPosition
= FileInterfaceFileGetPosition
;
2188 NewOne
->SetPosition
= FileInterfaceFileSetPosition
;
2189 NewOne
->GetInfo
= FileInterfaceFileGetInfo
;
2190 NewOne
->SetInfo
= FileInterfaceFileSetInfo
;
2191 NewOne
->Flush
= FileInterfaceFileFlush
;
2193 return ((EFI_FILE_PROTOCOL
*)NewOne
);