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