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