1 /** @file 2 * 3 * Copyright (c) 2012-2015, ARM Limited. All rights reserved. 4 * 5 * This program and the accompanying materials 6 * are licensed and made available under the terms and conditions of the BSD License 7 * which accompanies this distribution. The full text of the license may be found at 8 * http://opensource.org/licenses/bsd-license.php 9 * 10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 * 13 **/ 14 15 #include "BootMonFsInternal.h" 16 17 // Clear a file's image description on storage media: 18 // UEFI allows you to seek past the end of a file, a subsequent write will grow 19 // the file. It does not specify how space between the former end of the file 20 // and the beginning of the write should be filled. It's therefore possible that 21 // BootMonFs metadata, that comes after the end of a file, could be left there 22 // and wrongly detected by BootMonFsImageInBlock. 23 STATIC 24 EFI_STATUS 25 InvalidateImageDescription ( 26 IN BOOTMON_FS_FILE *File 27 ) 28 { 29 EFI_DISK_IO_PROTOCOL *DiskIo; 30 EFI_BLOCK_IO_PROTOCOL *BlockIo; 31 UINT32 MediaId; 32 VOID *Buffer; 33 EFI_STATUS Status; 34 35 DiskIo = File->Instance->DiskIo; 36 BlockIo = File->Instance->BlockIo; 37 MediaId = BlockIo->Media->MediaId; 38 39 Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION)); 40 41 if (Buffer == NULL) { 42 return EFI_OUT_OF_RESOURCES; 43 } 44 45 Status = DiskIo->WriteDisk (DiskIo, 46 MediaId, 47 File->HwDescAddress, 48 sizeof (HW_IMAGE_DESCRIPTION), 49 Buffer 50 ); 51 52 FreePool(Buffer); 53 54 return Status; 55 } 56 57 /** 58 Write the description of a file to storage media. 59 60 This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks() 61 after calling it to ensure the data are written on the media. 62 63 @param[in] File Description of the file whose description on the 64 storage media has to be updated. 65 @param[in] FileName Name of the file. Its length is assumed to be 66 lower than MAX_NAME_LENGTH. 67 @param[in] DataSize Number of data bytes of the file. 68 @param[in] FileStart File's starting position on media. FileStart must 69 be aligned to the media's block size. 70 71 @retval EFI_WRITE_PROTECTED The device cannot be written to. 72 @retval EFI_DEVICE_ERROR The device reported an error while performing 73 the write operation. 74 75 **/ 76 STATIC 77 EFI_STATUS 78 WriteFileDescription ( 79 IN BOOTMON_FS_FILE *File, 80 IN CHAR8 *FileName, 81 IN UINT32 DataSize, 82 IN UINT64 FileStart 83 ) 84 { 85 EFI_STATUS Status; 86 EFI_DISK_IO_PROTOCOL *DiskIo; 87 UINTN BlockSize; 88 UINT32 FileSize; 89 HW_IMAGE_DESCRIPTION *Description; 90 91 DiskIo = File->Instance->DiskIo; 92 BlockSize = File->Instance->BlockIo->Media->BlockSize; 93 ASSERT (FileStart % BlockSize == 0); 94 95 // 96 // Construct the file description 97 // 98 99 FileSize = DataSize + sizeof (HW_IMAGE_DESCRIPTION); 100 Description = &File->HwDescription; 101 Description->Attributes = 1; 102 Description->BlockStart = FileStart / BlockSize; 103 Description->BlockEnd = Description->BlockStart + (FileSize / BlockSize); 104 AsciiStrCpy (Description->Footer.Filename, FileName); 105 106 #ifdef MDE_CPU_ARM 107 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET; 108 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION; 109 #else 110 Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2; 111 Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2; 112 #endif 113 Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1; 114 Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2; 115 Description->RegionCount = 1; 116 Description->Region[0].Checksum = 0; 117 Description->Region[0].Offset = Description->BlockStart * BlockSize; 118 Description->Region[0].Size = DataSize; 119 120 Status = BootMonFsComputeFooterChecksum (Description); 121 if (EFI_ERROR (Status)) { 122 return Status; 123 } 124 125 File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION); 126 127 // Update the file description on the media 128 Status = DiskIo->WriteDisk ( 129 DiskIo, 130 File->Instance->Media->MediaId, 131 File->HwDescAddress, 132 sizeof (HW_IMAGE_DESCRIPTION), 133 Description 134 ); 135 ASSERT_EFI_ERROR (Status); 136 137 return Status; 138 } 139 140 // Find a space on media for a file that has not yet been flushed to disk. 141 // Just returns the first space that's big enough. 142 // This function could easily be adapted to: 143 // - Find space for moving an existing file that has outgrown its space 144 // (We do not currently move files, just return EFI_VOLUME_FULL) 145 // - Find space for a fragment of a file that has outgrown its space 146 // (We do not currently fragment files - it's not clear whether fragmentation 147 // is actually part of BootMonFs as there is no spec) 148 // - Be more clever about finding space (choosing the largest or smallest 149 // suitable space) 150 // Parameters: 151 // File - the new (not yet flushed) file for which we need to find space. 152 // FileStart - the position on media of the file (in bytes). 153 STATIC 154 EFI_STATUS 155 BootMonFsFindSpaceForNewFile ( 156 IN BOOTMON_FS_FILE *File, 157 IN UINT64 FileSize, 158 OUT UINT64 *FileStart 159 ) 160 { 161 LIST_ENTRY *FileLink; 162 BOOTMON_FS_FILE *RootFile; 163 BOOTMON_FS_FILE *FileEntry; 164 UINTN BlockSize; 165 EFI_BLOCK_IO_MEDIA *Media; 166 167 Media = File->Instance->BlockIo->Media; 168 BlockSize = Media->BlockSize; 169 RootFile = File->Instance->RootFile; 170 171 // This function must only be called for file which has not been flushed into 172 // Flash yet 173 ASSERT (File->HwDescription.RegionCount == 0); 174 175 *FileStart = 0; 176 // Go through all the files in the list 177 for (FileLink = GetFirstNode (&RootFile->Link); 178 !IsNull (&RootFile->Link, FileLink); 179 FileLink = GetNextNode (&RootFile->Link, FileLink) 180 ) 181 { 182 FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); 183 // Skip files that aren't on disk yet 184 if (FileEntry->HwDescription.RegionCount == 0) { 185 continue; 186 } 187 188 // If the free space preceding the file is big enough to contain the new 189 // file then use it! 190 if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart) 191 >= FileSize) { 192 // The file list must be in disk-order 193 RemoveEntryList (&File->Link); 194 File->Link.BackLink = FileLink->BackLink; 195 File->Link.ForwardLink = FileLink; 196 FileLink->BackLink->ForwardLink = &File->Link; 197 FileLink->BackLink = &File->Link; 198 199 return EFI_SUCCESS; 200 } else { 201 *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize; 202 } 203 } 204 // See if there's space after the last file 205 if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) { 206 return EFI_SUCCESS; 207 } else { 208 return EFI_VOLUME_FULL; 209 } 210 } 211 212 // Free the resources in the file's Region list. 213 STATIC 214 VOID 215 FreeFileRegions ( 216 IN BOOTMON_FS_FILE *File 217 ) 218 { 219 LIST_ENTRY *RegionToFlushLink; 220 BOOTMON_FS_FILE_REGION *Region; 221 222 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); 223 while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) { 224 // Repeatedly remove the first node from the list and free its resources. 225 Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink; 226 RemoveEntryList (RegionToFlushLink); 227 FreePool (Region->Buffer); 228 FreePool (Region); 229 230 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); 231 } 232 } 233 234 /** 235 Flush all modified data associated with a file to a device. 236 237 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the 238 file handle to flush. 239 240 @retval EFI_SUCCESS The data was flushed. 241 @retval EFI_ACCESS_DENIED The file was opened read-only. 242 @retval EFI_DEVICE_ERROR The device reported an error. 243 @retval EFI_VOLUME_FULL The volume is full. 244 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data. 245 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. 246 247 **/ 248 EFIAPI 249 EFI_STATUS 250 BootMonFsFlushFile ( 251 IN EFI_FILE_PROTOCOL *This 252 ) 253 { 254 EFI_STATUS Status; 255 BOOTMON_FS_INSTANCE *Instance; 256 EFI_FILE_INFO *Info; 257 EFI_BLOCK_IO_PROTOCOL *BlockIo; 258 EFI_BLOCK_IO_MEDIA *Media; 259 EFI_DISK_IO_PROTOCOL *DiskIo; 260 UINTN BlockSize; 261 CHAR8 AsciiFileName[MAX_NAME_LENGTH]; 262 LIST_ENTRY *RegionToFlushLink; 263 BOOTMON_FS_FILE *File; 264 BOOTMON_FS_FILE *NextFile; 265 BOOTMON_FS_FILE_REGION *Region; 266 LIST_ENTRY *FileLink; 267 UINTN CurrentPhysicalSize; 268 UINT64 FileStart; 269 UINT64 FileEnd; 270 UINT64 RegionStart; 271 UINT64 RegionEnd; 272 UINT64 NewDataSize; 273 UINT64 NewFileSize; 274 UINT64 EndOfAppendSpace; 275 BOOLEAN HasSpace; 276 277 if (This == NULL) { 278 return EFI_INVALID_PARAMETER; 279 } 280 281 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 282 if (File->Info == NULL) { 283 return EFI_INVALID_PARAMETER; 284 } 285 286 if (File->OpenMode == EFI_FILE_MODE_READ) { 287 return EFI_ACCESS_DENIED; 288 } 289 290 Instance = File->Instance; 291 Info = File->Info; 292 BlockIo = Instance->BlockIo; 293 Media = BlockIo->Media; 294 DiskIo = Instance->DiskIo; 295 BlockSize = Media->BlockSize; 296 297 UnicodeStrToAsciiStr (Info->FileName, AsciiFileName); 298 299 // If the file doesn't exist then find a space for it 300 if (File->HwDescription.RegionCount == 0) { 301 Status = BootMonFsFindSpaceForNewFile ( 302 File, 303 Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION), 304 &FileStart 305 ); 306 if (EFI_ERROR (Status)) { 307 return Status; 308 } 309 } else { 310 FileStart = File->HwDescription.BlockStart * BlockSize; 311 } 312 // FileEnd is the current NOR address of the end of the file's data 313 FileEnd = FileStart + File->HwDescription.Region[0].Size; 314 315 for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); 316 !IsNull (&File->RegionToFlushLink, RegionToFlushLink); 317 RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink) 318 ) 319 { 320 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; 321 if (Region->Size == 0) { 322 continue; 323 } 324 325 // RegionStart and RegionEnd are the the intended NOR address of the 326 // start and end of the region 327 RegionStart = FileStart + Region->Offset; 328 RegionEnd = RegionStart + Region->Size; 329 330 if (RegionEnd < FileEnd) { 331 // Handle regions representing edits to existing portions of the file 332 // Write the region data straight into the file 333 Status = DiskIo->WriteDisk (DiskIo, 334 Media->MediaId, 335 RegionStart, 336 Region->Size, 337 Region->Buffer 338 ); 339 if (EFI_ERROR (Status)) { 340 return Status; 341 } 342 } else { 343 // Handle regions representing appends to the file 344 // 345 // Note: Since seeking past the end of the file with SetPosition() is 346 // valid, it's possible there will be a gap between the current end of 347 // the file and the beginning of the new region. Since the UEFI spec 348 // says nothing about this case (except "a subsequent write would grow 349 // the file"), we just leave garbage in the gap. 350 351 // Check if there is space to append the new region 352 HasSpace = FALSE; 353 NewDataSize = RegionEnd - FileStart; 354 NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION); 355 CurrentPhysicalSize = BootMonFsGetPhysicalSize (File); 356 if (NewFileSize <= CurrentPhysicalSize) { 357 HasSpace = TRUE; 358 } else { 359 // Get the File Description for the next file 360 FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link); 361 if (!IsNull (&Instance->RootFile->Link, FileLink)) { 362 NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); 363 364 // If there is space between the beginning of the current file and the 365 // beginning of the next file then use it 366 EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize; 367 } else { 368 // We are flushing the last file. 369 EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize; 370 } 371 if (EndOfAppendSpace - FileStart >= NewFileSize) { 372 HasSpace = TRUE; 373 } 374 } 375 376 if (HasSpace == TRUE) { 377 // Invalidate the current image description of the file if any. 378 if (File->HwDescAddress != 0) { 379 Status = InvalidateImageDescription (File); 380 if (EFI_ERROR (Status)) { 381 return Status; 382 } 383 } 384 385 // Write the new file data 386 Status = DiskIo->WriteDisk ( 387 DiskIo, 388 Media->MediaId, 389 RegionStart, 390 Region->Size, 391 Region->Buffer 392 ); 393 if (EFI_ERROR (Status)) { 394 return Status; 395 } 396 397 Status = WriteFileDescription (File, AsciiFileName, NewDataSize, FileStart); 398 if (EFI_ERROR (Status)) { 399 return Status; 400 } 401 402 } else { 403 // There isn't a space for the file. 404 // Options here are to move the file or fragment it. However as files 405 // may represent boot images at fixed positions, these options will 406 // break booting if the bootloader doesn't use BootMonFs to find the 407 // image. 408 409 return EFI_VOLUME_FULL; 410 } 411 } 412 } 413 414 FreeFileRegions (File); 415 Info->PhysicalSize = BootMonFsGetPhysicalSize (File); 416 417 if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) || 418 (Info->FileSize != File->HwDescription.Region[0].Size) ) { 419 Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart); 420 if (EFI_ERROR (Status)) { 421 return Status; 422 } 423 } 424 425 // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by 426 // calling FlushBlocks on the same device's BlockIo). 427 BlockIo->FlushBlocks (BlockIo); 428 429 return EFI_SUCCESS; 430 } 431 432 /** 433 Close a specified file handle. 434 435 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file 436 handle to close. 437 438 @retval EFI_SUCCESS The file was closed. 439 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open 440 file handle. 441 442 **/ 443 EFIAPI 444 EFI_STATUS 445 BootMonFsCloseFile ( 446 IN EFI_FILE_PROTOCOL *This 447 ) 448 { 449 BOOTMON_FS_FILE *File; 450 451 if (This == NULL) { 452 return EFI_INVALID_PARAMETER; 453 } 454 455 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 456 if (File->Info == NULL) { 457 return EFI_INVALID_PARAMETER; 458 } 459 460 // In the case of a file and not the root directory 461 if (This != &File->Instance->RootFile->File) { 462 This->Flush (This); 463 FreePool (File->Info); 464 File->Info = NULL; 465 } 466 467 return EFI_SUCCESS; 468 } 469 470 /** 471 Open a file on the boot monitor file system. 472 473 The boot monitor file system does not allow for sub-directories. There is only 474 one directory, the root one. On any attempt to create a directory, the function 475 returns in error with the EFI_WRITE_PROTECTED error code. 476 477 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is 478 the file handle to source location. 479 @param[out] NewHandle A pointer to the location to return the opened 480 handle for the new file. 481 @param[in] FileName The Null-terminated string of the name of the file 482 to be opened. 483 @param[in] OpenMode The mode to open the file : Read or Read/Write or 484 Read/Write/Create 485 @param[in] Attributes Attributes of the file in case of a file creation 486 487 @retval EFI_SUCCESS The file was open. 488 @retval EFI_NOT_FOUND The specified file could not be found or the specified 489 directory in which to create a file could not be found. 490 @retval EFI_DEVICE_ERROR The device reported an error. 491 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible 492 with the Boot Monitor file system. 493 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. 494 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. 495 496 **/ 497 EFIAPI 498 EFI_STATUS 499 BootMonFsOpenFile ( 500 IN EFI_FILE_PROTOCOL *This, 501 OUT EFI_FILE_PROTOCOL **NewHandle, 502 IN CHAR16 *FileName, 503 IN UINT64 OpenMode, 504 IN UINT64 Attributes 505 ) 506 { 507 EFI_STATUS Status; 508 BOOTMON_FS_FILE *Directory; 509 BOOTMON_FS_FILE *File; 510 BOOTMON_FS_INSTANCE *Instance; 511 CHAR8 *Buf; 512 CHAR16 *Path; 513 CHAR16 *Separator; 514 CHAR8 *AsciiFileName; 515 EFI_FILE_INFO *Info; 516 517 if (This == NULL) { 518 return EFI_INVALID_PARAMETER; 519 } 520 521 Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 522 if (Directory->Info == NULL) { 523 return EFI_INVALID_PARAMETER; 524 } 525 526 if ((FileName == NULL) || (NewHandle == NULL)) { 527 return EFI_INVALID_PARAMETER; 528 } 529 530 // 531 // The only valid modes are read, read/write, and read/write/create 532 // 533 if ( (OpenMode != EFI_FILE_MODE_READ) && 534 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) && 535 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) { 536 return EFI_INVALID_PARAMETER; 537 } 538 539 Instance = Directory->Instance; 540 541 // 542 // If the instance has not been initialized yet then do it ... 543 // 544 if (!Instance->Initialized) { 545 Status = BootMonFsInitialize (Instance); 546 if (EFI_ERROR (Status)) { 547 return Status; 548 } 549 } 550 551 // 552 // Copy the file path to be able to work on it. We do not want to 553 // modify the input file name string "FileName". 554 // 555 Buf = AllocateCopyPool (StrSize (FileName), FileName); 556 if (Buf == NULL) { 557 return EFI_OUT_OF_RESOURCES; 558 } 559 Path = (CHAR16*)Buf; 560 AsciiFileName = NULL; 561 Info = NULL; 562 563 // 564 // Handle single periods, double periods and convert forward slashes '/' 565 // to backward '\' ones. Does not handle a '.' at the beginning of the 566 // path for the time being. 567 // 568 if (PathCleanUpDirectories (Path) == NULL) { 569 Status = EFI_INVALID_PARAMETER; 570 goto Error; 571 } 572 573 // 574 // Detect if the first component of the path refers to a directory. 575 // This is done to return the correct error code when trying to 576 // access or create a directory other than the root directory. 577 // 578 579 // 580 // Search for the '\\' sequence and if found return in error 581 // with the EFI_INVALID_PARAMETER error code. ere in the path. 582 // 583 if (StrStr (Path, L"\\\\") != NULL) { 584 Status = EFI_INVALID_PARAMETER; 585 goto Error; 586 } 587 // 588 // Get rid of the leading '\' if any. 589 // 590 Path += (Path[0] == L'\\'); 591 592 // 593 // Look for a '\' in the file path. If one is found then 594 // the first component of the path refers to a directory 595 // that is not the root directory. 596 // 597 Separator = StrStr (Path, L"\\"); 598 if (Separator != NULL) { 599 // 600 // In the case '<dir name>\' and a creation, return 601 // EFI_WRITE_PROTECTED if this is for a directory 602 // creation, EFI_INVALID_PARAMETER otherwise. 603 // 604 if ((*(Separator + 1) == '\0') && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) { 605 if (Attributes & EFI_FILE_DIRECTORY) { 606 Status = EFI_WRITE_PROTECTED; 607 } else { 608 Status = EFI_INVALID_PARAMETER; 609 } 610 } else { 611 // 612 // Attempt to open a file or a directory that is not in the 613 // root directory or to open without creation a directory 614 // located in the root directory, returns EFI_NOT_FOUND. 615 // 616 Status = EFI_NOT_FOUND; 617 } 618 goto Error; 619 } 620 621 // 622 // BootMonFs interface requires ASCII filenames 623 // 624 AsciiFileName = AllocatePool (StrLen (Path) + 1); 625 if (AsciiFileName == NULL) { 626 Status = EFI_OUT_OF_RESOURCES; 627 goto Error; 628 } 629 UnicodeStrToAsciiStr (Path, AsciiFileName); 630 if (AsciiStrSize (AsciiFileName) > MAX_NAME_LENGTH) { 631 AsciiFileName[MAX_NAME_LENGTH - 1] = '\0'; 632 } 633 634 if ((AsciiFileName[0] == '\0') || 635 (AsciiFileName[0] == '.' ) ) { 636 // 637 // Opening the root directory 638 // 639 640 *NewHandle = &Instance->RootFile->File; 641 Instance->RootFile->Position = 0; 642 Status = EFI_SUCCESS; 643 } else { 644 645 if ((OpenMode & EFI_FILE_MODE_CREATE) && 646 (Attributes & EFI_FILE_DIRECTORY) ) { 647 Status = EFI_WRITE_PROTECTED; 648 goto Error; 649 } 650 651 // 652 // Allocate a buffer to store the characteristics of the file while the 653 // file is open. We allocate the maximum size to not have to reallocate 654 // if the file name is changed. 655 // 656 Info = AllocateZeroPool ( 657 SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH)); 658 if (Info == NULL) { 659 Status = EFI_OUT_OF_RESOURCES; 660 goto Error; 661 } 662 663 // 664 // Open or create a file in the root directory. 665 // 666 667 Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File); 668 if (Status == EFI_NOT_FOUND) { 669 if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) { 670 goto Error; 671 } 672 673 Status = BootMonFsCreateFile (Instance, &File); 674 if (EFI_ERROR (Status)) { 675 goto Error; 676 } 677 InsertHeadList (&Instance->RootFile->Link, &File->Link); 678 Info->Attribute = Attributes; 679 } else { 680 // 681 // File already open, not supported yet. 682 // 683 if (File->Info != NULL) { 684 Status = EFI_UNSUPPORTED; 685 goto Error; 686 } 687 } 688 689 Info->FileSize = BootMonFsGetImageLength (File); 690 Info->PhysicalSize = BootMonFsGetPhysicalSize (File); 691 AsciiStrToUnicodeStr (AsciiFileName, Info->FileName); 692 693 File->Info = Info; 694 Info = NULL; 695 File->Position = 0; 696 File->OpenMode = OpenMode; 697 698 *NewHandle = &File->File; 699 } 700 701 Error: 702 703 FreePool (Buf); 704 if (AsciiFileName != NULL) { 705 FreePool (AsciiFileName); 706 } 707 if (Info != NULL) { 708 FreePool (Info); 709 } 710 711 return Status; 712 } 713 714 // Delete() for the root directory's EFI_FILE_PROTOCOL instance 715 EFIAPI 716 EFI_STATUS 717 BootMonFsDeleteFail ( 718 IN EFI_FILE_PROTOCOL *This 719 ) 720 { 721 This->Close(This); 722 // You can't delete the root directory 723 return EFI_WARN_DELETE_FAILURE; 724 } 725 726 /** 727 Close and delete a file from the boot monitor file system. 728 729 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file 730 handle to delete. 731 732 @retval EFI_SUCCESS The file was closed and deleted. 733 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open 734 file handle. 735 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted. 736 737 **/ 738 EFIAPI 739 EFI_STATUS 740 BootMonFsDelete ( 741 IN EFI_FILE_PROTOCOL *This 742 ) 743 { 744 EFI_STATUS Status; 745 BOOTMON_FS_FILE *File; 746 LIST_ENTRY *RegionToFlushLink; 747 BOOTMON_FS_FILE_REGION *Region; 748 749 if (This == NULL) { 750 return EFI_INVALID_PARAMETER; 751 } 752 753 File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); 754 if (File->Info == NULL) { 755 return EFI_INVALID_PARAMETER; 756 } 757 758 if (!IsListEmpty (&File->RegionToFlushLink)) { 759 // Free the entries from the Buffer List 760 RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); 761 do { 762 Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; 763 764 // 765 // Get next element of the list before deleting the region description 766 // that contain the LIST_ENTRY structure. 767 // 768 RegionToFlushLink = RemoveEntryList (RegionToFlushLink); 769 770 // Free the buffers 771 FreePool (Region->Buffer); 772 FreePool (Region); 773 } while (!IsListEmpty (&File->RegionToFlushLink)); 774 } 775 776 // If (RegionCount is greater than 0) then the file already exists 777 if (File->HwDescription.RegionCount > 0) { 778 // Invalidate the last Block 779 Status = InvalidateImageDescription (File); 780 ASSERT_EFI_ERROR (Status); 781 if (EFI_ERROR (Status)) { 782 return EFI_WARN_DELETE_FAILURE; 783 } 784 } 785 786 // Remove the entry from the list 787 RemoveEntryList (&File->Link); 788 FreePool (File->Info); 789 FreePool (File); 790 791 return EFI_SUCCESS; 792 } 793