mirror of
https://github.com/reactos/reactos.git
synced 2024-10-30 03:27:31 +00:00
633 lines
20 KiB
C++
633 lines
20 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
|
|
// All rights reserved
|
|
// This file was released under the GPLv2 on June 2015.
|
|
////////////////////////////////////////////////////////////////////
|
|
/*************************************************************************
|
|
*
|
|
* File: Flush.cpp
|
|
*
|
|
* Module: UDF File System Driver (Kernel mode execution only)
|
|
*
|
|
* Description:
|
|
* Contains code to handle the "Flush Buffers" dispatch entry point.
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include "udffs.h"
|
|
|
|
// define the file specific bug-check id
|
|
#define UDF_BUG_CHECK_ID UDF_FILE_FLUSH
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFFlush()
|
|
*
|
|
* Description:
|
|
* The I/O Manager will invoke this routine to handle a flush buffers
|
|
* request
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
|
|
* to be deferred to a worker thread context)
|
|
*
|
|
* Return Value: STATUS_SUCCESS/Error
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
NTAPI
|
|
UDFFlush(
|
|
PDEVICE_OBJECT DeviceObject, // the logical volume device object
|
|
PIRP Irp) // I/O Request Packet
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PtrUDFIrpContext PtrIrpContext = NULL;
|
|
BOOLEAN AreWeTopLevel = FALSE;
|
|
|
|
UDFPrint(("UDFFlush: \n"));
|
|
|
|
FsRtlEnterFileSystem();
|
|
ASSERT(DeviceObject);
|
|
ASSERT(Irp);
|
|
|
|
// set the top level context
|
|
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
|
|
ASSERT(!UDFIsFSDevObj(DeviceObject));
|
|
|
|
_SEH2_TRY {
|
|
|
|
// get an IRP context structure and issue the request
|
|
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
|
|
if(PtrIrpContext) {
|
|
RC = UDFCommonFlush(PtrIrpContext, Irp);
|
|
} else {
|
|
RC = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Status = RC;
|
|
Irp->IoStatus.Information = 0;
|
|
// complete the IRP
|
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
|
}
|
|
|
|
} _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
|
|
|
|
RC = UDFExceptionHandler(PtrIrpContext, Irp);
|
|
|
|
UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
|
|
} _SEH2_END;
|
|
|
|
if (AreWeTopLevel) {
|
|
IoSetTopLevelIrp(NULL);
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
return(RC);
|
|
} // end UDFFlush()
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFCommonFlush()
|
|
*
|
|
* Description:
|
|
* The actual work is performed here. This routine may be invoked in one'
|
|
* of the two possible contexts:
|
|
* (a) in the context of a system worker thread
|
|
* (b) in the context of the original caller
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: STATUS_SUCCESS/Error
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
UDFCommonFlush(
|
|
PtrUDFIrpContext PtrIrpContext,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS RC = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp = NULL;
|
|
PFILE_OBJECT FileObject = NULL;
|
|
PtrUDFFCB Fcb = NULL;
|
|
PtrUDFCCB Ccb = NULL;
|
|
PVCB Vcb = NULL;
|
|
PtrUDFNTRequiredFCB NtReqFcb = NULL;
|
|
BOOLEAN AcquiredVCB = FALSE;
|
|
BOOLEAN AcquiredFCB = FALSE;
|
|
BOOLEAN PostRequest = FALSE;
|
|
BOOLEAN CanWait = TRUE;
|
|
|
|
UDFPrint(("UDFCommonFlush: \n"));
|
|
|
|
_SEH2_TRY {
|
|
|
|
// Get some of the parameters supplied to us
|
|
CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
|
|
// If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous.
|
|
if (!CanWait) {
|
|
PostRequest = TRUE;
|
|
try_return(RC);
|
|
}
|
|
|
|
// First, get a pointer to the current I/O stack location
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ASSERT(IrpSp);
|
|
|
|
FileObject = IrpSp->FileObject;
|
|
ASSERT(FileObject);
|
|
|
|
// Get the FCB and CCB pointers
|
|
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
|
|
ASSERT(Ccb);
|
|
Fcb = Ccb->Fcb;
|
|
ASSERT(Fcb);
|
|
NtReqFcb = Fcb->NTRequiredFCB;
|
|
|
|
// Check the type of object passed-in. That will determine the course of
|
|
// action we take.
|
|
if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || (Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)) {
|
|
|
|
if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
|
|
Vcb = (PVCB)(Fcb);
|
|
} else {
|
|
Vcb = Fcb->Vcb;
|
|
}
|
|
Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
|
|
|
|
#ifdef UDF_DELAYED_CLOSE
|
|
UDFCloseAllDelayed(Vcb);
|
|
#endif //UDF_DELAYED_CLOSE
|
|
|
|
UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVCB = TRUE;
|
|
// The caller wishes to flush all files for the mounted
|
|
// logical volume. The flush volume routine below should simply
|
|
// walk through all of the open file streams, acquire the
|
|
// VCB resource, and request the flush operation from the Cache
|
|
// Manager. Basically, the sequence of operations listed below
|
|
// for a single file should be executed on all open files.
|
|
|
|
UDFFlushLogicalVolume(PtrIrpContext, Irp, Vcb, 0);
|
|
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVCB = FALSE;
|
|
|
|
try_return(RC);
|
|
} else
|
|
if (!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
|
|
// This is a regular file.
|
|
Vcb = Fcb->Vcb;
|
|
ASSERT(Vcb);
|
|
if(!ExIsResourceAcquiredExclusiveLite(&(Vcb->VCBResource)) &&
|
|
!ExIsResourceAcquiredSharedLite(&(Vcb->VCBResource))) {
|
|
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
|
|
AcquiredVCB = TRUE;
|
|
}
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), TRUE);
|
|
AcquiredFCB = TRUE;
|
|
|
|
// Request the Cache Manager to perform a flush operation.
|
|
// Further, instruct the Cache Manager that we wish to flush the
|
|
// entire file stream.
|
|
UDFFlushAFile(Fcb, Ccb, &(Irp->IoStatus), 0);
|
|
RC = Irp->IoStatus.Status;
|
|
|
|
// Some log-based FSD implementations may wish to flush their
|
|
// log files at this time. Finally, we should update the time-stamp
|
|
// values for the file stream appropriately. This would involve
|
|
// obtaining the current time and modifying the appropriate directory
|
|
// entry fields.
|
|
} else {
|
|
Vcb = Fcb->Vcb;
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (AcquiredFCB) {
|
|
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
|
UDFReleaseResource(&(NtReqFcb->MainResource));
|
|
AcquiredFCB = FALSE;
|
|
}
|
|
if (AcquiredVCB) {
|
|
UDFReleaseResource(&(Vcb->VCBResource));
|
|
AcquiredVCB = FALSE;
|
|
}
|
|
|
|
if(!_SEH2_AbnormalTermination()) {
|
|
if (PostRequest) {
|
|
// Nothing to lock now.
|
|
BrutePoint();
|
|
RC = UDFPostRequest(PtrIrpContext, Irp);
|
|
} else {
|
|
// Some applications like this request very much
|
|
// (ex. WinWord). But it's not a good idea for CD-R/RW media
|
|
if(Vcb->FlushMedia) {
|
|
PIO_STACK_LOCATION PtrNextIoStackLocation = NULL;
|
|
NTSTATUS RC1 = STATUS_SUCCESS;
|
|
|
|
// Send the request down at this point.
|
|
// To do this, we must set the next IRP stack location, and
|
|
// maybe set a completion routine.
|
|
// Be careful about marking the IRP pending if the lower level
|
|
// driver returned pending and we do have a completion routine!
|
|
PtrNextIoStackLocation = IoGetNextIrpStackLocation(Irp);
|
|
*PtrNextIoStackLocation = *IrpSp;
|
|
|
|
// Set the completion routine to "eat-up" any
|
|
// STATUS_INVALID_DEVICE_REQUEST error code returned by the lower
|
|
// level driver.
|
|
IoSetCompletionRoutine(Irp, UDFFlushCompletion, NULL, TRUE, TRUE, TRUE);
|
|
|
|
RC1 = IoCallDriver(Vcb->TargetDeviceObject, Irp);
|
|
|
|
RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1);
|
|
|
|
// Release the IRP context at this time.
|
|
UDFReleaseIrpContext(PtrIrpContext);
|
|
} else {
|
|
Irp->IoStatus.Status = RC;
|
|
Irp->IoStatus.Information = 0;
|
|
// Free up the Irp Context
|
|
UDFReleaseIrpContext(PtrIrpContext);
|
|
// complete the IRP
|
|
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
|
}
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return(RC);
|
|
} // end UDFCommonFlush()
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFFlushAFile()
|
|
*
|
|
* Description:
|
|
* Tell the Cache Manager to perform a flush.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*************************************************************************/
|
|
ULONG
|
|
UDFFlushAFile(
|
|
IN PtrUDFFCB Fcb,
|
|
IN PtrUDFCCB Ccb,
|
|
OUT PIO_STATUS_BLOCK PtrIoStatus,
|
|
IN ULONG FlushFlags
|
|
)
|
|
{
|
|
BOOLEAN SetArchive = FALSE;
|
|
// BOOLEAN PurgeCache = FALSE;
|
|
ULONG ret_val = 0;
|
|
|
|
UDFPrint(("UDFFlushAFile: \n"));
|
|
if(!Fcb)
|
|
return 0;
|
|
|
|
_SEH2_TRY {
|
|
if(Fcb->Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
|
|
return 0;
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
// Flush Security if required
|
|
_SEH2_TRY {
|
|
UDFWriteSecurity(Fcb->Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
// Flush SDir if any
|
|
_SEH2_TRY {
|
|
if(UDFHasAStreamDir(Fcb->FileInfo) &&
|
|
Fcb->FileInfo->Dloc->SDirInfo &&
|
|
!UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) ) {
|
|
ret_val |=
|
|
UDFFlushADirectory(Fcb->Vcb, Fcb->FileInfo->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
// Flush File
|
|
_SEH2_TRY {
|
|
if((Fcb->CachedOpenHandleCount || !Fcb->OpenHandleCount) &&
|
|
Fcb->NTRequiredFCB->SectionObject.DataSectionObject) {
|
|
if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)
|
|
&&
|
|
((Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED) ||
|
|
(Ccb && !(Ccb->CCBFlags & UDF_CCB_FLUSHED)) )) {
|
|
MmPrint((" CcFlushCache()\n"));
|
|
CcFlushCache(&(Fcb->NTRequiredFCB->SectionObject), NULL, 0, PtrIoStatus);
|
|
}
|
|
// notice, that we should purge cache
|
|
// we can't do it now, because it may cause last Close
|
|
// request & thus, structure deallocation
|
|
// PurgeCache = TRUE;
|
|
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if(Ccb) {
|
|
if( (Ccb->FileObject->Flags & FO_FILE_MODIFIED) &&
|
|
!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET)) {
|
|
if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME) {
|
|
LONGLONG NtTime;
|
|
KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
|
|
UDFSetFileXTime(Fcb->FileInfo, NULL, NULL, NULL, &NtTime);
|
|
Fcb->NTRequiredFCB->LastWriteTime.QuadPart = NtTime;
|
|
}
|
|
SetArchive = TRUE;
|
|
Ccb->FileObject->Flags &= ~FO_FILE_MODIFIED;
|
|
}
|
|
if(Ccb->FileObject->Flags & FO_FILE_SIZE_CHANGED) {
|
|
LONGLONG ASize = UDFGetFileAllocationSize(Fcb->Vcb, Fcb->FileInfo);
|
|
UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, &ASize);
|
|
Ccb->FileObject->Flags &= ~FO_FILE_SIZE_CHANGED;
|
|
}
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
|
|
_SEH2_TRY {
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
if(SetArchive &&
|
|
(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) {
|
|
ULONG Attr;
|
|
PDIR_INDEX_ITEM DirNdx;
|
|
DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index);
|
|
// Archive bit
|
|
Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry);
|
|
if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
|
|
UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
|
|
}
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
UDFFlushFile__( Fcb->Vcb, Fcb->FileInfo, FlushFlags);
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
|
|
/* if(PurgeCache) {
|
|
_SEH2_TRY {
|
|
MmPrint((" CcPurgeCacheSection()\n"));
|
|
CcPurgeCacheSection( &(Fcb->NTRequiredFCB->SectionObject), NULL, 0, FALSE );
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
}*/
|
|
|
|
return ret_val;
|
|
} // end UDFFlushAFile()
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFFlushADirectory()
|
|
*
|
|
* Description:
|
|
* Tell the Cache Manager to perform a flush for all files
|
|
* in current directory & all subdirectories and flush all metadata
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*************************************************************************/
|
|
ULONG
|
|
UDFFlushADirectory(
|
|
IN PVCB Vcb,
|
|
IN PUDF_FILE_INFO FI,
|
|
OUT PIO_STATUS_BLOCK PtrIoStatus,
|
|
IN ULONG FlushFlags
|
|
)
|
|
{
|
|
UDFPrint(("UDFFlushADirectory: \n"));
|
|
// PDIR_INDEX_HDR hDI;
|
|
PDIR_INDEX_ITEM DI;
|
|
// BOOLEAN Referenced = FALSE;
|
|
ULONG ret_val = 0;
|
|
|
|
if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK)
|
|
return 0;
|
|
|
|
if(!FI || !FI->Dloc || !FI->Dloc->DirIndex) goto SkipFlushDir;
|
|
// hDI = FI->Dloc->DirIndex;
|
|
|
|
// Flush Security if required
|
|
_SEH2_TRY {
|
|
UDFWriteSecurity(Vcb, FI->Fcb, &(FI->Fcb->NTRequiredFCB->SecurityDesc));
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
// Flush SDir if any
|
|
_SEH2_TRY {
|
|
if(UDFHasAStreamDir(FI) &&
|
|
FI->Dloc->SDirInfo &&
|
|
!UDFIsSDirDeleted(FI->Dloc->SDirInfo) ) {
|
|
ret_val |=
|
|
UDFFlushADirectory(Vcb, FI->Dloc->SDirInfo, PtrIoStatus, FlushFlags);
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
|
|
// Flush Dir Tree
|
|
_SEH2_TRY {
|
|
UDF_DIR_SCAN_CONTEXT ScanContext;
|
|
PUDF_FILE_INFO tempFI;
|
|
|
|
if(UDFDirIndexInitScan(FI, &ScanContext, 2)) {
|
|
while((DI = UDFDirIndexScan(&ScanContext, &tempFI))) {
|
|
// Flush Dir entry
|
|
_SEH2_TRY {
|
|
if(!tempFI) continue;
|
|
if(UDFIsADirectory(tempFI)) {
|
|
UDFFlushADirectory(Vcb, tempFI, PtrIoStatus, FlushFlags);
|
|
} else {
|
|
UDFFlushAFile(tempFI->Fcb, NULL, PtrIoStatus, FlushFlags);
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
if(UDFFlushIsBreaking(Vcb, FlushFlags)) {
|
|
ret_val |= UDF_FLUSH_FLAGS_INTERRUPTED;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
SkipFlushDir:
|
|
// Flush Dir
|
|
_SEH2_TRY {
|
|
UDFFlushFile__( Vcb, FI, FlushFlags );
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
BrutePoint();
|
|
} _SEH2_END;
|
|
|
|
return ret_val;
|
|
} // end UDFFlushADirectory()
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFFlushLogicalVolume()
|
|
*
|
|
* Description:
|
|
* Flush everything beginning from root directory.
|
|
* Vcb must be previously acquired exclusively.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*************************************************************************/
|
|
ULONG
|
|
UDFFlushLogicalVolume(
|
|
IN PtrUDFIrpContext PtrIrpContext,
|
|
IN PIRP Irp,
|
|
IN PVCB Vcb,
|
|
IN ULONG FlushFlags
|
|
)
|
|
{
|
|
ULONG ret_val = 0;
|
|
#ifndef UDF_READ_ONLY_BUILD
|
|
IO_STATUS_BLOCK IoStatus;
|
|
|
|
UDFPrint(("UDFFlushLogicalVolume: \n"));
|
|
|
|
_SEH2_TRY {
|
|
if(Vcb->VCBFlags & (UDF_VCB_FLAGS_RAW_DISK/* |
|
|
UDF_VCB_FLAGS_MEDIA_READ_ONLY*/))
|
|
return 0;
|
|
if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)
|
|
return 0;
|
|
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED))
|
|
return 0;
|
|
|
|
// NOTE: This function may also be invoked internally as part of
|
|
// processing a shutdown request.
|
|
ASSERT(Vcb->RootDirFCB);
|
|
ret_val |= UDFFlushADirectory(Vcb, Vcb->RootDirFCB->FileInfo, &IoStatus, FlushFlags);
|
|
|
|
// if(UDFFlushIsBreaking(Vcb, FlushFlags))
|
|
// return;
|
|
// flush internal cache
|
|
if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
|
|
UDFPrint((" Lite flush, keep Modified=%d.\n", Vcb->Modified));
|
|
} else {
|
|
if(Vcb->VerifyOnWrite) {
|
|
UDFPrint(("UDF: Flushing cache for verify\n"));
|
|
//WCacheFlushAll__(&(Vcb->FastCache), Vcb);
|
|
WCacheFlushBlocks__(&(Vcb->FastCache), Vcb, 0, Vcb->LastLBA);
|
|
UDFVFlush(Vcb);
|
|
}
|
|
// umount (this is internal operation, NT will "dismount" volume later)
|
|
UDFUmount__(Vcb);
|
|
|
|
UDFPreClrModified(Vcb);
|
|
WCacheFlushAll__(&(Vcb->FastCache), Vcb);
|
|
UDFClrModified(Vcb);
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
;
|
|
} _SEH2_END;
|
|
#endif //UDF_READ_ONLY_BUILD
|
|
|
|
return ret_val;
|
|
} // end UDFFlushLogicalVolume()
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: UDFFlushCompletion()
|
|
*
|
|
* Description:
|
|
* Eat up any bad errors.
|
|
*
|
|
* Expected Interrupt Level (for execution) :
|
|
*
|
|
* IRQL_PASSIVE_LEVEL
|
|
*
|
|
* Return Value: None
|
|
*
|
|
*************************************************************************/
|
|
NTSTATUS
|
|
NTAPI
|
|
UDFFlushCompletion(
|
|
PDEVICE_OBJECT PtrDeviceObject,
|
|
PIRP Irp,
|
|
PVOID Context
|
|
)
|
|
{
|
|
// NTSTATUS RC = STATUS_SUCCESS;
|
|
|
|
UDFPrint(("UDFFlushCompletion: \n"));
|
|
|
|
if (Irp->PendingReturned) {
|
|
IoMarkIrpPending(Irp);
|
|
}
|
|
|
|
if (Irp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
|
|
// cannot do much here, can we?
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
} // end UDFFlushCompletion()
|
|
|
|
|
|
/*
|
|
Check if we should break FlushTree process
|
|
*/
|
|
BOOLEAN
|
|
UDFFlushIsBreaking(
|
|
IN PVCB Vcb,
|
|
IN ULONG FlushFlags
|
|
)
|
|
{
|
|
BOOLEAN ret_val = FALSE;
|
|
// if(!(FlushFlags & UDF_FLUSH_FLAGS_BREAKABLE))
|
|
return FALSE;
|
|
UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
|
|
ret_val = (Vcb->VCBFlags & UDF_VCB_FLAGS_FLUSH_BREAK_REQ) ? TRUE : FALSE;
|
|
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
|
|
UDFReleaseResource(&(Vcb->FlushResource));
|
|
return ret_val;
|
|
} // end UDFFlushIsBreaking()
|
|
|
|
/*
|
|
Signal FlushTree break request. Note, this is
|
|
treated as recommendation only
|
|
*/
|
|
VOID
|
|
UDFFlushTryBreak(
|
|
IN PVCB Vcb
|
|
)
|
|
{
|
|
UDFAcquireResourceExclusive(&(Vcb->FlushResource),TRUE);
|
|
Vcb->VCBFlags |= UDF_VCB_FLAGS_FLUSH_BREAK_REQ;
|
|
UDFReleaseResource(&(Vcb->FlushResource));
|
|
} // end UDFFlushTryBreak()
|