Example #1
0
NTSTATUS VfatNotifyChangeDirectory(PVFAT_IRP_CONTEXT IrpContext)
{
    PVCB pVcb;
    PVFATFCB pFcb;
    PIO_STACK_LOCATION Stack;
    Stack = IrpContext->Stack;
    pVcb = IrpContext->DeviceExt;
    pFcb = (PVFATFCB) IrpContext->FileObject->FsContext;
 
    FsRtlNotifyFullChangeDirectory(pVcb->NotifySync,
                                   &(pVcb->NotifyList),
                                   IrpContext->FileObject->FsContext2,
                                   (PSTRING)&(pFcb->PathNameU),
                                   BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
                                   FALSE,
                                   Stack->Parameters.NotifyDirectory.CompletionFilter,
                                   IrpContext->Irp,
                                   NULL,
                                   NULL);

    /* We won't handle IRP completion */
    IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;

    return STATUS_PENDING;
}
Example #2
0
NTSTATUS
DokanNotifyChangeDirectory(
	__in PDEVICE_OBJECT DeviceObject,
	__in PIRP			Irp)
{
	PDokanCCB			ccb;
	PDokanFCB			fcb;
	PFILE_OBJECT		fileObject;
	PIO_STACK_LOCATION	irpSp;
	PDokanVCB			vcb;

	DDbgPrint("\tNotifyChangeDirectory");

	irpSp		= IoGetCurrentIrpStackLocation(Irp);
	fileObject	= irpSp->FileObject;

	vcb = DeviceObject->DeviceExtension;
	if (GetIdentifierType(vcb) != VCB) {
		return STATUS_INVALID_PARAMETER;
	}
	
	ccb = fileObject->FsContext2;
	ASSERT(ccb != NULL);

	fcb = ccb->Fcb;
	ASSERT(fcb != NULL);

	if (!(fcb->Flags & DOKAN_FILE_DIRECTORY)) {
		return STATUS_INVALID_PARAMETER;
	}

	FsRtlNotifyFullChangeDirectory(
		vcb->NotifySync,
		&vcb->DirNotifyList,
		ccb,
		(PSTRING)&fcb->FileName,
		irpSp->Flags & SL_WATCH_TREE ? TRUE : FALSE,
		FALSE,
		irpSp->Parameters.NotifyDirectory.CompletionFilter,
		Irp,
		NULL,
		NULL);

	return STATUS_PENDING;
}
Example #3
0
static NTSTATUS
CdfsNotifyChangeDirectory(PDEVICE_OBJECT DeviceObject,
                          PIRP Irp,
                          PCDFS_IRP_CONTEXT IrpContext)
{
    PDEVICE_EXTENSION DeviceExtension;
    PFCB Fcb;
    PCCB Ccb;
    PIO_STACK_LOCATION Stack;
    PFILE_OBJECT FileObject;

    DPRINT("CdfsNotifyChangeDirectory() called\n");

    DeviceExtension = DeviceObject->DeviceExtension;
    Stack = IoGetCurrentIrpStackLocation(Irp);
    FileObject = Stack->FileObject;

    Ccb = (PCCB)FileObject->FsContext2;
    Fcb = (PFCB)FileObject->FsContext;
 
    FsRtlNotifyFullChangeDirectory(DeviceExtension->NotifySync,
                                   &(DeviceExtension->NotifyList),
                                   Ccb,
                                   (PSTRING)&(Fcb->PathName),
                                   BooleanFlagOn(Stack->Flags, SL_WATCH_TREE),
                                   FALSE,
                                   Stack->Parameters.NotifyDirectory.CompletionFilter,
                                   Irp,
                                   NULL,
                                   NULL);

    /* We won't handle IRP completion */
    IrpContext->Flags &= ~IRPCONTEXT_COMPLETE;

    return STATUS_PENDING;
}
Example #4
0
__drv_mustHoldCriticalRegion
NTSTATUS
RfsdCleanup (IN PRFSD_IRP_CONTEXT IrpContext)
{
    PDEVICE_OBJECT  DeviceObject;
    NTSTATUS        Status = STATUS_SUCCESS;
    PRFSD_VCB       Vcb = 0;
    BOOLEAN         VcbResourceAcquired = FALSE;
    PFILE_OBJECT    FileObject;
    PRFSD_FCB       Fcb = 0;
    BOOLEAN         FcbResourceAcquired = FALSE;
    BOOLEAN         FcbPagingIoAcquired = FALSE;
    PRFSD_CCB       Ccb;
    PIRP            Irp;

    PAGED_CODE();

    _SEH2_TRY {

        ASSERT(IrpContext != NULL);
        
        ASSERT((IrpContext->Identifier.Type == RFSDICX) &&
            (IrpContext->Identifier.Size == sizeof(RFSD_IRP_CONTEXT)));
        
        DeviceObject = IrpContext->DeviceObject;
        
        if (DeviceObject == RfsdGlobal->DeviceObject) {
            Status = STATUS_SUCCESS;
            _SEH2_LEAVE;
        }
        
        Vcb = (PRFSD_VCB) DeviceObject->DeviceExtension;
        
        ASSERT(Vcb != NULL);
        
        ASSERT((Vcb->Identifier.Type == RFSDVCB) &&
            (Vcb->Identifier.Size == sizeof(RFSD_VCB)));

        if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED)) {
            Status = STATUS_SUCCESS;
            _SEH2_LEAVE;
        }

#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
        if (!ExAcquireResourceExclusiveLite(
                 &Vcb->MainResource,
                 IrpContext->IsSynchronous
                 ))  {
            Status = STATUS_PENDING;
            _SEH2_LEAVE;
        }

        VcbResourceAcquired = TRUE;
        
        FileObject = IrpContext->FileObject;
        
        Fcb = (PRFSD_FCB) FileObject->FsContext;
        
        if (!Fcb) {
            Status = STATUS_SUCCESS;
            _SEH2_LEAVE;
        }
        
        if (Fcb->Identifier.Type == RFSDVCB) {
            if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
                (Vcb->LockFile == FileObject) ) {
                ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
                Vcb->LockFile = NULL;

                RfsdClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
            }

            Vcb->OpenHandleCount--;

            if (!Vcb->OpenHandleCount) {
                IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);
            }

            Status = STATUS_SUCCESS;
            _SEH2_LEAVE;
        }
        
        ASSERT((Fcb->Identifier.Type == RFSDFCB) &&
            (Fcb->Identifier.Size == sizeof(RFSD_FCB)));

/*
        if ( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
             !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE))
*/
        {
#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
            if (!ExAcquireResourceExclusiveLite(
                     &Fcb->MainResource,
                     IrpContext->IsSynchronous
                     ))
            {
                Status = STATUS_PENDING;
                _SEH2_LEAVE;
            }

            FcbResourceAcquired = TRUE;
        }
        
        Ccb = (PRFSD_CCB) FileObject->FsContext2;

        if (!Ccb) {
            Status = STATUS_SUCCESS;
            _SEH2_LEAVE;
        }

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
                 !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                Status = RfsdFlushFile(Fcb);
            }
            _SEH2_LEAVE;
        }
        
        ASSERT((Ccb->Identifier.Type == RFSDCCB) &&
            (Ccb->Identifier.Size == sizeof(RFSD_CCB)));        
        Irp = IrpContext->Irp;

        Fcb->OpenHandleCount--;

        if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED )) {
            Fcb->NonCachedOpenCount--;
        }

        Vcb->OpenFileHandleCount--;

        if (IsFlagOn(Fcb->Flags, FCB_DELETE_ON_CLOSE))  {
            SetFlag(Fcb->Flags, FCB_DELETE_PENDING);

            if (IsDirectory(Fcb)) {
                FsRtlNotifyFullChangeDirectory(
                                            Vcb->NotifySync,
                                            &Vcb->NotifyList,
                                            Fcb,
                                            NULL,
                                            FALSE,
                                            FALSE,
                                            0,
                                            NULL,
                                            NULL,
                                            NULL );
            }
        }

        if (IsDirectory(Fcb)) {

            FsRtlNotifyCleanup(
                Vcb->NotifySync,
                &Vcb->NotifyList,
                Ccb   );

        } else {

            //
            // 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) {
                    RfsdPrint((
                        DBG_INFO, ": %-16.16s %-31s %s\n",
                        RfsdGetCurrentProcessName(),
                        "FastIoIsPossible",
                        Fcb->AnsiFileName.Buffer
                        ));

                    Fcb->Header.IsFastIoPossible = FastIoIsPossible;
                }
            }
        }

        if ( IsFlagOn( FileObject->Flags, FO_CACHE_SUPPORTED) &&
             (Fcb->NonCachedOpenCount != 0) &&
             (Fcb->NonCachedOpenCount == Fcb->ReferenceCount) &&
             (Fcb->SectionObject.DataSectionObject != NULL)) {

            if( !IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
                !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
                CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
            }

            ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE);
            ExReleaseResourceLite(&(Fcb->PagingIoResource));

            CcPurgeCacheSection( &Fcb->SectionObject,
                                 NULL,
                                 0,
                                 FALSE );
        }

        if (Fcb->OpenHandleCount == 0) {

            if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
                //
                //  Have to delete this file...
                //

#ifdef _MSC_VER
#pragma prefast( suppress: 28137, "by design" )
#endif
                if (!ExAcquireResourceExclusiveLite(
                         &Fcb->PagingIoResource,
                         IrpContext->IsSynchronous
                         )) {
                    Status = STATUS_PENDING;
                    _SEH2_LEAVE;
                }

                FcbPagingIoAcquired = TRUE;
DbgBreak();
#if DISABLED
                Status = RfsdDeleteFile(IrpContext, Vcb, Fcb);

                if (NT_SUCCESS(Status)) {
                    if (IsDirectory(Fcb)) {
                        RfsdNotifyReportChange( IrpContext, Vcb, Fcb,
                                                FILE_NOTIFY_CHANGE_DIR_NAME,
                                                FILE_ACTION_REMOVED );
                    } else {
                        RfsdNotifyReportChange( IrpContext, Vcb, Fcb,
                                                FILE_NOTIFY_CHANGE_FILE_NAME,
                                                FILE_ACTION_REMOVED );
                    }
                }
#endif
                if (CcIsFileCached(FileObject)) {

                    CcSetFileSizes(FileObject, 
                            (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
                }

                if (FcbPagingIoAcquired) {
                    ExReleaseResourceForThreadLite(
                        &Fcb->PagingIoResource,
                        ExGetCurrentResourceThread() );

                    FcbPagingIoAcquired = FALSE;
                }
            }
        }

        if (!IsDirectory(Fcb) && FileObject->PrivateCacheMap) {
            RfsdPrint((DBG_INFO, "RfsdCleanup: CcUninitializeCacheMap is called for %s.\n",
                                  Fcb->AnsiFileName.Buffer ));

            CcUninitializeCacheMap(
                    FileObject,
                    (PLARGE_INTEGER)(&(Fcb->Header.FileSize)),
                    NULL );
        }

        if (!Fcb->OpenHandleCount) {
            IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);
        }

        RfsdPrint((DBG_INFO, "RfsdCleanup: OpenCount: %u ReferCount: %u %s\n",
            Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->AnsiFileName.Buffer ));

        Status = STATUS_SUCCESS;

        if (FileObject) {
            SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
        }

    } _SEH2_FINALLY {
       
        if (FcbPagingIoAcquired) {
            ExReleaseResourceForThreadLite(
                &Fcb->PagingIoResource,
                ExGetCurrentResourceThread() );
        }

        if (FcbResourceAcquired) {
            ExReleaseResourceForThreadLite(
                &Fcb->MainResource,
                ExGetCurrentResourceThread() );
        }
        
        if (VcbResourceAcquired) {
            ExReleaseResourceForThreadLite(
                &Vcb->MainResource,
                ExGetCurrentResourceThread());
        }
        
        if (!IrpContext->ExceptionInProgress) {
            if (Status == STATUS_PENDING) {
                RfsdQueueRequest(IrpContext);
            } else {
                IrpContext->Irp->IoStatus.Status = Status;
                RfsdCompleteIrpContext(IrpContext, Status);
            }
        }
    } _SEH2_END;
    
    return Status;
}
Example #5
0
__drv_mustHoldCriticalRegion
NTSTATUS
CdNotifyChangeDirectory (
    __inout PIRP_CONTEXT IrpContext,
    __inout PIRP Irp,
    __in PIO_STACK_LOCATION IrpSp,
    __in PCCB Ccb
    )

/*++

Routine Description:

    This routine performs the notify change directory operation.  It is
    responsible for either completing of enqueuing the input Irp.  Although there
    will never be a notify signalled on a CDROM disk we still support this call.

    We have already checked that this is not an OpenById handle.

Arguments:

    Irp - Supplies the Irp to process

    IrpSp - Io stack location for this request.

    Ccb - Handle to the directory being watched.

Return Value:

    NTSTATUS - STATUS_PENDING, any other error will raise.

--*/

{
    PAGED_CODE();

    //
    //  Always set the wait bit in the IrpContext so the initial wait can't fail.
    //

    SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );

    //
    //  Acquire the Vcb shared.
    //

    CdAcquireVcbShared( IrpContext, IrpContext->Vcb, FALSE );

    //
    //  Use a try-finally to facilitate cleanup.
    //

    try {

        //
        //  Verify the Vcb.
        //

        CdVerifyVcb( IrpContext, IrpContext->Vcb );

        //
        //  Call the Fsrtl package to process the request.  We cast the
        //  unicode strings to ansi strings as the dir notify package
        //  only deals with memory matching.
        //

        FsRtlNotifyFullChangeDirectory( IrpContext->Vcb->NotifySync,
                                        &IrpContext->Vcb->DirNotifyList,
                                        Ccb,
                                        (PSTRING) &IrpSp->FileObject->FileName,
                                        BooleanFlagOn( IrpSp->Flags, SL_WATCH_TREE ),
                                        FALSE,
                                        IrpSp->Parameters.NotifyDirectory.CompletionFilter,
                                        Irp,
                                        NULL,
                                        NULL );

    } finally {

        //
        //  Release the Vcb.
        //

        CdReleaseVcb( IrpContext, IrpContext->Vcb );
    }

    //
    //  Cleanup the IrpContext.
    //

    CdCompleteRequest( IrpContext, NULL, STATUS_SUCCESS );

    return STATUS_PENDING;
}
Example #6
0
NTSTATUS
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
{
    PDEVICE_OBJECT  DeviceObject;
    NTSTATUS        Status = STATUS_SUCCESS;
    PEXT2_VCB       Vcb;
    PFILE_OBJECT    FileObject;
    PEXT2_FCB       Fcb;
    PEXT2_CCB       Ccb;
    PIRP            Irp;
    PEXT2_MCB       Mcb;


    BOOLEAN         VcbResourceAcquired = FALSE;
    BOOLEAN         FcbResourceAcquired = FALSE;
    BOOLEAN         FcbPagingIoResourceAcquired = FALSE;

    __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;
            __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;
            __leave;
        }

        FileObject = IrpContext->FileObject;
        Fcb = (PEXT2_FCB) FileObject->FsContext;
        if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
                     Fcb->Identifier.Type != EXT2FCB)) {
            Status = STATUS_SUCCESS;
            __leave;
        }
        Mcb = Fcb->Mcb;
        Ccb = (PEXT2_CCB) FileObject->FsContext2;

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        VcbResourceAcquired =
            ExAcquireResourceExclusiveLite(
                &Vcb->MainResource,
                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
            );

        if (Fcb->Identifier.Type == EXT2VCB) {

            if (IsFlagOn(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;
            __leave;
        }

        ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                    IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
                    !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
            }
            __leave;
        }

        if (Ccb == NULL) {
            Status = STATUS_SUCCESS;
            __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);

        }

        ExReleaseResourceLite(&Vcb->MainResource);
        VcbResourceAcquired = FALSE;

        FcbResourceAcquired =
            ExAcquireResourceExclusiveLite(
                &Fcb->MainResource,
                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
            );

        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))  {
                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 &&
                    (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) ||
                     IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) {

                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.ValidDataLength.QuadPart =
                        Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size;
                    Fcb->Header.AllocationSize = Size;
                    if (CcIsFileCached(FileObject)) {
                        CcSetFileSizes(FileObject,
                                       (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    }
                }
                ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);
                FcbPagingIoResourceAcquired = FALSE;
            }
        }

        if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {

            if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) {

                //
                // 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,
                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
                    );

                if (CcIsFileCached(FileObject)) {
                    CcSetFileSizes(FileObject,
                                   (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
                }
            }
        }

        if (!IsDirectory(Fcb)) {

            if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
                    (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) &&
                    (Fcb->SectionObject.DataSectionObject != NULL)) {

                if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
                        !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                    CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
                }

                if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
                    ExReleaseResourceLite(&(Fcb->PagingIoResource));
                }

                CcPurgeCacheSection( &Fcb->SectionObject,
                                     NULL,
                                     0,
                                     FALSE );
            }

            CcUninitializeCacheMap(FileObject, NULL, NULL);
        }

        IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);

        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);
        }

    } __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);
            }
        }
    }

    return Status;
}
Example #7
0
/*************************************************************************
*
* 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()
Example #8
0
__drv_mustHoldCriticalRegion
NTSTATUS
FFSNotifyChangeDirectory(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	PDEVICE_OBJECT      DeviceObject;
	BOOLEAN             CompleteRequest;
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;
	PFFS_VCB            Vcb;
	PFILE_OBJECT        FileObject;
	PFFS_FCB            Fcb = 0;
	PIRP                Irp;
	PIO_STACK_LOCATION  IrpSp;
	ULONG               CompletionFilter;
	BOOLEAN             WatchTree;

	BOOLEAN             bFcbAcquired = FALSE;

	PUNICODE_STRING     FullName;

    PAGED_CODE();

	_SEH2_TRY
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		//
		//  Always set the wait flag in the Irp context for the original request.
		//

		SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);

		DeviceObject = IrpContext->DeviceObject;

		if (DeviceObject == FFSGlobal->DeviceObject)
		{
			CompleteRequest = TRUE;
			Status = STATUS_INVALID_DEVICE_REQUEST;
			_SEH2_LEAVE;
		}

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		ASSERT(IsMounted(Vcb));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		if (Fcb->Identifier.Type == FFSVCB)
		{
			FFSBreakPoint();
			CompleteRequest = TRUE;
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		if (!IsDirectory(Fcb))
		{
			FFSBreakPoint();
			CompleteRequest = TRUE;
			Status = STATUS_INVALID_PARAMETER;
			_SEH2_LEAVE;
		}

		if (ExAcquireResourceExclusiveLite(
					&Fcb->MainResource,
					TRUE))
		{
			bFcbAcquired = TRUE;
		}
		else
		{
			Status = STATUS_PENDING;
			_SEH2_LEAVE;
		}

		Irp = IrpContext->Irp;

		IrpSp = IoGetCurrentIrpStackLocation(Irp);

#if !defined(_GNU_NTIFS_) || defined(__REACTOS__)

		CompletionFilter =
			IrpSp->Parameters.NotifyDirectory.CompletionFilter;

#else // _GNU_NTIFS_

		CompletionFilter = ((PEXTENDED_IO_STACK_LOCATION)
				IrpSp)->Parameters.NotifyDirectory.CompletionFilter;

#endif // _GNU_NTIFS_

		WatchTree = IsFlagOn(IrpSp->Flags, SL_WATCH_TREE);

		if (FlagOn(Fcb->Flags, FCB_DELETE_PENDING))
		{
			Status = STATUS_DELETE_PENDING;
			_SEH2_LEAVE;
		}

		FullName = &Fcb->LongName;

		if (FullName->Buffer == NULL)
		{
			if (!FFSGetFullFileName(Fcb->FFSMcb, FullName))
			{
				Status = STATUS_INSUFFICIENT_RESOURCES;
				_SEH2_LEAVE;
			}
		}

		FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
				&Vcb->NotifyList,
				FileObject->FsContext2,
				(PSTRING)FullName,
				WatchTree,
				FALSE,
				CompletionFilter,
				Irp,
				NULL,
				NULL);

		CompleteRequest = FALSE;

		Status = STATUS_PENDING;

		/*
		   Currently the driver is read-only but here is an example on how to use the
		   FsRtl-functions to report a change:

		   ANSI_STRING TestString;
		   USHORT      FileNamePartLength;

		   RtlInitAnsiString(&TestString, "\\ntifs.h");

		   FileNamePartLength = 7;

		   FsRtlNotifyReportChange(
		   Vcb->NotifySync,            // PNOTIFY_SYNC NotifySync
		   &Vcb->NotifyList,           // PLIST_ENTRY  NotifyList
		   &TestString,                // PSTRING      FullTargetName
		   &FileNamePartLength,        // PUSHORT      FileNamePartLength
		   FILE_NOTIFY_CHANGE_NAME     // ULONG        FilterMatch
		   );

		   or

		   ANSI_STRING TestString;

		   RtlInitAnsiString(&TestString, "\\ntifs.h");

		   FsRtlNotifyFullReportChange(
		   Vcb->NotifySync,            // PNOTIFY_SYNC NotifySync
		   &Vcb->NotifyList,           // PLIST_ENTRY  NotifyList
		   &TestString,                // PSTRING      FullTargetName
		   1,                          // USHORT       TargetNameOffset
		   NULL,                       // PSTRING      StreamName OPTIONAL
		   NULL,                       // PSTRING      NormalizedParentName OPTIONAL
		   FILE_NOTIFY_CHANGE_NAME,    // ULONG        FilterMatch
		   0,                          // ULONG        Action
		   NULL                        // PVOID        TargetContext
		   );
		   */

	}
	_SEH2_FINALLY
	{
		if (bFcbAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (!CompleteRequest)
			{
				IrpContext->Irp = NULL;
			}

			FFSCompleteIrpContext(IrpContext, Status);
		}
	} _SEH2_END;

	return Status;
}
Example #9
0
/*************************************************************************
*
* Function: UDFNotifyChangeDirectory()
*
* Description:
*   Handle the notify request.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS
NTAPI
UDFNotifyChangeDirectory(
    PtrUDFIrpContext            PtrIrpContext,
    PIRP                        Irp,
    PIO_STACK_LOCATION          IrpSp,
    PFILE_OBJECT                FileObject,
    PtrUDFFCB                   Fcb,
    PtrUDFCCB                   Ccb
    )
{
    NTSTATUS                    RC = STATUS_SUCCESS;
    BOOLEAN                     CompleteRequest = FALSE;
    BOOLEAN                     PostRequest = FALSE;
    PtrUDFNTRequiredFCB         NtReqFcb = NULL;
    BOOLEAN                     CanWait = FALSE;
    ULONG                       CompletionFilter = 0;
    BOOLEAN                     WatchTree = FALSE;
    PVCB                        Vcb = NULL;
    BOOLEAN                     AcquiredFCB = FALSE;
    PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp;

    UDFPrint(("UDFNotifyChangeDirectory\n"));

    _SEH2_TRY {

        // Validate the sent-in FCB
        if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
            !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {

            CompleteRequest = TRUE;
            try_return(RC = STATUS_INVALID_PARAMETER);
        }

        NtReqFcb = Fcb->NTRequiredFCB;
        CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
        Vcb = Fcb->Vcb;

        // Acquire the FCB resource shared
        UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
        if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
            PostRequest = TRUE;
            try_return(RC = STATUS_PENDING);
        }
        AcquiredFCB = TRUE;

        //  If the file is marked as DELETE_PENDING then complete this
        //  request immediately.
        if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
            ASSERT(!(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
            try_return(RC = STATUS_DELETE_PENDING);
        }

        // Obtain some parameters sent by the caller
        CompletionFilter = pStackLocation ->Parameters.NotifyDirectory.CompletionFilter;
        WatchTree = (IrpSp->Flags & SL_WATCH_TREE) ? TRUE : FALSE;

        // If we wish to capture the subject context, we can do so as
        // follows:
        // {
        //      PSECURITY_SUBJECT_CONTEXT SubjectContext;
        //  SubjectContext = MyAllocatePool__(PagedPool,
        //                                  sizeof(SECURITY_SUBJECT_CONTEXT));
        //      SeCaptureSubjectContext(SubjectContext);
        //  }

        FsRtlNotifyFullChangeDirectory(Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP), (PVOID)Ccb,
                            (Fcb->FileInfo->ParentFile) ? (PSTRING)&(Fcb->FCBName->ObjectName) : (PSTRING)&(UDFGlobalData.UnicodeStrRoot),
                            WatchTree, FALSE, CompletionFilter, Irp,
                            NULL,   // UDFTraverseAccessCheck(...) ?
                            NULL);  // SubjectContext ?

        RC = STATUS_PENDING;

        try_exit:   NOTHING;

    } _SEH2_FINALLY {

        if (PostRequest) {
            // Perform appropriate related post processing here
            if (AcquiredFCB) {
                UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
                UDFReleaseResource(&(NtReqFcb->MainResource));
                AcquiredFCB = FALSE;
            }
            RC = UDFPostRequest(PtrIrpContext, Irp);
        } else if (CompleteRequest) {

            if (!_SEH2_AbnormalTermination()) {
                Irp->IoStatus.Status = RC;
                Irp->IoStatus.Information = 0;
                // Free up the Irp Context
                UDFReleaseIrpContext(PtrIrpContext);
                // complete the IRP
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
            }

        } else {
            // Simply free up the IrpContext since the IRP has been queued
            if (!_SEH2_AbnormalTermination())
                UDFReleaseIrpContext(PtrIrpContext);
        }

        // Release the FCB resources if acquired.
        if (AcquiredFCB) {
            UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
            UDFReleaseResource(&(NtReqFcb->MainResource));
            AcquiredFCB = FALSE;
        }

    } _SEH2_END;

    return(RC);
} // end UDFNotifyChangeDirectory()
Example #10
0
/* Last handle to a file object is closed */
NTSTATUS
NTAPI
FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp)
{
    PIO_STACK_LOCATION IrpSp;
    PFILE_OBJECT FileObject;
    TYPE_OF_OPEN TypeOfOpen;
    PSHARE_ACCESS ShareAccess;
    BOOLEAN SendUnlockNotification = FALSE;
    PLARGE_INTEGER TruncateSize = NULL;
    //LARGE_INTEGER LocalTruncateSize;
    BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE;
    NTSTATUS Status;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DPRINT("FatiCleanup\n");
    DPRINT("\tIrp           = %p\n", Irp);
    DPRINT("\t->FileObject  = %p\n", IrpSp->FileObject);

    FileObject = IrpSp->FileObject;
    TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);

    if (TypeOfOpen == UnopenedFileObject)
    {
        DPRINT1("Unopened File Object\n");

        FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
        return STATUS_SUCCESS;
    }

    if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ))
    {
        /* Just flush the file */

        if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
            FlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) &&
            (TypeOfOpen == UserFileOpen))
        {
            //Status = FatFlushFile(IrpContext, Fcb, Flush);
            //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status);
            UNIMPLEMENTED;
        }

        FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS);
        return STATUS_SUCCESS;
    }

    if (TypeOfOpen == UserFileOpen ||
        TypeOfOpen == UserDirectoryOpen)
    {
        ASSERT(Fcb != NULL);

        (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);

        AcquiredFcb = TRUE;

        /* Set FCB flags according to DELETE_ON_CLOSE */
        if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))
        {
            ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB);

            SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE);

            /* Issue a notification */
            if (TypeOfOpen == UserDirectoryOpen)
            {
                FsRtlNotifyFullChangeDirectory(Vcb->NotifySync,
                                               &Vcb->NotifyList,
                                               FileObject->FsContext,
                                               NULL,
                                               FALSE,
                                               FALSE,
                                               0,
                                               NULL,
                                               NULL,
                                               NULL);
            }
        }

        /* If file should be deleted, acquire locks */
        if ((Fcb->UncleanCount == 1) &&
            FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            (Fcb->Condition != FcbBad) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
        {
            FatReleaseFcb(IrpContext, Fcb);
            AcquiredFcb = FALSE;

            (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
            AcquiredVcb = TRUE;

            (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb);
            AcquiredFcb = TRUE;
        }
    }

    /* Acquire VCB lock if it was a volume open */
    if (TypeOfOpen == UserVolumeOpen)
    {
        (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb);
        AcquiredVcb = TRUE;
    }

    /* Cleanup all notifications */
    if (TypeOfOpen == UserDirectoryOpen)
    {
        FsRtlNotifyCleanup(Vcb->NotifySync,
                           &Vcb->NotifyList,
                           Ccb);
    }

    if (Fcb)
    {
        //TODO: FatVerifyFcb
    }

    switch (TypeOfOpen)
    {
    case DirectoryFile:
    case VirtualVolumeFile:
        DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n");
        ShareAccess = NULL;
        break;

    case UserVolumeOpen:
        DPRINT("Cleanup UserVolumeOpen\n");

        if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT))
        {
            FatCheckForDismount( IrpContext, Vcb, TRUE );
        } else if (FileObject->WriteAccess &&
            FlagOn(FileObject->Flags, FO_FILE_MODIFIED))
        {
            UNIMPLEMENTED;
        }

        /* Release the volume and send notification */
        if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) &&
            (Vcb->FileObjectWithVcbLocked == FileObject))
        {
            UNIMPLEMENTED;
            SendUnlockNotification = TRUE;
        }

        ShareAccess = &Vcb->ShareAccess;
        break;

    case EaFile:
        DPRINT1("Cleanup EaFileObject\n");
        ShareAccess = NULL;
        break;

    case UserDirectoryOpen:
        DPRINT("Cleanup UserDirectoryOpen\n");

        ShareAccess = &Fcb->ShareAccess;

        /* Should it be a delayed close? */
        if ((Fcb->UncleanCount == 1) &&
            (Fcb->OpenCount == 1) &&
            (Fcb->Dcb.DirectoryFileOpenCount == 0) &&
            !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            Fcb->Condition == FcbGood)
        {
            /* Yes, a delayed one */
            SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
        }

        if (VcbGood == Vcb->Condition)
        {
            //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
            //TODO: Actually update dirent
        }

        if ((Fcb->UncleanCount == 1) &&
            (FatNodeType(Fcb) == FAT_NTC_DCB) &&
            (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) &&
            (Fcb->Condition != FcbBad) &&
            !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
        {
            UNIMPLEMENTED;
        }

        /*  Decrement unclean counter */
        ASSERT(Fcb->UncleanCount != 0);
        Fcb->UncleanCount--;
        break;

    case UserFileOpen:
        DPRINT("Cleanup UserFileOpen\n");

        ShareAccess = &Fcb->ShareAccess;

        /* Should it be a delayed close? */
        if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) &&
            (FileObject->SectionObjectPointer->ImageSectionObject == NULL) &&
            (Fcb->UncleanCount == 1) &&
            (Fcb->OpenCount == 1) &&
            !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
            Fcb->Condition == FcbGood)
        {
            /* Yes, a delayed one */
            //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE);
            DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName);
        }

        /* Unlock all file locks */
        FsRtlFastUnlockAll(&Fcb->Fcb.Lock,
                           FileObject,
                           IoGetRequestorProcess(Irp),
                           NULL);

        if (Vcb->Condition == VcbGood)
        {
            if (Fcb->Condition != FcbBad)
            {
                //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
                // TODO: Update on-disk structures
            }

            if (Fcb->UncleanCount == 1 &&
                Fcb->Condition != FcbBad)
            {
                //DELETE_CONTEXT DeleteContext;

                /* Should this file be deleted on close? */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
                    !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
                {
                    UNIMPLEMENTED;
                }
                else
                {
                    if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
                        (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart))
                    {
#if 0
                        ULONG ValidDataLength;

                        ValidDataLength = Fcb->Header.ValidDataLength.LowPart;

                        if (ValidDataLength < Fcb->ValidDataToDisk) {
                            ValidDataLength = Fcb->ValidDataToDisk;
                        }

                        if (ValidDataLength < Fcb->Header.FileSize.LowPart)
                        {
                            FatZeroData( IrpContext,
                                Vcb,
                                FileObject,
                                ValidDataLength,
                                Fcb->Header.FileSize.LowPart -
                                ValidDataLength );

                            Fcb->ValidDataToDisk =
                                Fcb->Header.ValidDataLength.LowPart =
                                Fcb->Header.FileSize.LowPart;

                            if (CcIsFileCached(FileObject))
                            {
                                CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
                            }
                        }
#endif
                        DPRINT1("Zeroing out data is not implemented\n");
                    }
                }

                /* Should the file be truncated on close? */
                if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE))
                {
                    if (Vcb->Condition == VcbGood)
                    {
                        // TODO: Actually truncate the file allocation
                        UNIMPLEMENTED;
                    }

                    /* Remove truncation flag */
                    Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE;
                }

                /* Check again if it should be deleted */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) &&
                    Fcb->Header.AllocationSize.LowPart == 0)
                {
                    FatNotifyReportChange(IrpContext,
                                          Vcb,
                                          Fcb,
                                          FILE_NOTIFY_CHANGE_FILE_NAME,
                                          FILE_ACTION_REMOVED);
                }

                /* Remove the entry from the splay table if the file was deleted */
                if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE))
                {
                    FatRemoveNames(IrpContext, Fcb);
                }
            }
        }

        ASSERT(Fcb->UncleanCount != 0);
        Fcb->UncleanCount--;
        if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED))
        {
            ASSERT(Fcb->NonCachedUncleanCount != 0);
            Fcb->NonCachedUncleanCount--;
        }

        if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
            (Fcb->NonCachedUncleanCount != 0) &&
            (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) &&
            (Fcb->SectionObjectPointers.DataSectionObject != NULL))
        {
            CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);

            /* Acquire and release PagingIo to get in sync with lazy writer */
            ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
            ExReleaseResourceLite(Fcb->Header.PagingIoResource);

            CcPurgeCacheSection(&Fcb->SectionObjectPointers,
                                NULL,
                                0,
                                FALSE);
        }

        if (Fcb->Condition == FcbBad)
        {
            //TruncateSize = &FatLargeZero;
            UNIMPLEMENTED;
        }

        /*  Cleanup the cache map */
        CcUninitializeCacheMap(FileObject, TruncateSize, NULL);
        break;

    default:
        KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0);
    }

    /* Cleanup the share access */

    if (ShareAccess)
    {
        DPRINT("Cleaning up the share access\n");
        IoRemoveShareAccess(FileObject, ShareAccess);
    }

    if (TypeOfOpen == UserFileOpen)
    {
        /* Update oplocks */
        FsRtlCheckOplock(&Fcb->Fcb.Oplock,
                         Irp,
                         IrpContext,
                         NULL,
                         NULL);

        Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
    }

    /* Set the FO_CLEANUP_COMPLETE flag */
    SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);

    Status = STATUS_SUCCESS;

    // TODO: Unpin repinned BCBs
    //FatUnpinRepinnedBcbs(IrpContext);

    /* Flush the volume if necessary */
    if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
        !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED))
    {
        UNIMPLEMENTED;
    }

    /* Cleanup */
    if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb);
    if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb);

    /* Send volume notification */
    if (SendUnlockNotification)
        FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK);

    return Status;
}
Example #11
0
/*************************************************************************
*
* Function: Ext2NotifyChangeDirectory()
*
* Description:
*	Handle the notify request.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS NTAPI Ext2NotifyChangeDirectory(
PtrExt2IrpContext			PtrIrpContext,
PIRP							PtrIrp,
#ifdef _GNU_NTIFS_
PEXTENDED_IO_STACK_LOCATION		PtrIoStackLocation,
#else
PIO_STACK_LOCATION		PtrIoStackLocation,
#endif
PFILE_OBJECT				PtrFileObject,
PtrExt2FCB					PtrFCB,
PtrExt2CCB					PtrCCB)
{
	NTSTATUS					RC = STATUS_SUCCESS;
	BOOLEAN					CompleteRequest = FALSE;
	BOOLEAN					PostRequest = FALSE;
	PtrExt2NTRequiredFCB	PtrReqdFCB = NULL;
	BOOLEAN					CanWait = FALSE;
	ULONG						CompletionFilter = 0;
	BOOLEAN					WatchTree = FALSE;
	PtrExt2VCB				PtrVCB = NULL;
	BOOLEAN					AcquiredFCB = FALSE;

	try {

		// Validate the sent-in FCB
		if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) {
			// We will only allow notify requests on directories.
			RC = STATUS_INVALID_PARAMETER;
			CompleteRequest = TRUE;
		}

		PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
		CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
	    PtrVCB = PtrFCB->PtrVCB;

		// Acquire the FCB resource shared
		DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Shared[DirCtrl]", 0);
		DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
		if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) 
		{
			DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquisition FAILED [DirCtrl]", 0);
			PostRequest = TRUE;
			try_return(RC = STATUS_PENDING);
		}
		AcquiredFCB = TRUE;
		DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquired [DirCtrl]", 0);

		// Obtain some parameters sent by the caller
		CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter;
		WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE);

		// If you wish to capture the subject context, you can do so as
		// follows:
		// {
		//		PSECURITY_SUBJECT_CONTEXT SubjectContext;
 		// 	SubjectContext = Ext2AllocatePool(PagedPool,
		//									sizeof(SECURITY_SUBJECT_CONTEXT) );
		//		SeCaptureSubjectContext(SubjectContext);
		//	}

		FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB,
							(PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp,
							NULL,		// Ext2TraverseAccessCheck(...) ?
							NULL);	// SubjectContext ?

		RC = STATUS_PENDING;

		try_exit:	NOTHING;

	} 
	finally 
	{

		if (PostRequest) 
		{
			// Perform appropriate post related processing here
			if (AcquiredFCB) 
			{
				Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
				DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released in DirCtrl", 0);
				DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
					PtrReqdFCB->MainResource.ActiveCount, 
					PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
					PtrReqdFCB->MainResource.NumberOfSharedWaiters );

				AcquiredFCB = FALSE;
			}
			RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
		} 
		else if (CompleteRequest) 
		{
			PtrIrp->IoStatus.Status = RC;
			PtrIrp->IoStatus.Information = 0;

			// Free up the Irp Context
			Ext2ReleaseIrpContext(PtrIrpContext);

			// complete the IRP
			IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
		} else {
			// Simply free up the IrpContext since the IRP has been queued
			Ext2ReleaseIrpContext(PtrIrpContext);
		}

		// Release the FCB resources if acquired.
		if (AcquiredFCB) 
		{
			Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
			DebugTrace(DEBUG_TRACE_MISC,  "*** FReleased in [DirCtrl]", 0);
			DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
					PtrReqdFCB->MainResource.ActiveCount, 
					PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
					PtrReqdFCB->MainResource.NumberOfSharedWaiters );

			AcquiredFCB = FALSE;
		}

	}

	return(RC);
}