From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/FatPkg/EnhancedFatDxe/Flush.c | 468 ++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100644 roms/edk2/FatPkg/EnhancedFatDxe/Flush.c (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/Flush.c') diff --git a/roms/edk2/FatPkg/EnhancedFatDxe/Flush.c b/roms/edk2/FatPkg/EnhancedFatDxe/Flush.c new file mode 100644 index 000000000..d53279107 --- /dev/null +++ b/roms/edk2/FatPkg/EnhancedFatDxe/Flush.c @@ -0,0 +1,468 @@ +/** @file + Routines that check references and flush OFiles + +Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#include "Fat.h" + +/** + + Flushes all data associated with the file handle. + + @param FHand - Handle to file to flush. + @param Token - A pointer to the token associated with the transaction. + + @retval EFI_SUCCESS - Flushed the file successfully. + @retval EFI_WRITE_PROTECTED - The volume is read only. + @retval EFI_ACCESS_DENIED - The file is read only. + @return Others - Flushing of the file failed. + +**/ +EFI_STATUS +EFIAPI +FatFlushEx ( + IN EFI_FILE_PROTOCOL *FHand, + IN EFI_FILE_IO_TOKEN *Token + ) +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + EFI_STATUS Status; + FAT_TASK *Task; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + Task = NULL; + + // + // If the file has a permanent error, return it + // + if (EFI_ERROR (OFile->Error)) { + return OFile->Error; + } + + if (Volume->ReadOnly) { + return EFI_WRITE_PROTECTED; + } + // + // If read only, return error + // + if (IFile->ReadOnly) { + return EFI_ACCESS_DENIED; + } + + if (Token == NULL) { + FatWaitNonblockingTask (IFile); + } else { + // + // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2. + // But if it calls, the below check can avoid crash. + // + if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) { + return EFI_UNSUPPORTED; + } + Task = FatCreateTask (IFile, Token); + if (Task == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Flush the OFile + // + FatAcquireLock (); + Status = FatOFileFlush (OFile); + Status = FatCleanupVolume (OFile->Volume, OFile, Status, Task); + FatReleaseLock (); + + if (Token != NULL) { + if (!EFI_ERROR (Status)) { + Status = FatQueueTask (IFile, Task); + } else { + FatDestroyTask (Task); + } + } + + return Status; +} + +/** + + Flushes all data associated with the file handle. + + @param FHand - Handle to file to flush. + + @retval EFI_SUCCESS - Flushed the file successfully. + @retval EFI_WRITE_PROTECTED - The volume is read only. + @retval EFI_ACCESS_DENIED - The file is read only. + @return Others - Flushing of the file failed. + +**/ +EFI_STATUS +EFIAPI +FatFlush ( + IN EFI_FILE_PROTOCOL *FHand + ) +{ + return FatFlushEx (FHand, NULL); +} + +/** + + Flushes & Closes the file handle. + + @param FHand - Handle to the file to delete. + + @retval EFI_SUCCESS - Closed the file successfully. + +**/ +EFI_STATUS +EFIAPI +FatClose ( + IN EFI_FILE_PROTOCOL *FHand + ) +{ + FAT_IFILE *IFile; + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + IFile = IFILE_FROM_FHAND (FHand); + OFile = IFile->OFile; + Volume = OFile->Volume; + + // + // Lock the volume + // + FatAcquireLock (); + + // + // Close the file instance handle + // + FatIFileClose (IFile); + + // + // Done. Unlock the volume + // + FatCleanupVolume (Volume, OFile, EFI_SUCCESS, NULL); + FatReleaseLock (); + + // + // Close always succeed + // + return EFI_SUCCESS; +} + +/** + + Close the open file instance. + + @param IFile - Open file instance. + + @retval EFI_SUCCESS - Closed the file successfully. + +**/ +EFI_STATUS +FatIFileClose ( + FAT_IFILE *IFile + ) +{ + FAT_OFILE *OFile; + FAT_VOLUME *Volume; + + OFile = IFile->OFile; + Volume = OFile->Volume; + + ASSERT_VOLUME_LOCKED (Volume); + + FatWaitNonblockingTask (IFile); + + // + // Remove the IFile struct + // + RemoveEntryList (&IFile->Link); + + // + // Add the OFile to the check reference list + // + if (OFile->CheckLink.ForwardLink == NULL) { + InsertHeadList (&Volume->CheckRef, &OFile->CheckLink); + } + // + // Done. Free the open instance structure + // + FreePool (IFile); + return EFI_SUCCESS; +} + +/** + + Flush the data associated with an open file. + In this implementation, only last Mod/Access time is updated. + + @param OFile - The open file. + + @retval EFI_SUCCESS - The OFile is flushed successfully. + @return Others - An error occurred when flushing this OFile. + +**/ +EFI_STATUS +FatOFileFlush ( + IN FAT_OFILE *OFile + ) +{ + EFI_STATUS Status; + FAT_OFILE *Parent; + FAT_DIRENT *DirEnt; + FAT_DATE_TIME FatNow; + + // + // Flush each entry up the tree while dirty + // + do { + // + // If the file has a permanent error, then don't write any + // of its data to the device (may be from different media) + // + if (EFI_ERROR (OFile->Error)) { + return OFile->Error; + } + + Parent = OFile->Parent; + DirEnt = OFile->DirEnt; + if (OFile->Dirty) { + // + // Update the last modification time + // + FatGetCurrentFatTime (&FatNow); + CopyMem (&DirEnt->Entry.FileLastAccess, &FatNow.Date, sizeof (FAT_DATE)); + if (!OFile->PreserveLastModification) { + FatGetCurrentFatTime (&DirEnt->Entry.FileModificationTime); + } + + OFile->PreserveLastModification = FALSE; + if (OFile->Archive) { + DirEnt->Entry.Attributes |= FAT_ATTRIBUTE_ARCHIVE; + OFile->Archive = FALSE; + } + // + // Write the directory entry + // + if (Parent != NULL && !DirEnt->Invalid) { + // + // Write the OFile's directory entry + // + Status = FatStoreDirEnt (Parent, DirEnt); + if (EFI_ERROR (Status)) { + return Status; + } + } + + OFile->Dirty = FALSE; + } + // + // Check the parent + // + OFile = Parent; + } while (OFile != NULL); + return EFI_SUCCESS; +} + +/** + + Check the references of the OFile. + If the OFile (that is checked) is no longer + referenced, then it is freed. + + @param OFile - The OFile to be checked. + + @retval TRUE - The OFile is not referenced and freed. + @retval FALSE - The OFile is kept. + +**/ +BOOLEAN +FatCheckOFileRef ( + IN FAT_OFILE *OFile + ) +{ + // + // If the OFile is on the check ref list, remove it + // + if (OFile->CheckLink.ForwardLink != NULL) { + RemoveEntryList (&OFile->CheckLink); + OFile->CheckLink.ForwardLink = NULL; + } + + FatOFileFlush (OFile); + // + // Are there any references to this OFile? + // + if (!IsListEmpty (&OFile->Opens) || !IsListEmpty (&OFile->ChildHead)) { + // + // The OFile cannot be freed + // + return FALSE; + } + // + // Free the Ofile + // + FatCloseDirEnt (OFile->DirEnt); + return TRUE; +} + +/** + + Check the references of all open files on the volume. + Any open file (that is checked) that is no longer + referenced, is freed - and its parent open file + is then referenced checked. + + @param Volume - The volume to check the pending open file list. + +**/ +STATIC +VOID +FatCheckVolumeRef ( + IN FAT_VOLUME *Volume + ) +{ + FAT_OFILE *OFile; + FAT_OFILE *Parent; + + // + // Check all files on the pending check list + // + while (!IsListEmpty (&Volume->CheckRef)) { + // + // Start with the first file listed + // + Parent = OFILE_FROM_CHECKLINK (Volume->CheckRef.ForwardLink); + // + // Go up the tree cleaning up any un-referenced OFiles + // + while (Parent != NULL) { + OFile = Parent; + Parent = OFile->Parent; + if (!FatCheckOFileRef (OFile)) { + break; + } + } + } +} + +/** + + Set error status for a specific OFile, reference checking the volume. + If volume is already marked as invalid, and all resources are freed + after reference checking, the file system protocol is uninstalled and + the volume structure is freed. + + @param Volume - the Volume that is to be reference checked and unlocked. + @param OFile - the OFile whose permanent error code is to be set. + @param EfiStatus - error code to be set. + @param Task point to task instance. + + @retval EFI_SUCCESS - Clean up the volume successfully. + @return Others - Cleaning up of the volume is failed. + +**/ +EFI_STATUS +FatCleanupVolume ( + IN FAT_VOLUME *Volume, + IN FAT_OFILE *OFile, + IN EFI_STATUS EfiStatus, + IN FAT_TASK *Task + ) +{ + EFI_STATUS Status; + // + // Flag the OFile + // + if (OFile != NULL) { + FatSetVolumeError (OFile, EfiStatus); + } + // + // Clean up any dangling OFiles that don't have IFiles + // we don't check return status here because we want the + // volume be cleaned up even the volume is invalid. + // + FatCheckVolumeRef (Volume); + if (Volume->Valid) { + // + // Update the free hint info. Volume->FreeInfoPos != 0 + // indicates this a FAT32 volume + // + if (Volume->FreeInfoValid && Volume->FatDirty && Volume->FreeInfoPos) { + Status = FatDiskIo (Volume, WriteDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, Task); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Update that the volume is not dirty + // + if (Volume->FatDirty && Volume->FatType != Fat12) { + Volume->FatDirty = FALSE; + Status = FatAccessVolumeDirty (Volume, WriteFat, &Volume->NotDirtyValue); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Flush all dirty cache entries to disk + // + Status = FatVolumeFlushCache (Volume, Task); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // If the volume is cleared , remove it. + // The only time volume be invalidated is in DriverBindingStop. + // + if (Volume->Root == NULL && !Volume->Valid) { + // + // Free the volume structure + // + FatFreeVolume (Volume); + } + + return EfiStatus; +} + +/** + + Set the OFile and its child OFile with the error Status + + @param OFile - The OFile whose permanent error code is to be set. + @param Status - Error code to be set. + +**/ +VOID +FatSetVolumeError ( + IN FAT_OFILE *OFile, + IN EFI_STATUS Status + ) +{ + LIST_ENTRY *Link; + FAT_OFILE *ChildOFile; + + // + // If this OFile doesn't already have an error, set one + // + if (!EFI_ERROR (OFile->Error)) { + OFile->Error = Status; + } + // + // Set the error on each child OFile + // + for (Link = OFile->ChildHead.ForwardLink; Link != &OFile->ChildHead; Link = Link->ForwardLink) { + ChildOFile = OFILE_FROM_CHILDLINK (Link); + FatSetVolumeError (ChildOFile, Status); + } +} -- cgit 1.2.3-korg