REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the FatPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Ray Ni <ray.ni@intel.com>
		
			
				
	
	
		
			482 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			482 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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);
 | 
						|
  }
 | 
						|
}
 |