aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/FatPkg/EnhancedFatDxe/Flush.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/FatPkg/EnhancedFatDxe/Flush.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/FatPkg/EnhancedFatDxe/Flush.c')
-rw-r--r--roms/edk2/FatPkg/EnhancedFatDxe/Flush.c468
1 files changed, 468 insertions, 0 deletions
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.<BR>
+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);
+ }
+}