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