Esempio n. 1
0
/*
Routine Description:

    This routines performs an IoVerifyVolume operation and takes the
    appropriate action.  If the verify is successful then we send the originating
    Irp off to an Ex Worker Thread.  This routine is called from the exception handler.
    No file system resources are held when this routine is called.

Arguments:

    Irp - The irp to send off after all is well and done.
    Device - The real device needing verification.

*/
NTSTATUS
UDFPerformVerify(
    IN PtrUDFIrpContext IrpContext,
    IN PIRP Irp,
    IN PDEVICE_OBJECT DeviceToVerify
    )
{

    PVCB Vcb;
    NTSTATUS RC = STATUS_SUCCESS;
    PIO_STACK_LOCATION IrpSp;

    KdPrint(("UDFPerformVerify:\n"));
    if(!IrpContext) return STATUS_INVALID_PARAMETER;
    if(!Irp) return STATUS_INVALID_PARAMETER;

    //  Check if this Irp has a status of Verify required and if it does
    //  then call the I/O system to do a verify.
    //
    //  Skip the IoVerifyVolume if this is a mount or verify request
    //  itself.  Trying a recursive mount will cause a deadlock with
    //  the DeviceObject->DeviceLock.
    if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) &&
       ((IrpContext->MinorFunction == IRP_MN_MOUNT_VOLUME) ||
        (IrpContext->MinorFunction == IRP_MN_VERIFY_VOLUME))) {

        return UDFPostRequest(IrpContext, Irp);
    }

    //  Extract a pointer to the Vcb from the VolumeDeviceObject.
    //  Note that since we have specifically excluded mount,
    //  requests, we know that IrpSp->DeviceObject is indeed a
    //  volume device object.

    IrpSp = IoGetCurrentIrpStackLocation(Irp);

    Vcb = (PVCB)IrpSp->DeviceObject->DeviceExtension;

    KdPrint(("UDFPerformVerify: check\n"));
    //  Check if the volume still thinks it needs to be verified,
    //  if it doesn't then we can skip doing a verify because someone
    //  else beat us to it.
    _SEH2_TRY {

        if (DeviceToVerify->Flags & DO_VERIFY_VOLUME) {

            //  If the IopMount in IoVerifyVolume did something, and
            //  this is an absolute open, force a reparse.
            RC = IoVerifyVolume( DeviceToVerify, FALSE );

            // Bug?
/*            if (UDFIsRawDevice(RC)) {
                RC = STATUS_WRONG_VOLUME;
            }*/

            //  If the verify operation completed it will return
            //  either STATUS_SUCCESS or STATUS_WRONG_VOLUME, exactly.
            if (RC == STATUS_SUCCESS) {
                IrpContext->IrpContextFlags &= ~UDF_IRP_CONTEXT_EXCEPTION;
            }
            //  If UDFVerifyVolume encountered an error during
            //  processing, it will return that error.  If we got
            //  STATUS_WRONG_VOLUME from the verify, and our volume
            //  is now mounted, commute the status to STATUS_SUCCESS.
            if ((RC == STATUS_WRONG_VOLUME) &&
                (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) {
                RC = STATUS_SUCCESS;
            }

            //  Do a quick unprotected check here.  The routine will do
            //  a safe check.  After here we can release the resource.
            //  Note that if the volume really went away, we will be taking
            //  the Reparse path.

            //  If the device might need to go away then call our dismount routine.
            if ( (!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) ||
                   (Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED)) &&
                   (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE) )
            {
                KdPrint(("UDFPerformVerify: UDFCheckForDismount\n"));
                UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
                UDFCheckForDismount( IrpContext, Vcb, FALSE );
                UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
            }

            //  If this is a create and the verify succeeded then complete the
            //  request with a REPARSE status.
            if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
                (IrpSp->FileObject->RelatedFileObject == NULL) &&
                ((RC == STATUS_SUCCESS) || (RC == STATUS_WRONG_VOLUME)) ) {

                KdPrint(("UDFPerformVerify: IO_REMOUNT\n"));

                Irp->IoStatus.Information = IO_REMOUNT;

                Irp->IoStatus.Status = STATUS_REPARSE;
                IoCompleteRequest(Irp,IO_DISK_INCREMENT);

                UDFReleaseIrpContext(IrpContext);

                RC = STATUS_REPARSE;
                Irp = NULL;
                IrpContext = NULL;

            //  If there is still an error to process then call the Io system
            //  for a popup.
            } else if ((Irp != NULL) && !NT_SUCCESS( RC )) {

                KdPrint(("UDFPerformVerify: check IoIsErrorUserInduced\n"));
                //  Fill in the device object if required.
                if (IoIsErrorUserInduced( RC ) ) {
                    IoSetHardErrorOrVerifyDevice( Irp, DeviceToVerify );
                }
                KdPrint(("UDFPerformVerify: UDFNormalizeAndRaiseStatus\n"));
                UDFNormalizeAndRaiseStatus( IrpContext, RC );
            }
        }

        //  If there is still an Irp, send it off to an Ex Worker thread.
        if (IrpContext != NULL) {

            RC = UDFPostRequest( IrpContext, Irp );
        }

    } _SEH2_EXCEPT(UDFExceptionFilter( IrpContext, _SEH2_GetExceptionInformation())) {
        //  We had some trouble trying to perform the verify or raised
        //  an error ourselves.  So we'll abort the I/O request with
        //  the error status that we get back from the execption code.
        RC = UDFExceptionHandler( IrpContext, Irp);
    } _SEH2_END;

    KdPrint(("UDFPerformVerify: RC = %x\n", RC));

    return RC;
    
} // end UDFPerformVerify()
Esempio n. 2
0
/*************************************************************************
*
* Function: UDFCommonShutdown()
*
* Description:
*   The actual work is performed here. Basically, all we do here is
*   internally invoke a flush on all mounted logical volumes. This, in
*   tuen, will result in all open file streams being flushed to disk.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: Irrelevant
*
*************************************************************************/
NTSTATUS
UDFCommonShutdown(
    PtrUDFIrpContext PtrIrpContext,
    PIRP             Irp
    )
{
    NTSTATUS            RC = STATUS_SUCCESS;
    PIO_STACK_LOCATION  IrpSp = NULL;
    PVCB Vcb;
    PLIST_ENTRY Link;
    PPREVENT_MEDIA_REMOVAL_USER_IN Buf = NULL;
    LARGE_INTEGER delay;

    KdPrint(("UDFCommonShutdown\n"));

    _SEH2_TRY {
        // First, get a pointer to the current I/O stack location
        IrpSp = IoGetCurrentIrpStackLocation(Irp);
        ASSERT(IrpSp);

        Buf = (PPREVENT_MEDIA_REMOVAL_USER_IN)MyAllocatePool__(NonPagedPool, sizeof(PREVENT_MEDIA_REMOVAL_USER_IN));
        if(!Buf)
            try_return(RC = STATUS_INSUFFICIENT_RESOURCES);

        // (a) Block all new "mount volume" requests by acquiring an appropriate
        //       global resource/lock.
        // (b) Go through your linked list of mounted logical volumes and for
        //       each such volume, do the following:
        //       (i) acquire the volume resource exclusively
        //       (ii) invoke UDFFlushLogicalVolume() (internally) to flush the
        //              open data streams belonging to the volume from the system
        //              cache
        //       (iii) Invoke the physical/virtual/logical target device object
        //              on which the volume is mounted and inform this device
        //              about the shutdown request (Use IoBuildSynchronouFsdRequest()
        //              to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you
        //              will then issue to the target device object).
        //       (iv) Wait for the completion of the shutdown processing by the target
        //              device object
        //       (v) Release the VCB resource we will have acquired in (i) above.

        // Acquire GlobalDataResource
        UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
        // Walk through all of the Vcb's attached to the global data.
        Link = UDFGlobalData.VCBQueue.Flink;

        while (Link != &(UDFGlobalData.VCBQueue)) {
            // Get 'next' Vcb
            Vcb = CONTAINING_RECORD( Link, VCB, NextVCB );
            // Move to the next link now since the current Vcb may be deleted.
            Link = Link->Flink;
            ASSERT(Link != Link->Flink);

            if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {

#ifdef UDF_DELAYED_CLOSE
                UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
                KdPrint(("    UDFCommonShutdown:     set UDF_VCB_FLAGS_NO_DELAYED_CLOSE\n"));
                Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
                UDFReleaseResource(&(Vcb->VCBResource));
#endif //UDF_DELAYED_CLOSE

                // Note: UDFCloseAllDelayed() doesn't acquire DelayedCloseResource if
                // GlobalDataResource is already acquired. Thus for now we should
                // release GlobalDataResource and re-acquire it later.
                UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
                if(Vcb->RootDirFCB && Vcb->RootDirFCB->FileInfo) {
                    KdPrint(("    UDFCommonShutdown:     UDFCloseAllSystemDelayedInDir\n"));
                    RC = UDFCloseAllSystemDelayedInDir(Vcb, Vcb->RootDirFCB->FileInfo);
                    ASSERT(OS_SUCCESS(RC));
                }

#ifdef UDF_DELAYED_CLOSE
                UDFCloseAllDelayed(Vcb);
//                UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
#endif //UDF_DELAYED_CLOSE

                // re-acquire GlobalDataResource
                UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);

                // disable Eject Waiter
                UDFStopEjectWaiter(Vcb);
                // Acquire Vcb resource
                UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);

                ASSERT(!Vcb->OverflowQueueCount);

                if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_SHUTDOWN)) {

                    UDFDoDismountSequence(Vcb, Buf, FALSE);
                    if(Vcb->VCBFlags & UDF_VCB_FLAGS_REMOVABLE_MEDIA) {
                        // let drive flush all data before reset
                        delay.QuadPart = -10000000; // 1 sec
                        KeDelayExecutionThread(KernelMode, FALSE, &delay);
                    }
                    Vcb->VCBFlags |= (UDF_VCB_FLAGS_SHUTDOWN |
                                      UDF_VCB_FLAGS_VOLUME_READ_ONLY);
                }

                UDFReleaseResource(&(Vcb->VCBResource));
            }
        }
        // Once we have processed all the mounted logical volumes, we can release
        // all acquired global resources and leave (in peace :-)
        UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
        RC = STATUS_SUCCESS;

try_exit: NOTHING;

    } _SEH2_FINALLY {

        if(Buf) MyFreePool__(Buf);
        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);
        }

    } _SEH2_END; // end of "__finally" processing

    return(RC);
} // end UDFCommonShutdown()
Esempio n. 3
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()
Esempio n. 4
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()
Esempio n. 5
0
/*************************************************************************
*
* Function: UDFQueryDirectory()
*
* Description:
*   Query directory request.
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS
NTAPI
UDFQueryDirectory(
    PtrUDFIrpContext            PtrIrpContext,
    PIRP                        Irp,
    PIO_STACK_LOCATION          IrpSp,
    PFILE_OBJECT                FileObject,
    PtrUDFFCB                   Fcb,
    PtrUDFCCB                   Ccb
    )
{
    NTSTATUS                    RC = STATUS_SUCCESS;
    BOOLEAN                     PostRequest = FALSE;
    PtrUDFNTRequiredFCB         NtReqFcb = NULL;
    BOOLEAN                     CanWait = FALSE;
    PVCB                        Vcb = NULL;
    BOOLEAN                     AcquiredFCB = FALSE;
    unsigned long               BufferLength = 0;
    UNICODE_STRING              SearchPattern;
    PUNICODE_STRING             PtrSearchPattern;
    FILE_INFORMATION_CLASS      FileInformationClass;
    BOOLEAN                     ReturnSingleEntry = FALSE;
    PUCHAR                      Buffer = NULL;
    BOOLEAN                     FirstTimeQuery = FALSE;
    LONG                        NextMatch;
    LONG                        PrevMatch = -1;
    ULONG                       CurrentOffset;
    ULONG                       BaseLength;
    ULONG                       FileNameBytes;
    ULONG                       Information = 0;
    ULONG                       LastOffset = 0;
    BOOLEAN                     AtLeastOneFound = FALSE;
    PEXTENDED_IO_STACK_LOCATION pStackLocation = (PEXTENDED_IO_STACK_LOCATION) IrpSp;
    PUDF_FILE_INFO              DirFileInfo = NULL;
    PDIR_INDEX_HDR              hDirIndex = NULL;
    PFILE_BOTH_DIR_INFORMATION  DirInformation = NULL;      // Returned from udf_info module
    PFILE_BOTH_DIR_INFORMATION  BothDirInformation = NULL;  // Pointer in callers buffer
    PFILE_NAMES_INFORMATION     NamesInfo;
    ULONG                       BytesRemainingInBuffer;
    UCHAR                       FNM_Flags = 0;
    PHASH_ENTRY                 cur_hashes = NULL;
    PDIR_INDEX_ITEM             DirNdx;
    // do some pre-init...
    SearchPattern.Buffer = NULL;

    UDFPrint(("UDFQueryDirectory: @=%#x\n", &PtrIrpContext));

#define CanBe8dot3    (FNM_Flags & UDF_FNM_FLAG_CAN_BE_8D3)
#define IgnoreCase    (FNM_Flags & UDF_FNM_FLAG_IGNORE_CASE)
#define ContainsWC    (FNM_Flags & UDF_FNM_FLAG_CONTAINS_WC)

    _SEH2_TRY
    {

        // Validate the sent-in FCB
        if ((Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) || !(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
            // We will only allow notify requests on directories.
            try_return(RC = STATUS_INVALID_PARAMETER);
        }

        // Obtain the callers parameters
        NtReqFcb = Fcb->NTRequiredFCB;
        CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
        Vcb = Fcb->Vcb;
        //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
        FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? 0 : UDF_FNM_FLAG_IGNORE_CASE;
        DirFileInfo = Fcb->FileInfo;
        BufferLength = pStackLocation->Parameters.QueryDirectory.Length;

        // If the caller does not want to block, it would be easier to
        // simply post the request now.
        if (!CanWait) {
            PostRequest = TRUE;
            try_return(RC = STATUS_PENDING);
        }

        // Continue obtaining the callers parameters...
        if(IgnoreCase && pStackLocation->Parameters.QueryDirectory.FileName) {
            PtrSearchPattern = &SearchPattern;
            if(!NT_SUCCESS(RC = RtlUpcaseUnicodeString(PtrSearchPattern, (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName), TRUE)))
                try_return(RC);
        } else {
            PtrSearchPattern = (PUNICODE_STRING)(pStackLocation->Parameters.QueryDirectory.FileName);
        }
        FileInformationClass = pStackLocation->Parameters.QueryDirectory.FileInformationClass;

        // Calculate baselength (without name) for each InfoClass
        switch (FileInformationClass) {
    
        case FileDirectoryInformation:
            BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] );
            break;
        case FileFullDirectoryInformation:
            BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,  FileName[0] );
            break;
        case FileNamesInformation:
            BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,     FileName[0] );  
            break;
        case FileBothDirectoryInformation:
            BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,  FileName[0] );
            break;
        default:
            try_return(RC = STATUS_INVALID_INFO_CLASS);
        }
    
        // Some additional arguments that affect the FSD behavior
        ReturnSingleEntry = (IrpSp->Flags & SL_RETURN_SINGLE_ENTRY) ? TRUE : FALSE;

        UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
        UDFAcquireResourceShared(&(NtReqFcb->MainResource), TRUE);
        AcquiredFCB = TRUE;

        // We must determine the buffer pointer to be used. Since this
        // routine could either be invoked directly in the context of the
        // calling thread, or in the context of a worker thread, here is
        // a general way of determining what we should use.
        if(Irp->MdlAddress) {
            Buffer = (PUCHAR) MmGetSystemAddressForMdlSafer(Irp->MdlAddress);
            if(!Buffer)
                try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
        } else {
            Buffer = (PUCHAR) Irp->UserBuffer;
            if(!Buffer)
                try_return(RC = STATUS_INVALID_USER_BUFFER);
        }

        // The method of determining where to look from and what to look for is
        // unfortunately extremely confusing. However, here is a methodology
        // we broadly adopt:
        // (a) We have to maintain a search buffer per CCB structure.
        // (b) This search buffer is initialized the very first time
        //       a query directory operation is performed using the file object.
        // (For the UDF FSD, the search buffer is stored in the
        //   DirectorySearchPattern field)
        // However, the caller still has the option of "overriding" this stored
        // search pattern by supplying a new one in a query directory operation.
        if(PtrSearchPattern &&
           PtrSearchPattern->Buffer &&
           !(PtrSearchPattern->Buffer[PtrSearchPattern->Length/sizeof(WCHAR) - 1])) {
            PtrSearchPattern->Length -= sizeof(WCHAR);
        }

        if(IrpSp->Flags & SL_INDEX_SPECIFIED) {
            // Good idea from M$: we should continue search from NEXT item
            // when FileIndex specified...
            // Strange idea from M$: we should do it with EMPTY pattern...
            PtrSearchPattern = NULL;
            Ccb->CCBFlags |= UDF_CCB_MATCH_ALL;
        } else if(PtrSearchPattern &&
                  PtrSearchPattern->Buffer &&
                  !UDFIsMatchAllMask(PtrSearchPattern, NULL) ) {

            Ccb->CCBFlags &= ~(UDF_CCB_MATCH_ALL |
                               UDF_CCB_WILDCARD_PRESENT |
                               UDF_CCB_CAN_BE_8_DOT_3);
            // Once we have validated the search pattern, we must
            // check whether we need to store this search pattern in
            // the CCB.
            if(Ccb->DirectorySearchPattern) {
                MyFreePool__(Ccb->DirectorySearchPattern->Buffer);
                MyFreePool__(Ccb->DirectorySearchPattern);
                Ccb->DirectorySearchPattern = NULL;
            }
            // This must be the very first query request.
            FirstTimeQuery = TRUE;

            // Now, allocate enough memory to contain the caller
            // supplied search pattern and fill in the DirectorySearchPattern
            // field in the CCB
            Ccb->DirectorySearchPattern = (PUNICODE_STRING)MyAllocatePool__(NonPagedPool,sizeof(UNICODE_STRING));
            if(!(Ccb->DirectorySearchPattern)) {
                try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
            }
            Ccb->DirectorySearchPattern->Length = PtrSearchPattern->Length;
            Ccb->DirectorySearchPattern->MaximumLength = PtrSearchPattern->MaximumLength;
            Ccb->DirectorySearchPattern->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool,PtrSearchPattern->MaximumLength);
            if(!(Ccb->DirectorySearchPattern->Buffer)) {
                try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
            }
            RtlCopyMemory(Ccb->DirectorySearchPattern->Buffer,PtrSearchPattern->Buffer,
                          PtrSearchPattern->MaximumLength);
            if(FsRtlDoesNameContainWildCards(PtrSearchPattern)) {
                Ccb->CCBFlags |= UDF_CCB_WILDCARD_PRESENT;
            } else {
                UDFBuildHashEntry(Vcb, PtrSearchPattern, cur_hashes = &(Ccb->hashes), HASH_POSIX | HASH_ULFN);
            }
            if(UDFCanNameBeA8dot3(PtrSearchPattern))
                Ccb->CCBFlags |= UDF_CCB_CAN_BE_8_DOT_3;

        } else if(!Ccb->DirectorySearchPattern &&
                  !(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) ) {

            // If the filename is not specified or is a single '*' then we will
            // match all names.
            FirstTimeQuery = TRUE;
            PtrSearchPattern = NULL;
            Ccb->CCBFlags |= UDF_CCB_MATCH_ALL;

        } else {
            // The caller has not supplied any search pattern that we are
            // forced to use. However, the caller had previously supplied
            // a pattern (or we must have invented one) and we will use it.
            // This is definitely not the first query operation on this
            // directory using this particular file object.
            if(Ccb->CCBFlags & UDF_CCB_MATCH_ALL) {
                PtrSearchPattern = NULL;
/*                if(Ccb->CurrentIndex)
                    Ccb->CurrentIndex++;*/
            } else {
                PtrSearchPattern = Ccb->DirectorySearchPattern;
                if(!(Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT)) {
                    cur_hashes = &(Ccb->hashes);
                }
            }
        }

        if(IrpSp->Flags & SL_INDEX_SPECIFIED) {
            // Caller has told us wherefrom to begin.
            // We may need to round this to an appropriate directory entry
            // entry alignment value.
            NextMatch = pStackLocation->Parameters.QueryDirectory.FileIndex + 1;
        } else if(IrpSp->Flags & SL_RESTART_SCAN) {
            NextMatch = 0;
        } else {
            // Get the starting offset from the CCB.
            // Remember to update this value on our way out from this function.
            // But, do not update the CCB CurrentByteOffset field if our reach
            // the end of the directory (or get an error reading the directory)
            // while performing the search.
            NextMatch = Ccb->CurrentIndex + 1; // Last good index
        }

        FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_WILDCARD_PRESENT) ? UDF_FNM_FLAG_CONTAINS_WC : 0;
        // this is used only when mask is supplied
        FNM_Flags |= (Ccb->CCBFlags & UDF_CCB_CAN_BE_8_DOT_3) ? UDF_FNM_FLAG_CAN_BE_8D3 : 0;

        // This is an additional verifying
        if(!UDFIsADirectory(DirFileInfo)) {
            try_return(RC = STATUS_INVALID_PARAMETER);
        }

        hDirIndex = DirFileInfo->Dloc->DirIndex;
        if(!hDirIndex) {
            try_return(RC = STATUS_INVALID_PARAMETER);
        }

        RC = STATUS_SUCCESS;
        // Allocate buffer enough to save both DirInformation and FileName
        DirInformation = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool,
                            sizeof(FILE_BOTH_DIR_INFORMATION)+((ULONG)UDF_NAME_LEN*sizeof(WCHAR)) );
        if(!DirInformation) {
            try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
        }
        CurrentOffset=0;
        BytesRemainingInBuffer = pStackLocation->Parameters.QueryDirectory.Length;
        RtlZeroMemory(Buffer,BytesRemainingInBuffer);

        if((!FirstTimeQuery) && !UDFDirIndex(hDirIndex, (uint_di)NextMatch) ) {
            try_return( RC = STATUS_NO_MORE_FILES);
        }

        // One final note though:
        // If we do not find a directory entry OR while searching we reach the
        // end of the directory, then the return code should be set as follows:

        // (a) If any files have been returned (i.e. ReturnSingleEntry was FALSE
        //       and we did find at least one match), then return STATUS_SUCCESS
        // (b) If no entry is being returned then:
        //       (i) If this is the first query i.e. FirstTimeQuery is TRUE
        //            then return STATUS_NO_SUCH_FILE
        //       (ii) Otherwise, return STATUS_NO_MORE_FILES

        while(TRUE) {
            // If the user had requested only a single match and we have
            // returned that, then we stop at this point.
            if(ReturnSingleEntry && AtLeastOneFound) {
                try_return(RC);
            }
            // We call UDFFindNextMatch to look down the next matching dirent.
            RC = UDFFindNextMatch(Vcb, hDirIndex,&NextMatch,PtrSearchPattern, FNM_Flags, cur_hashes, &DirNdx);
            // If we didn't receive next match, then we are at the end of the
            // directory.  If we have returned any files, we exit with
            // success, otherwise we return STATUS_NO_MORE_FILES.
            if(!NT_SUCCESS(RC)) {
                RC = AtLeastOneFound ? STATUS_SUCCESS :
                                      (FirstTimeQuery ? STATUS_NO_SUCH_FILE : STATUS_NO_MORE_FILES);
                try_return(RC);
            }
            // We found at least one matching file entry
            AtLeastOneFound = TRUE;
            if(!NT_SUCCESS(RC = UDFFileDirInfoToNT(Vcb, DirNdx, DirInformation))) {
                // this happends when we can't allocate tmp buffers
                try_return(RC);
            }
            DirInformation->FileIndex = NextMatch;
            FileNameBytes = DirInformation->FileNameLength;

            if ((BaseLength + FileNameBytes) > BytesRemainingInBuffer) {
                // We haven't successfully transfered current data &
                // later NextMatch will be incremented. Thus we should
                // prevent loosing information in such a way:
                if(NextMatch) NextMatch --;
                // If this won't fit and we have returned a previous entry then just
                // return STATUS_SUCCESS. Otherwise
                // use a status code of STATUS_BUFFER_OVERFLOW.
                if(CurrentOffset) {
                    try_return(RC = STATUS_SUCCESS);
                }
                // strange policy...
                ReturnSingleEntry = TRUE;
                FileNameBytes = BaseLength + FileNameBytes - BytesRemainingInBuffer;
                RC = STATUS_BUFFER_OVERFLOW;
            }
            //  Now we have an entry to return to our caller.
            //  We'll case on the type of information requested and fill up
            //  the user buffer if everything fits.
            switch (FileInformationClass) {

            case FileBothDirectoryInformation:
            case FileFullDirectoryInformation:
            case FileDirectoryInformation:
                    
                BothDirInformation = (PFILE_BOTH_DIR_INFORMATION)(Buffer + CurrentOffset);
                RtlCopyMemory(BothDirInformation,DirInformation,BaseLength);
                BothDirInformation->FileIndex = NextMatch;
                BothDirInformation->FileNameLength = FileNameBytes;
                break;

            case FileNamesInformation:

                NamesInfo = (PFILE_NAMES_INFORMATION)(Buffer + CurrentOffset);
                NamesInfo->FileIndex = NextMatch;
                NamesInfo->FileNameLength = FileNameBytes;
                break;

            default:
                break;
            }
            if (FileNameBytes) {
                //  This is a Unicode name, we can copy the bytes directly.
                RtlCopyMemory( (PVOID)(Buffer + CurrentOffset + BaseLength),
                               DirInformation->FileName, FileNameBytes );
            }

            Information = CurrentOffset + BaseLength + FileNameBytes;

            //  ((..._INFORMATION)(PointerToPreviousEntryInBuffer))->NextEntryOffset = CurrentOffset - LastOffset;
            *((PULONG)(Buffer+LastOffset)) = CurrentOffset - LastOffset;
            //  Set up our variables for the next dirent.
            FirstTimeQuery = FALSE;

            LastOffset    = CurrentOffset;
            PrevMatch     = NextMatch;
            NextMatch++;
            CurrentOffset = UDFQuadAlign(Information);
            BytesRemainingInBuffer = BufferLength - CurrentOffset;
        }

try_exit:   NOTHING;


    } _SEH2_FINALLY {

        if (PostRequest) {

            if (AcquiredFCB) {
                UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
                UDFReleaseResource(&(NtReqFcb->MainResource));
            }
            // Map the users buffer and then post the request.
            RC = UDFLockCallersBuffer(PtrIrpContext, Irp, TRUE, BufferLength);
            ASSERT(NT_SUCCESS(RC));

            RC = UDFPostRequest(PtrIrpContext, Irp);

        } else {
#ifdef UDF_DBG
            if(!NT_SUCCESS(RC)) {
               UDFPrint(("    Not found\n"));
            }
#endif // UDF_DBG
            // Remember to update the CurrentByteOffset field in the CCB if required.
            if(Ccb) Ccb->CurrentIndex = PrevMatch;

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

        if(SearchPattern.Buffer) RtlFreeUnicodeString(&SearchPattern);
        if(DirInformation) MyFreePool__(DirInformation);
    } _SEH2_END;

    return(RC);
} // end UDFQueryDirectory()
Esempio n. 6
0
/*************************************************************************
*
* Function: UDFCommonDirControl()
*
* Description:
*   The actual work is performed here. This routine may be invoked in one'
*   of the two possible contexts:
*   (a) in the context of a system worker thread
*   (b) in the context of the original caller
*
* Expected Interrupt Level (for execution) :
*
*  IRQL_PASSIVE_LEVEL
*
* Return Value: STATUS_SUCCESS/Error
*
*************************************************************************/
NTSTATUS
NTAPI
UDFCommonDirControl(
   PtrUDFIrpContext  PtrIrpContext,
   PIRP              Irp
   )
{
    NTSTATUS                RC = STATUS_SUCCESS;
    PIO_STACK_LOCATION      IrpSp = NULL;
    PFILE_OBJECT            FileObject = NULL;
    PtrUDFFCB               Fcb = NULL;
    PtrUDFCCB               Ccb = NULL;
    PVCB                    Vcb = NULL;
    BOOLEAN                 AcquiredVcb = FALSE;

    TmPrint(("UDFCommonDirControl: \n"));
//    BrutePoint();

    _SEH2_TRY {
        // First, get a pointer to the current I/O stack location
        IrpSp = IoGetCurrentIrpStackLocation(Irp);
        ASSERT(IrpSp);
    
        FileObject = IrpSp->FileObject;
        ASSERT(FileObject);
    
        // Get the FCB and CCB pointers
        Ccb = (PtrUDFCCB)(FileObject->FsContext2);
        ASSERT(Ccb);
        Fcb = Ccb->Fcb;
        ASSERT(Fcb);
    
        Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
        ASSERT(Vcb);
        ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
//        Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
    
        UDFFlushTryBreak(Vcb);
        UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
        AcquiredVcb = TRUE;
        // Get some of the parameters supplied to us
        switch (IrpSp->MinorFunction) {
        case IRP_MN_QUERY_DIRECTORY:
            RC = UDFQueryDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb);
            break;
        case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
            RC = UDFNotifyChangeDirectory(PtrIrpContext, Irp, IrpSp, FileObject, Fcb, Ccb);
            break;
        default:
            // This should not happen.
            RC = STATUS_INVALID_DEVICE_REQUEST;
            Irp->IoStatus.Status = RC;
            Irp->IoStatus.Information = 0;
    
            // Free up the Irp Context
            UDFReleaseIrpContext(PtrIrpContext);
    
            // complete the IRP
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            break;
        }

//try_exit: NOTHING;

    } _SEH2_FINALLY {

        if(AcquiredVcb) {
            UDFReleaseResource(&(Vcb->VCBResource));
            AcquiredVcb = FALSE;
        }
    } _SEH2_END;
    return(RC);
} // end UDFCommonDirControl()
Esempio n. 7
0
/*************************************************************************
*
* Function: UDFCommonClose()
*
* 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: must be STATUS_SUCCESS
*
*************************************************************************/
NTSTATUS
UDFCommonClose(
    PtrUDFIrpContext PtrIrpContext,
    PIRP             Irp
    )
{
    NTSTATUS                RC = STATUS_SUCCESS;
    PIO_STACK_LOCATION      IrpSp = NULL;
    PFILE_OBJECT            FileObject = NULL;
    PtrUDFFCB               Fcb = NULL;
    PtrUDFCCB               Ccb = NULL;
    PVCB                    Vcb = NULL;
//    PERESOURCE              PtrResourceAcquired = NULL;
    BOOLEAN                 AcquiredVcb = FALSE;
    BOOLEAN                 AcquiredGD = FALSE;
    PUDF_FILE_INFO          fi;
    ULONG                   i = 0;
//    ULONG                   clean_stat = 0;

//    BOOLEAN                 CompleteIrp = TRUE;
    BOOLEAN                 PostRequest = FALSE;

#ifdef UDF_DBG
    UNICODE_STRING          CurName;
    PDIR_INDEX_HDR          DirNdx;
#endif

    AdPrint(("UDFCommonClose: \n"));

    _SEH2_TRY {
        if (Irp) {

            // If this is the first (IOManager) request
            // First, get a pointer to the current I/O stack location
            IrpSp = IoGetCurrentIrpStackLocation(Irp);
            ASSERT(IrpSp);
    
            FileObject = IrpSp->FileObject;
            ASSERT(FileObject);
    
            // Get the FCB and CCB pointers
            Ccb = (PtrUDFCCB)(FileObject->FsContext2);
            ASSERT(Ccb);
            if(Ccb->CCBFlags & UDF_CCB_READ_ONLY) {
                PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_READ_ONLY;
            }
            Fcb = Ccb->Fcb;
        } else {
            // If this is a queued call (for our dispatch)
            // Get saved Fcb address
            Fcb = PtrIrpContext->Fcb;
            i = PtrIrpContext->TreeLength;
        }

        ASSERT(Fcb);
        Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
        ASSERT(Vcb);
        ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
//        Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;

        // Steps we shall take at this point are:
        // (a) Acquire the VCB shared
        // (b) Acquire the FCB's CCB list exclusively
        // (c) Delete the CCB structure (free memory)
        // (d) If this is the last close, release the FCB structure
        //       (unless we keep these around for "delayed close" functionality.
        // Note that it is often the case that the close dispatch entry point is invoked
        // in the most inconvenient of situations (when it is not possible, for example,
        // to safely acquire certain required resources without deadlocking or waiting).
        // Therefore, be extremely careful in implementing this close dispatch entry point.
        // Also note that we do not have the option of returning a failure code from the
        // close dispatch entry point; the system expects that the close will always succeed.
        
        UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
        AcquiredVcb = TRUE;

        // Is this is the first (IOManager) request ?
        if (Irp) {
            PtrIrpContext->TreeLength =
            i = Ccb->TreeLength;
            // remember the number of incomplete Close requests
            InterlockedIncrement((PLONG)&(Fcb->CcbCount));
            // we can release CCB in any case
            UDFCleanUpCCB(Ccb);
            FileObject->FsContext2 = NULL;
#ifdef DBG
/*        } else {
            ASSERT(Fcb->NTRequiredFCB);
            if(Fcb->NTRequiredFCB) {
                ASSERT(Fcb->NTRequiredFCB->FileObject);
                if(Fcb->NTRequiredFCB->FileObject) {
                    ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2);
                }
            }*/
#endif //DBG
        }

#ifdef UDF_DELAYED_CLOSE
        // check if this is the last Close (no more Handles)
        // and try to Delay it....
        if((Fcb->FCBFlags & UDF_FCB_DELAY_CLOSE) &&
           (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) &&
          !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) &&
          !(Fcb->OpenHandleCount)) {
            UDFReleaseResource(&(Vcb->VCBResource));
            AcquiredVcb = FALSE;
            if((RC = UDFQueueDelayedClose(PtrIrpContext,Fcb)) == STATUS_SUCCESS)
                try_return(RC = STATUS_SUCCESS);
            // do standard Close if we can't Delay this opeartion
            AdPrint(("   Cant queue Close Irp, status=%x\n", RC));
        }
#endif //UDF_DELAYED_CLOSE

        if(Irp) {
            // We should post actual procesing if this is a recursive call
            if((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) ||
               (Fcb->NTRequiredFCB->AcqFlushCount)) {
                AdPrint(("   post NOT_TOP_LEVEL Irp\n"));
                PostRequest = TRUE;
                try_return(RC = STATUS_SUCCESS);
            }
        }

        // Close request is near completion, Vcb is acquired.
        // Now we can safely decrease CcbCount, because no Rename
        // operation can run until Vcb release.
        InterlockedDecrement((PLONG)&(Fcb->CcbCount));

        UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
        if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_READ_ONLY)
            UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCountRO));

        if(!i || (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)) {

            AdPrint(("UDF: Closing volume\n"));
            AdPrint(("UDF: ReferenceCount:  %x\n",Fcb->ReferenceCount));

            if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE) {
                ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
                UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
                ASSERT(Fcb->NTRequiredFCB);
                UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));

                try_return(RC = STATUS_SUCCESS);
            }
    
            UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));

            if(AcquiredVcb) {
                UDFReleaseResource(&(Vcb->VCBResource));
                AcquiredVcb = FALSE;
            } else {
                BrutePoint();
            }
            // Acquire GlobalDataResource
            UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
            AcquiredGD = TRUE;
//            // Acquire Vcb
            UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
            AcquiredVcb = TRUE;

            UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));


            ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB);
            UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
            ASSERT(Fcb->NTRequiredFCB);
            UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));

            //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n"));
            //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);

            AdPrint(("UDF: Closing volume, reset write status\n"));
            RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS, Vcb->TargetDeviceObject,
                NULL, 0, NULL, 0, TRUE, NULL);

            if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) ||
                ((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) {
                // Try to KILL dismounted volume....
                // w2k requires this, NT4 - recomends
                AcquiredVcb = UDFCheckForDismount(PtrIrpContext, Vcb, TRUE);
            }

            try_return(RC = STATUS_SUCCESS);
        }

        fi = Fcb->FileInfo;
#ifdef UDF_DBG
        if(!fi) {
            BrutePoint();
        }

        DirNdx = UDFGetDirIndexByFileInfo(fi);
        if(DirNdx) {
            CurName.Buffer = UDFDirIndex(DirNdx,fi->Index)->FName.Buffer;
            if(CurName.Buffer) {
                AdPrint(("Closing file: %ws %8.8x\n", CurName.Buffer, FileObject));
            } else {
                AdPrint(("Closing file: ??? \n"));
            }
        }
        AdPrint(("UDF: ReferenceCount:  %x\n",Fcb->ReferenceCount));
#endif // UDF_DBG
        // try to clean up as long chain as it is possible
        UDFCleanUpFcbChain(Vcb, fi, i, TRUE);

try_exit: NOTHING;

    } _SEH2_FINALLY {

        if(AcquiredVcb) {
            UDFReleaseResource(&(Vcb->VCBResource));
        }
        if(AcquiredGD) {
            UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
        }

        // Post IRP if required
        if (PostRequest) {

            // Perform the post operation & complete the IRP
            // if this is first call of UDFCommonClose
            // and will return STATUS_SUCCESS back to us
            PtrIrpContext->Irp = NULL;
            PtrIrpContext->Fcb = Fcb;
            UDFPostRequest(PtrIrpContext, NULL);
        }

        if (!_SEH2_AbnormalTermination()) {
            // If this is not async close complete the IRP
            if (Irp) {
/*                if( FileObject ) {
                    if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) {
//                        ASSERT(!FileObject->FsContext2);
                        FileObject->FsContext = NULL;
#ifdef DBG
                    } else {
                        UDFNTRequiredFCB*  NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext));
                        if(NtReqFcb->FileObject == FileObject) {
                            NtReqFcb->FileObject = NULL;
                        }
#endif //DBG
                    }
                }*/
                Irp->IoStatus.Status = STATUS_SUCCESS;
                Irp->IoStatus.Information = 0;
                IoCompleteRequest(Irp, IO_DISK_INCREMENT);
            } 
            // Free up the Irp Context
            if(!PostRequest)
                UDFReleaseIrpContext(PtrIrpContext);
        }

    } _SEH2_END; // end of "__finally" processing

    return STATUS_SUCCESS ;
} // end UDFCommonClose()