From 40d0673c2e3db10e47fd0742bf484c3d0aea2efe Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 15 Nov 2017 16:20:55 +0000 Subject: Platform/ARM: import BootMonFs and ArmShellCmdRunAxf from EDK2 BootMonFs and ArmShellCmdRunAxf are only used on development boards manufactured by ARM itself, so let's keep it under Platform/ARM where it belongs. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel Reviewed-by: Leif Lindholm --- .../ARM/Drivers/BootMonFs/BootMonFsOpenClose.c | 795 +++++++++++++++++++++ 1 file changed, 795 insertions(+) create mode 100644 Platform/ARM/Drivers/BootMonFs/BootMonFsOpenClose.c (limited to 'Platform/ARM/Drivers/BootMonFs/BootMonFsOpenClose.c') diff --git a/Platform/ARM/Drivers/BootMonFs/BootMonFsOpenClose.c b/Platform/ARM/Drivers/BootMonFs/BootMonFsOpenClose.c new file mode 100644 index 0000000000..ae10055255 --- /dev/null +++ b/Platform/ARM/Drivers/BootMonFs/BootMonFsOpenClose.c @@ -0,0 +1,795 @@ +/** @file +* +* Copyright (c) 2012-2015, ARM Limited. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the BSD License +* which accompanies this distribution. The full text of the license may be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +* +**/ + +#include "BootMonFsInternal.h" + +// Clear a file's image description on storage media: +// UEFI allows you to seek past the end of a file, a subsequent write will grow +// the file. It does not specify how space between the former end of the file +// and the beginning of the write should be filled. It's therefore possible that +// BootMonFs metadata, that comes after the end of a file, could be left there +// and wrongly detected by BootMonFsImageInBlock. +STATIC +EFI_STATUS +InvalidateImageDescription ( + IN BOOTMON_FS_FILE *File + ) +{ + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + UINT32 MediaId; + VOID *Buffer; + EFI_STATUS Status; + + DiskIo = File->Instance->DiskIo; + BlockIo = File->Instance->BlockIo; + MediaId = BlockIo->Media->MediaId; + + Buffer = AllocateZeroPool (sizeof (HW_IMAGE_DESCRIPTION)); + + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = DiskIo->WriteDisk (DiskIo, + MediaId, + File->HwDescAddress, + sizeof (HW_IMAGE_DESCRIPTION), + Buffer + ); + + FreePool(Buffer); + + return Status; +} + +/** + Write the description of a file to storage media. + + This function uses DiskIo to write to the media, so call BlockIo->FlushBlocks() + after calling it to ensure the data are written on the media. + + @param[in] File Description of the file whose description on the + storage media has to be updated. + @param[in] FileName Name of the file. Its length is assumed to be + lower than MAX_NAME_LENGTH. + @param[in] DataSize Number of data bytes of the file. + @param[in] FileStart File's starting position on media. FileStart must + be aligned to the media's block size. + + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_DEVICE_ERROR The device reported an error while performing + the write operation. + +**/ +STATIC +EFI_STATUS +WriteFileDescription ( + IN BOOTMON_FS_FILE *File, + IN CHAR8 *FileName, + IN UINT32 DataSize, + IN UINT64 FileStart + ) +{ + EFI_STATUS Status; + EFI_DISK_IO_PROTOCOL *DiskIo; + UINTN BlockSize; + UINT32 FileSize; + HW_IMAGE_DESCRIPTION *Description; + + DiskIo = File->Instance->DiskIo; + BlockSize = File->Instance->BlockIo->Media->BlockSize; + ASSERT (FileStart % BlockSize == 0); + + // + // Construct the file description + // + + FileSize = DataSize + sizeof (HW_IMAGE_DESCRIPTION); + Description = &File->HwDescription; + Description->Attributes = 1; + Description->BlockStart = FileStart / BlockSize; + Description->BlockEnd = Description->BlockStart + (FileSize / BlockSize); + AsciiStrCpyS (Description->Footer.Filename, + sizeof Description->Footer.Filename, FileName); + +#ifdef MDE_CPU_ARM + Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET; + Description->Footer.Version = HW_IMAGE_FOOTER_VERSION; +#else + Description->Footer.Offset = HW_IMAGE_FOOTER_OFFSET2; + Description->Footer.Version = HW_IMAGE_FOOTER_VERSION2; +#endif + Description->Footer.FooterSignature1 = HW_IMAGE_FOOTER_SIGNATURE_1; + Description->Footer.FooterSignature2 = HW_IMAGE_FOOTER_SIGNATURE_2; + Description->RegionCount = 1; + Description->Region[0].Checksum = 0; + Description->Region[0].Offset = Description->BlockStart * BlockSize; + Description->Region[0].Size = DataSize; + + Status = BootMonFsComputeFooterChecksum (Description); + if (EFI_ERROR (Status)) { + return Status; + } + + File->HwDescAddress = ((Description->BlockEnd + 1) * BlockSize) - sizeof (HW_IMAGE_DESCRIPTION); + + // Update the file description on the media + Status = DiskIo->WriteDisk ( + DiskIo, + File->Instance->Media->MediaId, + File->HwDescAddress, + sizeof (HW_IMAGE_DESCRIPTION), + Description + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +// Find a space on media for a file that has not yet been flushed to disk. +// Just returns the first space that's big enough. +// This function could easily be adapted to: +// - Find space for moving an existing file that has outgrown its space +// (We do not currently move files, just return EFI_VOLUME_FULL) +// - Find space for a fragment of a file that has outgrown its space +// (We do not currently fragment files - it's not clear whether fragmentation +// is actually part of BootMonFs as there is no spec) +// - Be more clever about finding space (choosing the largest or smallest +// suitable space) +// Parameters: +// File - the new (not yet flushed) file for which we need to find space. +// FileStart - the position on media of the file (in bytes). +STATIC +EFI_STATUS +BootMonFsFindSpaceForNewFile ( + IN BOOTMON_FS_FILE *File, + IN UINT64 FileSize, + OUT UINT64 *FileStart + ) +{ + LIST_ENTRY *FileLink; + BOOTMON_FS_FILE *RootFile; + BOOTMON_FS_FILE *FileEntry; + UINTN BlockSize; + EFI_BLOCK_IO_MEDIA *Media; + + Media = File->Instance->BlockIo->Media; + BlockSize = Media->BlockSize; + RootFile = File->Instance->RootFile; + + // This function must only be called for file which has not been flushed into + // Flash yet + ASSERT (File->HwDescription.RegionCount == 0); + + *FileStart = 0; + // Go through all the files in the list + for (FileLink = GetFirstNode (&RootFile->Link); + !IsNull (&RootFile->Link, FileLink); + FileLink = GetNextNode (&RootFile->Link, FileLink) + ) + { + FileEntry = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); + // Skip files that aren't on disk yet + if (FileEntry->HwDescription.RegionCount == 0) { + continue; + } + + // If the free space preceding the file is big enough to contain the new + // file then use it! + if (((FileEntry->HwDescription.BlockStart * BlockSize) - *FileStart) + >= FileSize) { + // The file list must be in disk-order + RemoveEntryList (&File->Link); + File->Link.BackLink = FileLink->BackLink; + File->Link.ForwardLink = FileLink; + FileLink->BackLink->ForwardLink = &File->Link; + FileLink->BackLink = &File->Link; + + return EFI_SUCCESS; + } else { + *FileStart = (FileEntry->HwDescription.BlockEnd + 1) * BlockSize; + } + } + // See if there's space after the last file + if ((((Media->LastBlock + 1) * BlockSize) - *FileStart) >= FileSize) { + return EFI_SUCCESS; + } else { + return EFI_VOLUME_FULL; + } +} + +// Free the resources in the file's Region list. +STATIC +VOID +FreeFileRegions ( + IN BOOTMON_FS_FILE *File + ) +{ + LIST_ENTRY *RegionToFlushLink; + BOOTMON_FS_FILE_REGION *Region; + + RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); + while (!IsNull (&File->RegionToFlushLink, RegionToFlushLink)) { + // Repeatedly remove the first node from the list and free its resources. + Region = (BOOTMON_FS_FILE_REGION *) RegionToFlushLink; + RemoveEntryList (RegionToFlushLink); + FreePool (Region->Buffer); + FreePool (Region); + + RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); + } +} + +/** + Flush all modified data associated with a file to a device. + + @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the + file handle to flush. + + @retval EFI_SUCCESS The data was flushed. + @retval EFI_ACCESS_DENIED The file was opened read-only. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_FULL The volume is full. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to flush the data. + @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. + +**/ +EFIAPI +EFI_STATUS +BootMonFsFlushFile ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + BOOTMON_FS_INSTANCE *Instance; + EFI_FILE_INFO *Info; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_BLOCK_IO_MEDIA *Media; + EFI_DISK_IO_PROTOCOL *DiskIo; + UINTN BlockSize; + CHAR8 AsciiFileName[MAX_NAME_LENGTH]; + LIST_ENTRY *RegionToFlushLink; + BOOTMON_FS_FILE *File; + BOOTMON_FS_FILE *NextFile; + BOOTMON_FS_FILE_REGION *Region; + LIST_ENTRY *FileLink; + UINTN CurrentPhysicalSize; + UINT64 FileStart; + UINT64 FileEnd; + UINT64 RegionStart; + UINT64 RegionEnd; + UINT64 NewDataSize; + UINT64 NewFileSize; + UINT64 EndOfAppendSpace; + BOOLEAN HasSpace; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); + if (File->Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (File->OpenMode == EFI_FILE_MODE_READ) { + return EFI_ACCESS_DENIED; + } + + Instance = File->Instance; + Info = File->Info; + BlockIo = Instance->BlockIo; + Media = BlockIo->Media; + DiskIo = Instance->DiskIo; + BlockSize = Media->BlockSize; + + UnicodeStrToAsciiStrS (Info->FileName, AsciiFileName, MAX_NAME_LENGTH); + + // If the file doesn't exist then find a space for it + if (File->HwDescription.RegionCount == 0) { + Status = BootMonFsFindSpaceForNewFile ( + File, + Info->FileSize + sizeof (HW_IMAGE_DESCRIPTION), + &FileStart + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + FileStart = File->HwDescription.BlockStart * BlockSize; + } + // FileEnd is the current NOR address of the end of the file's data + FileEnd = FileStart + File->HwDescription.Region[0].Size; + + for (RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); + !IsNull (&File->RegionToFlushLink, RegionToFlushLink); + RegionToFlushLink = GetNextNode (&File->RegionToFlushLink, RegionToFlushLink) + ) + { + Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; + if (Region->Size == 0) { + continue; + } + + // RegionStart and RegionEnd are the the intended NOR address of the + // start and end of the region + RegionStart = FileStart + Region->Offset; + RegionEnd = RegionStart + Region->Size; + + if (RegionEnd < FileEnd) { + // Handle regions representing edits to existing portions of the file + // Write the region data straight into the file + Status = DiskIo->WriteDisk (DiskIo, + Media->MediaId, + RegionStart, + Region->Size, + Region->Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // Handle regions representing appends to the file + // + // Note: Since seeking past the end of the file with SetPosition() is + // valid, it's possible there will be a gap between the current end of + // the file and the beginning of the new region. Since the UEFI spec + // says nothing about this case (except "a subsequent write would grow + // the file"), we just leave garbage in the gap. + + // Check if there is space to append the new region + HasSpace = FALSE; + NewDataSize = RegionEnd - FileStart; + NewFileSize = NewDataSize + sizeof (HW_IMAGE_DESCRIPTION); + CurrentPhysicalSize = BootMonFsGetPhysicalSize (File); + if (NewFileSize <= CurrentPhysicalSize) { + HasSpace = TRUE; + } else { + // Get the File Description for the next file + FileLink = GetNextNode (&Instance->RootFile->Link, &File->Link); + if (!IsNull (&Instance->RootFile->Link, FileLink)) { + NextFile = BOOTMON_FS_FILE_FROM_LINK_THIS (FileLink); + + // If there is space between the beginning of the current file and the + // beginning of the next file then use it + EndOfAppendSpace = NextFile->HwDescription.BlockStart * BlockSize; + } else { + // We are flushing the last file. + EndOfAppendSpace = (Media->LastBlock + 1) * BlockSize; + } + if (EndOfAppendSpace - FileStart >= NewFileSize) { + HasSpace = TRUE; + } + } + + if (HasSpace == TRUE) { + // Invalidate the current image description of the file if any. + if (File->HwDescAddress != 0) { + Status = InvalidateImageDescription (File); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Write the new file data + Status = DiskIo->WriteDisk ( + DiskIo, + Media->MediaId, + RegionStart, + Region->Size, + Region->Buffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = WriteFileDescription (File, AsciiFileName, NewDataSize, FileStart); + if (EFI_ERROR (Status)) { + return Status; + } + + } else { + // There isn't a space for the file. + // Options here are to move the file or fragment it. However as files + // may represent boot images at fixed positions, these options will + // break booting if the bootloader doesn't use BootMonFs to find the + // image. + + return EFI_VOLUME_FULL; + } + } + } + + FreeFileRegions (File); + Info->PhysicalSize = BootMonFsGetPhysicalSize (File); + + if ((AsciiStrCmp (AsciiFileName, File->HwDescription.Footer.Filename) != 0) || + (Info->FileSize != File->HwDescription.Region[0].Size) ) { + Status = WriteFileDescription (File, AsciiFileName, Info->FileSize, FileStart); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // Flush DiskIo Buffers (see UEFI Spec 12.7 - DiskIo buffers are flushed by + // calling FlushBlocks on the same device's BlockIo). + BlockIo->FlushBlocks (BlockIo); + + return EFI_SUCCESS; +} + +/** + Close a specified file handle. + + @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to close. + + @retval EFI_SUCCESS The file was closed. + @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open + file handle. + +**/ +EFIAPI +EFI_STATUS +BootMonFsCloseFile ( + IN EFI_FILE_PROTOCOL *This + ) +{ + BOOTMON_FS_FILE *File; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); + if (File->Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + // In the case of a file and not the root directory + if (This != &File->Instance->RootFile->File) { + This->Flush (This); + FreePool (File->Info); + File->Info = NULL; + } + + return EFI_SUCCESS; +} + +/** + Open a file on the boot monitor file system. + + The boot monitor file system does not allow for sub-directories. There is only + one directory, the root one. On any attempt to create a directory, the function + returns in error with the EFI_WRITE_PROTECTED error code. + + @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is + the file handle to source location. + @param[out] NewHandle A pointer to the location to return the opened + handle for the new file. + @param[in] FileName The Null-terminated string of the name of the file + to be opened. + @param[in] OpenMode The mode to open the file : Read or Read/Write or + Read/Write/Create + @param[in] Attributes Attributes of the file in case of a file creation + + @retval EFI_SUCCESS The file was open. + @retval EFI_NOT_FOUND The specified file could not be found or the specified + directory in which to create a file could not be found. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible + with the Boot Monitor file system. + @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. + @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid. + +**/ +EFIAPI +EFI_STATUS +BootMonFsOpenFile ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + BOOTMON_FS_FILE *Directory; + BOOTMON_FS_FILE *File; + BOOTMON_FS_INSTANCE *Instance; + CHAR8 *Buf; + CHAR16 *Path; + CHAR16 *Separator; + CHAR8 *AsciiFileName; + EFI_FILE_INFO *Info; + UINTN AsciiFileNameSize; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Directory = BOOTMON_FS_FILE_FROM_FILE_THIS (This); + if (Directory->Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((FileName == NULL) || (NewHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid modes are read, read/write, and read/write/create + // + if ( (OpenMode != EFI_FILE_MODE_READ) && + (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) && + (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) { + return EFI_INVALID_PARAMETER; + } + + Instance = Directory->Instance; + + // + // If the instance has not been initialized yet then do it ... + // + if (!Instance->Initialized) { + Status = BootMonFsInitialize (Instance); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Copy the file path to be able to work on it. We do not want to + // modify the input file name string "FileName". + // + Buf = AllocateCopyPool (StrSize (FileName), FileName); + if (Buf == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Path = (CHAR16*)Buf; + AsciiFileName = NULL; + Info = NULL; + + // + // Handle single periods, double periods and convert forward slashes '/' + // to backward '\' ones. Does not handle a '.' at the beginning of the + // path for the time being. + // + if (PathCleanUpDirectories (Path) == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Error; + } + + // + // Detect if the first component of the path refers to a directory. + // This is done to return the correct error code when trying to + // access or create a directory other than the root directory. + // + + // + // Search for the '\\' sequence and if found return in error + // with the EFI_INVALID_PARAMETER error code. ere in the path. + // + if (StrStr (Path, L"\\\\") != NULL) { + Status = EFI_INVALID_PARAMETER; + goto Error; + } + // + // Get rid of the leading '\' if any. + // + Path += (Path[0] == L'\\'); + + // + // Look for a '\' in the file path. If one is found then + // the first component of the path refers to a directory + // that is not the root directory. + // + Separator = StrStr (Path, L"\\"); + if (Separator != NULL) { + // + // In the case '\' and a creation, return + // EFI_WRITE_PROTECTED if this is for a directory + // creation, EFI_INVALID_PARAMETER otherwise. + // + if ((*(Separator + 1) == '\0') && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) { + if (Attributes & EFI_FILE_DIRECTORY) { + Status = EFI_WRITE_PROTECTED; + } else { + Status = EFI_INVALID_PARAMETER; + } + } else { + // + // Attempt to open a file or a directory that is not in the + // root directory or to open without creation a directory + // located in the root directory, returns EFI_NOT_FOUND. + // + Status = EFI_NOT_FOUND; + } + goto Error; + } + + // + // BootMonFs interface requires ASCII filenames + // + AsciiFileNameSize = StrLen (Path) + 1; + if (AsciiFileNameSize > MAX_NAME_LENGTH) { + AsciiFileNameSize = MAX_NAME_LENGTH; + } + AsciiFileName = AllocatePool (AsciiFileNameSize); + if (AsciiFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + UnicodeStrToAsciiStrS (Path, AsciiFileName, AsciiFileNameSize); + + if ((AsciiFileName[0] == '\0') || + (AsciiFileName[0] == '.' ) ) { + // + // Opening the root directory + // + + *NewHandle = &Instance->RootFile->File; + Instance->RootFile->Position = 0; + Status = EFI_SUCCESS; + } else { + + if ((OpenMode & EFI_FILE_MODE_CREATE) && + (Attributes & EFI_FILE_DIRECTORY) ) { + Status = EFI_WRITE_PROTECTED; + goto Error; + } + + // + // Allocate a buffer to store the characteristics of the file while the + // file is open. We allocate the maximum size to not have to reallocate + // if the file name is changed. + // + Info = AllocateZeroPool ( + SIZE_OF_EFI_FILE_INFO + (sizeof (CHAR16) * MAX_NAME_LENGTH)); + if (Info == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error; + } + + // + // Open or create a file in the root directory. + // + + Status = BootMonGetFileFromAsciiFileName (Instance, AsciiFileName, &File); + if (Status == EFI_NOT_FOUND) { + if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) { + goto Error; + } + + Status = BootMonFsCreateFile (Instance, &File); + if (EFI_ERROR (Status)) { + goto Error; + } + InsertHeadList (&Instance->RootFile->Link, &File->Link); + Info->Attribute = Attributes; + } else { + // + // File already open, not supported yet. + // + if (File->Info != NULL) { + Status = EFI_UNSUPPORTED; + goto Error; + } + } + + Info->FileSize = BootMonFsGetImageLength (File); + Info->PhysicalSize = BootMonFsGetPhysicalSize (File); + AsciiStrToUnicodeStrS (AsciiFileName, Info->FileName, MAX_NAME_LENGTH); + + File->Info = Info; + Info = NULL; + File->Position = 0; + File->OpenMode = OpenMode; + + *NewHandle = &File->File; + } + +Error: + + FreePool (Buf); + if (AsciiFileName != NULL) { + FreePool (AsciiFileName); + } + if (Info != NULL) { + FreePool (Info); + } + + return Status; +} + +// Delete() for the root directory's EFI_FILE_PROTOCOL instance +EFIAPI +EFI_STATUS +BootMonFsDeleteFail ( + IN EFI_FILE_PROTOCOL *This + ) +{ + This->Close(This); + // You can't delete the root directory + return EFI_WARN_DELETE_FAILURE; +} + +/** + Close and delete a file from the boot monitor file system. + + @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file + handle to delete. + + @retval EFI_SUCCESS The file was closed and deleted. + @retval EFI_INVALID_PARAMETER The parameter "This" is NULL or is not an open + file handle. + @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted. + +**/ +EFIAPI +EFI_STATUS +BootMonFsDelete ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + BOOTMON_FS_FILE *File; + LIST_ENTRY *RegionToFlushLink; + BOOTMON_FS_FILE_REGION *Region; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + File = BOOTMON_FS_FILE_FROM_FILE_THIS (This); + if (File->Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IsListEmpty (&File->RegionToFlushLink)) { + // Free the entries from the Buffer List + RegionToFlushLink = GetFirstNode (&File->RegionToFlushLink); + do { + Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; + + // + // Get next element of the list before deleting the region description + // that contain the LIST_ENTRY structure. + // + RegionToFlushLink = RemoveEntryList (RegionToFlushLink); + + // Free the buffers + FreePool (Region->Buffer); + FreePool (Region); + } while (!IsListEmpty (&File->RegionToFlushLink)); + } + + // If (RegionCount is greater than 0) then the file already exists + if (File->HwDescription.RegionCount > 0) { + // Invalidate the last Block + Status = InvalidateImageDescription (File); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return EFI_WARN_DELETE_FAILURE; + } + } + + // Remove the entry from the list + RemoveEntryList (&File->Link); + FreePool (File->Info); + FreePool (File); + + return EFI_SUCCESS; +} -- cgit v1.2.3