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