mirror of
https://github.com/reactos/reactos.git
synced 2025-05-13 06:18:17 +00:00
399 lines
14 KiB
C
399 lines
14 KiB
C
/*
|
|
* COPYRIGHT: See COPYRIGHT.TXT
|
|
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
|
* FILE: cleanup.c
|
|
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
|
* HOMEPAGE: http://www.ext2fsd.com
|
|
* UPDATE HISTORY:
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "ext2fs.h"
|
|
|
|
/* GLOBALS ***************************************************************/
|
|
|
|
extern PEXT2_GLOBAL Ext2Global;
|
|
|
|
/* DEFINITIONS *************************************************************/
|
|
|
|
NTSTATUS
|
|
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PEXT2_VCB Vcb = NULL;
|
|
PFILE_OBJECT FileObject;
|
|
PEXT2_FCB Fcb = NULL;
|
|
PEXT2_CCB Ccb = NULL;
|
|
PIRP Irp = NULL;
|
|
PEXT2_MCB Mcb = NULL;
|
|
|
|
|
|
BOOLEAN VcbResourceAcquired = FALSE;
|
|
BOOLEAN FcbResourceAcquired = FALSE;
|
|
BOOLEAN FcbPagingIoResourceAcquired = FALSE;
|
|
BOOLEAN SymLinkDelete = FALSE;
|
|
|
|
_SEH2_TRY {
|
|
|
|
ASSERT(IrpContext != NULL);
|
|
ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
|
|
(IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
|
|
|
|
DeviceObject = IrpContext->DeviceObject;
|
|
if (IsExt2FsDevice(DeviceObject)) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
Irp = IrpContext->Irp;
|
|
Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
|
|
ASSERT(Vcb != NULL);
|
|
ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
|
|
(Vcb->Identifier.Size == sizeof(EXT2_VCB)));
|
|
|
|
if (!IsVcbInited(Vcb)) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
FileObject = IrpContext->FileObject;
|
|
Fcb = (PEXT2_FCB) FileObject->FsContext;
|
|
if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
|
|
Fcb->Identifier.Type != EXT2FCB)) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
Mcb = Fcb->Mcb;
|
|
Ccb = (PEXT2_CCB) FileObject->FsContext2;
|
|
|
|
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (Fcb->Identifier.Type == EXT2VCB) {
|
|
|
|
ExAcquireResourceExclusiveLite(
|
|
&Vcb->MainResource, TRUE);
|
|
VcbResourceAcquired = TRUE;
|
|
|
|
if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
|
|
Vcb->LockFile == FileObject ){
|
|
|
|
ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
|
|
Vcb->LockFile = NULL;
|
|
Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
|
|
}
|
|
|
|
if (Ccb) {
|
|
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
|
Ext2DerefXcb(&Vcb->OpenVolumeCount);
|
|
}
|
|
|
|
IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
|
|
(Fcb->Identifier.Size == sizeof(EXT2_FCB)));
|
|
|
|
FcbResourceAcquired =
|
|
ExAcquireResourceExclusiveLite(
|
|
&Fcb->MainResource,
|
|
TRUE
|
|
);
|
|
|
|
if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
|
|
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
|
IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
|
|
!IsVcbReadOnly(Vcb) ) {
|
|
Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
|
|
}
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (Ccb == NULL) {
|
|
Status = STATUS_SUCCESS;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
if (IsDirectory(Fcb)) {
|
|
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
|
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
|
|
|
FsRtlNotifyFullChangeDirectory(
|
|
Vcb->NotifySync,
|
|
&Vcb->NotifyList,
|
|
Ccb,
|
|
NULL,
|
|
FALSE,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL );
|
|
}
|
|
|
|
FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);
|
|
}
|
|
|
|
ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
|
|
(Ccb->Identifier.Size == sizeof(EXT2_CCB)));
|
|
|
|
Ext2DerefXcb(&Vcb->OpenHandleCount);
|
|
Ext2DerefXcb(&Fcb->OpenHandleCount);
|
|
|
|
if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
|
|
Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
|
|
}
|
|
|
|
if (IsDirectory(Fcb)) {
|
|
|
|
ext3_release_dir(Fcb->Inode, &Ccb->filp);
|
|
|
|
} else {
|
|
|
|
if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
|
|
!IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {
|
|
|
|
LARGE_INTEGER SysTime;
|
|
KeQuerySystemTime(&SysTime);
|
|
|
|
Fcb->Inode->i_atime =
|
|
Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
|
|
Fcb->Mcb->LastAccessTime =
|
|
Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);
|
|
|
|
Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
|
|
|
|
Ext2NotifyReportChange(
|
|
IrpContext,
|
|
Vcb,
|
|
Fcb->Mcb,
|
|
FILE_NOTIFY_CHANGE_ATTRIBUTES |
|
|
FILE_NOTIFY_CHANGE_LAST_WRITE |
|
|
FILE_NOTIFY_CHANGE_LAST_ACCESS,
|
|
FILE_ACTION_MODIFIED );
|
|
}
|
|
|
|
FsRtlCheckOplock( &Fcb->Oplock,
|
|
Irp,
|
|
IrpContext,
|
|
NULL,
|
|
NULL );
|
|
|
|
Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
|
|
|
|
if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
|
|
Fcb->NonCachedOpenCount--;
|
|
}
|
|
|
|
if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) {
|
|
if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
|
|
SymLinkDelete = TRUE;
|
|
} else {
|
|
SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Drop any byte range locks this process may have on the file.
|
|
//
|
|
|
|
FsRtlFastUnlockAll(
|
|
&Fcb->FileLockAnchor,
|
|
FileObject,
|
|
IoGetRequestorProcess(Irp),
|
|
NULL );
|
|
|
|
//
|
|
// If there are no byte range locks owned by other processes on the
|
|
// file the fast I/O read/write functions doesn't have to check for
|
|
// locks so we set IsFastIoPossible to FastIoIsPossible again.
|
|
//
|
|
if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
|
|
if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
|
|
#if EXT2_DEBUG
|
|
DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
|
|
Ext2GetCurrentProcessName(),
|
|
"FastIoIsPossible",
|
|
&Fcb->Mcb->FullName
|
|
));
|
|
#endif
|
|
|
|
Fcb->Header.IsFastIoPossible = FastIoIsPossible;
|
|
}
|
|
}
|
|
|
|
if (Fcb->OpenHandleCount == 0 && FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE |
|
|
FCB_ALLOC_IN_SETINFO) ){
|
|
|
|
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_SETINFO)) {
|
|
if (Fcb->Header.ValidDataLength.QuadPart < Fcb->Header.FileSize.QuadPart) {
|
|
if (!INODE_HAS_EXTENT(Fcb->Inode)) {
|
|
#if EXT2_PRE_ALLOCATION_SUPPORT
|
|
_SEH2_TRY {
|
|
CcZeroData( FileObject,
|
|
&Fcb->Header.ValidDataLength,
|
|
&Fcb->Header.AllocationSize,
|
|
TRUE);
|
|
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
|
|
DbgBreak();
|
|
} _SEH2_END;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
|
|
|
|
LARGE_INTEGER Size;
|
|
|
|
ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
|
|
FcbPagingIoResourceAcquired = TRUE;
|
|
|
|
Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
|
|
(ULONGLONG)Fcb->Mcb->Inode.i_size,
|
|
(ULONGLONG)BLOCK_SIZE);
|
|
if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
|
|
|
Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
|
|
Fcb->Header.AllocationSize = Size;
|
|
Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
|
|
if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart)
|
|
Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
|
|
if (CcIsFileCached(FileObject)) {
|
|
CcSetFileSizes(FileObject,
|
|
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
|
}
|
|
}
|
|
ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE|FCB_ALLOC_IN_SETINFO);
|
|
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
|
FcbPagingIoResourceAcquired = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
|
|
|
|
if (!IsDirectory(Fcb)) {
|
|
|
|
if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
|
|
(Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) &&
|
|
(Fcb->SectionObject.DataSectionObject != NULL)) {
|
|
|
|
if (!IsVcbReadOnly(Vcb)) {
|
|
CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
|
|
ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
|
|
}
|
|
|
|
/* purge cache if all remaining openings are non-cached */
|
|
if (Fcb->NonCachedOpenCount > 0 ||
|
|
IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
|
|
if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
|
|
ExReleaseResourceLite(&(Fcb->PagingIoResource));
|
|
}
|
|
|
|
/* CcPurge could generate recursive IRP_MJ_CLOSE request */
|
|
CcPurgeCacheSection( &Fcb->SectionObject,
|
|
NULL,
|
|
0,
|
|
FALSE );
|
|
}
|
|
}
|
|
|
|
CcUninitializeCacheMap(FileObject, NULL, NULL);
|
|
}
|
|
|
|
if (SymLinkDelete ||
|
|
(IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) &&
|
|
Fcb->OpenHandleCount == 0) ) {
|
|
|
|
//
|
|
// Ext2DeleteFile will acquire these lock inside
|
|
//
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
FcbResourceAcquired = FALSE;
|
|
}
|
|
|
|
//
|
|
// this file is to be deleted ...
|
|
//
|
|
if (Ccb->SymLink) {
|
|
Mcb = Ccb->SymLink;
|
|
FileObject->DeletePending = FALSE;
|
|
}
|
|
|
|
Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
if (IsMcbDirectory(Mcb)) {
|
|
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
|
FILE_NOTIFY_CHANGE_DIR_NAME,
|
|
FILE_ACTION_REMOVED );
|
|
} else {
|
|
Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
|
|
FILE_NOTIFY_CHANGE_FILE_NAME,
|
|
FILE_ACTION_REMOVED );
|
|
}
|
|
}
|
|
|
|
//
|
|
// re-acquire the main resource lock
|
|
//
|
|
|
|
FcbResourceAcquired =
|
|
ExAcquireResourceExclusiveLite(
|
|
&Fcb->MainResource,
|
|
TRUE
|
|
);
|
|
if (!SymLinkDelete) {
|
|
SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
|
|
if (CcIsFileCached(FileObject)) {
|
|
CcSetFileSizes(FileObject,
|
|
(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
|
|
Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
if (FileObject) {
|
|
SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
|
|
}
|
|
|
|
} _SEH2_FINALLY {
|
|
|
|
if (FcbPagingIoResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->PagingIoResource);
|
|
}
|
|
|
|
if (FcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Fcb->MainResource);
|
|
}
|
|
|
|
if (VcbResourceAcquired) {
|
|
ExReleaseResourceLite(&Vcb->MainResource);
|
|
}
|
|
|
|
if (!IrpContext->ExceptionInProgress) {
|
|
if (Status == STATUS_PENDING) {
|
|
Ext2QueueRequest(IrpContext);
|
|
} else {
|
|
IrpContext->Irp->IoStatus.Status = Status;
|
|
Ext2CompleteIrpContext(IrpContext, Status);
|
|
}
|
|
}
|
|
} _SEH2_END;
|
|
|
|
return Status;
|
|
}
|