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