FileHandleWrappers.c revision 323d3d111843cb4fbdf4f9918f72d305e63bc091
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**/ 31EFI_STATUS 32EFIAPI 33FileInterfaceOpenNotFound( 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**/ 51EFI_STATUS 52EFIAPI 53FileInterfaceNopGeneric( 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**/ 68EFI_STATUS 69EFIAPI 70FileInterfaceNopGetPosition( 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**/ 86EFI_STATUS 87EFIAPI 88FileInterfaceNopSetPosition( 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**/ 106EFI_STATUS 107EFIAPI 108FileInterfaceNopGetInfo( 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**/ 128EFI_STATUS 129EFIAPI 130FileInterfaceNopSetInfo( 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**/ 152EFI_STATUS 153EFIAPI 154FileInterfaceStdOutWrite( 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**/ 176EFI_STATUS 177EFIAPI 178FileInterfaceStdInWrite( 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**/ 198EFI_STATUS 199EFIAPI 200FileInterfaceStdErrWrite( 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**/ 218EFI_STATUS 219EFIAPI 220FileInterfaceStdOutRead( 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**/ 238EFI_STATUS 239EFIAPI 240FileInterfaceStdErrRead( 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**/ 258EFI_STATUS 259EFIAPI 260FileInterfaceNulRead( 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**/ 279EFI_STATUS 280EFIAPI 281FileInterfaceNulWrite( 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**/ 314EFI_STATUS 315EFIAPI 316FileInterfaceStdInRead( 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// 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 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**/ 1004EFI_STATUS 1005EFIAPI 1006FileInterfaceEnvDelete( 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**/ 1023EFI_STATUS 1024EFIAPI 1025FileInterfaceEnvRead( 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**/ 1046EFI_STATUS 1047EFIAPI 1048FileInterfaceEnvVolWrite( 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**/ 1093EFI_STATUS 1094EFIAPI 1095FileInterfaceEnvNonVolWrite( 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**/ 1136EFI_FILE_PROTOCOL* 1137EFIAPI 1138CreateFileInterfaceEnv( 1139 IN CONST CHAR16 *EnvName 1140 ) 1141{ 1142 EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface; 1143 UINTN EnvNameSize; 1144 1145 if (EnvName == NULL) { 1146 return (NULL); 1147 } 1148 1149 // 1150 // Get some memory 1151 // 1152 EnvNameSize = StrSize(EnvName); 1153 EnvFileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_ENVIRONMENT)+EnvNameSize); 1154 if (EnvFileInterface == NULL){ 1155 return (NULL); 1156 } 1157 1158 // 1159 // Assign the generic members 1160 // 1161 EnvFileInterface->Revision = EFI_FILE_REVISION; 1162 EnvFileInterface->Open = FileInterfaceOpenNotFound; 1163 EnvFileInterface->Close = FileInterfaceEnvClose; 1164 EnvFileInterface->GetPosition = FileInterfaceNopGetPosition; 1165 EnvFileInterface->SetPosition = FileInterfaceNopSetPosition; 1166 EnvFileInterface->GetInfo = FileInterfaceNopGetInfo; 1167 EnvFileInterface->SetInfo = FileInterfaceNopSetInfo; 1168 EnvFileInterface->Flush = FileInterfaceNopGeneric; 1169 EnvFileInterface->Delete = FileInterfaceEnvDelete; 1170 EnvFileInterface->Read = FileInterfaceEnvRead; 1171 1172 CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize); 1173 1174 // 1175 // Assign the different members for Volatile and Non-Volatile variables 1176 // 1177 if (IsVolatileEnv(EnvName)) { 1178 EnvFileInterface->Write = FileInterfaceEnvVolWrite; 1179 } else { 1180 EnvFileInterface->Write = FileInterfaceEnvNonVolWrite; 1181 } 1182 return ((EFI_FILE_PROTOCOL *)EnvFileInterface); 1183} 1184 1185/** 1186 Move the cursor position one character backward. 1187 1188 @param[in] LineLength Length of a line. Get it by calling QueryMode 1189 @param[in, out] Column Current column of the cursor position 1190 @param[in, out] Row Current row of the cursor position 1191**/ 1192VOID 1193EFIAPI 1194MoveCursorBackward ( 1195 IN UINTN LineLength, 1196 IN OUT UINTN *Column, 1197 IN OUT UINTN *Row 1198 ) 1199{ 1200 // 1201 // If current column is 0, move to the last column of the previous line, 1202 // otherwise, just decrement column. 1203 // 1204 if (*Column == 0) { 1205 *Column = LineLength - 1; 1206 if (*Row > 0) { 1207 (*Row)--; 1208 } 1209 return; 1210 } 1211 (*Column)--; 1212} 1213 1214/** 1215 Move the cursor position one character forward. 1216 1217 @param[in] LineLength Length of a line. 1218 @param[in] TotalRow Total row of a screen 1219 @param[in, out] Column Current column of the cursor position 1220 @param[in, out] Row Current row of the cursor position 1221**/ 1222VOID 1223EFIAPI 1224MoveCursorForward ( 1225 IN UINTN LineLength, 1226 IN UINTN TotalRow, 1227 IN OUT UINTN *Column, 1228 IN OUT UINTN *Row 1229 ) 1230{ 1231 // 1232 // Increment Column. 1233 // If this puts column past the end of the line, move to first column 1234 // of the next row. 1235 // 1236 (*Column)++; 1237 if (*Column >= LineLength) { 1238 (*Column) = 0; 1239 if ((*Row) < TotalRow - 1) { 1240 (*Row)++; 1241 } 1242 } 1243} 1244 1245/** 1246 Prints out each previously typed command in the command list history log. 1247 1248 When each screen is full it will pause for a key before continuing. 1249 1250 @param[in] TotalCols How many columns are on the screen 1251 @param[in] TotalRows How many rows are on the screen 1252 @param[in] StartColumn which column to start at 1253**/ 1254VOID 1255EFIAPI 1256PrintCommandHistory ( 1257 IN CONST UINTN TotalCols, 1258 IN CONST UINTN TotalRows, 1259 IN CONST UINTN StartColumn 1260 ) 1261{ 1262 BUFFER_LIST *Node; 1263 UINTN Index; 1264 UINTN LineNumber; 1265 UINTN LineCount; 1266 1267 ShellPrintEx (-1, -1, L"\n"); 1268 Index = 0; 1269 LineNumber = 0; 1270 // 1271 // go through history list... 1272 // 1273 for ( Node = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link) 1274 ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) 1275 ; Node = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link) 1276 ){ 1277 Index++; 1278 LineCount = ((StrLen (Node->Buffer) + StartColumn + 1) / TotalCols) + 1; 1279 1280 if (LineNumber + LineCount >= TotalRows) { 1281 ShellPromptForResponseHii( 1282 ShellPromptResponseTypeEnterContinue, 1283 STRING_TOKEN (STR_SHELL_ENTER_TO_CONT), 1284 ShellInfoObject.HiiHandle, 1285 NULL 1286 ); 1287 LineNumber = 0; 1288 } 1289 ShellPrintEx (-1, -1, L"%2d. %s\n", Index, Node->Buffer); 1290 LineNumber += LineCount; 1291 } 1292} 1293 1294 1295 1296 1297 1298 1299// 1300// This is identical to EFI_FILE_PROTOCOL except for the additional members 1301// for the buffer, size, and position. 1302// 1303 1304typedef struct { 1305 UINT64 Revision; 1306 EFI_FILE_OPEN Open; 1307 EFI_FILE_CLOSE Close; 1308 EFI_FILE_DELETE Delete; 1309 EFI_FILE_READ Read; 1310 EFI_FILE_WRITE Write; 1311 EFI_FILE_GET_POSITION GetPosition; 1312 EFI_FILE_SET_POSITION SetPosition; 1313 EFI_FILE_GET_INFO GetInfo; 1314 EFI_FILE_SET_INFO SetInfo; 1315 EFI_FILE_FLUSH Flush; 1316 VOID *Buffer; 1317 UINT64 Position; 1318 UINT64 BufferSize; 1319 BOOLEAN Unicode; 1320} EFI_FILE_PROTOCOL_MEM; 1321 1322/** 1323 File style interface for Mem (SetPosition). 1324 1325 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1326 @param[out] Position The position to set. 1327 1328 @retval EFI_SUCCESS The position was successfully changed. 1329 @retval EFI_INVALID_PARAMETER The Position was invalid. 1330**/ 1331EFI_STATUS 1332EFIAPI 1333FileInterfaceMemSetPosition( 1334 IN EFI_FILE_PROTOCOL *This, 1335 OUT UINT64 Position 1336 ) 1337{ 1338 if (Position <= ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) { 1339 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = Position; 1340 return (EFI_SUCCESS); 1341 } else { 1342 return (EFI_INVALID_PARAMETER); 1343 } 1344} 1345 1346/** 1347 File style interface for Mem (GetPosition). 1348 1349 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1350 @param[out] Position The pointer to the position. 1351 1352 @retval EFI_SUCCESS The position was retrieved. 1353**/ 1354EFI_STATUS 1355EFIAPI 1356FileInterfaceMemGetPosition( 1357 IN EFI_FILE_PROTOCOL *This, 1358 OUT UINT64 *Position 1359 ) 1360{ 1361 *Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position; 1362 return (EFI_SUCCESS); 1363} 1364 1365/** 1366 File style interface for Mem (Write). 1367 1368 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1369 @param[in, out] BufferSize Size in bytes of Buffer. 1370 @param[in] Buffer The pointer to the buffer to write. 1371 1372 @retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources. 1373 @retval EFI_SUCCESS The data was written. 1374**/ 1375EFI_STATUS 1376EFIAPI 1377FileInterfaceMemWrite( 1378 IN EFI_FILE_PROTOCOL *This, 1379 IN OUT UINTN *BufferSize, 1380 IN VOID *Buffer 1381 ) 1382{ 1383 CHAR8 *AsciiBuffer; 1384 if (((EFI_FILE_PROTOCOL_MEM*)This)->Unicode) { 1385 // 1386 // Unicode 1387 // 1388 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { 1389 ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + (*BufferSize) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); 1390 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += (*BufferSize) + 10; 1391 } 1392 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, Buffer, *BufferSize); 1393 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += (*BufferSize); 1394 return (EFI_SUCCESS); 1395 } else { 1396 // 1397 // Ascii 1398 // 1399 AsciiBuffer = AllocateZeroPool(*BufferSize); 1400 if (AsciiBuffer == NULL) { 1401 return (EFI_OUT_OF_RESOURCES); 1402 } 1403 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); 1404 if ((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize)) { 1405 ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer = ReallocatePool((UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize), (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) + AsciiStrSize(AsciiBuffer) + 10, ((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); 1406 ((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize += AsciiStrSize(AsciiBuffer) + 10; 1407 } 1408 CopyMem(((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer)); 1409 ((EFI_FILE_PROTOCOL_MEM*)This)->Position += AsciiStrSize(AsciiBuffer); 1410 FreePool(AsciiBuffer); 1411 return (EFI_SUCCESS); 1412 } 1413} 1414 1415/** 1416 File style interface for Mem (Read). 1417 1418 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1419 @param[in, out] BufferSize Size in bytes of Buffer. 1420 @param[in] Buffer The pointer to the buffer to fill. 1421 1422 @retval EFI_SUCCESS The data was read. 1423**/ 1424EFI_STATUS 1425EFIAPI 1426FileInterfaceMemRead( 1427 IN EFI_FILE_PROTOCOL *This, 1428 IN OUT UINTN *BufferSize, 1429 IN VOID *Buffer 1430 ) 1431{ 1432 if (*BufferSize > (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position))) { 1433 (*BufferSize) = (UINTN)((((EFI_FILE_PROTOCOL_MEM*)This)->BufferSize) - (UINTN)(((EFI_FILE_PROTOCOL_MEM*)This)->Position)); 1434 } 1435 CopyMem(Buffer, ((UINT8*)((EFI_FILE_PROTOCOL_MEM*)This)->Buffer) + ((EFI_FILE_PROTOCOL_MEM*)This)->Position, (*BufferSize)); 1436 ((EFI_FILE_PROTOCOL_MEM*)This)->Position = ((EFI_FILE_PROTOCOL_MEM*)This)->Position + (*BufferSize); 1437 return (EFI_SUCCESS); 1438} 1439 1440/** 1441 File style interface for Mem (Close). 1442 1443 Frees all memory associated with this object. 1444 1445 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1446 1447 @retval EFI_SUCCESS The 'file' was closed. 1448**/ 1449EFI_STATUS 1450EFIAPI 1451FileInterfaceMemClose( 1452 IN EFI_FILE_PROTOCOL *This 1453 ) 1454{ 1455 SHELL_FREE_NON_NULL(((EFI_FILE_PROTOCOL_MEM*)This)->Buffer); 1456 SHELL_FREE_NON_NULL(This); 1457 return (EFI_SUCCESS); 1458} 1459 1460/** 1461 Creates a EFI_FILE_PROTOCOL (almost) object for using to access 1462 a file entirely in memory through file operations. 1463 1464 @param[in] Unicode Boolean value with TRUE for Unicode and FALSE for Ascii. 1465 1466 @retval NULL Memory could not be allocated. 1467 @return other A pointer to an EFI_FILE_PROTOCOL structure. 1468**/ 1469EFI_FILE_PROTOCOL* 1470EFIAPI 1471CreateFileInterfaceMem( 1472 IN CONST BOOLEAN Unicode 1473 ) 1474{ 1475 EFI_FILE_PROTOCOL_MEM *FileInterface; 1476 1477 // 1478 // Get some memory 1479 // 1480 FileInterface = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_MEM)); 1481 if (FileInterface == NULL){ 1482 return (NULL); 1483 } 1484 1485 // 1486 // Assign the generic members 1487 // 1488 FileInterface->Revision = EFI_FILE_REVISION; 1489 FileInterface->Open = FileInterfaceOpenNotFound; 1490 FileInterface->Close = FileInterfaceMemClose; 1491 FileInterface->GetPosition = FileInterfaceMemGetPosition; 1492 FileInterface->SetPosition = FileInterfaceMemSetPosition; 1493 FileInterface->GetInfo = FileInterfaceNopGetInfo; 1494 FileInterface->SetInfo = FileInterfaceNopSetInfo; 1495 FileInterface->Flush = FileInterfaceNopGeneric; 1496 FileInterface->Delete = FileInterfaceNopGeneric; 1497 FileInterface->Read = FileInterfaceMemRead; 1498 FileInterface->Write = FileInterfaceMemWrite; 1499 FileInterface->Unicode = Unicode; 1500 1501 ASSERT(FileInterface->Buffer == NULL); 1502 ASSERT(FileInterface->BufferSize == 0); 1503 ASSERT(FileInterface->Position == 0); 1504 1505 return ((EFI_FILE_PROTOCOL *)FileInterface); 1506} 1507 1508typedef struct { 1509 UINT64 Revision; 1510 EFI_FILE_OPEN Open; 1511 EFI_FILE_CLOSE Close; 1512 EFI_FILE_DELETE Delete; 1513 EFI_FILE_READ Read; 1514 EFI_FILE_WRITE Write; 1515 EFI_FILE_GET_POSITION GetPosition; 1516 EFI_FILE_SET_POSITION SetPosition; 1517 EFI_FILE_GET_INFO GetInfo; 1518 EFI_FILE_SET_INFO SetInfo; 1519 EFI_FILE_FLUSH Flush; 1520 BOOLEAN Unicode; 1521 EFI_FILE_PROTOCOL *Orig; 1522} EFI_FILE_PROTOCOL_FILE; 1523 1524/** 1525 Set a files current position 1526 1527 @param This Protocol instance pointer. 1528 @param Position Byte position from the start of the file. 1529 1530 @retval EFI_SUCCESS Data was written. 1531 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. 1532 1533**/ 1534EFI_STATUS 1535EFIAPI 1536FileInterfaceFileSetPosition( 1537 IN EFI_FILE_PROTOCOL *This, 1538 IN UINT64 Position 1539 ) 1540{ 1541 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); 1542} 1543 1544/** 1545 Get a file's current position 1546 1547 @param This Protocol instance pointer. 1548 @param Position Byte position from the start of the file. 1549 1550 @retval EFI_SUCCESS Data was written. 1551 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. 1552 1553**/ 1554EFI_STATUS 1555EFIAPI 1556FileInterfaceFileGetPosition( 1557 IN EFI_FILE_PROTOCOL *This, 1558 OUT UINT64 *Position 1559 ) 1560{ 1561 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetPosition(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, Position); 1562} 1563 1564/** 1565 Get information about a file. 1566 1567 @param This Protocol instance pointer. 1568 @param InformationType Type of information to return in Buffer. 1569 @param BufferSize On input size of buffer, on output amount of data in buffer. 1570 @param Buffer The buffer to return data. 1571 1572 @retval EFI_SUCCESS Data was returned. 1573 @retval EFI_UNSUPPORT InformationType is not supported. 1574 @retval EFI_NO_MEDIA The device has no media. 1575 @retval EFI_DEVICE_ERROR The device reported an error. 1576 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1577 @retval EFI_WRITE_PROTECTED The device is write protected. 1578 @retval EFI_ACCESS_DENIED The file was open for read only. 1579 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. 1580 1581**/ 1582EFI_STATUS 1583EFIAPI 1584FileInterfaceFileGetInfo( 1585 IN EFI_FILE_PROTOCOL *This, 1586 IN EFI_GUID *InformationType, 1587 IN OUT UINTN *BufferSize, 1588 OUT VOID *Buffer 1589 ) 1590{ 1591 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->GetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); 1592} 1593 1594/** 1595 Set information about a file 1596 1597 @param This Protocol instance pointer. 1598 @param InformationType Type of information in Buffer. 1599 @param BufferSize Size of buffer. 1600 @param Buffer The data to write. 1601 1602 @retval EFI_SUCCESS Data was returned. 1603 @retval EFI_UNSUPPORT InformationType is not supported. 1604 @retval EFI_NO_MEDIA The device has no media. 1605 @retval EFI_DEVICE_ERROR The device reported an error. 1606 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1607 @retval EFI_WRITE_PROTECTED The device is write protected. 1608 @retval EFI_ACCESS_DENIED The file was open for read only. 1609 1610**/ 1611EFI_STATUS 1612EFIAPI 1613FileInterfaceFileSetInfo( 1614 IN EFI_FILE_PROTOCOL *This, 1615 IN EFI_GUID *InformationType, 1616 IN UINTN BufferSize, 1617 IN VOID *Buffer 1618 ) 1619{ 1620 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->SetInfo(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, InformationType, BufferSize, Buffer); 1621} 1622 1623/** 1624 Flush data back for the file handle. 1625 1626 @param This Protocol instance pointer. 1627 1628 @retval EFI_SUCCESS Data was written. 1629 @retval EFI_UNSUPPORT Writes to Open directory are not supported. 1630 @retval EFI_NO_MEDIA The device has no media. 1631 @retval EFI_DEVICE_ERROR The device reported an error. 1632 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1633 @retval EFI_WRITE_PROTECTED The device is write protected. 1634 @retval EFI_ACCESS_DENIED The file was open for read only. 1635 @retval EFI_VOLUME_FULL The volume is full. 1636 1637**/ 1638EFI_STATUS 1639EFIAPI 1640FileInterfaceFileFlush( 1641 IN EFI_FILE_PROTOCOL *This 1642 ) 1643{ 1644 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Flush(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1645} 1646 1647/** 1648 Read data from the file. 1649 1650 @param This Protocol instance pointer. 1651 @param BufferSize On input size of buffer, on output amount of data in buffer. 1652 @param Buffer The buffer in which data is read. 1653 1654 @retval EFI_SUCCESS Data was read. 1655 @retval EFI_NO_MEDIA The device has no media. 1656 @retval EFI_DEVICE_ERROR The device reported an error. 1657 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1658 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. 1659 1660**/ 1661EFI_STATUS 1662EFIAPI 1663FileInterfaceFileRead( 1664 IN EFI_FILE_PROTOCOL *This, 1665 IN OUT UINTN *BufferSize, 1666 OUT VOID *Buffer 1667 ) 1668{ 1669 CHAR8 *AsciiBuffer; 1670 UINTN Size; 1671 EFI_STATUS Status; 1672 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { 1673 // 1674 // Unicode 1675 // 1676 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); 1677 } else { 1678 // 1679 // Ascii 1680 // 1681 AsciiBuffer = AllocateZeroPool((Size = *BufferSize)); 1682 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); 1683 UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer); 1684 FreePool(AsciiBuffer); 1685 return (Status); 1686 } 1687} 1688 1689/** 1690 Opens a new file relative to the source file's location. 1691 1692 @param[in] This The protocol instance pointer. 1693 @param[out] NewHandle Returns File Handle for FileName. 1694 @param[in] FileName Null terminated string. "\", ".", and ".." are supported. 1695 @param[in] OpenMode Open mode for file. 1696 @param[in] Attributes Only used for EFI_FILE_MODE_CREATE. 1697 1698 @retval EFI_SUCCESS The device was opened. 1699 @retval EFI_NOT_FOUND The specified file could not be found on the device. 1700 @retval EFI_NO_MEDIA The device has no media. 1701 @retval EFI_MEDIA_CHANGED The media has changed. 1702 @retval EFI_DEVICE_ERROR The device reported an error. 1703 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. 1704 @retval EFI_ACCESS_DENIED The service denied access to the file. 1705 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. 1706 @retval EFI_VOLUME_FULL The volume is full. 1707**/ 1708EFI_STATUS 1709EFIAPI 1710FileInterfaceFileOpen ( 1711 IN EFI_FILE_PROTOCOL *This, 1712 OUT EFI_FILE_PROTOCOL **NewHandle, 1713 IN CHAR16 *FileName, 1714 IN UINT64 OpenMode, 1715 IN UINT64 Attributes 1716 ) 1717{ 1718 return ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Open(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, NewHandle, FileName, OpenMode, Attributes); 1719} 1720 1721/** 1722 Close and delete the file handle. 1723 1724 @param This Protocol instance pointer. 1725 1726 @retval EFI_SUCCESS The device was opened. 1727 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. 1728 1729**/ 1730EFI_STATUS 1731EFIAPI 1732FileInterfaceFileDelete( 1733 IN EFI_FILE_PROTOCOL *This 1734 ) 1735{ 1736 EFI_STATUS Status; 1737 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Delete(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1738 FreePool(This); 1739 return (Status); 1740} 1741 1742/** 1743 File style interface for File (Close). 1744 1745 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1746 1747 @retval EFI_SUCCESS The file was closed. 1748**/ 1749EFI_STATUS 1750EFIAPI 1751FileInterfaceFileClose( 1752 IN EFI_FILE_PROTOCOL *This 1753 ) 1754{ 1755 EFI_STATUS Status; 1756 Status = ((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Close(((EFI_FILE_PROTOCOL_FILE*)This)->Orig); 1757 FreePool(This); 1758 return (Status); 1759} 1760 1761/** 1762 File style interface for File (Write). 1763 1764 If the file was opened with ASCII mode the data will be processed through 1765 AsciiSPrint before writing. 1766 1767 @param[in] This The pointer to the EFI_FILE_PROTOCOL object. 1768 @param[in, out] BufferSize Size in bytes of Buffer. 1769 @param[in] Buffer The pointer to the buffer to write. 1770 1771 @retval EFI_SUCCESS The data was written. 1772**/ 1773EFI_STATUS 1774EFIAPI 1775FileInterfaceFileWrite( 1776 IN EFI_FILE_PROTOCOL *This, 1777 IN OUT UINTN *BufferSize, 1778 IN VOID *Buffer 1779 ) 1780{ 1781 CHAR8 *AsciiBuffer; 1782 UINTN Size; 1783 EFI_STATUS Status; 1784 if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { 1785 // 1786 // Unicode 1787 // 1788 return (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, BufferSize, Buffer)); 1789 } else { 1790 // 1791 // Ascii 1792 // 1793 AsciiBuffer = AllocateZeroPool(*BufferSize); 1794 AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer); 1795 Size = AsciiStrSize(AsciiBuffer) - 1; // (we dont need the null terminator) 1796 Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Write(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); 1797 FreePool(AsciiBuffer); 1798 return (Status); 1799 } 1800} 1801 1802/** 1803 Create a file interface with unicode information. 1804 1805 This will create a new EFI_FILE_PROTOCOL identical to the Templace 1806 except that the new one has Unicode and Ascii knowledge. 1807 1808 @param[in] Template A pointer to the EFI_FILE_PROTOCOL object. 1809 @param[in] Unicode TRUE for UCS-2, FALSE for ASCII. 1810 1811 @return a new EFI_FILE_PROTOCOL object to be used instead of the template. 1812**/ 1813EFI_FILE_PROTOCOL* 1814CreateFileInterfaceFile( 1815 IN CONST EFI_FILE_PROTOCOL *Template, 1816 IN CONST BOOLEAN Unicode 1817 ) 1818{ 1819 EFI_FILE_PROTOCOL_FILE *NewOne; 1820 1821 NewOne = AllocateZeroPool(sizeof(EFI_FILE_PROTOCOL_FILE)); 1822 if (NewOne == NULL) { 1823 return (NULL); 1824 } 1825 CopyMem(NewOne, Template, sizeof(EFI_FILE_PROTOCOL_FILE)); 1826 NewOne->Orig = (EFI_FILE_PROTOCOL *)Template; 1827 NewOne->Unicode = Unicode; 1828 NewOne->Open = FileInterfaceFileOpen; 1829 NewOne->Close = FileInterfaceFileClose; 1830 NewOne->Delete = FileInterfaceFileDelete; 1831 NewOne->Read = FileInterfaceFileRead; 1832 NewOne->Write = FileInterfaceFileWrite; 1833 NewOne->GetPosition = FileInterfaceFileGetPosition; 1834 NewOne->SetPosition = FileInterfaceFileSetPosition; 1835 NewOne->GetInfo = FileInterfaceFileGetInfo; 1836 NewOne->SetInfo = FileInterfaceFileSetInfo; 1837 NewOne->Flush = FileInterfaceFileFlush; 1838 1839 return ((EFI_FILE_PROTOCOL *)NewOne); 1840} 1841