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