2 Routines that check references and flush OFiles
4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
14 Flushes all data associated with the file handle.
16 @param FHand - Handle to file to flush.
17 @param Token - A pointer to the token associated with the transaction.
19 @retval EFI_SUCCESS - Flushed the file successfully.
20 @retval EFI_WRITE_PROTECTED - The volume is read only.
21 @retval EFI_ACCESS_DENIED - The file is read only.
22 @return Others - Flushing of the file failed.
28 IN EFI_FILE_PROTOCOL
*FHand
,
29 IN EFI_FILE_IO_TOKEN
*Token
38 IFile
= IFILE_FROM_FHAND (FHand
);
40 Volume
= OFile
->Volume
;
44 // If the file has a permanent error, return it
46 if (EFI_ERROR (OFile
->Error
)) {
50 if (Volume
->ReadOnly
) {
51 return EFI_WRITE_PROTECTED
;
55 // If read only, return error
57 if (IFile
->ReadOnly
) {
58 return EFI_ACCESS_DENIED
;
62 FatWaitNonblockingTask (IFile
);
65 // Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
66 // But if it calls, the below check can avoid crash.
68 if (FHand
->Revision
< EFI_FILE_PROTOCOL_REVISION2
) {
69 return EFI_UNSUPPORTED
;
72 Task
= FatCreateTask (IFile
, Token
);
74 return EFI_OUT_OF_RESOURCES
;
82 Status
= FatOFileFlush (OFile
);
83 Status
= FatCleanupVolume (OFile
->Volume
, OFile
, Status
, Task
);
87 if (!EFI_ERROR (Status
)) {
88 Status
= FatQueueTask (IFile
, Task
);
90 FatDestroyTask (Task
);
99 Flushes all data associated with the file handle.
101 @param FHand - Handle to file to flush.
103 @retval EFI_SUCCESS - Flushed the file successfully.
104 @retval EFI_WRITE_PROTECTED - The volume is read only.
105 @retval EFI_ACCESS_DENIED - The file is read only.
106 @return Others - Flushing of the file failed.
112 IN EFI_FILE_PROTOCOL
*FHand
115 return FatFlushEx (FHand
, NULL
);
120 Flushes & Closes the file handle.
122 @param FHand - Handle to the file to delete.
124 @retval EFI_SUCCESS - Closed the file successfully.
130 IN EFI_FILE_PROTOCOL
*FHand
137 IFile
= IFILE_FROM_FHAND (FHand
);
138 OFile
= IFile
->OFile
;
139 Volume
= OFile
->Volume
;
147 // Close the file instance handle
149 FatIFileClose (IFile
);
152 // Done. Unlock the volume
154 FatCleanupVolume (Volume
, OFile
, EFI_SUCCESS
, NULL
);
158 // Close always succeed
165 Close the open file instance.
167 @param IFile - Open file instance.
169 @retval EFI_SUCCESS - Closed the file successfully.
180 OFile
= IFile
->OFile
;
181 Volume
= OFile
->Volume
;
183 ASSERT_VOLUME_LOCKED (Volume
);
185 FatWaitNonblockingTask (IFile
);
188 // Remove the IFile struct
190 RemoveEntryList (&IFile
->Link
);
193 // Add the OFile to the check reference list
195 if (OFile
->CheckLink
.ForwardLink
== NULL
) {
196 InsertHeadList (&Volume
->CheckRef
, &OFile
->CheckLink
);
200 // Done. Free the open instance structure
208 Flush the data associated with an open file.
209 In this implementation, only last Mod/Access time is updated.
211 @param OFile - The open file.
213 @retval EFI_SUCCESS - The OFile is flushed successfully.
214 @return Others - An error occurred when flushing this OFile.
225 FAT_DATE_TIME FatNow
;
228 // Flush each entry up the tree while dirty
232 // If the file has a permanent error, then don't write any
233 // of its data to the device (may be from different media)
235 if (EFI_ERROR (OFile
->Error
)) {
239 Parent
= OFile
->Parent
;
240 DirEnt
= OFile
->DirEnt
;
243 // Update the last modification time
245 FatGetCurrentFatTime (&FatNow
);
246 CopyMem (&DirEnt
->Entry
.FileLastAccess
, &FatNow
.Date
, sizeof (FAT_DATE
));
247 if (!OFile
->PreserveLastModification
) {
248 FatGetCurrentFatTime (&DirEnt
->Entry
.FileModificationTime
);
251 OFile
->PreserveLastModification
= FALSE
;
252 if (OFile
->Archive
) {
253 DirEnt
->Entry
.Attributes
|= FAT_ATTRIBUTE_ARCHIVE
;
254 OFile
->Archive
= FALSE
;
258 // Write the directory entry
260 if ((Parent
!= NULL
) && !DirEnt
->Invalid
) {
262 // Write the OFile's directory entry
264 Status
= FatStoreDirEnt (Parent
, DirEnt
);
265 if (EFI_ERROR (Status
)) {
270 OFile
->Dirty
= FALSE
;
277 } while (OFile
!= NULL
);
284 Check the references of the OFile.
285 If the OFile (that is checked) is no longer
286 referenced, then it is freed.
288 @param OFile - The OFile to be checked.
290 @retval TRUE - The OFile is not referenced and freed.
291 @retval FALSE - The OFile is kept.
300 // If the OFile is on the check ref list, remove it
302 if (OFile
->CheckLink
.ForwardLink
!= NULL
) {
303 RemoveEntryList (&OFile
->CheckLink
);
304 OFile
->CheckLink
.ForwardLink
= NULL
;
307 FatOFileFlush (OFile
);
309 // Are there any references to this OFile?
311 if (!IsListEmpty (&OFile
->Opens
) || !IsListEmpty (&OFile
->ChildHead
)) {
313 // The OFile cannot be freed
321 FatCloseDirEnt (OFile
->DirEnt
);
327 Check the references of all open files on the volume.
328 Any open file (that is checked) that is no longer
329 referenced, is freed - and its parent open file
330 is then referenced checked.
332 @param Volume - The volume to check the pending open file list.
338 IN FAT_VOLUME
*Volume
345 // Check all files on the pending check list
347 while (!IsListEmpty (&Volume
->CheckRef
)) {
349 // Start with the first file listed
351 Parent
= OFILE_FROM_CHECKLINK (Volume
->CheckRef
.ForwardLink
);
353 // Go up the tree cleaning up any un-referenced OFiles
355 while (Parent
!= NULL
) {
357 Parent
= OFile
->Parent
;
358 if (!FatCheckOFileRef (OFile
)) {
367 Set error status for a specific OFile, reference checking the volume.
368 If volume is already marked as invalid, and all resources are freed
369 after reference checking, the file system protocol is uninstalled and
370 the volume structure is freed.
372 @param Volume - the Volume that is to be reference checked and unlocked.
373 @param OFile - the OFile whose permanent error code is to be set.
374 @param EfiStatus - error code to be set.
375 @param Task point to task instance.
377 @retval EFI_SUCCESS - Clean up the volume successfully.
378 @return Others - Cleaning up of the volume is failed.
383 IN FAT_VOLUME
*Volume
,
385 IN EFI_STATUS EfiStatus
,
395 FatSetVolumeError (OFile
, EfiStatus
);
399 // Clean up any dangling OFiles that don't have IFiles
400 // we don't check return status here because we want the
401 // volume be cleaned up even the volume is invalid.
403 FatCheckVolumeRef (Volume
);
406 // Update the free hint info. Volume->FreeInfoPos != 0
407 // indicates this a FAT32 volume
409 if (Volume
->FreeInfoValid
&& Volume
->FatDirty
&& Volume
->FreeInfoPos
) {
410 Status
= FatDiskIo (Volume
, WriteDisk
, Volume
->FreeInfoPos
, sizeof (FAT_INFO_SECTOR
), &Volume
->FatInfoSector
, Task
);
411 if (EFI_ERROR (Status
)) {
417 // Update that the volume is not dirty
419 if (Volume
->FatDirty
&& (Volume
->FatType
!= Fat12
)) {
420 Volume
->FatDirty
= FALSE
;
421 Status
= FatAccessVolumeDirty (Volume
, WriteFat
, &Volume
->NotDirtyValue
);
422 if (EFI_ERROR (Status
)) {
428 // Flush all dirty cache entries to disk
430 Status
= FatVolumeFlushCache (Volume
, Task
);
431 if (EFI_ERROR (Status
)) {
437 // If the volume is cleared , remove it.
438 // The only time volume be invalidated is in DriverBindingStop.
440 if ((Volume
->Root
== NULL
) && !Volume
->Valid
) {
442 // Free the volume structure
444 FatFreeVolume (Volume
);
452 Set the OFile and its child OFile with the error Status
454 @param OFile - The OFile whose permanent error code is to be set.
455 @param Status - Error code to be set.
465 FAT_OFILE
*ChildOFile
;
468 // If this OFile doesn't already have an error, set one
470 if (!EFI_ERROR (OFile
->Error
)) {
471 OFile
->Error
= Status
;
475 // Set the error on each child OFile
477 for (Link
= OFile
->ChildHead
.ForwardLink
; Link
!= &OFile
->ChildHead
; Link
= Link
->ForwardLink
) {
478 ChildOFile
= OFILE_FROM_CHILDLINK (Link
);
479 FatSetVolumeError (ChildOFile
, Status
);