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