Fix various typos in FatPkg/EnhancedFatDxe comments. Cc: Ray Ni <ray.ni@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Acked-by: Liming Gao <liming.gao@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-8-philmd@redhat.com>
		
			
				
	
	
		
			469 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			469 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);
 | |
|   }
 | |
| }
 |