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