mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 20:03:07 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
771
drivers/filesystems/udfs/cleanup.cpp
Normal file
771
drivers/filesystems/udfs/cleanup.cpp
Normal file
|
@ -0,0 +1,771 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
Module name: Cleanup.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Contains code to handle the "Cleanup" dispatch entry point.
|
||||
|
||||
Environment:
|
||||
|
||||
Kernel mode only
|
||||
*/
|
||||
|
||||
#include "udffs.h"
|
||||
|
||||
// define the file specific bug-check id
|
||||
#define UDF_BUG_CHECK_ID UDF_FILE_CLEANUP
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Function: UDFCleanup()
|
||||
*
|
||||
* Description:
|
||||
* The I/O Manager will invoke this routine to handle a cleanup
|
||||
* 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
|
||||
*
|
||||
*************************************************************************/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
UDFCleanup(
|
||||
PDEVICE_OBJECT DeviceObject, // the logical volume device object
|
||||
PIRP Irp // I/O Request Packet
|
||||
)
|
||||
{
|
||||
NTSTATUS RC = STATUS_SUCCESS;
|
||||
PtrUDFIrpContext PtrIrpContext = NULL;
|
||||
BOOLEAN AreWeTopLevel = FALSE;
|
||||
|
||||
TmPrint(("UDFCleanup\n"));
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
ASSERT(DeviceObject);
|
||||
ASSERT(Irp);
|
||||
|
||||
// If we were called with our file system device object instead of a
|
||||
// volume device object, just complete this request with STATUS_SUCCESS
|
||||
if (UDFIsFSDevObj(DeviceObject)) {
|
||||
// this is a cleanup of the FSD itself
|
||||
Irp->IoStatus.Status = RC;
|
||||
Irp->IoStatus.Information = 0;
|
||||
|
||||
if(UDFGlobalData.AutoFormatCount == IoGetCurrentIrpStackLocation(Irp)->FileObject) {
|
||||
UDFPrint(("Deregister Autoformat\n"));
|
||||
UDFGlobalData.AutoFormatCount = NULL;
|
||||
}
|
||||
|
||||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||||
FsRtlExitFileSystem();
|
||||
return(RC);
|
||||
}
|
||||
|
||||
// set the top level context
|
||||
AreWeTopLevel = UDFIsIrpTopLevel(Irp);
|
||||
|
||||
_SEH2_TRY {
|
||||
|
||||
// get an IRP context structure and issue the request
|
||||
PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
|
||||
if(PtrIrpContext) {
|
||||
RC = UDFCommonCleanup(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 UDFCleanup()
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Function: UDFCommonCleanup()
|
||||
*
|
||||
* 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: Does not matter!
|
||||
*
|
||||
*************************************************************************/
|
||||
NTSTATUS
|
||||
UDFCommonCleanup(
|
||||
PtrUDFIrpContext PtrIrpContext,
|
||||
PIRP Irp)
|
||||
{
|
||||
IO_STATUS_BLOCK IoStatus;
|
||||
NTSTATUS RC = STATUS_SUCCESS;
|
||||
NTSTATUS RC2;
|
||||
PIO_STACK_LOCATION IrpSp = NULL;
|
||||
PFILE_OBJECT FileObject = NULL;
|
||||
PtrUDFFCB Fcb = NULL;
|
||||
PtrUDFCCB Ccb = NULL;
|
||||
PVCB Vcb = NULL;
|
||||
PtrUDFNTRequiredFCB NtReqFcb = NULL;
|
||||
ULONG lc = 0;
|
||||
BOOLEAN AcquiredVcb = FALSE;
|
||||
BOOLEAN AcquiredFCB = FALSE;
|
||||
BOOLEAN AcquiredParentFCB = FALSE;
|
||||
|
||||
// BOOLEAN CompleteIrp = TRUE;
|
||||
// BOOLEAN PostRequest = FALSE;
|
||||
BOOLEAN ChangeTime = FALSE;
|
||||
#ifdef UDF_DBG
|
||||
BOOLEAN CanWait = FALSE;
|
||||
#endif // UDF_DBG
|
||||
BOOLEAN ForcedCleanUp = FALSE;
|
||||
|
||||
PUDF_FILE_INFO NextFileInfo = NULL;
|
||||
#ifdef UDF_DBG
|
||||
UNICODE_STRING CurName;
|
||||
PDIR_INDEX_HDR DirNdx;
|
||||
#endif // UDF_DBG
|
||||
// PUDF_DATALOC_INFO Dloc;
|
||||
|
||||
TmPrint(("UDFCommonCleanup\n"));
|
||||
|
||||
// BrutePoint();
|
||||
|
||||
_SEH2_TRY {
|
||||
// First, get a pointer to the current I/O stack location
|
||||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
if(!IrpSp) try_return(RC = STATUS_INVALID_PARAMETER);
|
||||
|
||||
FileObject = IrpSp->FileObject;
|
||||
|
||||
// Get the FCB and CCB pointers
|
||||
Ccb = (PtrUDFCCB)(FileObject->FsContext2);
|
||||
ASSERT(Ccb);
|
||||
Fcb = Ccb->Fcb;
|
||||
ASSERT(Fcb);
|
||||
|
||||
Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
|
||||
ASSERT(Vcb);
|
||||
ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
|
||||
// Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
|
||||
#ifdef UDF_DBG
|
||||
CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
|
||||
AdPrint((" %s\n", CanWait ? "Wt" : "nw"));
|
||||
ASSERT(CanWait);
|
||||
#endif // UDF_DBG
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
|
||||
AcquiredVcb = TRUE;
|
||||
// Steps we shall take at this point are:
|
||||
// (a) Acquire the file (FCB) exclusively
|
||||
// (b) Flush file data to disk
|
||||
// (c) Talk to the FSRTL package (if we use it) about pending oplocks.
|
||||
// (d) Notify the FSRTL package for use with pending notification IRPs
|
||||
// (e) Unlock byte-range locks (if any were acquired by process)
|
||||
// (f) Update time stamp values (e.g. fast-IO had been performed)
|
||||
// (g) Inform the Cache Manager to uninitialize Cache Maps ...
|
||||
// and other similar stuff.
|
||||
// BrutePoint();
|
||||
NtReqFcb = Fcb->NTRequiredFCB;
|
||||
|
||||
if (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) {
|
||||
AdPrint(("Cleaning up Volume\n"));
|
||||
AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount));
|
||||
|
||||
UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount));
|
||||
UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount));
|
||||
if(FileObject->Flags & FO_CACHE_SUPPORTED) {
|
||||
// we've cached close
|
||||
UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount));
|
||||
}
|
||||
ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1));
|
||||
|
||||
// If this handle had write access, and actually wrote something,
|
||||
// flush the device buffers, and then set the verify bit now
|
||||
// just to be safe (in case there is no dismount).
|
||||
if( FileObject->WriteAccess &&
|
||||
(FileObject->Flags & FO_FILE_MODIFIED)) {
|
||||
|
||||
Vcb->Vpb->RealDevice->Flags |= DO_VERIFY_VOLUME;
|
||||
}
|
||||
// User may decide to close locked volume without call to unlock proc
|
||||
// So, handle this situation properly & unlock it now...
|
||||
if (FileObject == Vcb->VolumeLockFileObject) {
|
||||
Vcb->VolumeLockFileObject = NULL;
|
||||
Vcb->VolumeLockPID = -1;
|
||||
Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_LOCKED;
|
||||
Vcb->Vpb->Flags &= ~VPB_LOCKED;
|
||||
UDFNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);
|
||||
}
|
||||
|
||||
MmPrint((" CcUninitializeCacheMap()\n"));
|
||||
CcUninitializeCacheMap(FileObject, NULL, NULL);
|
||||
// reset device
|
||||
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) &&
|
||||
(Vcb->VCBFlags & UDF_VCB_FLAGS_OUR_DEVICE_DRIVER)) {
|
||||
// this call doesn't modify data buffer
|
||||
// it just requires its presence
|
||||
UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, TRUE);
|
||||
}
|
||||
// We must clean up the share access at this time, since we may not
|
||||
// get a Close call for awhile if the file was mapped through this
|
||||
// File Object.
|
||||
IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
|
||||
|
||||
try_return(RC = STATUS_SUCCESS);
|
||||
}
|
||||
// BrutePoint();
|
||||
#ifdef UDF_DBG
|
||||
DirNdx = UDFGetDirIndexByFileInfo(Fcb->FileInfo);
|
||||
if(DirNdx) {
|
||||
CurName.Buffer = UDFDirIndex(DirNdx, Fcb->FileInfo->Index)->FName.Buffer;
|
||||
if(CurName.Buffer) {
|
||||
AdPrint(("Cleaning up file: %ws %8.8x\n", CurName.Buffer, FileObject));
|
||||
} else {
|
||||
AdPrint(("Cleaning up file: ??? \n"));
|
||||
}
|
||||
}
|
||||
#endif //UDF_DBG
|
||||
AdPrint(("UDF: OpenHandleCount: %x\n",Fcb->OpenHandleCount));
|
||||
// Acquire parent object
|
||||
if(Fcb->FileInfo->ParentFile) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
|
||||
UDFAcquireResourceExclusive(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource),TRUE);
|
||||
} else {
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
||||
}
|
||||
AcquiredParentFCB = TRUE;
|
||||
// Acquire current object
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
||||
UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
|
||||
AcquiredFCB = TRUE;
|
||||
// dereference object
|
||||
UDFInterlockedDecrement((PLONG)&(Fcb->OpenHandleCount));
|
||||
UDFInterlockedDecrement((PLONG)&(Vcb->VCBHandleCount));
|
||||
if(FileObject->Flags & FO_CACHE_SUPPORTED) {
|
||||
// we've cached close
|
||||
UDFInterlockedDecrement((PLONG)&(Fcb->CachedOpenHandleCount));
|
||||
}
|
||||
ASSERT(Fcb->OpenHandleCount <= (Fcb->ReferenceCount-1));
|
||||
// check if Ccb being cleaned up has DeleteOnClose flag set
|
||||
#ifndef UDF_READ_ONLY_BUILD
|
||||
if(Ccb->CCBFlags & UDF_CCB_DELETE_ON_CLOSE) {
|
||||
AdPrint((" DeleteOnClose\n"));
|
||||
// Ok, now we'll become 'delete on close'...
|
||||
ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
|
||||
Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
|
||||
FileObject->DeletePending = TRUE;
|
||||
// Report this to the dir notify package for a directory.
|
||||
if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
|
||||
FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
|
||||
(PVOID)Ccb, NULL, FALSE, FALSE,
|
||||
0, NULL, NULL, NULL );
|
||||
}
|
||||
}
|
||||
#endif //UDF_READ_ONLY_BUILD
|
||||
|
||||
if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
|
||||
// Unlock all outstanding file locks.
|
||||
FsRtlFastUnlockAll(&(NtReqFcb->FileLock),
|
||||
FileObject,
|
||||
IoGetRequestorProcess(Irp),
|
||||
NULL);
|
||||
}
|
||||
// get Link count
|
||||
lc = UDFGetFileLinkCount(Fcb->FileInfo);
|
||||
|
||||
#ifndef UDF_READ_ONLY_BUILD
|
||||
if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) &&
|
||||
!(Fcb->OpenHandleCount)) {
|
||||
// This can be useful for Streams, those were brutally deleted
|
||||
// (together with parent object)
|
||||
ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
|
||||
FileObject->DeletePending = TRUE;
|
||||
|
||||
// we should mark all streams of the file being deleted
|
||||
// for deletion too, if there are no more Links to
|
||||
// main data stream
|
||||
if((lc <= 1) &&
|
||||
!UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo)) {
|
||||
RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
|
||||
}
|
||||
// we can release these resources 'cause UDF_FCB_DELETE_ON_CLOSE
|
||||
// flag is already set & the file can't be opened
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
||||
UDFReleaseResource(&(NtReqFcb->MainResource));
|
||||
AcquiredFCB = FALSE;
|
||||
if(Fcb->FileInfo->ParentFile) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
|
||||
UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource));
|
||||
} else {
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
}
|
||||
AcquiredParentFCB = FALSE;
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
AcquiredVcb = FALSE;
|
||||
|
||||
// Make system to issue last Close request
|
||||
// for our Target ...
|
||||
UDFRemoveFromSystemDelayedQueue(Fcb);
|
||||
|
||||
#ifdef UDF_DELAYED_CLOSE
|
||||
// remove file from our DelayedClose queue
|
||||
UDFRemoveFromDelayedQueue(Fcb);
|
||||
ASSERT(!Fcb->IrpContextLite);
|
||||
#endif //UDF_DELAYED_CLOSE
|
||||
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
|
||||
AcquiredVcb = TRUE;
|
||||
if(Fcb->FileInfo->ParentFile) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
|
||||
UDFAcquireResourceExclusive(&(Fcb->ParentFcb->NTRequiredFCB->MainResource),TRUE);
|
||||
} else {
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
||||
}
|
||||
AcquiredParentFCB = TRUE;
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
||||
UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
|
||||
AcquiredFCB = TRUE;
|
||||
|
||||
// we should set file sizes to zero if there are no more
|
||||
// links to this file
|
||||
if(lc <= 1) {
|
||||
// Synchronize here with paging IO
|
||||
UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource),TRUE);
|
||||
// set file size to zero (for system cache manager)
|
||||
// NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
|
||||
NtReqFcb->CommonFCBHeader.FileSize.QuadPart =
|
||||
NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = 0;
|
||||
CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize));
|
||||
|
||||
UDFReleaseResource(&(NtReqFcb->PagingIoResource));
|
||||
}
|
||||
}
|
||||
#endif //UDF_READ_ONLY_BUILD
|
||||
|
||||
#ifdef UDF_DELAYED_CLOSE
|
||||
if ((Fcb->ReferenceCount == 1) &&
|
||||
/*(Fcb->NodeIdentifier.NodeType != UDF_NODE_TYPE_VCB) &&*/ // see above
|
||||
(!(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE)) ) {
|
||||
Fcb->FCBFlags |= UDF_FCB_DELAY_CLOSE;
|
||||
}
|
||||
#endif //UDF_DELAYED_CLOSE
|
||||
|
||||
NextFileInfo = Fcb->FileInfo;
|
||||
|
||||
#ifndef UDF_READ_ONLY_BUILD
|
||||
// do we need to delete it now ?
|
||||
if( (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) &&
|
||||
!(Fcb->OpenHandleCount)) {
|
||||
|
||||
// can we do it ?
|
||||
if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
|
||||
ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
|
||||
if(!UDFIsDirEmpty__(NextFileInfo)) {
|
||||
// forget about it
|
||||
Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
|
||||
goto DiscardDelete;
|
||||
}
|
||||
} else
|
||||
if (lc <= 1) {
|
||||
// Synchronize here with paging IO
|
||||
BOOLEAN AcquiredPagingIo;
|
||||
AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(NtReqFcb->PagingIoResource));
|
||||
// set file size to zero (for UdfInfo package)
|
||||
// we should not do this for directories and linked files
|
||||
UDFResizeFile__(Vcb, NextFileInfo, 0);
|
||||
if(AcquiredPagingIo) {
|
||||
UDFReleaseResource(&(NtReqFcb->PagingIoResource));
|
||||
}
|
||||
}
|
||||
// mark parent object for deletion if requested
|
||||
if((Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) &&
|
||||
Fcb->ParentFcb) {
|
||||
ASSERT(!(Fcb->ParentFcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
|
||||
Fcb->ParentFcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
|
||||
}
|
||||
// flush file. It is required by UDFUnlinkFile__()
|
||||
RC = UDFFlushFile__(Vcb, NextFileInfo);
|
||||
if(!NT_SUCCESS(RC)) {
|
||||
AdPrint(("Error flushing file !!!\n"));
|
||||
}
|
||||
// try to unlink
|
||||
if((RC = UDFUnlinkFile__(Vcb, NextFileInfo, TRUE)) == STATUS_CANNOT_DELETE) {
|
||||
// If we can't delete file with Streams due to references,
|
||||
// mark SDir & Streams
|
||||
// for Deletion. We shall also set DELETE_PARENT flag to
|
||||
// force Deletion of the current file later... when curently
|
||||
// opened Streams would be cleaned up.
|
||||
|
||||
// WARNING! We should keep SDir & Streams if there is a
|
||||
// link to this file
|
||||
if(NextFileInfo->Dloc &&
|
||||
NextFileInfo->Dloc->SDirInfo &&
|
||||
NextFileInfo->Dloc->SDirInfo->Fcb) {
|
||||
|
||||
BrutePoint();
|
||||
if(!UDFIsSDirDeleted(NextFileInfo->Dloc->SDirInfo)) {
|
||||
// RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
|
||||
//#ifdef UDF_ALLOW_PRETEND_DELETED
|
||||
UDFPretendFileDeleted__(Vcb, Fcb->FileInfo);
|
||||
//#endif //UDF_ALLOW_PRETEND_DELETED
|
||||
}
|
||||
goto NotifyDelete;
|
||||
|
||||
} else {
|
||||
// Getting here means that we can't delete file because of
|
||||
// References/PemissionsDenied/Smth.Else,
|
||||
// but not Linked+OpenedStream
|
||||
BrutePoint();
|
||||
// RC = STATUS_SUCCESS;
|
||||
goto DiscardDelete_1;
|
||||
}
|
||||
} else {
|
||||
DiscardDelete_1:
|
||||
// We have got an ugly ERROR, or
|
||||
// file is deleted, so forget about it
|
||||
ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
|
||||
ForcedCleanUp = TRUE;
|
||||
if(NT_SUCCESS(RC))
|
||||
Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
|
||||
Fcb->FCBFlags |= UDF_FCB_DELETED;
|
||||
RC = STATUS_SUCCESS;
|
||||
}
|
||||
NotifyDelete:
|
||||
// We should prevent SetEOF operations on completly
|
||||
// deleted data streams
|
||||
if(lc < 1) {
|
||||
NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED;
|
||||
}
|
||||
// Report that we have removed an entry.
|
||||
if(UDFIsAStream(NextFileInfo)) {
|
||||
UDFNotifyFullReportChange( Vcb, NextFileInfo,
|
||||
FILE_NOTIFY_CHANGE_STREAM_NAME,
|
||||
FILE_ACTION_REMOVED_STREAM);
|
||||
} else {
|
||||
UDFNotifyFullReportChange( Vcb, NextFileInfo,
|
||||
UDFIsADirectory(NextFileInfo) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
|
||||
FILE_ACTION_REMOVED);
|
||||
}
|
||||
} else
|
||||
if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
|
||||
DiscardDelete:
|
||||
UDFNotifyFullReportChange( Vcb, NextFileInfo,
|
||||
((Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) ? FILE_NOTIFY_CHANGE_LAST_ACCESS : 0) |
|
||||
((Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) ? (FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE) : 0) |
|
||||
0,
|
||||
UDFIsAStream(NextFileInfo) ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED);
|
||||
}
|
||||
#endif //UDF_READ_ONLY_BUILD
|
||||
|
||||
if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
|
||||
// Report to the dir notify package for a directory.
|
||||
FsRtlNotifyCleanup( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb );
|
||||
}
|
||||
|
||||
// we can't purge Cache when more than one link exists
|
||||
if(lc > 1) {
|
||||
ForcedCleanUp = FALSE;
|
||||
}
|
||||
|
||||
if ( (FileObject->Flags & FO_CACHE_SUPPORTED) &&
|
||||
(NtReqFcb->SectionObject.DataSectionObject) ) {
|
||||
BOOLEAN LastNonCached = (!Fcb->CachedOpenHandleCount &&
|
||||
Fcb->OpenHandleCount);
|
||||
// If this was the last cached open, and there are open
|
||||
// non-cached handles, attempt a flush and purge operation
|
||||
// to avoid cache coherency overhead from these non-cached
|
||||
// handles later. We ignore any I/O errors from the flush.
|
||||
// We shall not flush deleted files
|
||||
RC = STATUS_SUCCESS;
|
||||
if( LastNonCached
|
||||
||
|
||||
(!Fcb->OpenHandleCount &&
|
||||
!ForcedCleanUp) ) {
|
||||
|
||||
#ifndef UDF_READ_ONLY_BUILD
|
||||
LONGLONG OldFileSize, NewFileSize;
|
||||
|
||||
if( (OldFileSize = NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart) <
|
||||
(NewFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart)) {
|
||||
/* UDFZeroDataEx(NtReqFcb,
|
||||
OldFileSize,
|
||||
NewFileSize - OldFileSize,
|
||||
TRUE, Vcb, FileObject);*/
|
||||
|
||||
NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart = NewFileSize;
|
||||
}
|
||||
#endif //UDF_READ_ONLY_BUILD
|
||||
MmPrint((" CcFlushCache()\n"));
|
||||
CcFlushCache( &(NtReqFcb->SectionObject), NULL, 0, &IoStatus );
|
||||
if(!NT_SUCCESS(IoStatus.Status)) {
|
||||
MmPrint((" CcFlushCache() error: %x\n", IoStatus.Status));
|
||||
RC = IoStatus.Status;
|
||||
}
|
||||
}
|
||||
// If file is deleted or it is last cached open, but there are
|
||||
// some non-cached handles we should purge cache section
|
||||
if(ForcedCleanUp || LastNonCached) {
|
||||
if(NtReqFcb->SectionObject.DataSectionObject) {
|
||||
MmPrint((" CcPurgeCacheSection()\n"));
|
||||
CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
|
||||
}
|
||||
/* MmPrint((" CcPurgeCacheSection()\n"));
|
||||
CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );*/
|
||||
}
|
||||
// we needn't Flush here. It will be done in UDFCloseFileInfoChain()
|
||||
}
|
||||
|
||||
#ifndef UDF_READ_ONLY_BUILD
|
||||
// Update FileTimes & Attrs
|
||||
if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) &&
|
||||
!(Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE |
|
||||
UDF_FCB_DELETED /*|
|
||||
UDF_FCB_DIRECTORY |
|
||||
UDF_FCB_READ_ONLY*/)) &&
|
||||
!UDFIsAStreamDir(NextFileInfo)) {
|
||||
LONGLONG NtTime;
|
||||
LONGLONG ASize;
|
||||
KeQuerySystemTime((PLARGE_INTEGER)&NtTime);
|
||||
// Check if we should set ARCHIVE bit & LastWriteTime
|
||||
if(FileObject->Flags & FO_FILE_MODIFIED) {
|
||||
ULONG Attr;
|
||||
PDIR_INDEX_ITEM DirNdx;
|
||||
DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(NextFileInfo), NextFileInfo->Index);
|
||||
ASSERT(DirNdx);
|
||||
// Archive bit
|
||||
if(!(Ccb->CCBFlags & UDF_CCB_ATTRIBUTES_SET) &&
|
||||
(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT)) {
|
||||
Attr = UDFAttributesToNT(DirNdx, NextFileInfo->Dloc->FileEntry);
|
||||
if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
|
||||
UDFAttributesToUDF(DirNdx, NextFileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
|
||||
}
|
||||
// WriteTime
|
||||
if(!(Ccb->CCBFlags & UDF_CCB_WRITE_TIME_SET) &&
|
||||
(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_MODIFY_TIME)) {
|
||||
UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, &NtTime);
|
||||
NtReqFcb->LastWriteTime.QuadPart =
|
||||
NtReqFcb->LastAccessTime.QuadPart = NtTime;
|
||||
ChangeTime = TRUE;
|
||||
}
|
||||
}
|
||||
if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
|
||||
// Update sizes in DirIndex
|
||||
if(!Fcb->OpenHandleCount) {
|
||||
ASize = UDFGetFileAllocationSize(Vcb, NextFileInfo);
|
||||
// NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
|
||||
UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize);
|
||||
} else
|
||||
if(FileObject->Flags & FO_FILE_SIZE_CHANGED) {
|
||||
ASize = //UDFGetFileAllocationSize(Vcb, NextFileInfo);
|
||||
NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart;
|
||||
UDFSetFileSizeInDirNdx(Vcb, NextFileInfo, &ASize);
|
||||
}
|
||||
}
|
||||
// AccessTime
|
||||
if((FileObject->Flags & FO_FILE_FAST_IO_READ) &&
|
||||
!(Ccb->CCBFlags & UDF_CCB_ACCESS_TIME_SET) &&
|
||||
(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ACCESS_TIME)) {
|
||||
UDFSetFileXTime(NextFileInfo, NULL, &NtTime, NULL, NULL);
|
||||
NtReqFcb->LastAccessTime.QuadPart = NtTime;
|
||||
// ChangeTime = TRUE;
|
||||
}
|
||||
// ChangeTime (AttrTime)
|
||||
if(!(Ccb->CCBFlags & UDF_CCB_MODIFY_TIME_SET) &&
|
||||
(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ATTR_TIME) &&
|
||||
(ChangeTime || (Ccb->CCBFlags & (UDF_CCB_ATTRIBUTES_SET |
|
||||
UDF_CCB_CREATE_TIME_SET |
|
||||
UDF_CCB_ACCESS_TIME_SET |
|
||||
UDF_CCB_WRITE_TIME_SET))) ) {
|
||||
UDFSetFileXTime(NextFileInfo, NULL, NULL, &NtTime, NULL);
|
||||
NtReqFcb->ChangeTime.QuadPart = NtTime;
|
||||
}
|
||||
}
|
||||
#endif //UDF_READ_ONLY_BUILD
|
||||
|
||||
if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY) &&
|
||||
ForcedCleanUp) {
|
||||
// flush system cache
|
||||
MmPrint((" CcUninitializeCacheMap()\n"));
|
||||
CcUninitializeCacheMap(FileObject, &(UDFGlobalData.UDFLargeZero), NULL);
|
||||
} else {
|
||||
MmPrint((" CcUninitializeCacheMap()\n"));
|
||||
CcUninitializeCacheMap(FileObject, NULL, NULL);
|
||||
}
|
||||
|
||||
// release resources now.
|
||||
// they'll be acquired in UDFCloseFileInfoChain()
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
||||
UDFReleaseResource(&(NtReqFcb->MainResource));
|
||||
AcquiredFCB = FALSE;
|
||||
|
||||
if(Fcb->FileInfo->ParentFile) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
|
||||
UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource));
|
||||
} else {
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
}
|
||||
AcquiredParentFCB = FALSE;
|
||||
// close the chain
|
||||
ASSERT(AcquiredVcb);
|
||||
RC2 = UDFCloseFileInfoChain(Vcb, NextFileInfo, Ccb->TreeLength, TRUE);
|
||||
if(NT_SUCCESS(RC))
|
||||
RC = RC2;
|
||||
|
||||
Ccb->CCBFlags |= UDF_CCB_CLEANED;
|
||||
|
||||
// We must clean up the share access at this time, since we may not
|
||||
// get a Close call for awhile if the file was mapped through this
|
||||
// File Object.
|
||||
IoRemoveShareAccess( FileObject, &(NtReqFcb->FCBShareAccess) );
|
||||
|
||||
NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
|
||||
|
||||
FileObject->Flags |= FO_CLEANUP_COMPLETE;
|
||||
|
||||
try_exit: NOTHING;
|
||||
|
||||
} _SEH2_FINALLY {
|
||||
|
||||
if(AcquiredFCB) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
|
||||
UDFReleaseResource(&(NtReqFcb->MainResource));
|
||||
}
|
||||
|
||||
if(AcquiredParentFCB) {
|
||||
if(Fcb->FileInfo->ParentFile) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB);
|
||||
UDFReleaseResource(&(Fcb->FileInfo->ParentFile->Fcb->NTRequiredFCB->MainResource));
|
||||
} else {
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
}
|
||||
}
|
||||
|
||||
if(AcquiredVcb) {
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
AcquiredVcb = FALSE;
|
||||
}
|
||||
|
||||
if (!_SEH2_AbnormalTermination()) {
|
||||
// complete the IRP
|
||||
Irp->IoStatus.Status = RC;
|
||||
Irp->IoStatus.Information = 0;
|
||||
IoCompleteRequest(Irp, IO_DISK_INCREMENT);
|
||||
// Free up the Irp Context
|
||||
UDFReleaseIrpContext(PtrIrpContext);
|
||||
}
|
||||
|
||||
} _SEH2_END; // end of "__finally" processing
|
||||
return(RC);
|
||||
} // end UDFCommonCleanup()
|
||||
|
||||
/*
|
||||
This routine walks through the tree to RootDir &
|
||||
calls UDFCloseFile__() for each file instance
|
||||
imho, Useful feature
|
||||
*/
|
||||
NTSTATUS
|
||||
UDFCloseFileInfoChain(
|
||||
IN PVCB Vcb,
|
||||
IN PUDF_FILE_INFO fi,
|
||||
IN ULONG TreeLength,
|
||||
IN BOOLEAN VcbAcquired
|
||||
)
|
||||
{
|
||||
PUDF_FILE_INFO ParentFI;
|
||||
PtrUDFFCB Fcb;
|
||||
PtrUDFFCB ParentFcb = NULL;
|
||||
NTSTATUS RC = STATUS_SUCCESS;
|
||||
NTSTATUS RC2;
|
||||
|
||||
// we can't process Tree until we can acquire Vcb
|
||||
if(!VcbAcquired)
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
||||
|
||||
AdPrint(("UDFCloseFileInfoChain\n"));
|
||||
for(; TreeLength && fi; TreeLength--) {
|
||||
|
||||
// close parent chain (if any)
|
||||
// if we started path parsing not from RootDir on Create,
|
||||
// we would never get RootDir here
|
||||
ValidateFileInfo(fi);
|
||||
|
||||
// acquire parent
|
||||
if((ParentFI = fi->ParentFile)) {
|
||||
ParentFcb = fi->Fcb->ParentFcb;
|
||||
ASSERT(ParentFcb);
|
||||
ASSERT(ParentFcb->NTRequiredFCB);
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
||||
UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE);
|
||||
ASSERT(ParentFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
|
||||
ASSERT(ParentFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
|
||||
} else {
|
||||
AdPrint(("Acquiring VCB...\n"));
|
||||
UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
|
||||
AdPrint(("Done\n"));
|
||||
}
|
||||
// acquire current file/dir
|
||||
// we must assure that no more threads try to reuse this object
|
||||
if((Fcb = fi->Fcb)) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
|
||||
UDFAcquireResourceExclusive(&(Fcb->NTRequiredFCB->MainResource),TRUE);
|
||||
ASSERT_REF(Fcb->ReferenceCount >= fi->RefCount);
|
||||
if(!(Fcb->FCBFlags & UDF_FCB_DELETED) &&
|
||||
(Fcb->FCBFlags & UDF_FCB_VALID))
|
||||
UDFWriteSecurity(Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
|
||||
RC2 = UDFCloseFile__(Vcb,fi);
|
||||
if(!NT_SUCCESS(RC2))
|
||||
RC = RC2;
|
||||
ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
|
||||
UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
|
||||
} else {
|
||||
BrutePoint();
|
||||
RC2 = UDFCloseFile__(Vcb,fi);
|
||||
if(!NT_SUCCESS(RC2))
|
||||
RC = RC2;
|
||||
}
|
||||
|
||||
if(ParentFI) {
|
||||
UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
|
||||
UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
|
||||
} else {
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
}
|
||||
fi = ParentFI;
|
||||
}
|
||||
|
||||
if(!VcbAcquired)
|
||||
UDFReleaseResource(&(Vcb->VCBResource));
|
||||
|
||||
return RC;
|
||||
|
||||
} // end UDFCloseFileInfoChain()
|
Loading…
Add table
Add a link
Reference in a new issue