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