]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/FileHandleWrappers.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Application / Shell / FileHandleWrappers.c
1 /** @file
2 EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
3 StdIn, StdOut, StdErr, etc...).
4
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
9
10 **/
11
12 #include "Shell.h"
13 #include "FileHandleInternal.h"
14
15 #define MEM_WRITE_REALLOC_OVERHEAD 1024
16
17 /**
18 File style interface for console (Open).
19
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.
25
26 @retval EFI_NOT_FOUND
27 **/
28 EFI_STATUS
29 EFIAPI
30 FileInterfaceOpenNotFound (
31 IN EFI_FILE_PROTOCOL *This,
32 OUT EFI_FILE_PROTOCOL **NewHandle,
33 IN CHAR16 *FileName,
34 IN UINT64 OpenMode,
35 IN UINT64 Attributes
36 )
37 {
38 return (EFI_NOT_FOUND);
39 }
40
41 /**
42 File style interface for console (Close, Delete, & Flush)
43
44 @param[in] This Ignored.
45
46 @retval EFI_SUCCESS
47 **/
48 EFI_STATUS
49 EFIAPI
50 FileInterfaceNopGeneric (
51 IN EFI_FILE_PROTOCOL *This
52 )
53 {
54 return (EFI_SUCCESS);
55 }
56
57 /**
58 File style interface for console (GetPosition).
59
60 @param[in] This Ignored.
61 @param[out] Position Ignored.
62
63 @retval EFI_UNSUPPORTED
64 **/
65 EFI_STATUS
66 EFIAPI
67 FileInterfaceNopGetPosition (
68 IN EFI_FILE_PROTOCOL *This,
69 OUT UINT64 *Position
70 )
71 {
72 return (EFI_UNSUPPORTED);
73 }
74
75 /**
76 File style interface for console (SetPosition).
77
78 @param[in] This Ignored.
79 @param[in] Position Ignored.
80
81 @retval EFI_UNSUPPORTED
82 **/
83 EFI_STATUS
84 EFIAPI
85 FileInterfaceNopSetPosition (
86 IN EFI_FILE_PROTOCOL *This,
87 IN UINT64 Position
88 )
89 {
90 return (EFI_UNSUPPORTED);
91 }
92
93 /**
94 File style interface for console (GetInfo).
95
96 @param[in] This Ignored.
97 @param[in] InformationType Ignored.
98 @param[in, out] BufferSize Ignored.
99 @param[out] Buffer Ignored.
100
101 @retval EFI_UNSUPPORTED
102 **/
103 EFI_STATUS
104 EFIAPI
105 FileInterfaceNopGetInfo (
106 IN EFI_FILE_PROTOCOL *This,
107 IN EFI_GUID *InformationType,
108 IN OUT UINTN *BufferSize,
109 OUT VOID *Buffer
110 )
111 {
112 return (EFI_UNSUPPORTED);
113 }
114
115 /**
116 File style interface for console (SetInfo).
117
118 @param[in] This Ignored.
119 @param[in] InformationType Ignored.
120 @param[in] BufferSize Ignored.
121 @param[in] Buffer Ignored.
122
123 @retval EFI_UNSUPPORTED
124 **/
125 EFI_STATUS
126 EFIAPI
127 FileInterfaceNopSetInfo (
128 IN EFI_FILE_PROTOCOL *This,
129 IN EFI_GUID *InformationType,
130 IN UINTN BufferSize,
131 IN VOID *Buffer
132 )
133 {
134 return (EFI_UNSUPPORTED);
135 }
136
137 /**
138 File style interface for StdOut (Write).
139
140 Writes data to the screen.
141
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.
145
146 @retval EFI_UNSUPPORTED No output console is supported.
147 @return A return value from gST->ConOut->OutputString.
148 **/
149 EFI_STATUS
150 EFIAPI
151 FileInterfaceStdOutWrite (
152 IN EFI_FILE_PROTOCOL *This,
153 IN OUT UINTN *BufferSize,
154 IN VOID *Buffer
155 )
156 {
157 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
158 return (EFI_UNSUPPORTED);
159 }
160
161 if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {
162 return (gST->ConOut->OutputString (gST->ConOut, (CHAR16 *)Buffer + 1));
163 }
164
165 return (gST->ConOut->OutputString (gST->ConOut, Buffer));
166 }
167
168 /**
169 File style interface for StdIn (Write).
170
171 @param[in] This Ignored.
172 @param[in, out] BufferSize Ignored.
173 @param[in] Buffer Ignored.
174
175 @retval EFI_UNSUPPORTED
176 **/
177 EFI_STATUS
178 EFIAPI
179 FileInterfaceStdInWrite (
180 IN EFI_FILE_PROTOCOL *This,
181 IN OUT UINTN *BufferSize,
182 IN VOID *Buffer
183 )
184 {
185 return (EFI_UNSUPPORTED);
186 }
187
188 /**
189 File style interface for console StdErr (Write).
190
191 Writes error to the error output.
192
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.
196
197 @return A return value from gST->StdErr->OutputString.
198 **/
199 EFI_STATUS
200 EFIAPI
201 FileInterfaceStdErrWrite (
202 IN EFI_FILE_PROTOCOL *This,
203 IN OUT UINTN *BufferSize,
204 IN VOID *Buffer
205 )
206 {
207 return (gST->StdErr->OutputString (gST->StdErr, Buffer));
208 }
209
210 /**
211 File style interface for console StdOut (Read).
212
213 @param[in] This Ignored.
214 @param[in, out] BufferSize Ignored.
215 @param[out] Buffer Ignored.
216
217 @retval EFI_UNSUPPORTED
218 **/
219 EFI_STATUS
220 EFIAPI
221 FileInterfaceStdOutRead (
222 IN EFI_FILE_PROTOCOL *This,
223 IN OUT UINTN *BufferSize,
224 OUT VOID *Buffer
225 )
226 {
227 return (EFI_UNSUPPORTED);
228 }
229
230 /**
231 File style interface for console StdErr (Read).
232
233 @param[in] This Ignored.
234 @param[in, out] BufferSize Ignored.
235 @param[out] Buffer Ignored.
236
237 @retval EFI_UNSUPPORTED Always.
238 **/
239 EFI_STATUS
240 EFIAPI
241 FileInterfaceStdErrRead (
242 IN EFI_FILE_PROTOCOL *This,
243 IN OUT UINTN *BufferSize,
244 OUT VOID *Buffer
245 )
246 {
247 return (EFI_UNSUPPORTED);
248 }
249
250 /**
251 File style interface for NUL file (Read).
252
253 @param[in] This Ignored.
254 @param[in, out] BufferSize Poiner to 0 upon return.
255 @param[out] Buffer Ignored.
256
257 @retval EFI_SUCCESS Always.
258 **/
259 EFI_STATUS
260 EFIAPI
261 FileInterfaceNulRead (
262 IN EFI_FILE_PROTOCOL *This,
263 IN OUT UINTN *BufferSize,
264 OUT VOID *Buffer
265 )
266 {
267 *BufferSize = 0;
268 return (EFI_SUCCESS);
269 }
270
271 /**
272 File style interface for NUL file (Write).
273
274 @param[in] This Ignored.
275 @param[in, out] BufferSize Ignored.
276 @param[in] Buffer Ignored.
277
278 @retval EFI_SUCCESS
279 **/
280 EFI_STATUS
281 EFIAPI
282 FileInterfaceNulWrite (
283 IN EFI_FILE_PROTOCOL *This,
284 IN OUT UINTN *BufferSize,
285 IN VOID *Buffer
286 )
287 {
288 return (EFI_SUCCESS);
289 }
290
291 /**
292 Create the TAB completion list.
293
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.
299 **/
300 EFI_STATUS
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
307 )
308 {
309 BOOLEAN InQuotation;
310 UINTN TabPos;
311 UINTN Index;
312 CONST CHAR16 *Cwd;
313 EFI_STATUS Status;
314 CHAR16 *TabStr;
315 EFI_SHELL_FILE_INFO *FileList;
316 EFI_SHELL_FILE_INFO *FileInfo;
317 EFI_SHELL_FILE_INFO *TempFileInfo;
318
319 //
320 // Allocate buffers
321 //
322 TabStr = AllocateZeroPool (BufferSize);
323 if (TabStr == NULL) {
324 return EFI_OUT_OF_RESOURCES;
325 }
326
327 //
328 // handle auto complete of file and directory names...
329 // E.g.: cd fs0:\EFI\Bo<TAB>
330 // ^ ^
331 // TabPos TabUpdatePos
332 //
333 TabPos = 0;
334 *TabUpdatePos = 0;
335 FileList = NULL;
336 InQuotation = FALSE;
337 for (Index = 0; Index < StringLen; Index++) {
338 switch (InputString[Index]) {
339 case L'\"':
340 InQuotation = (BOOLEAN)(!InQuotation);
341 break;
342
343 case L' ':
344 if (!InQuotation) {
345 TabPos = Index + 1;
346 *TabUpdatePos = TabPos;
347 }
348
349 break;
350
351 case L':':
352 //
353 // handle the case "fs0:<TAB>"
354 // Update the TabUpdatePos as well.
355 //
356 case L'\\':
357 *TabUpdatePos = Index + 1;
358 break;
359
360 default:
361 break;
362 }
363 }
364
365 if (StrStr (InputString + TabPos, L":") == NULL) {
366 //
367 // If file path doesn't contain ":", ...
368 //
369 Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);
370 if (Cwd != NULL) {
371 if (InputString[TabPos] != L'\\') {
372 //
373 // and it doesn't begin with "\\", it's a path relative to current directory.
374 // TabStr = "<cwd>\\"
375 //
376 StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);
377 StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");
378 } else {
379 //
380 // and it begins with "\\", it's a path pointing to root directory of current map.
381 // TabStr = "fsx:"
382 //
383 Index = StrStr (Cwd, L":") - Cwd + 1;
384 StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);
385 }
386 }
387 }
388
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);
392
393 //
394 // Filter out the non-directory for "CD" command
395 // Filter "." and ".." for all
396 //
397 if (!EFI_ERROR (Status) && (FileList != NULL)) {
398 //
399 // Skip the spaces in the beginning
400 //
401 while (*InputString == L' ') {
402 InputString++;
403 }
404
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)))
409 {
410 TempFileInfo = FileInfo;
411 FileInfo = (EFI_SHELL_FILE_INFO *)RemoveEntryList (&FileInfo->Link);
412 InternalFreeShellFileInfoNode (TempFileInfo);
413 } else {
414 FileInfo = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &FileInfo->Link);
415 }
416 }
417 }
418
419 if ((FileList != NULL) && !IsListEmpty (&FileList->Link)) {
420 Status = EFI_SUCCESS;
421 } else {
422 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);
423 Status = EFI_NOT_FOUND;
424 }
425
426 FreePool (TabStr);
427
428 *TabCompletionList = FileList;
429 return Status;
430 }
431
432 /**
433 File style interface for console (Read).
434
435 This will return a single line of input from the console.
436
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
441 measured in bytes.
442 @param Buffer The buffer into which the data is read.
443
444
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.
455 **/
456 EFI_STATUS
457 EFIAPI
458 FileInterfaceStdInRead (
459 IN EFI_FILE_PROTOCOL *This,
460 IN OUT UINTN *BufferSize,
461 OUT VOID *Buffer
462 )
463 {
464 CHAR16 *CurrentString;
465 BOOLEAN Done;
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
477 UINTN SkipLength;
478 UINTN OutputLength; // Length of the update string
479 UINTN TailRow; // Row of end of line
480 UINTN TailColumn; // Column of end of line
481 EFI_INPUT_KEY Key;
482
483 BUFFER_LIST *LinePos;
484 BUFFER_LIST *NewPos;
485 BOOLEAN InScrolling;
486 EFI_STATUS Status;
487 BOOLEAN InTabScrolling; // Whether in TAB-completion state
488 EFI_SHELL_FILE_INFO *TabCompleteList;
489 EFI_SHELL_FILE_INFO *TabCurrent;
490 UINTN EventIndex;
491 CHAR16 *TabOutputStr;
492
493 //
494 // If buffer is not large enough to hold a CHAR16, return minimum buffer size
495 //
496 if (*BufferSize < sizeof (CHAR16) * 2) {
497 *BufferSize = sizeof (CHAR16) * 2;
498 return (EFI_BUFFER_TOO_SMALL);
499 }
500
501 Done = FALSE;
502 CurrentString = Buffer;
503 StringLen = 0;
504 StringCurPos = 0;
505 OutputLength = 0;
506 Update = 0;
507 Delete = 0;
508 LinePos = NewPos = (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory);
509 InScrolling = FALSE;
510 InTabScrolling = FALSE;
511 Status = EFI_SUCCESS;
512 TabOutputStr = NULL;
513 TabUpdatePos = 0;
514 TabCompleteList = NULL;
515 TabCurrent = NULL;
516
517 //
518 // Get the screen setting and the current cursor location
519 //
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);
523
524 //
525 // Limit the line length to the buffer size or the minimum size of the
526 // screen. (The smaller takes effect)
527 //
528 MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;
529 if (MaxStr > *BufferSize / sizeof (CHAR16)) {
530 MaxStr = *BufferSize / sizeof (CHAR16);
531 }
532
533 ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
534 do {
535 //
536 // Read a key
537 //
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) {
542 continue;
543 }
544
545 ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
546 StringLen = 0;
547 break;
548 }
549
550 //
551 // Press PageUp or PageDown to scroll the history screen up or down.
552 // Press any other key to quit scrolling.
553 //
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);
559 }
560
561 InScrolling = TRUE;
562 } else {
563 if (InScrolling) {
564 ConsoleLoggerStopHistory (ShellInfoObject.ConsoleInfo);
565 InScrolling = FALSE;
566 }
567 }
568
569 //
570 // If we are quitting TAB scrolling...
571 //
572 if (InTabScrolling && (Key.UnicodeChar != CHAR_TAB)) {
573 if (TabCompleteList != NULL) {
574 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
575 DEBUG_CODE (
576 TabCompleteList = NULL;
577 );
578 }
579
580 InTabScrolling = FALSE;
581 }
582
583 switch (Key.UnicodeChar) {
584 case CHAR_CARRIAGE_RETURN:
585 //
586 // All done, print a newline at the end of the string
587 //
588 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
589 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
590 ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");
591 Done = TRUE;
592 break;
593
594 case CHAR_BACKSPACE:
595 if (StringCurPos != 0) {
596 //
597 // If not move back beyond string beginning, move all characters behind
598 // the current position one character forward
599 //
600 StringCurPos--;
601 Update = StringCurPos;
602 Delete = 1;
603 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
604
605 //
606 // Adjust the current column and row
607 //
608 MoveCursorBackward (TotalColumn, &Column, &Row);
609 }
610
611 break;
612
613 case CHAR_TAB:
614 if (!InTabScrolling) {
615 TabCurrent = NULL;
616 //
617 // Initialize a tab complete operation.
618 //
619 Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);
620 if (!EFI_ERROR (Status)) {
621 InTabScrolling = TRUE;
622 }
623
624 //
625 // We do not set up the replacement.
626 // The next section will do that.
627 //
628 }
629
630 if (InTabScrolling) {
631 //
632 // We are in a tab complete operation.
633 // set up the next replacement.
634 //
635 ASSERT (TabCompleteList != NULL);
636 if (TabCurrent == NULL) {
637 TabCurrent = (EFI_SHELL_FILE_INFO *)GetFirstNode (&TabCompleteList->Link);
638 } else {
639 TabCurrent = (EFI_SHELL_FILE_INFO *)GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
640 }
641
642 //
643 // Skip over the empty list beginning node
644 //
645 if (IsNull (&TabCompleteList->Link, &TabCurrent->Link)) {
646 TabCurrent = (EFI_SHELL_FILE_INFO *)GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
647 }
648 }
649
650 break;
651
652 default:
653 if (Key.UnicodeChar >= ' ') {
654 //
655 // If we are at the buffer's end, drop the key
656 //
657 if ((StringLen == MaxStr - 1) && (ShellInfoObject.ViewingSettings.InsertMode || (StringCurPos == StringLen))) {
658 break;
659 }
660
661 //
662 // If in insert mode, make space by moving each other character 1
663 // space higher in the array
664 //
665 if (ShellInfoObject.ViewingSettings.InsertMode) {
666 CopyMem (CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof (CurrentString[0]));
667 }
668
669 CurrentString[StringCurPos] = Key.UnicodeChar;
670 Update = StringCurPos;
671
672 StringCurPos += 1;
673 OutputLength = 1;
674 }
675
676 break;
677
678 case 0:
679 switch (Key.ScanCode) {
680 case SCAN_DELETE:
681 //
682 // Move characters behind current position one character forward
683 //
684 if (StringLen != 0) {
685 Update = StringCurPos;
686 Delete = 1;
687 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
688 }
689
690 break;
691
692 case SCAN_UP:
693 //
694 // Prepare to print the previous command
695 //
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);
699 }
700
701 break;
702
703 case SCAN_DOWN:
704 //
705 // Prepare to print the next command
706 //
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);
710 }
711
712 break;
713
714 case SCAN_LEFT:
715 //
716 // Adjust current cursor position
717 //
718 if (StringCurPos != 0) {
719 --StringCurPos;
720 MoveCursorBackward (TotalColumn, &Column, &Row);
721 }
722
723 break;
724
725 case SCAN_RIGHT:
726 //
727 // Adjust current cursor position
728 //
729 if (StringCurPos < StringLen) {
730 ++StringCurPos;
731 MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
732 }
733
734 break;
735
736 case SCAN_HOME:
737 //
738 // Move current cursor position to the beginning of the command line
739 //
740 Row -= (StringCurPos + StartColumn) / TotalColumn;
741 Column = StartColumn;
742 StringCurPos = 0;
743 break;
744
745 case SCAN_END:
746 //
747 // Move current cursor position to the end of the command line
748 //
749 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn;
750 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn;
751 Row = TailRow;
752 Column = TailColumn;
753 StringCurPos = StringLen;
754 break;
755
756 case SCAN_ESC:
757 //
758 // Prepare to clear the current command line
759 //
760 CurrentString[0] = 0;
761 Update = 0;
762 Delete = StringLen;
763 Row -= (StringCurPos + StartColumn) / TotalColumn;
764 Column = StartColumn;
765 OutputLength = 0;
766 break;
767
768 case SCAN_INSERT:
769 //
770 // Toggle the SEnvInsertMode flag
771 //
772 ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN) !ShellInfoObject.ViewingSettings.InsertMode;
773 break;
774
775 case SCAN_F7:
776 //
777 // Print command history
778 //
779 PrintCommandHistory (TotalColumn, TotalRow, 4);
780 *CurrentString = CHAR_NULL;
781 Done = TRUE;
782 break;
783 }
784 }
785
786 if (Done) {
787 break;
788 }
789
790 //
791 // If we are in auto-complete mode, we are preparing to print
792 // the next file or directory name
793 //
794 if (InTabScrolling) {
795 TabOutputStr = AllocateZeroPool (*BufferSize);
796 if (TabOutputStr == NULL) {
797 Status = EFI_OUT_OF_RESOURCES;
798 }
799 }
800
801 if (InTabScrolling && (TabOutputStr != NULL)) {
802 //
803 // Adjust the column and row to the start of TAB-completion string.
804 //
805 Column = (StartColumn + TabUpdatePos) % TotalColumn;
806 Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
807 OutputLength = StrLen (TabCurrent->FileName);
808 //
809 // if the output string contains blank space, quotation marks L'\"'
810 // should be added to the output.
811 //
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;
817 } else {
818 CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
819 TabOutputStr[OutputLength] = CHAR_NULL;
820 }
821
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;
829 }
830
831 FreePool (TabOutputStr);
832 }
833
834 //
835 // If we have a new position, we are preparing to print a previous or
836 // next command.
837 //
838 if (NewPos != (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
839 Column = StartColumn;
840 Row -= (StringCurPos + StartColumn) / TotalColumn;
841
842 LinePos = NewPos;
843 NewPos = (BUFFER_LIST *)(&ShellInfoObject.ViewingSettings.CommandHistory);
844
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;
848
849 StringCurPos = OutputLength;
850
851 //
852 // Draw new input string
853 //
854 Update = 0;
855 if (StringLen > OutputLength) {
856 //
857 // If old string was longer, blank its tail
858 //
859 Delete = StringLen - OutputLength;
860 }
861 }
862
863 //
864 // If we need to update the output do so now
865 //
866 if (Update != (UINTN)-1) {
867 ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
868 StringLen = StrLen (CurrentString);
869
870 if (Delete != 0) {
871 SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
872 }
873
874 if (StringCurPos > StringLen) {
875 StringCurPos = StringLen;
876 }
877
878 Update = (UINTN)-1;
879
880 //
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.
884 //
885 if ((Key.UnicodeChar != CHAR_BACKSPACE) && !((Key.UnicodeChar == 0) && (Key.ScanCode == SCAN_DELETE))) {
886 //
887 // Calculate row and column of the tail of current string
888 //
889 TailRow = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
890 TailColumn = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
891
892 //
893 // If the tail of string reaches screen end, screen rolls up, so if
894 // Row does not equal TailRow, Row should be decremented
895 //
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.
898 //
899 if ((TailColumn == 0) && (TailRow >= TotalRow) && (Row != TailRow)) {
900 Row--;
901 }
902
903 //
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.
907 //
908 if (Column + OutputLength >= TotalColumn) {
909 SkipLength = OutputLength - (TotalColumn - Column);
910
911 Row += SkipLength / TotalColumn + 1;
912 if (Row > TotalRow - 1) {
913 Row = TotalRow - 1;
914 }
915
916 Column = SkipLength % TotalColumn;
917 } else {
918 Column += OutputLength;
919 }
920 }
921
922 Delete = 0;
923 }
924
925 //
926 // Set the cursor position for this key
927 //
928 gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
929 } while (!Done);
930
931 if ((CurrentString != NULL) && (StrLen (CurrentString) > 0)) {
932 //
933 // add the line to the history buffer
934 //
935 AddLineToCommandHistory (CurrentString);
936 }
937
938 //
939 // Return the data to the caller
940 //
941 *BufferSize = StringLen * sizeof (CHAR16);
942
943 //
944 // if this was used it should be deallocated by now...
945 // prevent memory leaks...
946 //
947 if (TabCompleteList != NULL) {
948 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
949 }
950
951 ASSERT (TabCompleteList == NULL);
952
953 return Status;
954 }
955
956 //
957 // FILE style interfaces for StdIn/StdOut/StdErr
958 //
959 EFI_FILE_PROTOCOL FileInterfaceStdIn = {
960 EFI_FILE_REVISION,
961 FileInterfaceOpenNotFound,
962 FileInterfaceNopGeneric,
963 FileInterfaceNopGeneric,
964 FileInterfaceStdInRead,
965 FileInterfaceStdInWrite,
966 FileInterfaceNopGetPosition,
967 FileInterfaceNopSetPosition,
968 FileInterfaceNopGetInfo,
969 FileInterfaceNopSetInfo,
970 FileInterfaceNopGeneric
971 };
972
973 EFI_FILE_PROTOCOL FileInterfaceStdOut = {
974 EFI_FILE_REVISION,
975 FileInterfaceOpenNotFound,
976 FileInterfaceNopGeneric,
977 FileInterfaceNopGeneric,
978 FileInterfaceStdOutRead,
979 FileInterfaceStdOutWrite,
980 FileInterfaceNopGetPosition,
981 FileInterfaceNopSetPosition,
982 FileInterfaceNopGetInfo,
983 FileInterfaceNopSetInfo,
984 FileInterfaceNopGeneric
985 };
986
987 EFI_FILE_PROTOCOL FileInterfaceStdErr = {
988 EFI_FILE_REVISION,
989 FileInterfaceOpenNotFound,
990 FileInterfaceNopGeneric,
991 FileInterfaceNopGeneric,
992 FileInterfaceStdErrRead,
993 FileInterfaceStdErrWrite,
994 FileInterfaceNopGetPosition,
995 FileInterfaceNopSetPosition,
996 FileInterfaceNopGetInfo,
997 FileInterfaceNopSetInfo,
998 FileInterfaceNopGeneric
999 };
1000
1001 EFI_FILE_PROTOCOL FileInterfaceNulFile = {
1002 EFI_FILE_REVISION,
1003 FileInterfaceOpenNotFound,
1004 FileInterfaceNopGeneric,
1005 FileInterfaceNopGeneric,
1006 FileInterfaceNulRead,
1007 FileInterfaceNulWrite,
1008 FileInterfaceNopGetPosition,
1009 FileInterfaceNopSetPosition,
1010 FileInterfaceNopGetInfo,
1011 FileInterfaceNopSetInfo,
1012 FileInterfaceNopGeneric
1013 };
1014
1015 //
1016 // This is identical to EFI_FILE_PROTOCOL except for the additional member
1017 // for the name.
1018 //
1019
1020 typedef struct {
1021 UINT64 Revision;
1022 EFI_FILE_OPEN Open;
1023 EFI_FILE_CLOSE Close;
1024 EFI_FILE_DELETE Delete;
1025 EFI_FILE_READ Read;
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;
1032 CHAR16 Name[1];
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)
1036
1037 /**
1038 File style interface for Environment Variable (Close).
1039
1040 Frees the memory for this object.
1041
1042 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1043
1044 @retval EFI_SUCCESS
1045 **/
1046 EFI_STATUS
1047 EFIAPI
1048 FileInterfaceEnvClose (
1049 IN EFI_FILE_PROTOCOL *This
1050 )
1051 {
1052 VOID *NewBuffer;
1053 UINTN NewSize;
1054 EFI_STATUS Status;
1055 BOOLEAN Volatile;
1056 UINTN TotalSize;
1057
1058 //
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
1062 // if it exists.
1063 //
1064 NewBuffer = NULL;
1065 NewSize = 0;
1066 TotalSize = 0;
1067
1068 Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &Volatile);
1069 if (EFI_ERROR (Status)) {
1070 return Status;
1071 }
1072
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;
1079 }
1080
1081 Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer);
1082 }
1083
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)
1088 )
1089 {
1090 ((CHAR16 *)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;
1091 //
1092 // If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize.
1093 //
1094 TotalSize -= sizeof (CHAR16) * 2;
1095 }
1096
1097 if (Volatile) {
1098 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
1099 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1100 TotalSize - sizeof (CHAR16),
1101 NewBuffer
1102 );
1103
1104 if (!EFI_ERROR (Status)) {
1105 Status = ShellAddEnvVarToList (
1106 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1107 NewBuffer,
1108 TotalSize,
1109 EFI_VARIABLE_BOOTSERVICE_ACCESS
1110 );
1111 }
1112 } else {
1113 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1114 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1115 TotalSize - sizeof (CHAR16),
1116 NewBuffer
1117 );
1118
1119 if (!EFI_ERROR (Status)) {
1120 Status = ShellAddEnvVarToList (
1121 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1122 NewBuffer,
1123 TotalSize,
1124 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
1125 );
1126 }
1127 }
1128 }
1129 }
1130
1131 SHELL_FREE_NON_NULL (NewBuffer);
1132 FreePool ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This);
1133 return (Status);
1134 }
1135
1136 /**
1137 File style interface for Environment Variable (Delete).
1138
1139 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1140
1141 @retval The return value from FileInterfaceEnvClose().
1142 **/
1143 EFI_STATUS
1144 EFIAPI
1145 FileInterfaceEnvDelete (
1146 IN EFI_FILE_PROTOCOL *This
1147 )
1148 {
1149 SHELL_DELETE_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name);
1150 return (FileInterfaceEnvClose (This));
1151 }
1152
1153 /**
1154 File style interface for Environment Variable (Read).
1155
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.
1159
1160 @retval EFI_SUCCESS The data was read.
1161 **/
1162 EFI_STATUS
1163 EFIAPI
1164 FileInterfaceEnvRead (
1165 IN EFI_FILE_PROTOCOL *This,
1166 IN OUT UINTN *BufferSize,
1167 OUT VOID *Buffer
1168 )
1169 {
1170 EFI_STATUS Status;
1171
1172 *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
1173 if (*BufferSize != 0) {
1174 //
1175 // Make sure the first unicode character is \xFEFF
1176 //
1177 *(CHAR16 *)Buffer = gUnicodeFileTag;
1178 Buffer = (CHAR16 *)Buffer + 1;
1179 *BufferSize -= sizeof (gUnicodeFileTag);
1180 }
1181
1182 Status = SHELL_GET_ENVIRONMENT_VARIABLE (
1183 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1184 BufferSize,
1185 Buffer
1186 );
1187 if (!EFI_ERROR (Status) || (Status == EFI_BUFFER_TOO_SMALL)) {
1188 //
1189 // BufferSize is valid and needs update when Status is Success or BufferTooSmall.
1190 //
1191 *BufferSize += sizeof (gUnicodeFileTag);
1192 }
1193
1194 return Status;
1195 }
1196
1197 /**
1198 File style interface for Volatile Environment Variable (Write).
1199 This function also caches the environment variable into gShellEnvVarList.
1200
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.
1204
1205 @retval EFI_SUCCESS The data was successfully write to variable.
1206 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1207 **/
1208 EFI_STATUS
1209 EFIAPI
1210 FileInterfaceEnvVolWrite (
1211 IN EFI_FILE_PROTOCOL *This,
1212 IN OUT UINTN *BufferSize,
1213 IN VOID *Buffer
1214 )
1215 {
1216 VOID *NewBuffer;
1217 UINTN NewSize;
1218 EFI_STATUS Status;
1219 UINTN TotalSize;
1220
1221 NewBuffer = NULL;
1222 NewSize = 0;
1223 TotalSize = 0;
1224
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);
1230 } else {
1231 return Status;
1232 }
1233
1234 NewBuffer = AllocateZeroPool (TotalSize);
1235 if (NewBuffer == NULL) {
1236 return EFI_OUT_OF_RESOURCES;
1237 }
1238
1239 if (Status == EFI_BUFFER_TOO_SMALL) {
1240 Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer);
1241 }
1242
1243 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1244 FreePool (NewBuffer);
1245 return Status;
1246 }
1247
1248 CopyMem ((UINT8 *)NewBuffer + NewSize, Buffer, *BufferSize);
1249 Status = ShellAddEnvVarToList (
1250 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1251 NewBuffer,
1252 TotalSize,
1253 EFI_VARIABLE_BOOTSERVICE_ACCESS
1254 );
1255 if (EFI_ERROR (Status)) {
1256 FreePool (NewBuffer);
1257 return Status;
1258 }
1259
1260 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
1261 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1262 TotalSize - sizeof (CHAR16),
1263 NewBuffer
1264 );
1265 if (EFI_ERROR (Status)) {
1266 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name);
1267 }
1268
1269 FreePool (NewBuffer);
1270 return Status;
1271 }
1272
1273 /**
1274 File style interface for Non Volatile Environment Variable (Write).
1275 This function also caches the environment variable into gShellEnvVarList.
1276
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.
1280
1281 @retval EFI_SUCCESS The data was successfully write to variable.
1282 @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
1283 **/
1284 EFI_STATUS
1285 EFIAPI
1286 FileInterfaceEnvNonVolWrite (
1287 IN EFI_FILE_PROTOCOL *This,
1288 IN OUT UINTN *BufferSize,
1289 IN VOID *Buffer
1290 )
1291 {
1292 VOID *NewBuffer;
1293 UINTN NewSize;
1294 EFI_STATUS Status;
1295 UINTN TotalSize;
1296
1297 NewBuffer = NULL;
1298 NewSize = 0;
1299 TotalSize = 0;
1300
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);
1306 } else {
1307 return Status;
1308 }
1309
1310 NewBuffer = AllocateZeroPool (TotalSize);
1311 if (NewBuffer == NULL) {
1312 return EFI_OUT_OF_RESOURCES;
1313 }
1314
1315 if (Status == EFI_BUFFER_TOO_SMALL) {
1316 Status = SHELL_GET_ENVIRONMENT_VARIABLE (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name, &NewSize, NewBuffer);
1317 }
1318
1319 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
1320 FreePool (NewBuffer);
1321 return Status;
1322 }
1323
1324 CopyMem ((UINT8 *)NewBuffer + NewSize, Buffer, *BufferSize);
1325 Status = ShellAddEnvVarToList (
1326 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1327 NewBuffer,
1328 TotalSize,
1329 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
1330 );
1331 if (EFI_ERROR (Status)) {
1332 FreePool (NewBuffer);
1333 return Status;
1334 }
1335
1336 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1337 ((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name,
1338 TotalSize - sizeof (CHAR16),
1339 NewBuffer
1340 );
1341 if (EFI_ERROR (Status)) {
1342 ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT *)This)->Name);
1343 }
1344
1345 FreePool (NewBuffer);
1346 return Status;
1347 }
1348
1349 /**
1350 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1351 environment variables through file operations.
1352
1353 @param EnvName The name of the Environment Variable to be operated on.
1354
1355 @retval NULL Memory could not be allocated.
1356 @return other a pointer to an EFI_FILE_PROTOCOL structure
1357 **/
1358 EFI_FILE_PROTOCOL *
1359 CreateFileInterfaceEnv (
1360 IN CONST CHAR16 *EnvName
1361 )
1362 {
1363 EFI_STATUS Status;
1364 EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface;
1365 UINTN EnvNameSize;
1366 BOOLEAN Volatile;
1367
1368 if (EnvName == NULL) {
1369 return (NULL);
1370 }
1371
1372 Status = IsVolatileEnv (EnvName, &Volatile);
1373 if (EFI_ERROR (Status)) {
1374 return NULL;
1375 }
1376
1377 //
1378 // Get some memory
1379 //
1380 EnvNameSize = StrSize (EnvName);
1381 EnvFileInterface = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);
1382 if (EnvFileInterface == NULL) {
1383 return (NULL);
1384 }
1385
1386 //
1387 // Assign the generic members
1388 //
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;
1399
1400 CopyMem (EnvFileInterface->Name, EnvName, EnvNameSize);
1401
1402 //
1403 // Assign the different members for Volatile and Non-Volatile variables
1404 //
1405 if (Volatile) {
1406 EnvFileInterface->Write = FileInterfaceEnvVolWrite;
1407 } else {
1408 EnvFileInterface->Write = FileInterfaceEnvNonVolWrite;
1409 }
1410
1411 return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
1412 }
1413
1414 /**
1415 Move the cursor position one character backward.
1416
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
1420 **/
1421 VOID
1422 MoveCursorBackward (
1423 IN UINTN LineLength,
1424 IN OUT UINTN *Column,
1425 IN OUT UINTN *Row
1426 )
1427 {
1428 //
1429 // If current column is 0, move to the last column of the previous line,
1430 // otherwise, just decrement column.
1431 //
1432 if (*Column == 0) {
1433 *Column = LineLength - 1;
1434 if (*Row > 0) {
1435 (*Row)--;
1436 }
1437
1438 return;
1439 }
1440
1441 (*Column)--;
1442 }
1443
1444 /**
1445 Move the cursor position one character forward.
1446
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
1451 **/
1452 VOID
1453 MoveCursorForward (
1454 IN UINTN LineLength,
1455 IN UINTN TotalRow,
1456 IN OUT UINTN *Column,
1457 IN OUT UINTN *Row
1458 )
1459 {
1460 //
1461 // Increment Column.
1462 // If this puts column past the end of the line, move to first column
1463 // of the next row.
1464 //
1465 (*Column)++;
1466 if (*Column >= LineLength) {
1467 (*Column) = 0;
1468 if ((*Row) < TotalRow - 1) {
1469 (*Row)++;
1470 }
1471 }
1472 }
1473
1474 /**
1475 Prints out each previously typed command in the command list history log.
1476
1477 When each screen is full it will pause for a key before continuing.
1478
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
1482 **/
1483 VOID
1484 PrintCommandHistory (
1485 IN CONST UINTN TotalCols,
1486 IN CONST UINTN TotalRows,
1487 IN CONST UINTN StartColumn
1488 )
1489 {
1490 BUFFER_LIST *Node;
1491 UINTN Index;
1492 UINTN LineNumber;
1493 UINTN LineCount;
1494
1495 ShellPrintEx (-1, -1, L"\n");
1496 Index = 0;
1497 LineNumber = 0;
1498 //
1499 // go through history list...
1500 //
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)
1504 )
1505 {
1506 Index++;
1507 LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
1508
1509 if (LineNumber + LineCount >= TotalRows) {
1510 ShellPromptForResponseHii (
1511 ShellPromptResponseTypeEnterContinue,
1512 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
1513 ShellInfoObject.HiiHandle,
1514 NULL
1515 );
1516 LineNumber = 0;
1517 }
1518
1519 ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
1520 LineNumber += LineCount;
1521 }
1522 }
1523
1524 //
1525 // This is identical to EFI_FILE_PROTOCOL except for the additional members
1526 // for the buffer, size, and position.
1527 //
1528
1529 typedef struct {
1530 UINT64 Revision;
1531 EFI_FILE_OPEN Open;
1532 EFI_FILE_CLOSE Close;
1533 EFI_FILE_DELETE Delete;
1534 EFI_FILE_READ Read;
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;
1541 VOID *Buffer;
1542 UINT64 Position;
1543 UINT64 BufferSize;
1544 BOOLEAN Unicode;
1545 UINT64 FileSize;
1546 } EFI_FILE_PROTOCOL_MEM;
1547
1548 /**
1549 File style interface for Mem (SetPosition).
1550
1551 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1552 @param[out] Position The position to set.
1553
1554 @retval EFI_SUCCESS The position was successfully changed.
1555 @retval EFI_INVALID_PARAMETER The Position was invalid.
1556 **/
1557 EFI_STATUS
1558 EFIAPI
1559 FileInterfaceMemSetPosition (
1560 IN EFI_FILE_PROTOCOL *This,
1561 OUT UINT64 Position
1562 )
1563 {
1564 if (Position <= ((EFI_FILE_PROTOCOL_MEM *)This)->FileSize) {
1565 ((EFI_FILE_PROTOCOL_MEM *)This)->Position = Position;
1566 return (EFI_SUCCESS);
1567 } else {
1568 return (EFI_INVALID_PARAMETER);
1569 }
1570 }
1571
1572 /**
1573 File style interface for Mem (GetPosition).
1574
1575 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1576 @param[out] Position The pointer to the position.
1577
1578 @retval EFI_SUCCESS The position was retrieved.
1579 **/
1580 EFI_STATUS
1581 EFIAPI
1582 FileInterfaceMemGetPosition (
1583 IN EFI_FILE_PROTOCOL *This,
1584 OUT UINT64 *Position
1585 )
1586 {
1587 *Position = ((EFI_FILE_PROTOCOL_MEM *)This)->Position;
1588 return (EFI_SUCCESS);
1589 }
1590
1591 /**
1592 File style interface for Mem (GetInfo).
1593
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.
1598
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.
1607
1608 **/
1609 EFI_STATUS
1610 EFIAPI
1611 FileInterfaceMemGetInfo (
1612 IN EFI_FILE_PROTOCOL *This,
1613 IN EFI_GUID *InformationType,
1614 IN OUT UINTN *BufferSize,
1615 OUT VOID *Buffer
1616 )
1617 {
1618 EFI_FILE_INFO *FileInfo;
1619
1620 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1621 if (*BufferSize < sizeof (EFI_FILE_INFO)) {
1622 *BufferSize = sizeof (EFI_FILE_INFO);
1623 return EFI_BUFFER_TOO_SMALL;
1624 }
1625
1626 if (Buffer == NULL) {
1627 return EFI_INVALID_PARAMETER;
1628 }
1629
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;
1635 return EFI_SUCCESS;
1636 }
1637
1638 return EFI_UNSUPPORTED;
1639 }
1640
1641 /**
1642 File style interface for Mem (Write).
1643
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.
1647
1648 @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
1649 @retval EFI_SUCCESS The data was written.
1650 **/
1651 EFI_STATUS
1652 EFIAPI
1653 FileInterfaceMemWrite (
1654 IN EFI_FILE_PROTOCOL *This,
1655 IN OUT UINTN *BufferSize,
1656 IN VOID *Buffer
1657 )
1658 {
1659 CHAR8 *AsciiBuffer;
1660 EFI_FILE_PROTOCOL_MEM *MemFile;
1661
1662 MemFile = (EFI_FILE_PROTOCOL_MEM *)This;
1663 if (MemFile->Unicode) {
1664 //
1665 // Unicode
1666 //
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;
1671 }
1672
1673 MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;
1674 }
1675
1676 CopyMem (((UINT8 *)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);
1677 MemFile->Position += (*BufferSize);
1678 MemFile->FileSize = MemFile->Position;
1679 return (EFI_SUCCESS);
1680 } else {
1681 //
1682 // Ascii
1683 //
1684 AsciiBuffer = AllocateZeroPool (*BufferSize);
1685 if (AsciiBuffer == NULL) {
1686 return (EFI_OUT_OF_RESOURCES);
1687 }
1688
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;
1695 }
1696
1697 MemFile->BufferSize += AsciiStrSize (AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;
1698 }
1699
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);
1705 }
1706 }
1707
1708 /**
1709 File style interface for Mem (Read).
1710
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.
1714
1715 @retval EFI_SUCCESS The data was read.
1716 **/
1717 EFI_STATUS
1718 EFIAPI
1719 FileInterfaceMemRead (
1720 IN EFI_FILE_PROTOCOL *This,
1721 IN OUT UINTN *BufferSize,
1722 IN VOID *Buffer
1723 )
1724 {
1725 EFI_FILE_PROTOCOL_MEM *MemFile;
1726
1727 MemFile = (EFI_FILE_PROTOCOL_MEM *)This;
1728 if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {
1729 (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));
1730 }
1731
1732 CopyMem (Buffer, ((UINT8 *)MemFile->Buffer) + MemFile->Position, (*BufferSize));
1733 MemFile->Position = MemFile->Position + (*BufferSize);
1734 return (EFI_SUCCESS);
1735 }
1736
1737 /**
1738 File style interface for Mem (Close).
1739
1740 Frees all memory associated with this object.
1741
1742 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
1743
1744 @retval EFI_SUCCESS The 'file' was closed.
1745 **/
1746 EFI_STATUS
1747 EFIAPI
1748 FileInterfaceMemClose (
1749 IN EFI_FILE_PROTOCOL *This
1750 )
1751 {
1752 SHELL_FREE_NON_NULL (((EFI_FILE_PROTOCOL_MEM *)This)->Buffer);
1753 SHELL_FREE_NON_NULL (This);
1754 return (EFI_SUCCESS);
1755 }
1756
1757 /**
1758 Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1759 a file entirely in memory through file operations.
1760
1761 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1762
1763 @retval NULL Memory could not be allocated.
1764 @return other A pointer to an EFI_FILE_PROTOCOL structure.
1765 **/
1766 EFI_FILE_PROTOCOL *
1767 CreateFileInterfaceMem (
1768 IN CONST BOOLEAN Unicode
1769 )
1770 {
1771 EFI_FILE_PROTOCOL_MEM *FileInterface;
1772
1773 //
1774 // Get some memory
1775 //
1776 FileInterface = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_MEM));
1777 if (FileInterface == NULL) {
1778 return (NULL);
1779 }
1780
1781 //
1782 // Assign the generic members
1783 //
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;
1796
1797 ASSERT (FileInterface->Buffer == NULL);
1798 ASSERT (FileInterface->BufferSize == 0);
1799 ASSERT (FileInterface->Position == 0);
1800
1801 if (Unicode) {
1802 FileInterface->Buffer = AllocateZeroPool (sizeof (gUnicodeFileTag));
1803 if (FileInterface->Buffer == NULL) {
1804 FreePool (FileInterface);
1805 return NULL;
1806 }
1807
1808 *((CHAR16 *)(FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;
1809 FileInterface->BufferSize = 2;
1810 FileInterface->Position = 2;
1811 }
1812
1813 return ((EFI_FILE_PROTOCOL *)FileInterface);
1814 }
1815
1816 typedef struct {
1817 UINT64 Revision;
1818 EFI_FILE_OPEN Open;
1819 EFI_FILE_CLOSE Close;
1820 EFI_FILE_DELETE Delete;
1821 EFI_FILE_READ Read;
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;
1828 BOOLEAN Unicode;
1829 EFI_FILE_PROTOCOL *Orig;
1830 } EFI_FILE_PROTOCOL_FILE;
1831
1832 /**
1833 Set a files current position
1834
1835 @param This Protocol instance pointer.
1836 @param Position Byte position from the start of the file.
1837
1838 @retval EFI_SUCCESS Data was written.
1839 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
1840
1841 **/
1842 EFI_STATUS
1843 EFIAPI
1844 FileInterfaceFileSetPosition (
1845 IN EFI_FILE_PROTOCOL *This,
1846 IN UINT64 Position
1847 )
1848 {
1849 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->SetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, Position);
1850 }
1851
1852 /**
1853 Get a file's current position
1854
1855 @param This Protocol instance pointer.
1856 @param Position Byte position from the start of the file.
1857
1858 @retval EFI_SUCCESS Data was written.
1859 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
1860
1861 **/
1862 EFI_STATUS
1863 EFIAPI
1864 FileInterfaceFileGetPosition (
1865 IN EFI_FILE_PROTOCOL *This,
1866 OUT UINT64 *Position
1867 )
1868 {
1869 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, Position);
1870 }
1871
1872 /**
1873 Get information about a file.
1874
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.
1879
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.
1888
1889 **/
1890 EFI_STATUS
1891 EFIAPI
1892 FileInterfaceFileGetInfo (
1893 IN EFI_FILE_PROTOCOL *This,
1894 IN EFI_GUID *InformationType,
1895 IN OUT UINTN *BufferSize,
1896 OUT VOID *Buffer
1897 )
1898 {
1899 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetInfo (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, InformationType, BufferSize, Buffer);
1900 }
1901
1902 /**
1903 Set information about a file
1904
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.
1909
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.
1917
1918 **/
1919 EFI_STATUS
1920 EFIAPI
1921 FileInterfaceFileSetInfo (
1922 IN EFI_FILE_PROTOCOL *This,
1923 IN EFI_GUID *InformationType,
1924 IN UINTN BufferSize,
1925 IN VOID *Buffer
1926 )
1927 {
1928 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->SetInfo (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, InformationType, BufferSize, Buffer);
1929 }
1930
1931 /**
1932 Flush data back for the file handle.
1933
1934 @param This Protocol instance pointer.
1935
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.
1944
1945 **/
1946 EFI_STATUS
1947 EFIAPI
1948 FileInterfaceFileFlush (
1949 IN EFI_FILE_PROTOCOL *This
1950 )
1951 {
1952 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Flush (((EFI_FILE_PROTOCOL_FILE *)This)->Orig);
1953 }
1954
1955 /**
1956 Read data from the file.
1957
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.
1961
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.
1967
1968 **/
1969 EFI_STATUS
1970 EFIAPI
1971 FileInterfaceFileRead (
1972 IN EFI_FILE_PROTOCOL *This,
1973 IN OUT UINTN *BufferSize,
1974 OUT VOID *Buffer
1975 )
1976 {
1977 EFI_STATUS Status;
1978 UINT64 Position;
1979 CHAR8 *AsciiStrBuffer;
1980 CHAR16 *UscStrBuffer;
1981 UINTN Size;
1982
1983 if (((EFI_FILE_PROTOCOL_FILE *)This)->Unicode) {
1984 //
1985 // 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.
1988 //
1989 return (((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, BufferSize, Buffer));
1990 } else {
1991 //
1992 // Ascii
1993 //
1994 *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
1995 if (*BufferSize == 0) {
1996 return EFI_SUCCESS;
1997 }
1998
1999 Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, &Position);
2000 if (EFI_ERROR (Status)) {
2001 return Status;
2002 }
2003
2004 if (Position == 0) {
2005 //
2006 // First two bytes in Buffer is for the Unicode file tag.
2007 //
2008 *(CHAR16 *)Buffer = gUnicodeFileTag;
2009 Buffer = (CHAR16 *)Buffer + 1;
2010 Size = *BufferSize / sizeof (CHAR16) - 1;
2011 } else {
2012 Size = *BufferSize / sizeof (CHAR16);
2013 }
2014
2015 AsciiStrBuffer = AllocateZeroPool (Size + 1);
2016 if (AsciiStrBuffer == NULL) {
2017 return EFI_OUT_OF_RESOURCES;
2018 }
2019
2020 UscStrBuffer = AllocateZeroPool ((Size + 1) * sizeof (CHAR16));
2021 if (UscStrBuffer == NULL) {
2022 SHELL_FREE_NON_NULL (AsciiStrBuffer);
2023 return EFI_OUT_OF_RESOURCES;
2024 }
2025
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);
2031 }
2032
2033 SHELL_FREE_NON_NULL (AsciiStrBuffer);
2034 SHELL_FREE_NON_NULL (UscStrBuffer);
2035 return Status;
2036 }
2037 }
2038
2039 /**
2040 Opens a new file relative to the source file's location.
2041
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.
2047
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.
2057 **/
2058 EFI_STATUS
2059 EFIAPI
2060 FileInterfaceFileOpen (
2061 IN EFI_FILE_PROTOCOL *This,
2062 OUT EFI_FILE_PROTOCOL **NewHandle,
2063 IN CHAR16 *FileName,
2064 IN UINT64 OpenMode,
2065 IN UINT64 Attributes
2066 )
2067 {
2068 return ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Open (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, NewHandle, FileName, OpenMode, Attributes);
2069 }
2070
2071 /**
2072 Close and delete the file handle.
2073
2074 @param This Protocol instance pointer.
2075
2076 @retval EFI_SUCCESS The device was opened.
2077 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
2078
2079 **/
2080 EFI_STATUS
2081 EFIAPI
2082 FileInterfaceFileDelete (
2083 IN EFI_FILE_PROTOCOL *This
2084 )
2085 {
2086 EFI_STATUS Status;
2087
2088 Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Delete (((EFI_FILE_PROTOCOL_FILE *)This)->Orig);
2089 FreePool (This);
2090 return (Status);
2091 }
2092
2093 /**
2094 File style interface for File (Close).
2095
2096 @param[in] This The pointer to the EFI_FILE_PROTOCOL object.
2097
2098 @retval EFI_SUCCESS The file was closed.
2099 **/
2100 EFI_STATUS
2101 EFIAPI
2102 FileInterfaceFileClose (
2103 IN EFI_FILE_PROTOCOL *This
2104 )
2105 {
2106 EFI_STATUS Status;
2107
2108 Status = ((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Close (((EFI_FILE_PROTOCOL_FILE *)This)->Orig);
2109 FreePool (This);
2110 return (Status);
2111 }
2112
2113 /**
2114 File style interface for File (Write).
2115
2116 If the file was opened with ASCII mode the data will be processed through
2117 AsciiSPrint before writing.
2118
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.
2122
2123 @retval EFI_SUCCESS The data was written.
2124 **/
2125 EFI_STATUS
2126 EFIAPI
2127 FileInterfaceFileWrite (
2128 IN EFI_FILE_PROTOCOL *This,
2129 IN OUT UINTN *BufferSize,
2130 IN VOID *Buffer
2131 )
2132 {
2133 CHAR8 *AsciiBuffer;
2134 UINTN Size;
2135 EFI_STATUS Status;
2136
2137 if (((EFI_FILE_PROTOCOL_FILE *)This)->Unicode) {
2138 //
2139 // Unicode
2140 //
2141 return (((EFI_FILE_PROTOCOL_FILE *)This)->Orig->Write (((EFI_FILE_PROTOCOL_FILE *)This)->Orig, BufferSize, Buffer));
2142 } else {
2143 //
2144 // Ascii
2145 //
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);
2151 return (Status);
2152 }
2153 }
2154
2155 /**
2156 Create a file interface with unicode information.
2157
2158 This will create a new EFI_FILE_PROTOCOL identical to the Templace
2159 except that the new one has Unicode and Ascii knowledge.
2160
2161 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object.
2162 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII.
2163
2164 @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
2165 **/
2166 EFI_FILE_PROTOCOL *
2167 CreateFileInterfaceFile (
2168 IN CONST EFI_FILE_PROTOCOL *Template,
2169 IN CONST BOOLEAN Unicode
2170 )
2171 {
2172 EFI_FILE_PROTOCOL_FILE *NewOne;
2173
2174 NewOne = AllocateZeroPool (sizeof (EFI_FILE_PROTOCOL_FILE));
2175 if (NewOne == NULL) {
2176 return (NULL);
2177 }
2178
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;
2192
2193 return ((EFI_FILE_PROTOCOL *)NewOne);
2194 }