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
FileInterfaceOpenNotFound(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)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
FileInterfaceNopGeneric(IN EFI_FILE_PROTOCOL * This)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
FileInterfaceNopGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)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
FileInterfaceNopSetPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)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
FileInterfaceNopGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)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
FileInterfaceNopSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)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
FileInterfaceStdOutWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)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   if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {
161     return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));
162   }
163   return (gST->ConOut->OutputString(gST->ConOut, Buffer));
164 }
165 
166 /**
167   File style interface for StdIn (Write).
168 
169   @param[in] This            Ignored.
170   @param[in, out] BufferSize Ignored.
171   @param[in] Buffer          Ignored.
172 
173   @retval EFI_UNSUPPORTED
174 **/
175 EFI_STATUS
176 EFIAPI
FileInterfaceStdInWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)177 FileInterfaceStdInWrite(
178   IN      EFI_FILE_PROTOCOL *This,
179   IN OUT  UINTN             *BufferSize,
180   IN      VOID              *Buffer
181   )
182 {
183   return (EFI_UNSUPPORTED);
184 }
185 
186 /**
187   File style interface for console StdErr (Write).
188 
189   Writes error to the error output.
190 
191   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
192   @param[in, out] BufferSize   Size in bytes of Buffer.
193   @param[in] Buffer            The pointer to the buffer to write.
194 
195   @return A return value from gST->StdErr->OutputString.
196 **/
197 EFI_STATUS
198 EFIAPI
FileInterfaceStdErrWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)199 FileInterfaceStdErrWrite(
200   IN EFI_FILE_PROTOCOL *This,
201   IN OUT UINTN *BufferSize,
202   IN VOID *Buffer
203   )
204 {
205   return (gST->StdErr->OutputString(gST->StdErr, Buffer));
206 }
207 
208 /**
209   File style interface for console StdOut (Read).
210 
211   @param[in] This              Ignored.
212   @param[in, out] BufferSize   Ignored.
213   @param[out] Buffer           Ignored.
214 
215   @retval EFI_UNSUPPORTED
216 **/
217 EFI_STATUS
218 EFIAPI
FileInterfaceStdOutRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)219 FileInterfaceStdOutRead(
220   IN EFI_FILE_PROTOCOL *This,
221   IN OUT UINTN *BufferSize,
222   OUT VOID *Buffer
223   )
224 {
225   return (EFI_UNSUPPORTED);
226 }
227 
228 /**
229   File style interface for console StdErr (Read).
230 
231   @param[in] This              Ignored.
232   @param[in, out] BufferSize   Ignored.
233   @param[out] Buffer           Ignored.
234 
235   @retval EFI_UNSUPPORTED Always.
236 **/
237 EFI_STATUS
238 EFIAPI
FileInterfaceStdErrRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)239 FileInterfaceStdErrRead(
240   IN EFI_FILE_PROTOCOL *This,
241   IN OUT UINTN *BufferSize,
242   OUT VOID *Buffer
243   )
244 {
245   return (EFI_UNSUPPORTED);
246 }
247 
248 /**
249   File style interface for NUL file (Read).
250 
251   @param[in] This              Ignored.
252   @param[in, out] BufferSize   Poiner to 0 upon return.
253   @param[out] Buffer           Ignored.
254 
255   @retval EFI_SUCCESS Always.
256 **/
257 EFI_STATUS
258 EFIAPI
FileInterfaceNulRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)259 FileInterfaceNulRead(
260   IN      EFI_FILE_PROTOCOL *This,
261   IN OUT  UINTN             *BufferSize,
262   OUT     VOID              *Buffer
263   )
264 {
265   *BufferSize = 0;
266   return (EFI_SUCCESS);
267 }
268 
269 /**
270   File style interface for NUL file (Write).
271 
272   @param[in] This              Ignored.
273   @param[in, out] BufferSize   Ignored.
274   @param[in] Buffer            Ignored.
275 
276   @retval EFI_SUCCESS
277 **/
278 EFI_STATUS
279 EFIAPI
FileInterfaceNulWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)280 FileInterfaceNulWrite(
281   IN EFI_FILE_PROTOCOL *This,
282   IN OUT UINTN *BufferSize,
283   IN VOID *Buffer
284   )
285 {
286   return (EFI_SUCCESS);
287 }
288 
289 /**
290   Create the TAB completion list.
291 
292   @param[in]  InputString       The command line to expand.
293   @param[in]  StringLen         Length of the command line.
294   @param[in]  BufferSize        Buffer size.
295   @param[in, out] TabCompletionList Return the TAB completion list.
296   @param[in, out] TabUpdatePos      Return the TAB update position.
297 **/
298 EFI_STATUS
CreateTabCompletionList(IN CONST CHAR16 * InputString,IN CONST UINTN StringLen,IN CONST UINTN BufferSize,IN OUT EFI_SHELL_FILE_INFO ** TabCompletionList,IN OUT UINTN * TabUpdatePos)299 CreateTabCompletionList (
300   IN CONST CHAR16             *InputString,
301   IN CONST UINTN              StringLen,
302   IN CONST UINTN              BufferSize,
303   IN OUT EFI_SHELL_FILE_INFO  **TabCompletionList,
304   IN OUT   UINTN              *TabUpdatePos
305 )
306 {
307   BOOLEAN             InQuotation;
308   UINTN               TabPos;
309   UINTN               Index;
310   CONST CHAR16        *Cwd;
311   EFI_STATUS          Status;
312   CHAR16              *TabStr;
313   EFI_SHELL_FILE_INFO *FileList;
314   EFI_SHELL_FILE_INFO *FileInfo;
315   EFI_SHELL_FILE_INFO *TempFileInfo;
316 
317   //
318   // Allocate buffers
319   //
320   TabStr = AllocateZeroPool (BufferSize);
321   if (TabStr == NULL) {
322     return EFI_OUT_OF_RESOURCES;
323   }
324 
325   //
326   // handle auto complete of file and directory names...
327   // E.g.: cd fs0:\EFI\Bo<TAB>
328   //          ^        ^
329   //          TabPos   TabUpdatePos
330   //
331   TabPos        = 0;
332   *TabUpdatePos = 0;
333   FileList      = NULL;
334   InQuotation   = FALSE;
335   for (Index = 0; Index < StringLen; Index++) {
336     switch (InputString[Index]) {
337     case L'\"':
338       InQuotation = (BOOLEAN) (!InQuotation);
339       break;
340 
341     case L' ':
342       if (!InQuotation) {
343         TabPos = Index + 1;
344         *TabUpdatePos = TabPos;
345       }
346       break;
347 
348     case L':':
349       //
350       // handle the case "fs0:<TAB>"
351       // Update the TabUpdatePos as well.
352       //
353     case L'\\':
354       *TabUpdatePos = Index + 1;
355       break;
356 
357     default:
358       break;
359     }
360   }
361 
362   if (StrStr (InputString + TabPos, L":") == NULL) {
363     //
364     // If file path doesn't contain ":", ...
365     //
366     Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);
367     if (Cwd != NULL) {
368       if (InputString[TabPos] != L'\\') {
369         //
370         // and it doesn't begin with "\\", it's a path relative to current directory.
371         // TabStr = "<cwd>\\"
372         //
373         StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);
374         StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");
375       } else {
376         //
377         // and it begins with "\\", it's a path pointing to root directory of current map.
378         // TabStr = "fsx:"
379         //
380         Index = StrStr (Cwd, L":") - Cwd + 1;
381         StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);
382       }
383     }
384   }
385   StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);
386   StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));
387   Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);
388 
389   //
390   // Filter out the non-directory for "CD" command
391   // Filter "." and ".." for all
392   //
393   if (!EFI_ERROR (Status) && FileList != NULL) {
394     //
395     // Skip the spaces in the beginning
396     //
397     while (*InputString == L' ') {
398       InputString++;
399     }
400 
401     for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {
402       if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||
403           (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&
404            (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {
405         TempFileInfo = FileInfo;
406         FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);
407         InternalFreeShellFileInfoNode (TempFileInfo);
408       } else {
409         FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);
410       }
411     }
412   }
413 
414   if (FileList != NULL && !IsListEmpty (&FileList->Link)) {
415     Status = EFI_SUCCESS;
416   } else {
417     ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);
418     Status = EFI_NOT_FOUND;
419   }
420 
421   FreePool (TabStr);
422 
423   *TabCompletionList = FileList;
424   return Status;
425 }
426 
427 /**
428   File style interface for console (Read).
429 
430   This will return a single line of input from the console.
431 
432   @param This           A pointer to the EFI_FILE_PROTOCOL instance that is the
433                         file handle to read data from. Not used.
434   @param BufferSize     On input, the size of the Buffer. On output, the amount
435                         of data returned in Buffer. In both cases, the size is
436                         measured in bytes.
437   @param Buffer         The buffer into which the data is read.
438 
439 
440   @retval EFI_SUCCESS           The data was read.
441   @retval EFI_NO_MEDIA          The device has no medium.
442   @retval EFI_DEVICE_ERROR      The device reported an error.
443   @retval EFI_DEVICE_ERROR      An attempt was made to read from a deleted file.
444   @retval EFI_DEVICE_ERROR      On entry, the current file position is beyond the end of the file.
445   @retval EFI_VOLUME_CORRUPTED  The file system structures are corrupted.
446   @retval EFI_BUFFER_TOO_SMALL  The BufferSize is too small to read the current directory
447                                 entry. BufferSize has been updated with the size
448                                 needed to complete the request.
449   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
450 **/
451 EFI_STATUS
452 EFIAPI
FileInterfaceStdInRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)453 FileInterfaceStdInRead(
454   IN EFI_FILE_PROTOCOL *This,
455   IN OUT UINTN *BufferSize,
456   OUT VOID *Buffer
457   )
458 {
459   CHAR16              *CurrentString;
460   BOOLEAN             Done;
461   UINTN               TabUpdatePos;   // Start index of the string updated by TAB stroke
462   UINTN               Column;         // Column of current cursor
463   UINTN               Row;            // Row of current cursor
464   UINTN               StartColumn;    // Column at the beginning of the line
465   UINTN               Update;         // Line index for update
466   UINTN               Delete;         // Num of chars to delete from console after update
467   UINTN               StringLen;      // Total length of the line
468   UINTN               StringCurPos;   // Line index corresponding to the cursor
469   UINTN               MaxStr;         // Maximum possible line length
470   UINTN               TotalColumn;     // Num of columns in the console
471   UINTN               TotalRow;       // Num of rows in the console
472   UINTN               SkipLength;
473   UINTN               OutputLength;   // Length of the update string
474   UINTN               TailRow;        // Row of end of line
475   UINTN               TailColumn;     // Column of end of line
476   EFI_INPUT_KEY       Key;
477 
478   BUFFER_LIST         *LinePos;
479   BUFFER_LIST         *NewPos;
480   BOOLEAN             InScrolling;
481   EFI_STATUS          Status;
482   BOOLEAN             InTabScrolling; // Whether in TAB-completion state
483   EFI_SHELL_FILE_INFO *TabCompleteList;
484   EFI_SHELL_FILE_INFO *TabCurrent;
485   UINTN               EventIndex;
486   CHAR16              *TabOutputStr;
487 
488   //
489   // If buffer is not large enough to hold a CHAR16, return minimum buffer size
490   //
491   if (*BufferSize < sizeof (CHAR16) * 2) {
492     *BufferSize = sizeof (CHAR16) * 2;
493     return (EFI_BUFFER_TOO_SMALL);
494   }
495 
496   Done              = FALSE;
497   CurrentString     = Buffer;
498   StringLen         = 0;
499   StringCurPos      = 0;
500   OutputLength      = 0;
501   Update            = 0;
502   Delete            = 0;
503   LinePos           = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
504   InScrolling       = FALSE;
505   InTabScrolling    = FALSE;
506   Status            = EFI_SUCCESS;
507   TabOutputStr      = NULL;
508   TabUpdatePos      = 0;
509   TabCompleteList   = NULL;
510   TabCurrent        = NULL;
511 
512   //
513   // Get the screen setting and the current cursor location
514   //
515   Column      = StartColumn = gST->ConOut->Mode->CursorColumn;
516   Row         = gST->ConOut->Mode->CursorRow;
517   gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow);
518 
519   //
520   // Limit the line length to the buffer size or the minimum size of the
521   // screen. (The smaller takes effect)
522   //
523   MaxStr = TotalColumn * (TotalRow - 1) - StartColumn;
524   if (MaxStr > *BufferSize / sizeof (CHAR16)) {
525     MaxStr = *BufferSize / sizeof (CHAR16);
526   }
527   ZeroMem (CurrentString, MaxStr * sizeof (CHAR16));
528   do {
529     //
530     // Read a key
531     //
532     gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
533     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
534     if (EFI_ERROR (Status)) {
535 
536       if (Status == EFI_NOT_READY)
537         continue;
538 
539       ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));
540       StringLen = 0;
541       break;
542     }
543 
544     //
545     // Press PageUp or PageDown to scroll the history screen up or down.
546     // Press any other key to quit scrolling.
547     //
548     if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) {
549       if (Key.ScanCode == SCAN_PAGE_UP) {
550         ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo);
551       } else if (Key.ScanCode == SCAN_PAGE_DOWN) {
552         ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo);
553       }
554 
555       InScrolling = TRUE;
556     } else {
557       if (InScrolling) {
558         ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo);
559         InScrolling = FALSE;
560       }
561     }
562 
563     //
564     // If we are quitting TAB scrolling...
565     //
566     if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {
567       if (TabCompleteList != NULL) {
568         ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
569         DEBUG_CODE(TabCompleteList = NULL;);
570       }
571       InTabScrolling = FALSE;
572     }
573 
574     switch (Key.UnicodeChar) {
575     case CHAR_CARRIAGE_RETURN:
576       //
577       // All done, print a newline at the end of the string
578       //
579       TailRow     = Row + (StringLen - StringCurPos + Column) / TotalColumn;
580       TailColumn  = (StringLen - StringCurPos + Column) % TotalColumn;
581       ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n");
582       Done = TRUE;
583       break;
584 
585     case CHAR_BACKSPACE:
586       if (StringCurPos != 0) {
587         //
588         // If not move back beyond string beginning, move all characters behind
589         // the current position one character forward
590         //
591         StringCurPos--;
592         Update  = StringCurPos;
593         Delete  = 1;
594         CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
595 
596         //
597         // Adjust the current column and row
598         //
599         MoveCursorBackward (TotalColumn, &Column, &Row);
600       }
601       break;
602 
603     case CHAR_TAB:
604       if (!InTabScrolling) {
605         TabCurrent = NULL;
606         //
607         // Initialize a tab complete operation.
608         //
609         Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);
610         if (!EFI_ERROR(Status)) {
611           InTabScrolling = TRUE;
612         }
613 
614         //
615         // We do not set up the replacement.
616         // The next section will do that.
617         //
618       }
619 
620       if (InTabScrolling) {
621         //
622         // We are in a tab complete operation.
623         // set up the next replacement.
624         //
625         ASSERT(TabCompleteList != NULL);
626         if (TabCurrent == NULL) {
627           TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);
628         } else {
629           TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
630         }
631 
632         //
633         // Skip over the empty list beginning node
634         //
635         if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {
636           TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);
637         }
638       }
639       break;
640 
641     default:
642       if (Key.UnicodeChar >= ' ') {
643         //
644         // If we are at the buffer's end, drop the key
645         //
646         if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {
647           break;
648         }
649         //
650         // If in insert mode, make space by moving each other character 1
651         // space higher in the array
652         //
653         if (ShellInfoObject.ViewingSettings.InsertMode) {
654           CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));
655         }
656 
657         CurrentString[StringCurPos] = Key.UnicodeChar;
658         Update      = StringCurPos;
659 
660         StringCurPos += 1;
661         OutputLength = 1;
662       }
663       break;
664 
665     case 0:
666       switch (Key.ScanCode) {
667       case SCAN_DELETE:
668         //
669         // Move characters behind current position one character forward
670         //
671         if (StringLen != 0) {
672           Update  = StringCurPos;
673           Delete  = 1;
674           CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
675         }
676         break;
677 
678       case SCAN_UP:
679         //
680         // Prepare to print the previous command
681         //
682         NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
683         if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {
684           NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
685         }
686         break;
687 
688       case SCAN_DOWN:
689         //
690         // Prepare to print the next command
691         //
692         NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
693         if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
694           NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
695         }
696         break;
697 
698       case SCAN_LEFT:
699         //
700         // Adjust current cursor position
701         //
702         if (StringCurPos != 0) {
703           --StringCurPos;
704           MoveCursorBackward (TotalColumn, &Column, &Row);
705         }
706         break;
707 
708       case SCAN_RIGHT:
709         //
710         // Adjust current cursor position
711         //
712         if (StringCurPos < StringLen) {
713           ++StringCurPos;
714           MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
715         }
716         break;
717 
718       case SCAN_HOME:
719         //
720         // Move current cursor position to the beginning of the command line
721         //
722         Row -= (StringCurPos + StartColumn) / TotalColumn;
723         Column  = StartColumn;
724         StringCurPos  = 0;
725         break;
726 
727       case SCAN_END:
728         //
729         // Move current cursor position to the end of the command line
730         //
731         TailRow       = Row + (StringLen - StringCurPos + Column) / TotalColumn;
732         TailColumn    = (StringLen - StringCurPos + Column) % TotalColumn;
733         Row           = TailRow;
734         Column        = TailColumn;
735         StringCurPos  = StringLen;
736         break;
737 
738       case SCAN_ESC:
739         //
740         // Prepare to clear the current command line
741         //
742         CurrentString[0]  = 0;
743         Update  = 0;
744         Delete  = StringLen;
745         Row -= (StringCurPos + StartColumn) / TotalColumn;
746         Column        = StartColumn;
747         OutputLength  = 0;
748         break;
749 
750       case SCAN_INSERT:
751         //
752         // Toggle the SEnvInsertMode flag
753         //
754         ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;
755         break;
756 
757       case SCAN_F7:
758         //
759         // Print command history
760         //
761         PrintCommandHistory (TotalColumn, TotalRow, 4);
762         *CurrentString  = CHAR_NULL;
763         Done  = TRUE;
764         break;
765       }
766     }
767 
768     if (Done) {
769       break;
770     }
771 
772     //
773     // If we are in auto-complete mode, we are preparing to print
774     // the next file or directory name
775     //
776     if (InTabScrolling) {
777       TabOutputStr = AllocateZeroPool (*BufferSize);
778       if (TabOutputStr == NULL) {
779         Status = EFI_OUT_OF_RESOURCES;
780       }
781     }
782 
783     if (InTabScrolling && TabOutputStr != NULL) {
784 
785       //
786       // Adjust the column and row to the start of TAB-completion string.
787       //
788       Column = (StartColumn + TabUpdatePos) % TotalColumn;
789       Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
790       OutputLength = StrLen (TabCurrent->FileName);
791       //
792       // if the output string contains  blank space, quotation marks L'\"'
793       // should be added to the output.
794       //
795       if (StrStr(TabCurrent->FileName, L" ") != NULL){
796         TabOutputStr[0] = L'\"';
797         CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
798         TabOutputStr[OutputLength + 1] = L'\"';
799         TabOutputStr[OutputLength + 2] = CHAR_NULL;
800       } else {
801         CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));
802         TabOutputStr[OutputLength] = CHAR_NULL;
803       }
804       OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;
805       CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));
806       CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;
807       StringCurPos = TabUpdatePos + OutputLength;
808       Update = TabUpdatePos;
809       if (StringLen > TabUpdatePos + OutputLength) {
810         Delete = StringLen - TabUpdatePos - OutputLength;
811       }
812 
813       FreePool(TabOutputStr);
814     }
815 
816     //
817     // If we have a new position, we are preparing to print a previous or
818     // next command.
819     //
820     if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
821       Column = StartColumn;
822       Row -= (StringCurPos + StartColumn) / TotalColumn;
823 
824       LinePos       = NewPos;
825       NewPos        = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
826 
827       OutputLength  = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;
828       CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));
829       CurrentString[OutputLength] = CHAR_NULL;
830 
831       StringCurPos            = OutputLength;
832 
833       //
834       // Draw new input string
835       //
836       Update = 0;
837       if (StringLen > OutputLength) {
838         //
839         // If old string was longer, blank its tail
840         //
841         Delete = StringLen - OutputLength;
842       }
843     }
844     //
845     // If we need to update the output do so now
846     //
847     if (Update != (UINTN) -1) {
848       ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
849       StringLen = StrLen (CurrentString);
850 
851       if (Delete != 0) {
852         SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
853       }
854 
855       if (StringCurPos > StringLen) {
856         StringCurPos = StringLen;
857       }
858 
859       Update = (UINTN) -1;
860 
861       //
862       // After using print to reflect newly updates, if we're not using
863       // BACKSPACE and DELETE, we need to move the cursor position forward,
864       // so adjust row and column here.
865       //
866       if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
867         //
868         // Calculate row and column of the tail of current string
869         //
870         TailRow     = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
871         TailColumn  = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
872 
873         //
874         // If the tail of string reaches screen end, screen rolls up, so if
875         // Row does not equal TailRow, Row should be decremented
876         //
877         // (if we are recalling commands using UPPER and DOWN key, and if the
878         // old command is too long to fit the screen, TailColumn must be 79.
879         //
880         if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
881           Row--;
882         }
883         //
884         // Calculate the cursor position after current operation. If cursor
885         // reaches line end, update both row and column, otherwise, only
886         // column will be changed.
887         //
888         if (Column + OutputLength >= TotalColumn) {
889           SkipLength = OutputLength - (TotalColumn - Column);
890 
891           Row += SkipLength / TotalColumn + 1;
892           if (Row > TotalRow - 1) {
893             Row = TotalRow - 1;
894           }
895 
896           Column = SkipLength % TotalColumn;
897         } else {
898           Column += OutputLength;
899         }
900       }
901 
902       Delete = 0;
903     }
904     //
905     // Set the cursor position for this key
906     //
907     gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
908   } while (!Done);
909 
910   if (CurrentString != NULL && StrLen(CurrentString) > 0) {
911     //
912     // add the line to the history buffer
913     //
914     AddLineToCommandHistory(CurrentString);
915   }
916 
917   //
918   // Return the data to the caller
919   //
920   *BufferSize = StringLen * sizeof (CHAR16);
921 
922   //
923   // if this was used it should be deallocated by now...
924   // prevent memory leaks...
925   //
926   if (TabCompleteList != NULL) {
927     ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);
928   }
929   ASSERT(TabCompleteList == NULL);
930 
931   return Status;
932 }
933 
934 //
935 // FILE style interfaces for StdIn/StdOut/StdErr
936 //
937 EFI_FILE_PROTOCOL FileInterfaceStdIn = {
938   EFI_FILE_REVISION,
939   FileInterfaceOpenNotFound,
940   FileInterfaceNopGeneric,
941   FileInterfaceNopGeneric,
942   FileInterfaceStdInRead,
943   FileInterfaceStdInWrite,
944   FileInterfaceNopGetPosition,
945   FileInterfaceNopSetPosition,
946   FileInterfaceNopGetInfo,
947   FileInterfaceNopSetInfo,
948   FileInterfaceNopGeneric
949 };
950 
951 EFI_FILE_PROTOCOL FileInterfaceStdOut = {
952   EFI_FILE_REVISION,
953   FileInterfaceOpenNotFound,
954   FileInterfaceNopGeneric,
955   FileInterfaceNopGeneric,
956   FileInterfaceStdOutRead,
957   FileInterfaceStdOutWrite,
958   FileInterfaceNopGetPosition,
959   FileInterfaceNopSetPosition,
960   FileInterfaceNopGetInfo,
961   FileInterfaceNopSetInfo,
962   FileInterfaceNopGeneric
963 };
964 
965 EFI_FILE_PROTOCOL FileInterfaceStdErr = {
966   EFI_FILE_REVISION,
967   FileInterfaceOpenNotFound,
968   FileInterfaceNopGeneric,
969   FileInterfaceNopGeneric,
970   FileInterfaceStdErrRead,
971   FileInterfaceStdErrWrite,
972   FileInterfaceNopGetPosition,
973   FileInterfaceNopSetPosition,
974   FileInterfaceNopGetInfo,
975   FileInterfaceNopSetInfo,
976   FileInterfaceNopGeneric
977 };
978 
979 EFI_FILE_PROTOCOL FileInterfaceNulFile = {
980   EFI_FILE_REVISION,
981   FileInterfaceOpenNotFound,
982   FileInterfaceNopGeneric,
983   FileInterfaceNopGeneric,
984   FileInterfaceNulRead,
985   FileInterfaceNulWrite,
986   FileInterfaceNopGetPosition,
987   FileInterfaceNopSetPosition,
988   FileInterfaceNopGetInfo,
989   FileInterfaceNopSetInfo,
990   FileInterfaceNopGeneric
991 };
992 
993 
994 
995 
996 //
997 // This is identical to EFI_FILE_PROTOCOL except for the additional member
998 // for the name.
999 //
1000 
1001 typedef struct {
1002   UINT64                Revision;
1003   EFI_FILE_OPEN         Open;
1004   EFI_FILE_CLOSE        Close;
1005   EFI_FILE_DELETE       Delete;
1006   EFI_FILE_READ         Read;
1007   EFI_FILE_WRITE        Write;
1008   EFI_FILE_GET_POSITION GetPosition;
1009   EFI_FILE_SET_POSITION SetPosition;
1010   EFI_FILE_GET_INFO     GetInfo;
1011   EFI_FILE_SET_INFO     SetInfo;
1012   EFI_FILE_FLUSH        Flush;
1013   CHAR16                Name[1];
1014 } EFI_FILE_PROTOCOL_ENVIRONMENT;
1015 //ANSI compliance helper to get size of the struct.
1016 #define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
1017 
1018 /**
1019   File style interface for Environment Variable (Close).
1020 
1021   Frees the memory for this object.
1022 
1023   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1024 
1025   @retval EFI_SUCCESS
1026 **/
1027 EFI_STATUS
1028 EFIAPI
FileInterfaceEnvClose(IN EFI_FILE_PROTOCOL * This)1029 FileInterfaceEnvClose(
1030   IN EFI_FILE_PROTOCOL *This
1031   )
1032 {
1033   VOID*       NewBuffer;
1034   UINTN       NewSize;
1035   EFI_STATUS  Status;
1036   BOOLEAN     Volatile;
1037   UINTN       TotalSize;
1038 
1039   //
1040   // Most if not all UEFI commands will have an '\r\n' at the end of any output.
1041   // Since the output was redirected to a variable, it does not make sense to
1042   // keep this.  So, before closing, strip the trailing '\r\n' from the variable
1043   // if it exists.
1044   //
1045   NewBuffer   = NULL;
1046   NewSize     = 0;
1047   TotalSize   = 0;
1048 
1049   Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);
1050   if (EFI_ERROR (Status)) {
1051     return Status;
1052   }
1053 
1054   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1055   if (Status == EFI_BUFFER_TOO_SMALL) {
1056     TotalSize = NewSize + sizeof (CHAR16);
1057     NewBuffer = AllocateZeroPool (TotalSize);
1058     if (NewBuffer == NULL) {
1059       return EFI_OUT_OF_RESOURCES;
1060     }
1061     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1062   }
1063 
1064   if (!EFI_ERROR(Status) && NewBuffer != NULL) {
1065 
1066     if (TotalSize / sizeof (CHAR16) >= 3) {
1067       if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) &&
1068            (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN)
1069          ) {
1070         ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;
1071         //
1072         // If the NewBuffer end with \r\n\0, We will replace '\r' by '\0' and then update TotalSize.
1073         //
1074         TotalSize -= sizeof(CHAR16) * 2;
1075       }
1076 
1077       if (Volatile) {
1078         Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
1079                    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1080                    TotalSize - sizeof (CHAR16),
1081                    NewBuffer
1082                    );
1083 
1084         if (!EFI_ERROR(Status)) {
1085           Status = ShellAddEnvVarToList (
1086                      ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1087                      NewBuffer,
1088                      TotalSize,
1089                      EFI_VARIABLE_BOOTSERVICE_ACCESS
1090                      );
1091         }
1092       } else {
1093         Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1094                    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1095                    TotalSize - sizeof (CHAR16),
1096                    NewBuffer
1097                    );
1098 
1099         if (!EFI_ERROR(Status)) {
1100           Status = ShellAddEnvVarToList (
1101                      ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1102                      NewBuffer,
1103                      TotalSize,
1104                      EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
1105                      );
1106         }
1107       }
1108     }
1109   }
1110 
1111   SHELL_FREE_NON_NULL(NewBuffer);
1112   FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);
1113   return (Status);
1114 }
1115 
1116 /**
1117   File style interface for Environment Variable (Delete).
1118 
1119   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1120 
1121   @retval The return value from FileInterfaceEnvClose().
1122 **/
1123 EFI_STATUS
1124 EFIAPI
FileInterfaceEnvDelete(IN EFI_FILE_PROTOCOL * This)1125 FileInterfaceEnvDelete(
1126   IN EFI_FILE_PROTOCOL *This
1127   )
1128 {
1129   SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
1130   return (FileInterfaceEnvClose(This));
1131 }
1132 
1133 /**
1134   File style interface for Environment Variable (Read).
1135 
1136   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1137   @param[in, out] BufferSize   Size in bytes of Buffer.
1138   @param[out] Buffer           The pointer to the buffer to fill.
1139 
1140   @retval EFI_SUCCESS   The data was read.
1141 **/
1142 EFI_STATUS
1143 EFIAPI
FileInterfaceEnvRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)1144 FileInterfaceEnvRead(
1145   IN     EFI_FILE_PROTOCOL *This,
1146   IN OUT UINTN             *BufferSize,
1147   OUT    VOID              *Buffer
1148   )
1149 {
1150   EFI_STATUS     Status;
1151 
1152   *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
1153   if (*BufferSize != 0) {
1154     //
1155     // Make sure the first unicode character is \xFEFF
1156     //
1157     *(CHAR16 *)Buffer = gUnicodeFileTag;
1158     Buffer            = (CHAR16 *)Buffer + 1;
1159     *BufferSize      -= sizeof (gUnicodeFileTag);
1160   }
1161 
1162   Status = SHELL_GET_ENVIRONMENT_VARIABLE (
1163              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1164              BufferSize,
1165              Buffer
1166              );
1167   if (!EFI_ERROR (Status) || (Status == EFI_BUFFER_TOO_SMALL)) {
1168     //
1169     // BufferSize is valid and needs update when Status is Success or BufferTooSmall.
1170     //
1171     *BufferSize += sizeof (gUnicodeFileTag);
1172   }
1173   return Status;
1174 }
1175 
1176 /**
1177   File style interface for Volatile Environment Variable (Write).
1178   This function also caches the environment variable into gShellEnvVarList.
1179 
1180   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1181   @param[in, out] BufferSize   Size in bytes of Buffer.
1182   @param[in] Buffer            The pointer to the buffer to write.
1183 
1184   @retval EFI_SUCCESS             The data was successfully write to variable.
1185   @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.
1186 **/
1187 EFI_STATUS
1188 EFIAPI
FileInterfaceEnvVolWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)1189 FileInterfaceEnvVolWrite(
1190   IN EFI_FILE_PROTOCOL *This,
1191   IN OUT UINTN *BufferSize,
1192   IN VOID *Buffer
1193   )
1194 {
1195   VOID*       NewBuffer;
1196   UINTN       NewSize;
1197   EFI_STATUS  Status;
1198   UINTN       TotalSize;
1199 
1200   NewBuffer   = NULL;
1201   NewSize     = 0;
1202   TotalSize   = 0;
1203 
1204   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1205   if (Status == EFI_BUFFER_TOO_SMALL) {
1206     TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
1207   } else if (Status == EFI_NOT_FOUND) {
1208     TotalSize = *BufferSize + sizeof(CHAR16);
1209   } else {
1210     return Status;
1211   }
1212 
1213   NewBuffer = AllocateZeroPool (TotalSize);
1214   if (NewBuffer == NULL) {
1215     return EFI_OUT_OF_RESOURCES;
1216   }
1217 
1218   if (Status == EFI_BUFFER_TOO_SMALL) {
1219     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1220   }
1221 
1222   if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
1223     FreePool (NewBuffer);
1224     return Status;
1225   }
1226 
1227   CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
1228   Status = ShellAddEnvVarToList (
1229              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1230              NewBuffer,
1231              TotalSize,
1232              EFI_VARIABLE_BOOTSERVICE_ACCESS
1233              );
1234   if (EFI_ERROR(Status)) {
1235     FreePool (NewBuffer);
1236     return Status;
1237   }
1238 
1239   Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (
1240              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1241              TotalSize - sizeof (CHAR16),
1242              NewBuffer
1243              );
1244   if (EFI_ERROR(Status)) {
1245     ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
1246   }
1247 
1248   FreePool (NewBuffer);
1249   return Status;
1250 }
1251 
1252 
1253 /**
1254   File style interface for Non Volatile Environment Variable (Write).
1255   This function also caches the environment variable into gShellEnvVarList.
1256 
1257   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1258   @param[in, out] BufferSize   Size in bytes of Buffer.
1259   @param[in] Buffer            The pointer to the buffer to write.
1260 
1261   @retval EFI_SUCCESS             The data was successfully write to variable.
1262   @retval SHELL_OUT_OF_RESOURCES  A memory allocation failed.
1263 **/
1264 EFI_STATUS
1265 EFIAPI
FileInterfaceEnvNonVolWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)1266 FileInterfaceEnvNonVolWrite(
1267   IN EFI_FILE_PROTOCOL *This,
1268   IN OUT UINTN *BufferSize,
1269   IN VOID *Buffer
1270   )
1271 {
1272   VOID*       NewBuffer;
1273   UINTN       NewSize;
1274   EFI_STATUS  Status;
1275   UINTN       TotalSize;
1276 
1277   NewBuffer   = NULL;
1278   NewSize     = 0;
1279   TotalSize   = 0;
1280 
1281   Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1282   if (Status == EFI_BUFFER_TOO_SMALL) {
1283     TotalSize = NewSize + *BufferSize + sizeof (CHAR16);
1284   } else if (Status == EFI_NOT_FOUND) {
1285     TotalSize = *BufferSize + sizeof (CHAR16);
1286   } else {
1287     return Status;
1288   }
1289 
1290   NewBuffer = AllocateZeroPool (TotalSize);
1291   if (NewBuffer == NULL) {
1292     return EFI_OUT_OF_RESOURCES;
1293   }
1294 
1295   if (Status == EFI_BUFFER_TOO_SMALL) {
1296     Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1297   }
1298 
1299   if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {
1300     FreePool (NewBuffer);
1301     return Status;
1302   }
1303 
1304   CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize);
1305   Status = ShellAddEnvVarToList (
1306              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1307              NewBuffer,
1308              TotalSize,
1309              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
1310              );
1311   if (EFI_ERROR (Status)) {
1312     FreePool (NewBuffer);
1313     return Status;
1314   }
1315 
1316   Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (
1317              ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1318              TotalSize - sizeof (CHAR16),
1319              NewBuffer
1320              );
1321   if (EFI_ERROR (Status)) {
1322     ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
1323   }
1324 
1325   FreePool (NewBuffer);
1326   return Status;
1327 }
1328 
1329 /**
1330   Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1331   environment variables through file operations.
1332 
1333   @param EnvName    The name of the Environment Variable to be operated on.
1334 
1335   @retval NULL      Memory could not be allocated.
1336   @return other     a pointer to an EFI_FILE_PROTOCOL structure
1337 **/
1338 EFI_FILE_PROTOCOL*
CreateFileInterfaceEnv(IN CONST CHAR16 * EnvName)1339 CreateFileInterfaceEnv(
1340   IN CONST CHAR16 *EnvName
1341   )
1342 {
1343   EFI_STATUS                     Status;
1344   EFI_FILE_PROTOCOL_ENVIRONMENT  *EnvFileInterface;
1345   UINTN                          EnvNameSize;
1346   BOOLEAN                        Volatile;
1347 
1348   if (EnvName == NULL) {
1349     return (NULL);
1350   }
1351 
1352   Status = IsVolatileEnv (EnvName, &Volatile);
1353   if (EFI_ERROR (Status)) {
1354     return NULL;
1355   }
1356 
1357   //
1358   // Get some memory
1359   //
1360   EnvNameSize = StrSize(EnvName);
1361   EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);
1362   if (EnvFileInterface == NULL){
1363     return (NULL);
1364   }
1365 
1366   //
1367   // Assign the generic members
1368   //
1369   EnvFileInterface->Revision    = EFI_FILE_REVISION;
1370   EnvFileInterface->Open        = FileInterfaceOpenNotFound;
1371   EnvFileInterface->Close       = FileInterfaceEnvClose;
1372   EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;
1373   EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;
1374   EnvFileInterface->GetInfo     = FileInterfaceNopGetInfo;
1375   EnvFileInterface->SetInfo     = FileInterfaceNopSetInfo;
1376   EnvFileInterface->Flush       = FileInterfaceNopGeneric;
1377   EnvFileInterface->Delete      = FileInterfaceEnvDelete;
1378   EnvFileInterface->Read        = FileInterfaceEnvRead;
1379 
1380   CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);
1381 
1382   //
1383   // Assign the different members for Volatile and Non-Volatile variables
1384   //
1385   if (Volatile) {
1386     EnvFileInterface->Write       = FileInterfaceEnvVolWrite;
1387   } else {
1388     EnvFileInterface->Write       = FileInterfaceEnvNonVolWrite;
1389   }
1390   return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
1391 }
1392 
1393 /**
1394   Move the cursor position one character backward.
1395 
1396   @param[in] LineLength       Length of a line. Get it by calling QueryMode
1397   @param[in, out] Column      Current column of the cursor position
1398   @param[in, out] Row         Current row of the cursor position
1399 **/
1400 VOID
MoveCursorBackward(IN UINTN LineLength,IN OUT UINTN * Column,IN OUT UINTN * Row)1401 MoveCursorBackward (
1402   IN     UINTN                   LineLength,
1403   IN OUT UINTN                   *Column,
1404   IN OUT UINTN                   *Row
1405   )
1406 {
1407   //
1408   // If current column is 0, move to the last column of the previous line,
1409   // otherwise, just decrement column.
1410   //
1411   if (*Column == 0) {
1412     *Column = LineLength - 1;
1413     if (*Row > 0) {
1414       (*Row)--;
1415     }
1416     return;
1417   }
1418   (*Column)--;
1419 }
1420 
1421 /**
1422   Move the cursor position one character forward.
1423 
1424   @param[in] LineLength       Length of a line.
1425   @param[in] TotalRow         Total row of a screen
1426   @param[in, out] Column      Current column of the cursor position
1427   @param[in, out] Row         Current row of the cursor position
1428 **/
1429 VOID
MoveCursorForward(IN UINTN LineLength,IN UINTN TotalRow,IN OUT UINTN * Column,IN OUT UINTN * Row)1430 MoveCursorForward (
1431   IN     UINTN                   LineLength,
1432   IN     UINTN                   TotalRow,
1433   IN OUT UINTN                   *Column,
1434   IN OUT UINTN                   *Row
1435   )
1436 {
1437   //
1438   // Increment Column.
1439   // If this puts column past the end of the line, move to first column
1440   // of the next row.
1441   //
1442   (*Column)++;
1443   if (*Column >= LineLength) {
1444     (*Column) = 0;
1445     if ((*Row) < TotalRow - 1) {
1446       (*Row)++;
1447     }
1448   }
1449 }
1450 
1451 /**
1452   Prints out each previously typed command in the command list history log.
1453 
1454   When each screen is full it will pause for a key before continuing.
1455 
1456   @param[in] TotalCols    How many columns are on the screen
1457   @param[in] TotalRows    How many rows are on the screen
1458   @param[in] StartColumn  which column to start at
1459 **/
1460 VOID
PrintCommandHistory(IN CONST UINTN TotalCols,IN CONST UINTN TotalRows,IN CONST UINTN StartColumn)1461 PrintCommandHistory (
1462   IN CONST UINTN TotalCols,
1463   IN CONST UINTN TotalRows,
1464   IN CONST UINTN StartColumn
1465   )
1466 {
1467   BUFFER_LIST     *Node;
1468   UINTN           Index;
1469   UINTN           LineNumber;
1470   UINTN           LineCount;
1471 
1472   ShellPrintEx (-1, -1, L"\n");
1473   Index       = 0;
1474   LineNumber  = 0;
1475   //
1476   // go through history list...
1477   //
1478   for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)
1479       ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1480       ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1481    ){
1482     Index++;
1483     LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
1484 
1485     if (LineNumber + LineCount >= TotalRows) {
1486       ShellPromptForResponseHii(
1487         ShellPromptResponseTypeEnterContinue,
1488         STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
1489         ShellInfoObject.HiiHandle,
1490         NULL
1491        );
1492       LineNumber = 0;
1493     }
1494     ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
1495     LineNumber += LineCount;
1496   }
1497 }
1498 
1499 
1500 
1501 
1502 
1503 
1504 //
1505 // This is identical to EFI_FILE_PROTOCOL except for the additional members
1506 // for the buffer, size, and position.
1507 //
1508 
1509 typedef struct {
1510   UINT64                Revision;
1511   EFI_FILE_OPEN         Open;
1512   EFI_FILE_CLOSE        Close;
1513   EFI_FILE_DELETE       Delete;
1514   EFI_FILE_READ         Read;
1515   EFI_FILE_WRITE        Write;
1516   EFI_FILE_GET_POSITION GetPosition;
1517   EFI_FILE_SET_POSITION SetPosition;
1518   EFI_FILE_GET_INFO     GetInfo;
1519   EFI_FILE_SET_INFO     SetInfo;
1520   EFI_FILE_FLUSH        Flush;
1521   VOID                  *Buffer;
1522   UINT64                Position;
1523   UINT64                BufferSize;
1524   BOOLEAN               Unicode;
1525   UINT64                FileSize;
1526 } EFI_FILE_PROTOCOL_MEM;
1527 
1528 /**
1529   File style interface for Mem (SetPosition).
1530 
1531   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1532   @param[out] Position  The position to set.
1533 
1534   @retval EFI_SUCCESS             The position was successfully changed.
1535   @retval EFI_INVALID_PARAMETER   The Position was invalid.
1536 **/
1537 EFI_STATUS
1538 EFIAPI
FileInterfaceMemSetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 Position)1539 FileInterfaceMemSetPosition(
1540   IN EFI_FILE_PROTOCOL *This,
1541   OUT UINT64 Position
1542   )
1543 {
1544   if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize) {
1545     ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;
1546     return (EFI_SUCCESS);
1547   } else {
1548     return (EFI_INVALID_PARAMETER);
1549   }
1550 }
1551 
1552 /**
1553   File style interface for Mem (GetPosition).
1554 
1555   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1556   @param[out] Position  The pointer to the position.
1557 
1558   @retval EFI_SUCCESS   The position was retrieved.
1559 **/
1560 EFI_STATUS
1561 EFIAPI
FileInterfaceMemGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)1562 FileInterfaceMemGetPosition(
1563   IN EFI_FILE_PROTOCOL *This,
1564   OUT UINT64 *Position
1565   )
1566 {
1567   *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;
1568   return (EFI_SUCCESS);
1569 }
1570 
1571 /**
1572   File style interface for Mem (GetInfo).
1573 
1574   @param  This            Protocol instance pointer.
1575   @param  InformationType Type of information to return in Buffer.
1576   @param  BufferSize      On input size of buffer, on output amount of data in buffer.
1577   @param  Buffer          The buffer to return data.
1578 
1579   @retval EFI_SUCCESS          Data was returned.
1580   @retval EFI_UNSUPPORT        InformationType is not supported.
1581   @retval EFI_NO_MEDIA         The device has no media.
1582   @retval EFI_DEVICE_ERROR     The device reported an error.
1583   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1584   @retval EFI_WRITE_PROTECTED  The device is write protected.
1585   @retval EFI_ACCESS_DENIED    The file was open for read only.
1586   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1587 
1588 **/
1589 EFI_STATUS
1590 EFIAPI
FileInterfaceMemGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)1591 FileInterfaceMemGetInfo(
1592   IN EFI_FILE_PROTOCOL        *This,
1593   IN EFI_GUID                 *InformationType,
1594   IN OUT UINTN                *BufferSize,
1595   OUT VOID                    *Buffer
1596   )
1597 {
1598   EFI_FILE_INFO               *FileInfo;
1599 
1600   if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
1601     if (*BufferSize < sizeof (EFI_FILE_INFO)) {
1602       *BufferSize = sizeof (EFI_FILE_INFO);
1603       return EFI_BUFFER_TOO_SMALL;
1604     }
1605     if (Buffer == NULL) {
1606       return EFI_INVALID_PARAMETER;
1607     }
1608     FileInfo = (EFI_FILE_INFO *)Buffer;
1609     FileInfo->Size = sizeof (*FileInfo);
1610     ZeroMem (FileInfo, sizeof (*FileInfo));
1611     FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize;
1612     FileInfo->PhysicalSize = FileInfo->FileSize;
1613     return EFI_SUCCESS;
1614   }
1615 
1616   return EFI_UNSUPPORTED;
1617 }
1618 
1619 /**
1620   File style interface for Mem (Write).
1621 
1622   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1623   @param[in, out] BufferSize   Size in bytes of Buffer.
1624   @param[in] Buffer            The pointer to the buffer to write.
1625 
1626   @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
1627   @retval EFI_SUCCESS          The data was written.
1628 **/
1629 EFI_STATUS
1630 EFIAPI
FileInterfaceMemWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)1631 FileInterfaceMemWrite(
1632   IN EFI_FILE_PROTOCOL *This,
1633   IN OUT UINTN *BufferSize,
1634   IN VOID *Buffer
1635   )
1636 {
1637   CHAR8                  *AsciiBuffer;
1638   EFI_FILE_PROTOCOL_MEM  *MemFile;
1639 
1640   MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
1641   if (MemFile->Unicode) {
1642     //
1643     // Unicode
1644     //
1645     if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {
1646       MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
1647       if (MemFile->Buffer == NULL){
1648         return EFI_OUT_OF_RESOURCES;
1649       }
1650       MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;
1651     }
1652     CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);
1653     MemFile->Position += (*BufferSize);
1654     MemFile->FileSize = MemFile->Position;
1655     return (EFI_SUCCESS);
1656   } else {
1657     //
1658     // Ascii
1659     //
1660     AsciiBuffer = AllocateZeroPool(*BufferSize);
1661     if (AsciiBuffer == NULL) {
1662       return (EFI_OUT_OF_RESOURCES);
1663     }
1664     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
1665     if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {
1666       MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);
1667       if (MemFile->Buffer == NULL){
1668         FreePool(AsciiBuffer);
1669         return EFI_OUT_OF_RESOURCES;
1670       }
1671       MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;
1672     }
1673     CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));
1674     MemFile->Position += (*BufferSize / sizeof(CHAR16));
1675     MemFile->FileSize = MemFile->Position;
1676     FreePool(AsciiBuffer);
1677     return (EFI_SUCCESS);
1678   }
1679 }
1680 
1681 /**
1682   File style interface for Mem (Read).
1683 
1684   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1685   @param[in, out] BufferSize   Size in bytes of Buffer.
1686   @param[in] Buffer            The pointer to the buffer to fill.
1687 
1688   @retval EFI_SUCCESS   The data was read.
1689 **/
1690 EFI_STATUS
1691 EFIAPI
FileInterfaceMemRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)1692 FileInterfaceMemRead(
1693   IN EFI_FILE_PROTOCOL *This,
1694   IN OUT UINTN *BufferSize,
1695   IN VOID *Buffer
1696   )
1697 {
1698   EFI_FILE_PROTOCOL_MEM  *MemFile;
1699 
1700   MemFile = (EFI_FILE_PROTOCOL_MEM *) This;
1701   if (*BufferSize > (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position))) {
1702     (*BufferSize) = (UINTN)((MemFile->FileSize) - (UINTN)(MemFile->Position));
1703   }
1704   CopyMem(Buffer, ((UINT8*)MemFile->Buffer) + MemFile->Position, (*BufferSize));
1705   MemFile->Position = MemFile->Position + (*BufferSize);
1706   return (EFI_SUCCESS);
1707 }
1708 
1709 /**
1710   File style interface for Mem (Close).
1711 
1712   Frees all memory associated with this object.
1713 
1714   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1715 
1716   @retval EFI_SUCCESS   The 'file' was closed.
1717 **/
1718 EFI_STATUS
1719 EFIAPI
FileInterfaceMemClose(IN EFI_FILE_PROTOCOL * This)1720 FileInterfaceMemClose(
1721   IN EFI_FILE_PROTOCOL *This
1722   )
1723 {
1724   SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);
1725   SHELL_FREE_NON_NULL(This);
1726   return (EFI_SUCCESS);
1727 }
1728 
1729 /**
1730   Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1731   a file entirely in memory through file operations.
1732 
1733   @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1734 
1735   @retval NULL      Memory could not be allocated.
1736   @return other     A pointer to an EFI_FILE_PROTOCOL structure.
1737 **/
1738 EFI_FILE_PROTOCOL*
CreateFileInterfaceMem(IN CONST BOOLEAN Unicode)1739 CreateFileInterfaceMem(
1740   IN CONST BOOLEAN Unicode
1741   )
1742 {
1743   EFI_FILE_PROTOCOL_MEM  *FileInterface;
1744 
1745   //
1746   // Get some memory
1747   //
1748   FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));
1749   if (FileInterface == NULL){
1750     return (NULL);
1751   }
1752 
1753   //
1754   // Assign the generic members
1755   //
1756   FileInterface->Revision    = EFI_FILE_REVISION;
1757   FileInterface->Open        = FileInterfaceOpenNotFound;
1758   FileInterface->Close       = FileInterfaceMemClose;
1759   FileInterface->GetPosition = FileInterfaceMemGetPosition;
1760   FileInterface->SetPosition = FileInterfaceMemSetPosition;
1761   FileInterface->GetInfo     = FileInterfaceMemGetInfo;
1762   FileInterface->SetInfo     = FileInterfaceNopSetInfo;
1763   FileInterface->Flush       = FileInterfaceNopGeneric;
1764   FileInterface->Delete      = FileInterfaceNopGeneric;
1765   FileInterface->Read        = FileInterfaceMemRead;
1766   FileInterface->Write       = FileInterfaceMemWrite;
1767   FileInterface->Unicode     = Unicode;
1768 
1769   ASSERT(FileInterface->Buffer      == NULL);
1770   ASSERT(FileInterface->BufferSize  == 0);
1771   ASSERT(FileInterface->Position    == 0);
1772 
1773   if (Unicode) {
1774     FileInterface->Buffer = AllocateZeroPool(sizeof(gUnicodeFileTag));
1775     if (FileInterface->Buffer == NULL) {
1776       FreePool (FileInterface);
1777       return NULL;
1778     }
1779     *((CHAR16 *) (FileInterface->Buffer)) = EFI_UNICODE_BYTE_ORDER_MARK;
1780     FileInterface->BufferSize = 2;
1781     FileInterface->Position = 2;
1782   }
1783 
1784   return ((EFI_FILE_PROTOCOL *)FileInterface);
1785 }
1786 
1787 typedef struct {
1788   UINT64                Revision;
1789   EFI_FILE_OPEN         Open;
1790   EFI_FILE_CLOSE        Close;
1791   EFI_FILE_DELETE       Delete;
1792   EFI_FILE_READ         Read;
1793   EFI_FILE_WRITE        Write;
1794   EFI_FILE_GET_POSITION GetPosition;
1795   EFI_FILE_SET_POSITION SetPosition;
1796   EFI_FILE_GET_INFO     GetInfo;
1797   EFI_FILE_SET_INFO     SetInfo;
1798   EFI_FILE_FLUSH        Flush;
1799   BOOLEAN               Unicode;
1800   EFI_FILE_PROTOCOL     *Orig;
1801 } EFI_FILE_PROTOCOL_FILE;
1802 
1803 /**
1804   Set a files current position
1805 
1806   @param  This            Protocol instance pointer.
1807   @param  Position        Byte position from the start of the file.
1808 
1809   @retval EFI_SUCCESS     Data was written.
1810   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
1811 
1812 **/
1813 EFI_STATUS
1814 EFIAPI
FileInterfaceFileSetPosition(IN EFI_FILE_PROTOCOL * This,IN UINT64 Position)1815 FileInterfaceFileSetPosition(
1816   IN EFI_FILE_PROTOCOL        *This,
1817   IN UINT64                   Position
1818   )
1819 {
1820   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
1821 }
1822 
1823 /**
1824   Get a file's current position
1825 
1826   @param  This            Protocol instance pointer.
1827   @param  Position        Byte position from the start of the file.
1828 
1829   @retval EFI_SUCCESS     Data was written.
1830   @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
1831 
1832 **/
1833 EFI_STATUS
1834 EFIAPI
FileInterfaceFileGetPosition(IN EFI_FILE_PROTOCOL * This,OUT UINT64 * Position)1835 FileInterfaceFileGetPosition(
1836   IN EFI_FILE_PROTOCOL        *This,
1837   OUT UINT64                  *Position
1838   )
1839 {
1840   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
1841 }
1842 
1843 /**
1844   Get information about a file.
1845 
1846   @param  This            Protocol instance pointer.
1847   @param  InformationType Type of information to return in Buffer.
1848   @param  BufferSize      On input size of buffer, on output amount of data in buffer.
1849   @param  Buffer          The buffer to return data.
1850 
1851   @retval EFI_SUCCESS          Data was returned.
1852   @retval EFI_UNSUPPORT        InformationType is not supported.
1853   @retval EFI_NO_MEDIA         The device has no media.
1854   @retval EFI_DEVICE_ERROR     The device reported an error.
1855   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1856   @retval EFI_WRITE_PROTECTED  The device is write protected.
1857   @retval EFI_ACCESS_DENIED    The file was open for read only.
1858   @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1859 
1860 **/
1861 EFI_STATUS
1862 EFIAPI
FileInterfaceFileGetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN OUT UINTN * BufferSize,OUT VOID * Buffer)1863 FileInterfaceFileGetInfo(
1864   IN EFI_FILE_PROTOCOL        *This,
1865   IN EFI_GUID                 *InformationType,
1866   IN OUT UINTN                *BufferSize,
1867   OUT VOID                    *Buffer
1868   )
1869 {
1870   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
1871 }
1872 
1873 /**
1874   Set information about a file
1875 
1876   @param  This            Protocol instance pointer.
1877   @param  InformationType Type of information in Buffer.
1878   @param  BufferSize      Size of buffer.
1879   @param  Buffer          The data to write.
1880 
1881   @retval EFI_SUCCESS          Data was returned.
1882   @retval EFI_UNSUPPORT        InformationType is not supported.
1883   @retval EFI_NO_MEDIA         The device has no media.
1884   @retval EFI_DEVICE_ERROR     The device reported an error.
1885   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1886   @retval EFI_WRITE_PROTECTED  The device is write protected.
1887   @retval EFI_ACCESS_DENIED    The file was open for read only.
1888 
1889 **/
1890 EFI_STATUS
1891 EFIAPI
FileInterfaceFileSetInfo(IN EFI_FILE_PROTOCOL * This,IN EFI_GUID * InformationType,IN UINTN BufferSize,IN VOID * Buffer)1892 FileInterfaceFileSetInfo(
1893   IN EFI_FILE_PROTOCOL        *This,
1894   IN EFI_GUID                 *InformationType,
1895   IN UINTN                    BufferSize,
1896   IN VOID                     *Buffer
1897   )
1898 {
1899   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
1900 }
1901 
1902 /**
1903   Flush data back for the file handle.
1904 
1905   @param  This Protocol instance pointer.
1906 
1907   @retval EFI_SUCCESS          Data was written.
1908   @retval EFI_UNSUPPORT        Writes to Open directory are not supported.
1909   @retval EFI_NO_MEDIA         The device has no media.
1910   @retval EFI_DEVICE_ERROR     The device reported an error.
1911   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1912   @retval EFI_WRITE_PROTECTED  The device is write protected.
1913   @retval EFI_ACCESS_DENIED    The file was open for read only.
1914   @retval EFI_VOLUME_FULL      The volume is full.
1915 
1916 **/
1917 EFI_STATUS
1918 EFIAPI
FileInterfaceFileFlush(IN EFI_FILE_PROTOCOL * This)1919 FileInterfaceFileFlush(
1920   IN EFI_FILE_PROTOCOL  *This
1921   )
1922 {
1923   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
1924 }
1925 
1926 /**
1927   Read data from the file.
1928 
1929   @param  This       Protocol instance pointer.
1930   @param  BufferSize On input size of buffer, on output amount of data in buffer.
1931   @param  Buffer     The buffer in which data is read.
1932 
1933   @retval EFI_SUCCESS          Data was read.
1934   @retval EFI_NO_MEDIA         The device has no media.
1935   @retval EFI_DEVICE_ERROR     The device reported an error.
1936   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1937   @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
1938 
1939 **/
1940 EFI_STATUS
1941 EFIAPI
FileInterfaceFileRead(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,OUT VOID * Buffer)1942 FileInterfaceFileRead(
1943   IN EFI_FILE_PROTOCOL        *This,
1944   IN OUT UINTN                *BufferSize,
1945   OUT VOID                    *Buffer
1946   )
1947 {
1948   EFI_STATUS  Status;
1949   UINT64      Position;
1950   CHAR8       *AsciiStrBuffer;
1951   CHAR16      *UscStrBuffer;
1952   UINTN       Size;
1953   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
1954     //
1955     // Unicode
1956     // There might be different file tag for the Unicode file. We cannot unconditionally insert the \xFEFF.
1957     // So we choose to leave the file content as is.
1958     //
1959     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
1960   } else {
1961     //
1962     // Ascii
1963     //
1964     *BufferSize = *BufferSize / sizeof (CHAR16) * sizeof (CHAR16);
1965     if (*BufferSize == 0) {
1966       return EFI_SUCCESS;
1967     }
1968     Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Position);
1969     if (EFI_ERROR (Status)) {
1970       return Status;
1971     }
1972     if (Position == 0) {
1973       //
1974       // First two bytes in Buffer is for the Unicode file tag.
1975       //
1976       *(CHAR16 *)Buffer = gUnicodeFileTag;
1977       Buffer = (CHAR16 *)Buffer + 1;
1978       Size   = *BufferSize / sizeof (CHAR16) - 1;
1979     } else {
1980       Size   = *BufferSize / sizeof (CHAR16);
1981     }
1982     AsciiStrBuffer = AllocateZeroPool (Size + 1);
1983     if (AsciiStrBuffer == NULL) {
1984       return EFI_OUT_OF_RESOURCES;
1985     }
1986     UscStrBuffer = AllocateZeroPool ((Size + 1) * sizeof(CHAR16));
1987     if (UscStrBuffer== NULL) {
1988       SHELL_FREE_NON_NULL(AsciiStrBuffer);
1989       return EFI_OUT_OF_RESOURCES;
1990     }
1991     Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read (((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiStrBuffer);
1992     if (!EFI_ERROR(Status)) {
1993       AsciiStrToUnicodeStrS (AsciiStrBuffer, UscStrBuffer, Size + 1);
1994       *BufferSize = Size * sizeof (CHAR16);
1995       CopyMem (Buffer, UscStrBuffer, *BufferSize);
1996     }
1997     SHELL_FREE_NON_NULL (AsciiStrBuffer);
1998     SHELL_FREE_NON_NULL (UscStrBuffer);
1999     return Status;
2000   }
2001 }
2002 
2003 /**
2004   Opens a new file relative to the source file's location.
2005 
2006   @param[in]  This       The protocol instance pointer.
2007   @param[out]  NewHandle Returns File Handle for FileName.
2008   @param[in]  FileName   Null terminated string. "\", ".", and ".." are supported.
2009   @param[in]  OpenMode   Open mode for file.
2010   @param[in]  Attributes Only used for EFI_FILE_MODE_CREATE.
2011 
2012   @retval EFI_SUCCESS          The device was opened.
2013   @retval EFI_NOT_FOUND        The specified file could not be found on the device.
2014   @retval EFI_NO_MEDIA         The device has no media.
2015   @retval EFI_MEDIA_CHANGED    The media has changed.
2016   @retval EFI_DEVICE_ERROR     The device reported an error.
2017   @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
2018   @retval EFI_ACCESS_DENIED    The service denied access to the file.
2019   @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
2020   @retval EFI_VOLUME_FULL      The volume is full.
2021 **/
2022 EFI_STATUS
2023 EFIAPI
FileInterfaceFileOpen(IN EFI_FILE_PROTOCOL * This,OUT EFI_FILE_PROTOCOL ** NewHandle,IN CHAR16 * FileName,IN UINT64 OpenMode,IN UINT64 Attributes)2024 FileInterfaceFileOpen (
2025   IN EFI_FILE_PROTOCOL        *This,
2026   OUT EFI_FILE_PROTOCOL       **NewHandle,
2027   IN CHAR16                   *FileName,
2028   IN UINT64                   OpenMode,
2029   IN UINT64                   Attributes
2030   )
2031 {
2032   return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);
2033 }
2034 
2035 /**
2036   Close and delete the file handle.
2037 
2038   @param  This                     Protocol instance pointer.
2039 
2040   @retval EFI_SUCCESS              The device was opened.
2041   @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
2042 
2043 **/
2044 EFI_STATUS
2045 EFIAPI
FileInterfaceFileDelete(IN EFI_FILE_PROTOCOL * This)2046 FileInterfaceFileDelete(
2047   IN EFI_FILE_PROTOCOL  *This
2048   )
2049 {
2050   EFI_STATUS Status;
2051   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
2052   FreePool(This);
2053   return (Status);
2054 }
2055 
2056 /**
2057   File style interface for File (Close).
2058 
2059   @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
2060 
2061   @retval EFI_SUCCESS   The file was closed.
2062 **/
2063 EFI_STATUS
2064 EFIAPI
FileInterfaceFileClose(IN EFI_FILE_PROTOCOL * This)2065 FileInterfaceFileClose(
2066   IN EFI_FILE_PROTOCOL *This
2067   )
2068 {
2069   EFI_STATUS Status;
2070   Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
2071   FreePool(This);
2072   return (Status);
2073 }
2074 
2075 /**
2076   File style interface for File (Write).
2077 
2078   If the file was opened with ASCII mode the data will be processed through
2079   AsciiSPrint before writing.
2080 
2081   @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
2082   @param[in, out] BufferSize   Size in bytes of Buffer.
2083   @param[in] Buffer            The pointer to the buffer to write.
2084 
2085   @retval EFI_SUCCESS   The data was written.
2086 **/
2087 EFI_STATUS
2088 EFIAPI
FileInterfaceFileWrite(IN EFI_FILE_PROTOCOL * This,IN OUT UINTN * BufferSize,IN VOID * Buffer)2089 FileInterfaceFileWrite(
2090   IN     EFI_FILE_PROTOCOL  *This,
2091   IN OUT UINTN              *BufferSize,
2092   IN     VOID               *Buffer
2093   )
2094 {
2095   CHAR8       *AsciiBuffer;
2096   UINTN       Size;
2097   EFI_STATUS  Status;
2098   if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
2099     //
2100     // Unicode
2101     //
2102     return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
2103   } else {
2104     //
2105     // Ascii
2106     //
2107     AsciiBuffer = AllocateZeroPool(*BufferSize);
2108     AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
2109     Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)
2110     Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
2111     FreePool(AsciiBuffer);
2112     return (Status);
2113   }
2114 }
2115 
2116 /**
2117   Create a file interface with unicode information.
2118 
2119   This will create a new EFI_FILE_PROTOCOL identical to the Templace
2120   except that the new one has Unicode and Ascii knowledge.
2121 
2122   @param[in] Template   A pointer to the EFI_FILE_PROTOCOL object.
2123   @param[in] Unicode    TRUE for UCS-2, FALSE for ASCII.
2124 
2125   @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
2126 **/
2127 EFI_FILE_PROTOCOL*
CreateFileInterfaceFile(IN CONST EFI_FILE_PROTOCOL * Template,IN CONST BOOLEAN Unicode)2128 CreateFileInterfaceFile(
2129   IN CONST EFI_FILE_PROTOCOL  *Template,
2130   IN CONST BOOLEAN            Unicode
2131   )
2132 {
2133   EFI_FILE_PROTOCOL_FILE *NewOne;
2134 
2135   NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));
2136   if (NewOne == NULL) {
2137     return (NULL);
2138   }
2139   CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));
2140   NewOne->Orig        = (EFI_FILE_PROTOCOL *)Template;
2141   NewOne->Unicode     = Unicode;
2142   NewOne->Open        = FileInterfaceFileOpen;
2143   NewOne->Close       = FileInterfaceFileClose;
2144   NewOne->Delete      = FileInterfaceFileDelete;
2145   NewOne->Read        = FileInterfaceFileRead;
2146   NewOne->Write       = FileInterfaceFileWrite;
2147   NewOne->GetPosition = FileInterfaceFileGetPosition;
2148   NewOne->SetPosition = FileInterfaceFileSetPosition;
2149   NewOne->GetInfo     = FileInterfaceFileGetInfo;
2150   NewOne->SetInfo     = FileInterfaceFileSetInfo;
2151   NewOne->Flush       = FileInterfaceFileFlush;
2152 
2153   return ((EFI_FILE_PROTOCOL *)NewOne);
2154 }
2155