FileHandleWrappers.c revision 4ff7e37b4f7e336a8ecb7080b8f48eef4b52d396
1/** @file 2 EFI_FILE_PROTOCOL wrappers for other items (Like Environment Variables, 3 StdIn, StdOut, StdErr, etc...). 4 5 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14**/ 15 16#include "Shell.h" 17#include "FileHandleInternal.h" 18 19/** 20 File style interface for console (Open). 21 22 @param[in] This Ignored. 23 @param[out] NewHandle Ignored. 24 @param[in] FileName Ignored. 25 @param[in] OpenMode Ignored. 26 @param[in] Attributes Ignored. 27 28 @retval EFI_NOT_FOUND 29**/ 30EFI_STATUS 31EFIAPI 32FileInterfaceOpenNotFound( 33 IN EFI_FILE_PROTOCOL *This, 34 OUT EFI_FILE_PROTOCOL **NewHandle, 35 IN CHAR16 *FileName, 36 IN UINT64 OpenMode, 37 IN UINT64 Attributes 38 ) 39{ 40 return (EFI_NOT_FOUND); 41} 42 43/** 44 File style interface for console (Close, Delete, & Flush) 45 46 @param[in] This Ignored. 47 48 @retval EFI_SUCCESS 49**/ 50EFI_STATUS 51EFIAPI 52FileInterfaceNopGeneric( 53 IN EFI_FILE_PROTOCOL *This 54 ) 55{ 56 return (EFI_SUCCESS); 57} 58 59/** 60 File style interface for console (GetPosition). 61 62 @param[in] This Ignored. 63 @param[out] Position Ignored. 64 65 @retval EFI_UNSUPPORTED 66**/ 67EFI_STATUS 68EFIAPI 69FileInterfaceNopGetPosition( 70 IN EFI_FILE_PROTOCOL *This, 71 OUT UINT64 *Position 72 ) 73{ 74 return (EFI_UNSUPPORTED); 75} 76 77/** 78 File style interface for console (SetPosition). 79 80 @param[in] This Ignored. 81 @param[in] Position Ignored. 82 83 @retval EFI_UNSUPPORTED 84**/ 85EFI_STATUS 86EFIAPI 87FileInterfaceNopSetPosition( 88 IN EFI_FILE_PROTOCOL *This, 89 IN UINT64 Position 90 ) 91{ 92 return (EFI_UNSUPPORTED); 93} 94 95/** 96 File style interface for console (GetInfo). 97 98 @param[in] This Ignored. 99 @param[in] InformationType Ignored. 100 @param[in, out] BufferSize Ignored. 101 @param[out] Buffer Ignored. 102 103 @retval EFI_UNSUPPORTED 104**/ 105EFI_STATUS 106EFIAPI 107FileInterfaceNopGetInfo( 108 IN EFI_FILE_PROTOCOL *This, 109 IN EFI_GUID *InformationType, 110 IN OUT UINTN *BufferSize, 111 OUT VOID *Buffer 112 ) 113{ 114 return (EFI_UNSUPPORTED); 115} 116 117/** 118 File style interface for console (SetInfo). 119 120 @param[in] This Ignored. 121 @param[in] InformationType Ignored. 122 @param[in] BufferSize Ignored. 123 @param[in] Buffer Ignored. 124 125 @retval EFI_UNSUPPORTED 126**/ 127EFI_STATUS 128EFIAPI 129FileInterfaceNopSetInfo( 130 IN EFI_FILE_PROTOCOL *This, 131 IN EFI_GUID *InformationType, 132 IN UINTN BufferSize, 133 IN VOID *Buffer 134 ) 135{ 136 return (EFI_UNSUPPORTED); 137} 138 139/** 140 File style interface for StdOut (Write). 141 142 Writes data to the screen. 143 144 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 145 @param[in, out] BufferSize Size in bytes of Buffer. 146 @param[in] Buffer The pointer to the buffer to write. 147 148 @retval EFI_UNSUPPORTED No output console is supported. 149 @return A return value from gST->ConOut->OutputString. 150**/ 151EFI_STATUS 152EFIAPI 153FileInterfaceStdOutWrite( 154 IN EFI_FILE_PROTOCOL *This, 155 IN OUT UINTN *BufferSize, 156 IN VOID *Buffer 157 ) 158{ 159 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) { 160 return (EFI_UNSUPPORTED); 161 } else { 162 return (gST->ConOut->OutputString(gST->ConOut, Buffer)); 163 } 164} 165 166/** 167 File style interface for StdIn (Write). 168 169 @param[in] This Ignored. 170 @param[in, out] BufferSize Ignored. 171 @param[in] Buffer Ignored. 172 173 @retval EFI_UNSUPPORTED 174**/ 175EFI_STATUS 176EFIAPI 177FileInterfaceStdInWrite( 178 IN EFI_FILE_PROTOCOL *This, 179 IN OUT UINTN *BufferSize, 180 IN VOID *Buffer 181 ) 182{ 183 return (EFI_UNSUPPORTED); 184} 185 186/** 187 File style interface for console StdErr (Write). 188 189 Writes error to the error output. 190 191 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 192 @param[in, out] BufferSize Size in bytes of Buffer. 193 @param[in] Buffer The pointer to the buffer to write. 194 195 @return A return value from gST->StdErr->OutputString. 196**/ 197EFI_STATUS 198EFIAPI 199FileInterfaceStdErrWrite( 200 IN EFI_FILE_PROTOCOL *This, 201 IN OUT UINTN *BufferSize, 202 IN VOID *Buffer 203 ) 204{ 205 return (gST->StdErr->OutputString(gST->StdErr, Buffer)); 206} 207 208/** 209 File style interface for console StdOut (Read). 210 211 @param[in] This Ignored. 212 @param[in, out] BufferSize Ignored. 213 @param[out] Buffer Ignored. 214 215 @retval EFI_UNSUPPORTED 216**/ 217EFI_STATUS 218EFIAPI 219FileInterfaceStdOutRead( 220 IN EFI_FILE_PROTOCOL *This, 221 IN OUT UINTN *BufferSize, 222 OUT VOID *Buffer 223 ) 224{ 225 return (EFI_UNSUPPORTED); 226} 227 228/** 229 File style interface for console StdErr (Read). 230 231 @param[in] This Ignored. 232 @param[in, out] BufferSize Ignored. 233 @param[out] Buffer Ignored. 234 235 @retval EFI_UNSUPPORTED Always. 236**/ 237EFI_STATUS 238EFIAPI 239FileInterfaceStdErrRead( 240 IN EFI_FILE_PROTOCOL *This, 241 IN OUT UINTN *BufferSize, 242 OUT VOID *Buffer 243 ) 244{ 245 return (EFI_UNSUPPORTED); 246} 247 248/** 249 File style interface for NUL file (Read). 250 251 @param[in] This Ignored. 252 @param[in, out] BufferSize Poiner to 0 upon return. 253 @param[out] Buffer Ignored. 254 255 @retval EFI_SUCCESS Always. 256**/ 257EFI_STATUS 258EFIAPI 259FileInterfaceNulRead( 260 IN EFI_FILE_PROTOCOL *This, 261 IN OUT UINTN *BufferSize, 262 OUT VOID *Buffer 263 ) 264{ 265 *BufferSize = 0; 266 return (EFI_SUCCESS); 267} 268 269/** 270 File style interface for NUL file (Write). 271 272 @param[in] This Ignored. 273 @param[in, out] BufferSize Ignored. 274 @param[in] Buffer Ignored. 275 276 @retval EFI_SUCCESS 277**/ 278EFI_STATUS 279EFIAPI 280FileInterfaceNulWrite( 281 IN EFI_FILE_PROTOCOL *This, 282 IN OUT UINTN *BufferSize, 283 IN VOID *Buffer 284 ) 285{ 286 return (EFI_SUCCESS); 287} 288 289/** 290 File style interface for console (Read). 291 292 This will return a single line of input from the console. 293 294 @param This A pointer to the EFI_FILE_PROTOCOL instance that is the 295 file handle to read data from. Not used. 296 @param BufferSize On input, the size of the Buffer. On output, the amount 297 of data returned in Buffer. In both cases, the size is 298 measured in bytes. 299 @param Buffer The buffer into which the data is read. 300 301 302 @retval EFI_SUCCESS The data was read. 303 @retval EFI_NO_MEDIA The device has no medium. 304 @retval EFI_DEVICE_ERROR The device reported an error. 305 @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. 306 @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. 307 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 308 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory 309 entry. BufferSize has been updated with the size 310 needed to complete the request. 311 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 312**/ 313EFI_STATUS 314EFIAPI 315FileInterfaceStdInRead( 316 IN EFI_FILE_PROTOCOL *This, 317 IN OUT UINTN *BufferSize, 318 OUT VOID *Buffer 319 ) 320{ 321 CHAR16 *CurrentString; 322 BOOLEAN Done; 323 UINTN Column; // Column of current cursor 324 UINTN Row; // Row of current cursor 325 UINTN StartColumn; // Column at the beginning of the line 326 UINTN Update; // Line index for update 327 UINTN Delete; // Num of chars to delete from console after update 328 UINTN StringLen; // Total length of the line 329 UINTN StringCurPos; // Line index corresponding to the cursor 330 UINTN MaxStr; // Maximum possible line length 331 UINTN Index; 332 UINTN TotalColumn; // Num of columns in the console 333 UINTN TotalRow; // Num of rows in the console 334 UINTN SkipLength; 335 UINTN OutputLength; // Length of the update string 336 UINTN TailRow; // Row of end of line 337 UINTN TailColumn; // Column of end of line 338 EFI_INPUT_KEY Key; 339 340 BUFFER_LIST *LinePos; 341 BUFFER_LIST *NewPos; 342 BOOLEAN InScrolling; 343 EFI_STATUS Status; 344 BOOLEAN InTabScrolling; // Whether in TAB-completion state 345 EFI_SHELL_FILE_INFO *FoundFileList; 346 EFI_SHELL_FILE_INFO *TabLinePos; 347 EFI_SHELL_FILE_INFO *TempPos; 348 CHAR16 *TabStr; 349 CHAR16 *TabOutputStr; 350 BOOLEAN InQuotationMode; 351 CHAR16 *TempStr; 352 UINTN TabPos; // Start index of the string to search for TAB completion. 353 UINTN TabUpdatePos; // Start index of the string updated by TAB stroke 354// UINTN Count; 355 UINTN EventIndex; 356 CONST CHAR16 *Cwd; 357 358 // 359 // If buffer is not large enough to hold a CHAR16, return minimum buffer size 360 // 361 if (*BufferSize < sizeof (CHAR16) * 2) { 362 *BufferSize = sizeof (CHAR16) * 2; 363 return (EFI_BUFFER_TOO_SMALL); 364 } 365 366 Done = FALSE; 367 CurrentString = Buffer; 368 StringLen = 0; 369 StringCurPos = 0; 370 OutputLength = 0; 371 Update = 0; 372 Delete = 0; 373 LinePos = NewPos = (BUFFER_LIST*)(&ShellInfoObject.ViewingSettings.CommandHistory); 374 InScrolling = FALSE; 375 InTabScrolling = FALSE; 376 Status = EFI_SUCCESS; 377 TabLinePos = NULL; 378 FoundFileList = NULL; 379 TempPos = NULL; 380 TabPos = 0; 381 TabUpdatePos = 0; 382 383 // 384 // Allocate buffers 385 // 386 TabStr = AllocateZeroPool (*BufferSize); 387 if (TabStr == NULL) { 388 return EFI_OUT_OF_RESOURCES; 389 } 390 TabOutputStr = AllocateZeroPool (*BufferSize); 391 if (TabOutputStr == NULL) { 392 FreePool(TabStr); 393 return EFI_OUT_OF_RESOURCES; 394 } 395 396 // 397 // Get the screen setting and the current cursor location 398 // 399 Column = StartColumn = gST->ConOut->Mode->CursorColumn; 400 Row = gST->ConOut->Mode->CursorRow; 401 gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &TotalColumn, &TotalRow); 402 403 // 404 // Limit the line length to the buffer size or the minimun size of the 405 // screen. (The smaller takes effect) 406 // 407 MaxStr = TotalColumn * (TotalRow - 1) - StartColumn; 408 if (MaxStr > *BufferSize / sizeof (CHAR16)) { 409 MaxStr = *BufferSize / sizeof (CHAR16); 410 } 411 ZeroMem (CurrentString, MaxStr * sizeof (CHAR16)); 412 do { 413 // 414 // Read a key 415 // 416 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex); 417 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 418 if (EFI_ERROR (Status)) { 419 continue; 420 } 421 422 // 423 // Press PageUp or PageDown to scroll the history screen up or down. 424 // Press any other key to quit scrolling. 425 // 426 if (Key.UnicodeChar == 0 && (Key.ScanCode == SCAN_PAGE_UP || Key.ScanCode == SCAN_PAGE_DOWN)) { 427 if (Key.ScanCode == SCAN_PAGE_UP) { 428 ConsoleLoggerDisplayHistory(FALSE, 0, ShellInfoObject.ConsoleInfo); 429 } else if (Key.ScanCode == SCAN_PAGE_DOWN) { 430 ConsoleLoggerDisplayHistory(TRUE, 0, ShellInfoObject.ConsoleInfo); 431 } 432 433 InScrolling = TRUE; 434 } else { 435 if (InScrolling) { 436 ConsoleLoggerStopHistory(ShellInfoObject.ConsoleInfo); 437 InScrolling = FALSE; 438 } 439 } 440 441 // 442 // If we are quitting TAB scrolling... 443 // 444 if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) { 445 if (FoundFileList != NULL) { 446 ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList); 447 DEBUG_CODE(FoundFileList = NULL;); 448 } 449 InTabScrolling = FALSE; 450 } 451 452 switch (Key.UnicodeChar) { 453 case CHAR_CARRIAGE_RETURN: 454 // 455 // All done, print a newline at the end of the string 456 // 457 TailRow = Row + (StringLen - StringCurPos + Column) / TotalColumn; 458 TailColumn = (StringLen - StringCurPos + Column) % TotalColumn; 459 ShellPrintEx ((INT32)TailColumn, (INT32)TailRow, L"%N\n"); 460 Done = TRUE; 461 break; 462 463 case CHAR_BACKSPACE: 464 if (StringCurPos != 0) { 465 // 466 // If not move back beyond string beginning, move all characters behind 467 // the current position one character forward 468 // 469 StringCurPos--; 470 Update = StringCurPos; 471 Delete = 1; 472 CopyMem (CurrentString + StringCurPos, CurrentString + StringCurPos + 1, sizeof (CHAR16) * (StringLen - StringCurPos)); 473 474 // 475 // Adjust the current column and row 476 // 477 MoveCursorBackward (TotalColumn, &Column, &Row); 478 } 479 break; 480 481 case CHAR_TAB: 482 // 483 // handle auto complete of file and directory names... 484 // 485 if (InTabScrolling) { 486 ASSERT(FoundFileList != NULL); 487 ASSERT(TabLinePos != NULL); 488 TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link); 489 if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) { 490 TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link); 491 } 492 } else { 493 TabPos = 0; 494 TabUpdatePos = 0; 495 InQuotationMode = FALSE; 496 for (Index = 0; Index < StringLen; Index++) { 497 if (CurrentString[Index] == L'\"') { 498 InQuotationMode = (BOOLEAN)(!InQuotationMode); 499 } 500 if (CurrentString[Index] == L' ' && !InQuotationMode) { 501 TabPos = Index + 1; 502 TabUpdatePos = Index + 1; 503 } 504 if (CurrentString[Index] == L'\\') { 505 TabUpdatePos = Index + 1; 506 } 507 } 508 if (StrStr(CurrentString + TabPos, L":") == NULL) { 509 Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL); 510 if (Cwd != NULL) { 511 StrCpy(TabStr, Cwd); 512 if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) { 513 TabStr[StrLen(TabStr)-1] = CHAR_NULL; 514 } 515 StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16)); 516 } else { 517 StrCpy(TabStr, L""); 518 StrnCat(TabStr, CurrentString + TabPos, (StringLen - TabPos) * sizeof (CHAR16)); 519 } 520 } else { 521 StrCpy(TabStr, CurrentString + TabPos); 522 } 523 StrCat(TabStr, L"*"); 524 FoundFileList = NULL; 525// TabStr = PathCleanUpDirectories(TabStr); 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 EFI_SUCCESS; 852} 853 854// 855// FILE sytle interfaces for StdIn/StdOut/StdErr 856// 857EFI_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 871EFI_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 885EFI_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 899EFI_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 921typedef 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**/ 947EFI_STATUS 948EFIAPI 949FileInterfaceEnvClose( 950 IN EFI_FILE_PROTOCOL *This 951 ) 952{ 953 FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This); 954 return (EFI_SUCCESS); 955} 956 957/** 958 File style interface for Environment Variable (Delete). 959 960 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 961 962 @retval The return value from FileInterfaceEnvClose(). 963**/ 964EFI_STATUS 965EFIAPI 966FileInterfaceEnvDelete( 967 IN EFI_FILE_PROTOCOL *This 968 ) 969{ 970 SHELL_DELETE_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name); 971 return (FileInterfaceEnvClose(This)); 972} 973 974/** 975 File style interface for Environment Variable (Read). 976 977 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 978 @param[in, out] BufferSize Size in bytes of Buffer. 979 @param[out] Buffer The pointer to the buffer to fill. 980 981 @retval EFI_SUCCESS The data was read. 982**/ 983EFI_STATUS 984EFIAPI 985FileInterfaceEnvRead( 986 IN EFI_FILE_PROTOCOL *This, 987 IN OUT UINTN *BufferSize, 988 OUT VOID *Buffer 989 ) 990{ 991 return (SHELL_GET_ENVIRONMENT_VARIABLE( 992 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, 993 BufferSize, 994 Buffer)); 995} 996 997/** 998 File style interface for Volatile Environment Variable (Write). 999 1000 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1001 @param[in, out] BufferSize Size in bytes of Buffer. 1002 @param[in] Buffer The pointer to the buffer to write. 1003 1004 @retval EFI_SUCCESS The data was read. 1005**/ 1006EFI_STATUS 1007EFIAPI 1008FileInterfaceEnvVolWrite( 1009 IN EFI_FILE_PROTOCOL *This, 1010 IN OUT UINTN *BufferSize, 1011 IN VOID *Buffer 1012 ) 1013{ 1014 VOID* NewBuffer; 1015 UINTN NewSize; 1016 EFI_STATUS Status; 1017 1018 NewBuffer = NULL; 1019 NewSize = 0; 1020 1021 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); 1022 if (Status == EFI_BUFFER_TOO_SMALL){ 1023 NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16)); 1024 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); 1025 } 1026 if (!EFI_ERROR(Status) && NewBuffer != NULL) { 1027 while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) { 1028 // 1029 // We want to overwrite the CHAR_NULL 1030 // 1031 NewSize -= 2; 1032 } 1033 CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize); 1034 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer); 1035 FreePool(NewBuffer); 1036 return (Status); 1037 } else { 1038 SHELL_FREE_NON_NULL(NewBuffer); 1039 return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer)); 1040 } 1041} 1042 1043 1044/** 1045 File style interface for Non Volatile Environment Variable (Write). 1046 1047 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1048 @param[in, out] BufferSize Size in bytes of Buffer. 1049 @param[in] Buffer The pointer to the buffer to write. 1050 1051 @retval EFI_SUCCESS The data was read. 1052**/ 1053EFI_STATUS 1054EFIAPI 1055FileInterfaceEnvNonVolWrite( 1056 IN EFI_FILE_PROTOCOL *This, 1057 IN OUT UINTN *BufferSize, 1058 IN VOID *Buffer 1059 ) 1060{ 1061 VOID* NewBuffer; 1062 UINTN NewSize; 1063 EFI_STATUS Status; 1064 1065 NewBuffer = NULL; 1066 NewSize = 0; 1067 1068 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); 1069 if (Status == EFI_BUFFER_TOO_SMALL){ 1070 NewBuffer = AllocateZeroPool(NewSize + *BufferSize); 1071 Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer); 1072 } 1073 if (!EFI_ERROR(Status)) { 1074 CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize); 1075 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV( 1076 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, 1077 NewSize + *BufferSize, 1078 NewBuffer)); 1079 } else { 1080 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV( 1081 ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, 1082 *BufferSize, 1083 Buffer)); 1084 } 1085} 1086 1087/** 1088 Creates a EFI_FILE_PROTOCOL (almost) object for using to access 1089 environment variables through file operations. 1090 1091 @param EnvName The name of the Environment Variable to be operated on. 1092 1093 @retval NULL Memory could not be allocated. 1094 @return other a pointer to an EFI_FILE_PROTOCOL structure 1095**/ 1096EFI_FILE_PROTOCOL* 1097EFIAPI 1098CreateFileInterfaceEnv( 1099 IN CONST CHAR16 *EnvName 1100 ) 1101{ 1102 EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface; 1103 1104 if (EnvName == NULL) { 1105 return (NULL); 1106 } 1107 1108 // 1109 // Get some memory 1110 // 1111 EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+StrSize(EnvName)); 1112 if (EnvFileInterface == NULL){ 1113 return (NULL); 1114 } 1115 1116 // 1117 // Assign the generic members 1118 // 1119 EnvFileInterface->Revision = EFI_FILE_REVISION; 1120 EnvFileInterface->Open = FileInterfaceOpenNotFound; 1121 EnvFileInterface->Close = FileInterfaceEnvClose; 1122 EnvFileInterface->GetPosition = FileInterfaceNopGetPosition; 1123 EnvFileInterface->SetPosition = FileInterfaceNopSetPosition; 1124 EnvFileInterface->GetInfo = FileInterfaceNopGetInfo; 1125 EnvFileInterface->SetInfo = FileInterfaceNopSetInfo; 1126 EnvFileInterface->Flush = FileInterfaceNopGeneric; 1127 EnvFileInterface->Delete = FileInterfaceEnvDelete; 1128 EnvFileInterface->Read = FileInterfaceEnvRead; 1129 1130 StrCpy(EnvFileInterface->Name, EnvName); 1131 1132 // 1133 // Assign the different members for Volatile and Non-Volatile variables 1134 // 1135 if (IsVolatileEnv(EnvName)) { 1136 EnvFileInterface->Write = FileInterfaceEnvVolWrite; 1137 } else { 1138 EnvFileInterface->Write = FileInterfaceEnvNonVolWrite; 1139 } 1140 return ((EFI_FILE_PROTOCOL *)EnvFileInterface); 1141} 1142 1143/** 1144 Move the cursor position one character backward. 1145 1146 @param[in] LineLength Length of a line. Get it by calling QueryMode 1147 @param[in, out] Column Current column of the cursor position 1148 @param[in, out] Row Current row of the cursor position 1149**/ 1150VOID 1151EFIAPI 1152MoveCursorBackward ( 1153 IN UINTN LineLength, 1154 IN OUT UINTN *Column, 1155 IN OUT UINTN *Row 1156 ) 1157{ 1158 // 1159 // If current column is 0, move to the last column of the previous line, 1160 // otherwise, just decrement column. 1161 // 1162 if (*Column == 0) { 1163 *Column = LineLength - 1; 1164 if (*Row > 0) { 1165 (*Row)--; 1166 } 1167 return; 1168 } 1169 (*Column)--; 1170} 1171 1172/** 1173 Move the cursor position one character forward. 1174 1175 @param[in] LineLength Length of a line. 1176 @param[in] TotalRow Total row of a screen 1177 @param[in, out] Column Current column of the cursor position 1178 @param[in, out] Row Current row of the cursor position 1179**/ 1180VOID 1181EFIAPI 1182MoveCursorForward ( 1183 IN UINTN LineLength, 1184 IN UINTN TotalRow, 1185 IN OUT UINTN *Column, 1186 IN OUT UINTN *Row 1187 ) 1188{ 1189 // 1190 // Increment Column. 1191 // If this puts column past the end of the line, move to first column 1192 // of the next row. 1193 // 1194 (*Column)++; 1195 if (*Column >= LineLength) { 1196 (*Column) = 0; 1197 if ((*Row) < TotalRow - 1) { 1198 (*Row)++; 1199 } 1200 } 1201} 1202 1203/** 1204 Prints out each previously typed command in the command list history log. 1205 1206 When each screen is full it will pause for a key before continuing. 1207 1208 @param[in] TotalCols How many columns are on the screen 1209 @param[in] TotalRows How many rows are on the screen 1210 @param[in] StartColumn which column to start at 1211**/ 1212VOID 1213EFIAPI 1214PrintCommandHistory ( 1215 IN CONST UINTN TotalCols, 1216 IN CONST UINTN TotalRows, 1217 IN CONST UINTN StartColumn 1218 ) 1219{ 1220 BUFFER_LIST *Node; 1221 UINTN Index; 1222 UINTN LineNumber; 1223 UINTN LineCount; 1224 1225 ShellPrintEx (-1, -1, L"\n"); 1226 Index = 0; 1227 LineNumber = 0; 1228 // 1229 // go through history list... 1230 // 1231 for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link) 1232 ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) 1233 ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) 1234 ){ 1235 Index++; 1236 LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1; 1237 1238 if (LineNumber + LineCount >= TotalRows) { 1239 ShellPromptForResponseHii( 1240 ShellPromptResponseTypeEnterContinue, 1241 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT), 1242 ShellInfoObject.HiiHandle, 1243 NULL 1244 ); 1245 LineNumber = 0; 1246 } 1247 ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer); 1248 LineNumber += LineCount; 1249 } 1250} 1251 1252 1253 1254 1255 1256 1257// 1258// This is identical to EFI_FILE_PROTOCOL except for the additional members 1259// for the buffer, size, and position. 1260// 1261 1262typedef struct { 1263 UINT64 Revision; 1264 EFI_FILE_OPEN Open; 1265 EFI_FILE_CLOSE Close; 1266 EFI_FILE_DELETE Delete; 1267 EFI_FILE_READ Read; 1268 EFI_FILE_WRITE Write; 1269 EFI_FILE_GET_POSITION GetPosition; 1270 EFI_FILE_SET_POSITION SetPosition; 1271 EFI_FILE_GET_INFO GetInfo; 1272 EFI_FILE_SET_INFO SetInfo; 1273 EFI_FILE_FLUSH Flush; 1274 VOID *Buffer; 1275 UINT64 Position; 1276 UINT64 BufferSize; 1277 BOOLEAN Unicode; 1278} EFI_FILE_PROTOCOL_MEM; 1279 1280/** 1281 File style interface for Mem (SetPosition). 1282 1283 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1284 @param[out] Position The position to set. 1285 1286 @retval EFI_SUCCESS The position was successfully changed. 1287 @retval EFI_INVALID_PARAMETER The Position was invalid. 1288**/ 1289EFI_STATUS 1290EFIAPI 1291FileInterfaceMemSetPosition( 1292 IN EFI_FILE_PROTOCOL *This, 1293 OUT UINT64 Position 1294 ) 1295{ 1296 if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) { 1297 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position; 1298 return (EFI_SUCCESS); 1299 } else { 1300 return (EFI_INVALID_PARAMETER); 1301 } 1302} 1303 1304/** 1305 File style interface for Mem (GetPosition). 1306 1307 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1308 @param[out] Position The pointer to the position. 1309 1310 @retval EFI_SUCCESS The position was retrieved. 1311**/ 1312EFI_STATUS 1313EFIAPI 1314FileInterfaceMemGetPosition( 1315 IN EFI_FILE_PROTOCOL *This, 1316 OUT UINT64 *Position 1317 ) 1318{ 1319 *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position; 1320 return (EFI_SUCCESS); 1321} 1322 1323/** 1324 File style interface for Mem (Write). 1325 1326 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1327 @param[in, out] BufferSize Size in bytes of Buffer. 1328 @param[in] Buffer The pointer to the buffer to write. 1329 1330 @retval EFI_SUCCESS The data was written. 1331**/ 1332EFI_STATUS 1333EFIAPI 1334FileInterfaceMemWrite( 1335 IN EFI_FILE_PROTOCOL *This, 1336 IN OUT UINTN *BufferSize, 1337 IN VOID *Buffer 1338 ) 1339{ 1340 CHAR8 *AsciiBuffer; 1341 if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) { 1342 // 1343 // Unicode 1344 // 1345 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { 1346 ((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); 1347 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10; 1348 } 1349 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize); 1350 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize); 1351 return (EFI_SUCCESS); 1352 } else { 1353 // 1354 // Ascii 1355 // 1356 AsciiBuffer = AllocateZeroPool(*BufferSize); 1357 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); 1358 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { 1359 ((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); 1360 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10; 1361 } 1362 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer)); 1363 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer); 1364 FreePool(AsciiBuffer); 1365 return (EFI_SUCCESS); 1366 } 1367} 1368 1369/** 1370 File style interface for Mem (Read). 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 fill. 1375 1376 @retval EFI_SUCCESS The data was read. 1377**/ 1378EFI_STATUS 1379EFIAPI 1380FileInterfaceMemRead( 1381 IN EFI_FILE_PROTOCOL *This, 1382 IN OUT UINTN *BufferSize, 1383 IN VOID *Buffer 1384 ) 1385{ 1386 if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) { 1387 (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position)); 1388 } 1389 CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize)); 1390 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize); 1391 return (EFI_SUCCESS); 1392} 1393 1394/** 1395 File style interface for Mem (Close). 1396 1397 Frees all memory associated with this object. 1398 1399 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1400 1401 @retval EFI_SUCCESS The 'file' was closed. 1402**/ 1403EFI_STATUS 1404EFIAPI 1405FileInterfaceMemClose( 1406 IN EFI_FILE_PROTOCOL *This 1407 ) 1408{ 1409 SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); 1410 SHELL_FREE_NON_NULL(This); 1411 return (EFI_SUCCESS); 1412} 1413 1414/** 1415 Creates a EFI_FILE_PROTOCOL (almost) object for using to access 1416 a file entirely in memory through file operations. 1417 1418 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii. 1419 1420 @retval NULL Memory could not be allocated. 1421 @return other A pointer to an EFI_FILE_PROTOCOL structure. 1422**/ 1423EFI_FILE_PROTOCOL* 1424EFIAPI 1425CreateFileInterfaceMem( 1426 IN CONST BOOLEAN Unicode 1427 ) 1428{ 1429 EFI_FILE_PROTOCOL_MEM *FileInterface; 1430 1431 // 1432 // Get some memory 1433 // 1434 FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM)); 1435 if (FileInterface == NULL){ 1436 return (NULL); 1437 } 1438 1439 // 1440 // Assign the generic members 1441 // 1442 FileInterface->Revision = EFI_FILE_REVISION; 1443 FileInterface->Open = FileInterfaceOpenNotFound; 1444 FileInterface->Close = FileInterfaceMemClose; 1445 FileInterface->GetPosition = FileInterfaceMemGetPosition; 1446 FileInterface->SetPosition = FileInterfaceMemSetPosition; 1447 FileInterface->GetInfo = FileInterfaceNopGetInfo; 1448 FileInterface->SetInfo = FileInterfaceNopSetInfo; 1449 FileInterface->Flush = FileInterfaceNopGeneric; 1450 FileInterface->Delete = FileInterfaceNopGeneric; 1451 FileInterface->Read = FileInterfaceMemRead; 1452 FileInterface->Write = FileInterfaceMemWrite; 1453 FileInterface->Unicode = Unicode; 1454 1455 ASSERT(FileInterface->Buffer == NULL); 1456 ASSERT(FileInterface->BufferSize == 0); 1457 ASSERT(FileInterface->Position == 0); 1458 1459 return ((EFI_FILE_PROTOCOL *)FileInterface); 1460} 1461 1462typedef struct { 1463 UINT64 Revision; 1464 EFI_FILE_OPEN Open; 1465 EFI_FILE_CLOSE Close; 1466 EFI_FILE_DELETE Delete; 1467 EFI_FILE_READ Read; 1468 EFI_FILE_WRITE Write; 1469 EFI_FILE_GET_POSITION GetPosition; 1470 EFI_FILE_SET_POSITION SetPosition; 1471 EFI_FILE_GET_INFO GetInfo; 1472 EFI_FILE_SET_INFO SetInfo; 1473 EFI_FILE_FLUSH Flush; 1474 BOOLEAN Unicode; 1475 EFI_FILE_PROTOCOL *Orig; 1476} EFI_FILE_PROTOCOL_FILE; 1477 1478/** 1479 Set a files current position 1480 1481 @param This Protocol instance pointer. 1482 @param Position Byte position from the start of the file. 1483 1484 @retval EFI_SUCCESS Data was written. 1485 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. 1486 1487**/ 1488EFI_STATUS 1489EFIAPI 1490FileInterfaceFileSetPosition( 1491 IN EFI_FILE_PROTOCOL *This, 1492 IN UINT64 Position 1493 ) 1494{ 1495 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); 1496} 1497 1498/** 1499 Get a file's current position 1500 1501 @param This Protocol instance pointer. 1502 @param Position Byte position from the start of the file. 1503 1504 @retval EFI_SUCCESS Data was written. 1505 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. 1506 1507**/ 1508EFI_STATUS 1509EFIAPI 1510FileInterfaceFileGetPosition( 1511 IN EFI_FILE_PROTOCOL *This, 1512 OUT UINT64 *Position 1513 ) 1514{ 1515 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); 1516} 1517 1518/** 1519 Get information about a file. 1520 1521 @param This Protocol instance pointer. 1522 @param InformationType Type of information to return in Buffer. 1523 @param BufferSize On input size of buffer, on output amount of data in buffer. 1524 @param Buffer The buffer to return data. 1525 1526 @retval EFI_SUCCESS Data was returned. 1527 @retval EFI_UNSUPPORT InformationType is not supported. 1528 @retval EFI_NO_MEDIA The device has no media. 1529 @retval EFI_DEVICE_ERROR The device reported an error. 1530 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1531 @retval EFI_WRITE_PROTECTED The device is write protected. 1532 @retval EFI_ACCESS_DENIED The file was open for read only. 1533 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. 1534 1535**/ 1536EFI_STATUS 1537EFIAPI 1538FileInterfaceFileGetInfo( 1539 IN EFI_FILE_PROTOCOL *This, 1540 IN EFI_GUID *InformationType, 1541 IN OUT UINTN *BufferSize, 1542 OUT VOID *Buffer 1543 ) 1544{ 1545 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); 1546} 1547 1548/** 1549 Set information about a file 1550 1551 @param This Protocol instance pointer. 1552 @param InformationType Type of information in Buffer. 1553 @param BufferSize Size of buffer. 1554 @param Buffer The data to write. 1555 1556 @retval EFI_SUCCESS Data was returned. 1557 @retval EFI_UNSUPPORT InformationType is not supported. 1558 @retval EFI_NO_MEDIA The device has no media. 1559 @retval EFI_DEVICE_ERROR The device reported an error. 1560 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1561 @retval EFI_WRITE_PROTECTED The device is write protected. 1562 @retval EFI_ACCESS_DENIED The file was open for read only. 1563 1564**/ 1565EFI_STATUS 1566EFIAPI 1567FileInterfaceFileSetInfo( 1568 IN EFI_FILE_PROTOCOL *This, 1569 IN EFI_GUID *InformationType, 1570 IN UINTN BufferSize, 1571 IN VOID *Buffer 1572 ) 1573{ 1574 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); 1575} 1576 1577/** 1578 Flush data back for the file handle. 1579 1580 @param This Protocol instance pointer. 1581 1582 @retval EFI_SUCCESS Data was written. 1583 @retval EFI_UNSUPPORT Writes to Open directory are not supported. 1584 @retval EFI_NO_MEDIA The device has no media. 1585 @retval EFI_DEVICE_ERROR The device reported an error. 1586 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1587 @retval EFI_WRITE_PROTECTED The device is write protected. 1588 @retval EFI_ACCESS_DENIED The file was open for read only. 1589 @retval EFI_VOLUME_FULL The volume is full. 1590 1591**/ 1592EFI_STATUS 1593EFIAPI 1594FileInterfaceFileFlush( 1595 IN EFI_FILE_PROTOCOL *This 1596 ) 1597{ 1598 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1599} 1600 1601/** 1602 Read data from the file. 1603 1604 @param This Protocol instance pointer. 1605 @param BufferSize On input size of buffer, on output amount of data in buffer. 1606 @param Buffer The buffer in which data is read. 1607 1608 @retval EFI_SUCCESS Data was read. 1609 @retval EFI_NO_MEDIA The device has no media. 1610 @retval EFI_DEVICE_ERROR The device reported an error. 1611 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1612 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. 1613 1614**/ 1615EFI_STATUS 1616EFIAPI 1617FileInterfaceFileRead( 1618 IN EFI_FILE_PROTOCOL *This, 1619 IN OUT UINTN *BufferSize, 1620 OUT VOID *Buffer 1621 ) 1622{ 1623 CHAR8 *AsciiBuffer; 1624 UINTN Size; 1625 EFI_STATUS Status; 1626 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { 1627 // 1628 // Unicode 1629 // 1630 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); 1631 } else { 1632 // 1633 // Ascii 1634 // 1635 AsciiBuffer = AllocateZeroPool((Size = *BufferSize)); 1636 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); 1637 UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer); 1638 FreePool(AsciiBuffer); 1639 return (Status); 1640 } 1641} 1642 1643/** 1644 Opens a new file relative to the source file's location. 1645 1646 @param[in] This The protocol instance pointer. 1647 @param[out] NewHandle Returns File Handle for FileName. 1648 @param[in] FileName Null terminated string. "\", ".", and ".." are supported. 1649 @param[in] OpenMode Open mode for file. 1650 @param[in] Attributes Only used for EFI_FILE_MODE_CREATE. 1651 1652 @retval EFI_SUCCESS The device was opened. 1653 @retval EFI_NOT_FOUND The specified file could not be found on the device. 1654 @retval EFI_NO_MEDIA The device has no media. 1655 @retval EFI_MEDIA_CHANGED The media has changed. 1656 @retval EFI_DEVICE_ERROR The device reported an error. 1657 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1658 @retval EFI_ACCESS_DENIED The service denied access to the file. 1659 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. 1660 @retval EFI_VOLUME_FULL The volume is full. 1661**/ 1662EFI_STATUS 1663EFIAPI 1664FileInterfaceFileOpen ( 1665 IN EFI_FILE_PROTOCOL *This, 1666 OUT EFI_FILE_PROTOCOL **NewHandle, 1667 IN CHAR16 *FileName, 1668 IN UINT64 OpenMode, 1669 IN UINT64 Attributes 1670 ) 1671{ 1672 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes); 1673} 1674 1675/** 1676 Close and delete the file handle. 1677 1678 @param This Protocol instance pointer. 1679 1680 @retval EFI_SUCCESS The device was opened. 1681 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. 1682 1683**/ 1684EFI_STATUS 1685EFIAPI 1686FileInterfaceFileDelete( 1687 IN EFI_FILE_PROTOCOL *This 1688 ) 1689{ 1690 EFI_STATUS Status; 1691 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1692 FreePool(This); 1693 return (Status); 1694} 1695 1696/** 1697 File style interface for File (Close). 1698 1699 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1700 1701 @retval EFI_SUCCESS The file was closed. 1702**/ 1703EFI_STATUS 1704EFIAPI 1705FileInterfaceFileClose( 1706 IN EFI_FILE_PROTOCOL *This 1707 ) 1708{ 1709 EFI_STATUS Status; 1710 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1711 FreePool(This); 1712 return (Status); 1713} 1714 1715/** 1716 File style interface for File (Write). 1717 1718 If the file was opened with ASCII mode the data will be processed through 1719 AsciiSPrint before writing. 1720 1721 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1722 @param[in, out] BufferSize Size in bytes of Buffer. 1723 @param[in] Buffer The pointer to the buffer to write. 1724 1725 @retval EFI_SUCCESS The data was written. 1726**/ 1727EFI_STATUS 1728EFIAPI 1729FileInterfaceFileWrite( 1730 IN EFI_FILE_PROTOCOL *This, 1731 IN OUT UINTN *BufferSize, 1732 IN VOID *Buffer 1733 ) 1734{ 1735 CHAR8 *AsciiBuffer; 1736 UINTN Size; 1737 EFI_STATUS Status; 1738 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { 1739 // 1740 // Unicode 1741 // 1742 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); 1743 } else { 1744 // 1745 // Ascii 1746 // 1747 AsciiBuffer = AllocateZeroPool(*BufferSize); 1748 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); 1749 Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator) 1750 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); 1751 FreePool(AsciiBuffer); 1752 return (Status); 1753 } 1754} 1755 1756/** 1757 Create a file interface with unicode information. 1758 1759 This will create a new EFI_FILE_PROTOCOL identical to the Templace 1760 except that the new one has Unicode and Ascii knowledge. 1761 1762 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object. 1763 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII. 1764 1765 @return a new EFI_FILE_PROTOCOL object to be used instead of the template. 1766**/ 1767EFI_FILE_PROTOCOL* 1768CreateFileInterfaceFile( 1769 IN CONST EFI_FILE_PROTOCOL *Template, 1770 IN CONST BOOLEAN Unicode 1771 ) 1772{ 1773 EFI_FILE_PROTOCOL_FILE *NewOne; 1774 1775 NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE)); 1776 if (NewOne == NULL) { 1777 return (NULL); 1778 } 1779 CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE)); 1780 NewOne->Orig = (EFI_FILE_PROTOCOL *)Template; 1781 NewOne->Unicode = Unicode; 1782 NewOne->Open = FileInterfaceFileOpen; 1783 NewOne->Close = FileInterfaceFileClose; 1784 NewOne->Delete = FileInterfaceFileDelete; 1785 NewOne->Read = FileInterfaceFileRead; 1786 NewOne->Write = FileInterfaceFileWrite; 1787 NewOne->GetPosition = FileInterfaceFileGetPosition; 1788 NewOne->SetPosition = FileInterfaceFileSetPosition; 1789 NewOne->GetInfo = FileInterfaceFileGetInfo; 1790 NewOne->SetInfo = FileInterfaceFileSetInfo; 1791 NewOne->Flush = FileInterfaceFileFlush; 1792 1793 return ((EFI_FILE_PROTOCOL *)NewOne); 1794} 1795