FileHandleWrappers.c revision 323d3d111843cb4fbdf4f9918f72d305e63bc091
1/** @file
2  EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables,
3  StdIn, StdOut, StdErr, etc...).
4
5  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6  Copyright (c) 2013, Hewlett-Packard Development Company, L.P.
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**/
31EFI_STATUS
32EFIAPI
33FileInterfaceOpenNotFound(
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**/
51EFI_STATUS
52EFIAPI
53FileInterfaceNopGeneric(
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**/
68EFI_STATUS
69EFIAPI
70FileInterfaceNopGetPosition(
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**/
86EFI_STATUS
87EFIAPI
88FileInterfaceNopSetPosition(
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**/
106EFI_STATUS
107EFIAPI
108FileInterfaceNopGetInfo(
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**/
128EFI_STATUS
129EFIAPI
130FileInterfaceNopSetInfo(
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**/
152EFI_STATUS
153EFIAPI
154FileInterfaceStdOutWrite(
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**/
176EFI_STATUS
177EFIAPI
178FileInterfaceStdInWrite(
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**/
198EFI_STATUS
199EFIAPI
200FileInterfaceStdErrWrite(
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**/
218EFI_STATUS
219EFIAPI
220FileInterfaceStdOutRead(
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**/
238EFI_STATUS
239EFIAPI
240FileInterfaceStdErrRead(
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**/
258EFI_STATUS
259EFIAPI
260FileInterfaceNulRead(
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**/
279EFI_STATUS
280EFIAPI
281FileInterfaceNulWrite(
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**/
314EFI_STATUS
315EFIAPI
316FileInterfaceStdInRead(
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            StrnCpy(TabStr, Cwd, (*BufferSize)/sizeof(CHAR16) - 1);
513            if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {
514              TabStr[StrLen(TabStr)-1] = CHAR_NULL;
515            }
516            StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));
517          } else {
518            *TabStr = CHAR_NULL;
519            StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16));
520          }
521        } else {
522          StrnCpy(TabStr, CurrentString + TabPos, (*BufferSize)/sizeof(CHAR16) - 1);
523        }
524        StrnCat(TabStr, L"*", (*BufferSize)/sizeof(CHAR16) - 1 - StrLen(TabStr));
525        FoundFileList = NULL;
526        Status  = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);
527        for ( TempStr = CurrentString
528            ; *TempStr == L' '
529            ; TempStr++); // note the ';'... empty for loop
530        //
531        // make sure we have a list before we do anything more...
532        //
533        if (EFI_ERROR (Status) || FoundFileList == NULL) {
534          InTabScrolling = FALSE;
535          TabLinePos = NULL;
536          continue;
537        } else {
538          //
539          // enumerate through the list of files
540          //
541          for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))
542              ; !IsNull(&FoundFileList->Link, &TempPos->Link)
543              ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))
544             ){
545            //
546            // If "cd" is typed, only directory name will be auto-complete filled
547            // in either case . and .. will be removed.
548            //
549            if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&
550                (TempStr[1] == L'd' || TempStr[1] == L'D')
551               ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)
552                ||(StrCmp(TempPos->FileName, L".") == 0)
553                ||(StrCmp(TempPos->FileName, L"..") == 0)
554               )) || ((StrCmp(TempPos->FileName, L".") == 0)
555                ||(StrCmp(TempPos->FileName, L"..") == 0))){
556                TabLinePos = TempPos;
557                TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);
558                InternalFreeShellFileInfoNode(TabLinePos);
559            }
560          }
561          if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {
562            TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);
563            InTabScrolling = TRUE;
564          } else {
565            FreePool(FoundFileList);
566            FoundFileList = NULL;
567          }
568        }
569      }
570      break;
571
572    default:
573      if (Key.UnicodeChar >= ' ') {
574        //
575        // If we are at the buffer's end, drop the key
576        //
577        if (StringLen == MaxStr - 1 && (ShellInfoObject.ViewingSettings.InsertMode || StringCurPos == StringLen)) {
578          break;
579        }
580        //
581        // If in insert mode, make space by moving each other character 1
582        // space higher in the array
583        //
584        if (ShellInfoObject.ViewingSettings.InsertMode) {
585          CopyMem(CurrentString + StringCurPos + 1, CurrentString + StringCurPos, (StringLen - StringCurPos)*sizeof(CurrentString[0]));
586        }
587
588        CurrentString[StringCurPos] = Key.UnicodeChar;
589        Update      = StringCurPos;
590
591        StringCurPos += 1;
592        OutputLength = 1;
593      }
594      break;
595
596    case 0:
597      switch (Key.ScanCode) {
598      case SCAN_DELETE:
599        //
600        // Move characters behind current position one character forward
601        //
602        if (StringLen != 0) {
603          Update  = StringCurPos;
604          Delete  = 1;
605          CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos));
606        }
607        break;
608
609      case SCAN_UP:
610        //
611        // Prepare to print the previous command
612        //
613        NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
614        if (IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link)) {
615          NewPos = (BUFFER_LIST*)GetPreviousNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
616        }
617        break;
618
619      case SCAN_DOWN:
620        //
621        // Prepare to print the next command
622        //
623        NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
624        if (NewPos == (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
625          NewPos = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &LinePos->Link);
626        }
627        break;
628
629      case SCAN_LEFT:
630        //
631        // Adjust current cursor position
632        //
633        if (StringCurPos != 0) {
634          --StringCurPos;
635          MoveCursorBackward (TotalColumn, &Column, &Row);
636        }
637        break;
638
639      case SCAN_RIGHT:
640        //
641        // Adjust current cursor position
642        //
643        if (StringCurPos < StringLen) {
644          ++StringCurPos;
645          MoveCursorForward (TotalColumn, TotalRow, &Column, &Row);
646        }
647        break;
648
649      case SCAN_HOME:
650        //
651        // Move current cursor position to the beginning of the command line
652        //
653        Row -= (StringCurPos + StartColumn) / TotalColumn;
654        Column  = StartColumn;
655        StringCurPos  = 0;
656        break;
657
658      case SCAN_END:
659        //
660        // Move current cursor position to the end of the command line
661        //
662        TailRow       = Row + (StringLen - StringCurPos + Column) / TotalColumn;
663        TailColumn    = (StringLen - StringCurPos + Column) % TotalColumn;
664        Row           = TailRow;
665        Column        = TailColumn;
666        StringCurPos  = StringLen;
667        break;
668
669      case SCAN_ESC:
670        //
671        // Prepare to clear the current command line
672        //
673        CurrentString[0]  = 0;
674        Update  = 0;
675        Delete  = StringLen;
676        Row -= (StringCurPos + StartColumn) / TotalColumn;
677        Column        = StartColumn;
678        OutputLength  = 0;
679        break;
680
681      case SCAN_INSERT:
682        //
683        // Toggle the SEnvInsertMode flag
684        //
685        ShellInfoObject.ViewingSettings.InsertMode = (BOOLEAN)!ShellInfoObject.ViewingSettings.InsertMode;
686        break;
687
688      case SCAN_F7:
689        //
690        // Print command history
691        //
692        PrintCommandHistory (TotalColumn, TotalRow, 4);
693        *CurrentString  = CHAR_NULL;
694        Done  = TRUE;
695        break;
696      }
697    }
698
699    if (Done) {
700      break;
701    }
702
703    //
704    // If we are in auto-complete mode, we are preparing to print
705    // the next file or directory name
706    //
707    if (InTabScrolling) {
708      //
709      // Adjust the column and row to the start of TAB-completion string.
710      //
711      Column = (StartColumn + TabUpdatePos) % TotalColumn;
712      Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;
713      OutputLength = StrLen (TabLinePos->FileName);
714      //
715      // if the output string contains  blank space, quotation marks L'\"'
716      // should be added to the output.
717      //
718      if (StrStr(TabLinePos->FileName, L" ") != NULL){
719        TabOutputStr[0] = L'\"';
720        CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));
721        TabOutputStr[OutputLength + 1] = L'\"';
722        TabOutputStr[OutputLength + 2] = CHAR_NULL;
723      } else {
724        CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));
725        TabOutputStr[OutputLength] = CHAR_NULL;
726      }
727      OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;
728      CopyMem (CurrentString + TabUpdatePos, TabOutputStr, OutputLength * sizeof (CHAR16));
729      CurrentString[TabUpdatePos + OutputLength] = CHAR_NULL;
730      StringCurPos = TabUpdatePos + OutputLength;
731      Update = TabUpdatePos;
732      if (StringLen > TabUpdatePos + OutputLength) {
733        Delete = StringLen - TabUpdatePos - OutputLength;
734      }
735    }
736
737    //
738    // If we have a new position, we are preparing to print a previous or
739    // next command.
740    //
741    if (NewPos != (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory)) {
742      Column = StartColumn;
743      Row -= (StringCurPos + StartColumn) / TotalColumn;
744
745      LinePos       = NewPos;
746      NewPos        = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory);
747
748      OutputLength  = StrLen (LinePos->Buffer) < MaxStr - 1 ? StrLen (LinePos->Buffer) : MaxStr - 1;
749      CopyMem (CurrentString, LinePos->Buffer, OutputLength * sizeof (CHAR16));
750      CurrentString[OutputLength] = CHAR_NULL;
751
752      StringCurPos            = OutputLength;
753
754      //
755      // Draw new input string
756      //
757      Update = 0;
758      if (StringLen > OutputLength) {
759        //
760        // If old string was longer, blank its tail
761        //
762        Delete = StringLen - OutputLength;
763      }
764    }
765    //
766    // If we need to update the output do so now
767    //
768    if (Update != (UINTN) -1) {
769      ShellPrintEx ((INT32)Column, (INT32)Row, L"%s%.*s", CurrentString + Update, Delete, L"");
770      StringLen = StrLen (CurrentString);
771
772      if (Delete != 0) {
773        SetMem (CurrentString + StringLen, Delete * sizeof (CHAR16), CHAR_NULL);
774      }
775
776      if (StringCurPos > StringLen) {
777        StringCurPos = StringLen;
778      }
779
780      Update = (UINTN) -1;
781
782      //
783      // After using print to reflect newly updates, if we're not using
784      // BACKSPACE and DELETE, we need to move the cursor position forward,
785      // so adjust row and column here.
786      //
787      if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
788        //
789        // Calulate row and column of the tail of current string
790        //
791        TailRow     = Row + (StringLen - StringCurPos + Column + OutputLength) / TotalColumn;
792        TailColumn  = (StringLen - StringCurPos + Column + OutputLength) % TotalColumn;
793
794        //
795        // If the tail of string reaches screen end, screen rolls up, so if
796        // Row does not equal TailRow, Row should be decremented
797        //
798        // (if we are recalling commands using UPPER and DOWN key, and if the
799        // old command is too long to fit the screen, TailColumn must be 79.
800        //
801        if (TailColumn == 0 && TailRow >= TotalRow && Row != TailRow) {
802          Row--;
803        }
804        //
805        // Calculate the cursor position after current operation. If cursor
806        // reaches line end, update both row and column, otherwise, only
807        // column will be changed.
808        //
809        if (Column + OutputLength >= TotalColumn) {
810          SkipLength = OutputLength - (TotalColumn - Column);
811
812          Row += SkipLength / TotalColumn + 1;
813          if (Row > TotalRow - 1) {
814            Row = TotalRow - 1;
815          }
816
817          Column = SkipLength % TotalColumn;
818        } else {
819          Column += OutputLength;
820        }
821      }
822
823      Delete = 0;
824    }
825    //
826    // Set the cursor position for this key
827    //
828    gST->ConOut->SetCursorPosition (gST->ConOut, Column, Row);
829  } while (!Done);
830
831  if (CurrentString != NULL && StrLen(CurrentString) > 0) {
832    //
833    // add the line to the history buffer
834    //
835    AddLineToCommandHistory(CurrentString);
836  }
837
838  FreePool (TabStr);
839  FreePool (TabOutputStr);
840  //
841  // Return the data to the caller
842  //
843  *BufferSize = StringLen * sizeof (CHAR16);
844
845  //
846  // if this was used it should be deallocated by now...
847  // prevent memory leaks...
848  //
849  ASSERT(FoundFileList == NULL);
850
851  return Status;
852}
853
854//
855// FILE sytle interfaces for StdIn/StdOut/StdErr
856//
857EFI_FILE_PROTOCOL FileInterfaceStdIn = {
858  EFI_FILE_REVISION,
859  FileInterfaceOpenNotFound,
860  FileInterfaceNopGeneric,
861  FileInterfaceNopGeneric,
862  FileInterfaceStdInRead,
863  FileInterfaceStdInWrite,
864  FileInterfaceNopGetPosition,
865  FileInterfaceNopSetPosition,
866  FileInterfaceNopGetInfo,
867  FileInterfaceNopSetInfo,
868  FileInterfaceNopGeneric
869};
870
871EFI_FILE_PROTOCOL FileInterfaceStdOut = {
872  EFI_FILE_REVISION,
873  FileInterfaceOpenNotFound,
874  FileInterfaceNopGeneric,
875  FileInterfaceNopGeneric,
876  FileInterfaceStdOutRead,
877  FileInterfaceStdOutWrite,
878  FileInterfaceNopGetPosition,
879  FileInterfaceNopSetPosition,
880  FileInterfaceNopGetInfo,
881  FileInterfaceNopSetInfo,
882  FileInterfaceNopGeneric
883};
884
885EFI_FILE_PROTOCOL FileInterfaceStdErr = {
886  EFI_FILE_REVISION,
887  FileInterfaceOpenNotFound,
888  FileInterfaceNopGeneric,
889  FileInterfaceNopGeneric,
890  FileInterfaceStdErrRead,
891  FileInterfaceStdErrWrite,
892  FileInterfaceNopGetPosition,
893  FileInterfaceNopSetPosition,
894  FileInterfaceNopGetInfo,
895  FileInterfaceNopSetInfo,
896  FileInterfaceNopGeneric
897};
898
899EFI_FILE_PROTOCOL FileInterfaceNulFile = {
900  EFI_FILE_REVISION,
901  FileInterfaceOpenNotFound,
902  FileInterfaceNopGeneric,
903  FileInterfaceNopGeneric,
904  FileInterfaceNulRead,
905  FileInterfaceNulWrite,
906  FileInterfaceNopGetPosition,
907  FileInterfaceNopSetPosition,
908  FileInterfaceNopGetInfo,
909  FileInterfaceNopSetInfo,
910  FileInterfaceNopGeneric
911};
912
913
914
915
916//
917// This is identical to EFI_FILE_PROTOCOL except for the additional member
918// for the name.
919//
920
921typedef struct {
922  UINT64                Revision;
923  EFI_FILE_OPEN         Open;
924  EFI_FILE_CLOSE        Close;
925  EFI_FILE_DELETE       Delete;
926  EFI_FILE_READ         Read;
927  EFI_FILE_WRITE        Write;
928  EFI_FILE_GET_POSITION GetPosition;
929  EFI_FILE_SET_POSITION SetPosition;
930  EFI_FILE_GET_INFO     GetInfo;
931  EFI_FILE_SET_INFO     SetInfo;
932  EFI_FILE_FLUSH        Flush;
933  CHAR16                Name[1];
934} EFI_FILE_PROTOCOL_ENVIRONMENT;
935//ANSI compliance helper to get size of the struct.
936#define SIZE_OF_EFI_FILE_PROTOCOL_ENVIRONMENT EFI_FIELD_OFFSET (EFI_FILE_PROTOCOL_ENVIRONMENT, Name)
937
938/**
939  File style interface for Environment Variable (Close).
940
941  Frees the memory for this object.
942
943  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
944
945  @retval EFI_SUCCESS
946**/
947EFI_STATUS
948EFIAPI
949FileInterfaceEnvClose(
950  IN EFI_FILE_PROTOCOL *This
951  )
952{
953  VOID*       NewBuffer;
954  UINTN       NewSize;
955  EFI_STATUS  Status;
956
957  //
958  // Most if not all UEFI commands will have an '\r\n' at the end of any output.
959  // Since the output was redirected to a variable, it does not make sense to
960  // keep this.  So, before closing, strip the trailing '\r\n' from the variable
961  // if it exists.
962  //
963  NewBuffer   = NULL;
964  NewSize     = 0;
965
966  Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
967  if (Status == EFI_BUFFER_TOO_SMALL) {
968    NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));
969    if (NewBuffer == NULL) {
970      return EFI_OUT_OF_RESOURCES;
971    }
972    Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
973  }
974
975  if (!EFI_ERROR(Status) && NewBuffer != NULL) {
976
977    if (StrSize(NewBuffer) > 6)
978    {
979      if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED)
980           && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {
981        ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL;
982      }
983
984      if (IsVolatileEnv(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name)) {
985        Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
986      } else {
987        Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
988      }
989    }
990  }
991
992  SHELL_FREE_NON_NULL(NewBuffer);
993  FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);
994  return (Status);
995}
996
997/**
998  File style interface for Environment Variable (Delete).
999
1000  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1001
1002  @retval The return value from FileInterfaceEnvClose().
1003**/
1004EFI_STATUS
1005EFIAPI
1006FileInterfaceEnvDelete(
1007  IN EFI_FILE_PROTOCOL *This
1008  )
1009{
1010  SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);
1011  return (FileInterfaceEnvClose(This));
1012}
1013
1014/**
1015  File style interface for Environment Variable (Read).
1016
1017  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1018  @param[in, out] BufferSize   Size in bytes of Buffer.
1019  @param[out] Buffer           The pointer to the buffer to fill.
1020
1021  @retval EFI_SUCCESS   The data was read.
1022**/
1023EFI_STATUS
1024EFIAPI
1025FileInterfaceEnvRead(
1026  IN EFI_FILE_PROTOCOL *This,
1027  IN OUT UINTN *BufferSize,
1028  OUT VOID *Buffer
1029  )
1030{
1031  return (SHELL_GET_ENVIRONMENT_VARIABLE(
1032    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1033    BufferSize,
1034    Buffer));
1035}
1036
1037/**
1038  File style interface for Volatile Environment Variable (Write).
1039
1040  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1041  @param[in, out] BufferSize   Size in bytes of Buffer.
1042  @param[in] Buffer            The pointer to the buffer to write.
1043
1044  @retval EFI_SUCCESS   The data was read.
1045**/
1046EFI_STATUS
1047EFIAPI
1048FileInterfaceEnvVolWrite(
1049  IN EFI_FILE_PROTOCOL *This,
1050  IN OUT UINTN *BufferSize,
1051  IN VOID *Buffer
1052  )
1053{
1054  VOID*       NewBuffer;
1055  UINTN       NewSize;
1056  EFI_STATUS  Status;
1057
1058  NewBuffer   = NULL;
1059  NewSize     = 0;
1060
1061  Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1062  if (Status == EFI_BUFFER_TOO_SMALL){
1063    NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));
1064    Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1065  }
1066  if (!EFI_ERROR(Status) && NewBuffer != NULL) {
1067    while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {
1068      //
1069      // We want to overwrite the CHAR_NULL
1070      //
1071      NewSize -= 2;
1072    }
1073    CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);
1074    Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);
1075    FreePool(NewBuffer);
1076    return (Status);
1077  } else {
1078    SHELL_FREE_NON_NULL(NewBuffer);
1079    return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));
1080  }
1081}
1082
1083
1084/**
1085  File style interface for Non Volatile Environment Variable (Write).
1086
1087  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1088  @param[in, out] BufferSize   Size in bytes of Buffer.
1089  @param[in] Buffer            The pointer to the buffer to write.
1090
1091  @retval EFI_SUCCESS   The data was read.
1092**/
1093EFI_STATUS
1094EFIAPI
1095FileInterfaceEnvNonVolWrite(
1096  IN EFI_FILE_PROTOCOL *This,
1097  IN OUT UINTN *BufferSize,
1098  IN VOID *Buffer
1099  )
1100{
1101  VOID*       NewBuffer;
1102  UINTN       NewSize;
1103  EFI_STATUS  Status;
1104
1105  NewBuffer   = NULL;
1106  NewSize     = 0;
1107
1108  Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1109  if (Status == EFI_BUFFER_TOO_SMALL){
1110    NewBuffer = AllocateZeroPool(NewSize + *BufferSize);
1111    Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);
1112  }
1113  if (!EFI_ERROR(Status)) {
1114    CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);
1115    return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
1116    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1117    NewSize + *BufferSize,
1118    NewBuffer));
1119  } else {
1120    return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(
1121    ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,
1122    *BufferSize,
1123    Buffer));
1124  }
1125}
1126
1127/**
1128  Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1129  environment variables through file operations.
1130
1131  @param EnvName    The name of the Environment Variable to be operated on.
1132
1133  @retval NULL      Memory could not be allocated.
1134  @return other     a pointer to an EFI_FILE_PROTOCOL structure
1135**/
1136EFI_FILE_PROTOCOL*
1137EFIAPI
1138CreateFileInterfaceEnv(
1139  IN CONST CHAR16 *EnvName
1140  )
1141{
1142  EFI_FILE_PROTOCOL_ENVIRONMENT  *EnvFileInterface;
1143  UINTN                          EnvNameSize;
1144
1145  if (EnvName == NULL) {
1146    return (NULL);
1147  }
1148
1149  //
1150  // Get some memory
1151  //
1152  EnvNameSize = StrSize(EnvName);
1153  EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize);
1154  if (EnvFileInterface == NULL){
1155    return (NULL);
1156  }
1157
1158  //
1159  // Assign the generic members
1160  //
1161  EnvFileInterface->Revision    = EFI_FILE_REVISION;
1162  EnvFileInterface->Open        = FileInterfaceOpenNotFound;
1163  EnvFileInterface->Close       = FileInterfaceEnvClose;
1164  EnvFileInterface->GetPosition = FileInterfaceNopGetPosition;
1165  EnvFileInterface->SetPosition = FileInterfaceNopSetPosition;
1166  EnvFileInterface->GetInfo     = FileInterfaceNopGetInfo;
1167  EnvFileInterface->SetInfo     = FileInterfaceNopSetInfo;
1168  EnvFileInterface->Flush       = FileInterfaceNopGeneric;
1169  EnvFileInterface->Delete      = FileInterfaceEnvDelete;
1170  EnvFileInterface->Read        = FileInterfaceEnvRead;
1171
1172  CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);
1173
1174  //
1175  // Assign the different members for Volatile and Non-Volatile variables
1176  //
1177  if (IsVolatileEnv(EnvName)) {
1178    EnvFileInterface->Write       = FileInterfaceEnvVolWrite;
1179  } else {
1180    EnvFileInterface->Write       = FileInterfaceEnvNonVolWrite;
1181  }
1182  return ((EFI_FILE_PROTOCOL *)EnvFileInterface);
1183}
1184
1185/**
1186  Move the cursor position one character backward.
1187
1188  @param[in] LineLength       Length of a line. Get it by calling QueryMode
1189  @param[in, out] Column      Current column of the cursor position
1190  @param[in, out] Row         Current row of the cursor position
1191**/
1192VOID
1193EFIAPI
1194MoveCursorBackward (
1195  IN     UINTN                   LineLength,
1196  IN OUT UINTN                   *Column,
1197  IN OUT UINTN                   *Row
1198  )
1199{
1200  //
1201  // If current column is 0, move to the last column of the previous line,
1202  // otherwise, just decrement column.
1203  //
1204  if (*Column == 0) {
1205    *Column = LineLength - 1;
1206    if (*Row > 0) {
1207      (*Row)--;
1208    }
1209    return;
1210  }
1211  (*Column)--;
1212}
1213
1214/**
1215  Move the cursor position one character forward.
1216
1217  @param[in] LineLength       Length of a line.
1218  @param[in] TotalRow         Total row of a screen
1219  @param[in, out] Column      Current column of the cursor position
1220  @param[in, out] Row         Current row of the cursor position
1221**/
1222VOID
1223EFIAPI
1224MoveCursorForward (
1225  IN     UINTN                   LineLength,
1226  IN     UINTN                   TotalRow,
1227  IN OUT UINTN                   *Column,
1228  IN OUT UINTN                   *Row
1229  )
1230{
1231  //
1232  // Increment Column.
1233  // If this puts column past the end of the line, move to first column
1234  // of the next row.
1235  //
1236  (*Column)++;
1237  if (*Column >= LineLength) {
1238    (*Column) = 0;
1239    if ((*Row) < TotalRow - 1) {
1240      (*Row)++;
1241    }
1242  }
1243}
1244
1245/**
1246  Prints out each previously typed command in the command list history log.
1247
1248  When each screen is full it will pause for a key before continuing.
1249
1250  @param[in] TotalCols    How many columns are on the screen
1251  @param[in] TotalRows    How many rows are on the screen
1252  @param[in] StartColumn  which column to start at
1253**/
1254VOID
1255EFIAPI
1256PrintCommandHistory (
1257  IN CONST UINTN TotalCols,
1258  IN CONST UINTN TotalRows,
1259  IN CONST UINTN StartColumn
1260  )
1261{
1262  BUFFER_LIST     *Node;
1263  UINTN           Index;
1264  UINTN           LineNumber;
1265  UINTN           LineCount;
1266
1267  ShellPrintEx (-1, -1, L"\n");
1268  Index       = 0;
1269  LineNumber  = 0;
1270  //
1271  // go through history list...
1272  //
1273  for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)
1274      ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1275      ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link)
1276   ){
1277    Index++;
1278    LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1;
1279
1280    if (LineNumber + LineCount >= TotalRows) {
1281      ShellPromptForResponseHii(
1282        ShellPromptResponseTypeEnterContinue,
1283        STRING_TOKEN (STR_SHELL_ENTER_TO_CONT),
1284        ShellInfoObject.HiiHandle,
1285        NULL
1286       );
1287      LineNumber = 0;
1288    }
1289    ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer);
1290    LineNumber += LineCount;
1291  }
1292}
1293
1294
1295
1296
1297
1298
1299//
1300// This is identical to EFI_FILE_PROTOCOL except for the additional members
1301// for the buffer, size, and position.
1302//
1303
1304typedef struct {
1305  UINT64                Revision;
1306  EFI_FILE_OPEN         Open;
1307  EFI_FILE_CLOSE        Close;
1308  EFI_FILE_DELETE       Delete;
1309  EFI_FILE_READ         Read;
1310  EFI_FILE_WRITE        Write;
1311  EFI_FILE_GET_POSITION GetPosition;
1312  EFI_FILE_SET_POSITION SetPosition;
1313  EFI_FILE_GET_INFO     GetInfo;
1314  EFI_FILE_SET_INFO     SetInfo;
1315  EFI_FILE_FLUSH        Flush;
1316  VOID                  *Buffer;
1317  UINT64                Position;
1318  UINT64                BufferSize;
1319  BOOLEAN               Unicode;
1320} EFI_FILE_PROTOCOL_MEM;
1321
1322/**
1323  File style interface for Mem (SetPosition).
1324
1325  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1326  @param[out] Position  The position to set.
1327
1328  @retval EFI_SUCCESS             The position was successfully changed.
1329  @retval EFI_INVALID_PARAMETER   The Position was invalid.
1330**/
1331EFI_STATUS
1332EFIAPI
1333FileInterfaceMemSetPosition(
1334  IN EFI_FILE_PROTOCOL *This,
1335  OUT UINT64 Position
1336  )
1337{
1338  if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) {
1339    ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position;
1340    return (EFI_SUCCESS);
1341  } else {
1342    return (EFI_INVALID_PARAMETER);
1343  }
1344}
1345
1346/**
1347  File style interface for Mem (GetPosition).
1348
1349  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1350  @param[out] Position  The pointer to the position.
1351
1352  @retval EFI_SUCCESS   The position was retrieved.
1353**/
1354EFI_STATUS
1355EFIAPI
1356FileInterfaceMemGetPosition(
1357  IN EFI_FILE_PROTOCOL *This,
1358  OUT UINT64 *Position
1359  )
1360{
1361  *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position;
1362  return (EFI_SUCCESS);
1363}
1364
1365/**
1366  File style interface for Mem (Write).
1367
1368  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1369  @param[in, out] BufferSize   Size in bytes of Buffer.
1370  @param[in] Buffer            The pointer to the buffer to write.
1371
1372  @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.
1373  @retval EFI_SUCCESS          The data was written.
1374**/
1375EFI_STATUS
1376EFIAPI
1377FileInterfaceMemWrite(
1378  IN EFI_FILE_PROTOCOL *This,
1379  IN OUT UINTN *BufferSize,
1380  IN VOID *Buffer
1381  )
1382{
1383  CHAR8 *AsciiBuffer;
1384  if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) {
1385    //
1386    // Unicode
1387    //
1388    if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {
1389      ((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);
1390      ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10;
1391    }
1392    CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize);
1393    ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize);
1394    return (EFI_SUCCESS);
1395  } else {
1396    //
1397    // Ascii
1398    //
1399    AsciiBuffer = AllocateZeroPool(*BufferSize);
1400    if (AsciiBuffer == NULL) {
1401      return (EFI_OUT_OF_RESOURCES);
1402    }
1403    AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
1404    if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) {
1405      ((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);
1406      ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10;
1407    }
1408    CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));
1409    ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer);
1410    FreePool(AsciiBuffer);
1411    return (EFI_SUCCESS);
1412  }
1413}
1414
1415/**
1416  File style interface for Mem (Read).
1417
1418  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1419  @param[in, out] BufferSize   Size in bytes of Buffer.
1420  @param[in] Buffer            The pointer to the buffer to fill.
1421
1422  @retval EFI_SUCCESS   The data was read.
1423**/
1424EFI_STATUS
1425EFIAPI
1426FileInterfaceMemRead(
1427  IN EFI_FILE_PROTOCOL *This,
1428  IN OUT UINTN *BufferSize,
1429  IN VOID *Buffer
1430  )
1431{
1432  if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) {
1433    (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position));
1434  }
1435  CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize));
1436  ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize);
1437  return (EFI_SUCCESS);
1438}
1439
1440/**
1441  File style interface for Mem (Close).
1442
1443  Frees all memory associated with this object.
1444
1445  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1446
1447  @retval EFI_SUCCESS   The 'file' was closed.
1448**/
1449EFI_STATUS
1450EFIAPI
1451FileInterfaceMemClose(
1452  IN EFI_FILE_PROTOCOL *This
1453  )
1454{
1455  SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer);
1456  SHELL_FREE_NON_NULL(This);
1457  return (EFI_SUCCESS);
1458}
1459
1460/**
1461  Creates a EFI_FILE_PROTOCOL (almost) object for using to access
1462  a file entirely in memory through file operations.
1463
1464  @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii.
1465
1466  @retval NULL      Memory could not be allocated.
1467  @return other     A pointer to an EFI_FILE_PROTOCOL structure.
1468**/
1469EFI_FILE_PROTOCOL*
1470EFIAPI
1471CreateFileInterfaceMem(
1472  IN CONST BOOLEAN Unicode
1473  )
1474{
1475  EFI_FILE_PROTOCOL_MEM  *FileInterface;
1476
1477  //
1478  // Get some memory
1479  //
1480  FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM));
1481  if (FileInterface == NULL){
1482    return (NULL);
1483  }
1484
1485  //
1486  // Assign the generic members
1487  //
1488  FileInterface->Revision    = EFI_FILE_REVISION;
1489  FileInterface->Open        = FileInterfaceOpenNotFound;
1490  FileInterface->Close       = FileInterfaceMemClose;
1491  FileInterface->GetPosition = FileInterfaceMemGetPosition;
1492  FileInterface->SetPosition = FileInterfaceMemSetPosition;
1493  FileInterface->GetInfo     = FileInterfaceNopGetInfo;
1494  FileInterface->SetInfo     = FileInterfaceNopSetInfo;
1495  FileInterface->Flush       = FileInterfaceNopGeneric;
1496  FileInterface->Delete      = FileInterfaceNopGeneric;
1497  FileInterface->Read        = FileInterfaceMemRead;
1498  FileInterface->Write       = FileInterfaceMemWrite;
1499  FileInterface->Unicode     = Unicode;
1500
1501  ASSERT(FileInterface->Buffer      == NULL);
1502  ASSERT(FileInterface->BufferSize  == 0);
1503  ASSERT(FileInterface->Position    == 0);
1504
1505  return ((EFI_FILE_PROTOCOL *)FileInterface);
1506}
1507
1508typedef struct {
1509  UINT64                Revision;
1510  EFI_FILE_OPEN         Open;
1511  EFI_FILE_CLOSE        Close;
1512  EFI_FILE_DELETE       Delete;
1513  EFI_FILE_READ         Read;
1514  EFI_FILE_WRITE        Write;
1515  EFI_FILE_GET_POSITION GetPosition;
1516  EFI_FILE_SET_POSITION SetPosition;
1517  EFI_FILE_GET_INFO     GetInfo;
1518  EFI_FILE_SET_INFO     SetInfo;
1519  EFI_FILE_FLUSH        Flush;
1520  BOOLEAN               Unicode;
1521  EFI_FILE_PROTOCOL     *Orig;
1522} EFI_FILE_PROTOCOL_FILE;
1523
1524/**
1525  Set a files current position
1526
1527  @param  This            Protocol instance pointer.
1528  @param  Position        Byte position from the start of the file.
1529
1530  @retval EFI_SUCCESS     Data was written.
1531  @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
1532
1533**/
1534EFI_STATUS
1535EFIAPI
1536FileInterfaceFileSetPosition(
1537  IN EFI_FILE_PROTOCOL        *This,
1538  IN UINT64                   Position
1539  )
1540{
1541  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
1542}
1543
1544/**
1545  Get a file's current position
1546
1547  @param  This            Protocol instance pointer.
1548  @param  Position        Byte position from the start of the file.
1549
1550  @retval EFI_SUCCESS     Data was written.
1551  @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..
1552
1553**/
1554EFI_STATUS
1555EFIAPI
1556FileInterfaceFileGetPosition(
1557  IN EFI_FILE_PROTOCOL        *This,
1558  OUT UINT64                  *Position
1559  )
1560{
1561  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position);
1562}
1563
1564/**
1565  Get information about a file.
1566
1567  @param  This            Protocol instance pointer.
1568  @param  InformationType Type of information to return in Buffer.
1569  @param  BufferSize      On input size of buffer, on output amount of data in buffer.
1570  @param  Buffer          The buffer to return data.
1571
1572  @retval EFI_SUCCESS          Data was returned.
1573  @retval EFI_UNSUPPORT        InformationType is not supported.
1574  @retval EFI_NO_MEDIA         The device has no media.
1575  @retval EFI_DEVICE_ERROR     The device reported an error.
1576  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1577  @retval EFI_WRITE_PROTECTED  The device is write protected.
1578  @retval EFI_ACCESS_DENIED    The file was open for read only.
1579  @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.
1580
1581**/
1582EFI_STATUS
1583EFIAPI
1584FileInterfaceFileGetInfo(
1585  IN EFI_FILE_PROTOCOL        *This,
1586  IN EFI_GUID                 *InformationType,
1587  IN OUT UINTN                *BufferSize,
1588  OUT VOID                    *Buffer
1589  )
1590{
1591  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
1592}
1593
1594/**
1595  Set information about a file
1596
1597  @param  This            Protocol instance pointer.
1598  @param  InformationType Type of information in Buffer.
1599  @param  BufferSize      Size of buffer.
1600  @param  Buffer          The data to write.
1601
1602  @retval EFI_SUCCESS          Data was returned.
1603  @retval EFI_UNSUPPORT        InformationType is not supported.
1604  @retval EFI_NO_MEDIA         The device has no media.
1605  @retval EFI_DEVICE_ERROR     The device reported an error.
1606  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1607  @retval EFI_WRITE_PROTECTED  The device is write protected.
1608  @retval EFI_ACCESS_DENIED    The file was open for read only.
1609
1610**/
1611EFI_STATUS
1612EFIAPI
1613FileInterfaceFileSetInfo(
1614  IN EFI_FILE_PROTOCOL        *This,
1615  IN EFI_GUID                 *InformationType,
1616  IN UINTN                    BufferSize,
1617  IN VOID                     *Buffer
1618  )
1619{
1620  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer);
1621}
1622
1623/**
1624  Flush data back for the file handle.
1625
1626  @param  This Protocol instance pointer.
1627
1628  @retval EFI_SUCCESS          Data was written.
1629  @retval EFI_UNSUPPORT        Writes to Open directory are not supported.
1630  @retval EFI_NO_MEDIA         The device has no media.
1631  @retval EFI_DEVICE_ERROR     The device reported an error.
1632  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1633  @retval EFI_WRITE_PROTECTED  The device is write protected.
1634  @retval EFI_ACCESS_DENIED    The file was open for read only.
1635  @retval EFI_VOLUME_FULL      The volume is full.
1636
1637**/
1638EFI_STATUS
1639EFIAPI
1640FileInterfaceFileFlush(
1641  IN EFI_FILE_PROTOCOL  *This
1642  )
1643{
1644  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
1645}
1646
1647/**
1648  Read data from the file.
1649
1650  @param  This       Protocol instance pointer.
1651  @param  BufferSize On input size of buffer, on output amount of data in buffer.
1652  @param  Buffer     The buffer in which data is read.
1653
1654  @retval EFI_SUCCESS          Data was read.
1655  @retval EFI_NO_MEDIA         The device has no media.
1656  @retval EFI_DEVICE_ERROR     The device reported an error.
1657  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1658  @retval EFI_BUFFER_TO_SMALL  BufferSize is too small. BufferSize contains required size.
1659
1660**/
1661EFI_STATUS
1662EFIAPI
1663FileInterfaceFileRead(
1664  IN EFI_FILE_PROTOCOL        *This,
1665  IN OUT UINTN                *BufferSize,
1666  OUT VOID                    *Buffer
1667  )
1668{
1669  CHAR8       *AsciiBuffer;
1670  UINTN       Size;
1671  EFI_STATUS  Status;
1672  if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
1673    //
1674    // Unicode
1675    //
1676    return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
1677  } else {
1678    //
1679    // Ascii
1680    //
1681    AsciiBuffer = AllocateZeroPool((Size = *BufferSize));
1682    Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
1683    UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer);
1684    FreePool(AsciiBuffer);
1685    return (Status);
1686  }
1687}
1688
1689/**
1690  Opens a new file relative to the source file's location.
1691
1692  @param[in]  This       The protocol instance pointer.
1693  @param[out]  NewHandle Returns File Handle for FileName.
1694  @param[in]  FileName   Null terminated string. "\", ".", and ".." are supported.
1695  @param[in]  OpenMode   Open mode for file.
1696  @param[in]  Attributes Only used for EFI_FILE_MODE_CREATE.
1697
1698  @retval EFI_SUCCESS          The device was opened.
1699  @retval EFI_NOT_FOUND        The specified file could not be found on the device.
1700  @retval EFI_NO_MEDIA         The device has no media.
1701  @retval EFI_MEDIA_CHANGED    The media has changed.
1702  @retval EFI_DEVICE_ERROR     The device reported an error.
1703  @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1704  @retval EFI_ACCESS_DENIED    The service denied access to the file.
1705  @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources.
1706  @retval EFI_VOLUME_FULL      The volume is full.
1707**/
1708EFI_STATUS
1709EFIAPI
1710FileInterfaceFileOpen (
1711  IN EFI_FILE_PROTOCOL        *This,
1712  OUT EFI_FILE_PROTOCOL       **NewHandle,
1713  IN CHAR16                   *FileName,
1714  IN UINT64                   OpenMode,
1715  IN UINT64                   Attributes
1716  )
1717{
1718  return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes);
1719}
1720
1721/**
1722  Close and delete the file handle.
1723
1724  @param  This                     Protocol instance pointer.
1725
1726  @retval EFI_SUCCESS              The device was opened.
1727  @retval EFI_WARN_DELETE_FAILURE  The handle was closed but the file was not deleted.
1728
1729**/
1730EFI_STATUS
1731EFIAPI
1732FileInterfaceFileDelete(
1733  IN EFI_FILE_PROTOCOL  *This
1734  )
1735{
1736  EFI_STATUS Status;
1737  Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
1738  FreePool(This);
1739  return (Status);
1740}
1741
1742/**
1743  File style interface for File (Close).
1744
1745  @param[in] This       The pointer to the EFI_FILE_PROTOCOL object.
1746
1747  @retval EFI_SUCCESS   The file was closed.
1748**/
1749EFI_STATUS
1750EFIAPI
1751FileInterfaceFileClose(
1752  IN EFI_FILE_PROTOCOL *This
1753  )
1754{
1755  EFI_STATUS Status;
1756  Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig);
1757  FreePool(This);
1758  return (Status);
1759}
1760
1761/**
1762  File style interface for File (Write).
1763
1764  If the file was opened with ASCII mode the data will be processed through
1765  AsciiSPrint before writing.
1766
1767  @param[in] This              The pointer to the EFI_FILE_PROTOCOL object.
1768  @param[in, out] BufferSize   Size in bytes of Buffer.
1769  @param[in] Buffer            The pointer to the buffer to write.
1770
1771  @retval EFI_SUCCESS   The data was written.
1772**/
1773EFI_STATUS
1774EFIAPI
1775FileInterfaceFileWrite(
1776  IN     EFI_FILE_PROTOCOL  *This,
1777  IN OUT UINTN              *BufferSize,
1778  IN     VOID               *Buffer
1779  )
1780{
1781  CHAR8       *AsciiBuffer;
1782  UINTN       Size;
1783  EFI_STATUS  Status;
1784  if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) {
1785    //
1786    // Unicode
1787    //
1788    return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer));
1789  } else {
1790    //
1791    // Ascii
1792    //
1793    AsciiBuffer = AllocateZeroPool(*BufferSize);
1794    AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);
1795    Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator)
1796    Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer));
1797    FreePool(AsciiBuffer);
1798    return (Status);
1799  }
1800}
1801
1802/**
1803  Create a file interface with unicode information.
1804
1805  This will create a new EFI_FILE_PROTOCOL identical to the Templace
1806  except that the new one has Unicode and Ascii knowledge.
1807
1808  @param[in] Template   A pointer to the EFI_FILE_PROTOCOL object.
1809  @param[in] Unicode    TRUE for UCS-2, FALSE for ASCII.
1810
1811  @return a new EFI_FILE_PROTOCOL object to be used instead of the template.
1812**/
1813EFI_FILE_PROTOCOL*
1814CreateFileInterfaceFile(
1815  IN CONST EFI_FILE_PROTOCOL  *Template,
1816  IN CONST BOOLEAN            Unicode
1817  )
1818{
1819  EFI_FILE_PROTOCOL_FILE *NewOne;
1820
1821  NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE));
1822  if (NewOne == NULL) {
1823    return (NULL);
1824  }
1825  CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE));
1826  NewOne->Orig        = (EFI_FILE_PROTOCOL *)Template;
1827  NewOne->Unicode     = Unicode;
1828  NewOne->Open        = FileInterfaceFileOpen;
1829  NewOne->Close       = FileInterfaceFileClose;
1830  NewOne->Delete      = FileInterfaceFileDelete;
1831  NewOne->Read        = FileInterfaceFileRead;
1832  NewOne->Write       = FileInterfaceFileWrite;
1833  NewOne->GetPosition = FileInterfaceFileGetPosition;
1834  NewOne->SetPosition = FileInterfaceFileSetPosition;
1835  NewOne->GetInfo     = FileInterfaceFileGetInfo;
1836  NewOne->SetInfo     = FileInterfaceFileSetInfo;
1837  NewOne->Flush       = FileInterfaceFileFlush;
1838
1839  return ((EFI_FILE_PROTOCOL *)NewOne);
1840}
1841