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