Exemple #1
0
/*
    This routine removes request from Delayed Close queue.
    It operates until reach lower threshold
 */
VOID
UDFDelayedClose(
    PVOID unused
    )
{
    PLIST_ENTRY             Entry;
    PtrUDFIrpContextLite    NextIrpContextLite;

    AdPrint(("  UDFDelayedClose\n"));
    // Acquire DelayedCloseResource
    UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);

    while (UDFGlobalData.ReduceDelayedClose &&
          (UDFGlobalData.DelayedCloseCount > UDFGlobalData.MinDelayedCloseCount)) {

        Entry = UDFGlobalData.DelayedCloseQueue.Flink;

        if (!IsListEmpty(Entry)) {
            //  Extract the IrpContext.
            NextIrpContextLite = CONTAINING_RECORD( Entry,
                                                    UDFIrpContextLite,
                                                    DelayedCloseLinks );

            RemoveEntryList( Entry );
            UDFGlobalData.DelayedCloseCount--;
            UDFDoDelayedClose(NextIrpContextLite);
        } else {
            BrutePoint();
        }
    }

    while (UDFGlobalData.ReduceDirDelayedClose &&
          (UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MinDirDelayedCloseCount)) {

        Entry = UDFGlobalData.DirDelayedCloseQueue.Flink;

        if (!IsListEmpty(Entry)) {
            //  Extract the IrpContext.
            NextIrpContextLite = CONTAINING_RECORD( Entry,
                                                    UDFIrpContextLite,
                                                    DelayedCloseLinks );

            RemoveEntryList( Entry );
            UDFGlobalData.DirDelayedCloseCount--;
            UDFDoDelayedClose(NextIrpContextLite);
        } else {
            BrutePoint();
        }
    }

    UDFGlobalData.FspCloseActive = FALSE;
    UDFGlobalData.ReduceDelayedClose = FALSE;
    UDFGlobalData.ReduceDirDelayedClose = FALSE;

    // Release DelayedCloseResource
    UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));

    return;
} // end UDFDelayedClose()
Exemple #2
0
PTHREAD_STRUCT DLDAllocFindThread(ULONG ThreadId) {
    ULONG i = 0;
    PTHREAD_STRUCT Temp = DLDThreadTable;
    ULONG FirstEmpty = -1;

    while (i<MaxThreadCount) {
        if (Temp->ThreadId == ThreadId) {
            return Temp;
        } else if (FirstEmpty == -1 && !Temp->ThreadId) {
            FirstEmpty = i;
        }
        Temp++;
        i++;
    }
    // Not found. Allocate new one.
    if (i == MaxThreadCount) {
        if (FirstEmpty == -1) {
            UDFPrint(("Not enough table entries. Try to increase MaxThrdCount on next build"));
            BrutePoint();
        }
        i = FirstEmpty;
    }
    Temp = DLDThreadTable + i;

    RtlZeroMemory(Temp, sizeof(THREAD_STRUCT));
    Temp->ThreadId = ThreadId;

    return Temp;
}
Exemple #3
0
VOID DLDpWaitForResource(
    IN PERESOURCE Resource, 
    IN DISPATCHER_HEADER *DispatcherObject,
    IN PTHREAD_STRUCT ThrdStruct
    ) {
    KIRQL oldIrql;
    ULONG ResourceWaitCount = 0;

    Resource->ContentionCount++;

    while (KeWaitForSingleObject(DispatcherObject,Executive,KernelMode,FALSE,&DLDpTimeout) == STATUS_TIMEOUT) {
        KeAcquireSpinLock(&Resource->SpinLock, &oldIrql);
        if (++ResourceWaitCount>DLDpResourceTimeoutCount) {
            // May be deadlock?
            ResourceWaitCount = 0;

            if (DLDProcessResource(Resource, ThrdStruct,DLD_MAX_REC_LEVEL)) {
                UDFPrint((" which thread %x has tried to acquire at (BugCheckId:%x:Line:%d)\n",
                ThrdStruct->ThreadId,
                ThrdStruct->BugCheckId,
                ThrdStruct->Line      
                ));
                BrutePoint();
            }
        } 
        // Priority boosts
        // .....
        // End of priority boosts
        KeReleaseSpinLock(&Resource->SpinLock, oldIrql);
    }

}        
Exemple #4
0
/// Initialize deadlock detector
VOID DLDInit(ULONG MaxThrdCount /// Maximum supported number of threads
) {
    if (KeNumberProcessors>1) {
        UDFPrint(("Deadlock Detector is designed for uniprocessor machines only!\n"));
        BrutePoint();
    }
    DLDpTimeout.QuadPart = -40000000I64;

    MaxThreadCount = MaxThrdCount;
    DLDThreadTable = (PTHREAD_STRUCT) DLDAllocatePool(MaxThreadCount*sizeof(THREAD_STRUCT));
    RtlZeroMemory(DLDThreadTable, sizeof(THREAD_STRUCT)*MaxThreadCount);
}
Exemple #5
0
/// TRUE Indicates deadlock
BOOLEAN DLDProcessResource( PERESOURCE Resource,        // resource to process
                            PTHREAD_STRUCT ThrdStruct,  // thread structure of caller's thread
                            ULONG RecLevel)             // current recurse level
{
    if (RecLevel <= 0) {
        BrutePoint();
        return FALSE;
    }


    // If resource is free, just return. Not possible, but we must check.
    if (!Resource->ActiveCount) {
        return FALSE;
    }

    PTHREAD_STRUCT ThreadOwner;


    if (Resource->Flag & ResourceOwnedExclusive || (Resource->OwnerThreads[1].OwnerCount == 1)) {

        // If only one owner

        // Find thread owning this resource 
        if (Resource->Flag & ResourceOwnedExclusive) {
            ThreadOwner = DLDFindThread(Resource->OwnerThreads[0].OwnerThread);
        } else {
            ThreadOwner = DLDFindThread(Resource->OwnerThreads[1].OwnerThread);
        }

        BOOLEAN Result = FALSE;
        if (ThreadOwner) { 
            Result = DLDProcessThread(ThreadOwner, ThrdStruct, Resource,RecLevel-1);
        }
        return Result;
    } else {
        // Many owners
        int i;
        for (i=0; i<Resource->OwnerThreads[0].TableSize; i++) {
            if (Resource->OwnerTable[i].OwnerThread) {

                ThreadOwner = DLDFindThread(Resource->OwnerTable[i].OwnerThread);
                if (ThreadOwner && DLDProcessThread(ThreadOwner, ThrdStruct, Resource,RecLevel-1)) {

                    return TRUE;
                }
            }
        }
    }

    return FALSE;
}
Exemple #6
0
/// TRUE Indicates deadlock
BOOLEAN DLDProcessThread(PTHREAD_STRUCT ThrdOwner,
                      PTHREAD_STRUCT ThrdStruct,
                      PERESOURCE Resource,
                      ULONG RecLevel) {

    if (ThrdOwner == ThrdStruct) {
        // ERESOURCE wait cycle. Deadlock detected.
        UDFPrint(("DLD: *********DEADLOCK DETECTED*********\n"));
        UDFPrint(("Thread %x holding resource %x\n",ThrdOwner->ThreadId,Resource));
        return TRUE;
    }

    for (int i=RecLevel+1;i<DLD_MAX_REC_LEVEL;i++) {
        if (DLDThreadAcquireChain[i].Thread->ThreadId == ThrdOwner->ThreadId) {
            // ERESOURCE wait cycle. Deadlock detected.
            UDFPrint(("DLD: *********DEADLOCK DETECTED*********\n"));
            UDFPrint(("Thread %x holding resource %x\n",ThrdOwner->ThreadId,Resource));
            for (int j=RecLevel+1;j<=i;j++) {
                UDFPrint((" awaited by thread %x at (BugCheckId:%x:Line:%d) holding resource %x\n",
                DLDThreadAcquireChain[i].Thread->ThreadId,
                DLDThreadAcquireChain[i].Thread->BugCheckId, 
                DLDThreadAcquireChain[i].Thread->Line,
                Resource));
            }
            BrutePoint();
            return FALSE;
        }
    }
    DLDThreadAcquireChain[RecLevel].Thread          = ThrdOwner;
    DLDThreadAcquireChain[RecLevel].HoldingResource = Resource;

    // Find resource, awaited by thread
    if (ThrdOwner->WaitingResource) {
        if (DLDProcessResource(ThrdOwner->WaitingResource, ThrdStruct,RecLevel)) {
            UDFPrint((" awaited by thread %x at (BugCheckId:%x:Line:%d) holding resource %x\n",
            ThrdOwner->ThreadId, 
            ThrdOwner->BugCheckId, 
            ThrdOwner->Line, 
            Resource));
            return TRUE;
        }
    }

    return FALSE;
}
Exemple #7
0
/*
    This routine walks through the tree to RootDir &
    calls UDFCloseFile__() for each file instance
    imho, Useful feature
 */
NTSTATUS
UDFCloseFileInfoChain(
    IN PVCB Vcb,
    IN PUDF_FILE_INFO fi,
    IN ULONG TreeLength,
    IN BOOLEAN VcbAcquired
    )
{
    PUDF_FILE_INFO ParentFI;
    PtrUDFFCB Fcb;
    PtrUDFFCB ParentFcb = NULL;
    NTSTATUS RC = STATUS_SUCCESS;
    NTSTATUS RC2;

    // we can't process Tree until we can acquire Vcb
    if(!VcbAcquired)
        UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);

    AdPrint(("UDFCloseFileInfoChain\n"));
    for(; TreeLength && fi; TreeLength--) {

        // close parent chain (if any)
        // if we started path parsing not from RootDir on Create,
        // we would never get RootDir here
        ValidateFileInfo(fi);

        // acquire parent
        if((ParentFI = fi->ParentFile)) {
            ParentFcb = fi->Fcb->ParentFcb;
            ASSERT(ParentFcb);
            ASSERT(ParentFcb->NTRequiredFCB);
            UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
            UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE);
            ASSERT(ParentFcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
            ASSERT(ParentFcb->NTRequiredFCB->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);
        } else {
            AdPrint(("Acquiring VCB...\n"));
            UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
            AdPrint(("Done\n"));
        }
        // acquire current file/dir
        // we must assure that no more threads try to reuse this object
        if((Fcb = fi->Fcb)) {
            UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
            UDFAcquireResourceExclusive(&(Fcb->NTRequiredFCB->MainResource),TRUE);
            ASSERT_REF(Fcb->ReferenceCount >= fi->RefCount);
            if(!(Fcb->FCBFlags & UDF_FCB_DELETED) &&
                (Fcb->FCBFlags & UDF_FCB_VALID))
                UDFWriteSecurity(Vcb, Fcb, &(Fcb->NTRequiredFCB->SecurityDesc));
            RC2 = UDFCloseFile__(Vcb,fi);
            if(!NT_SUCCESS(RC2))
                RC = RC2;
            ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
            UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
            UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
        } else {
            BrutePoint();
            RC2 = UDFCloseFile__(Vcb,fi);
            if(!NT_SUCCESS(RC2))
                RC = RC2;
        }

        if(ParentFI) {
            UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
            UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
        } else {
            UDFReleaseResource(&(Vcb->VCBResource));
        }
        fi = ParentFI;
    }

    if(!VcbAcquired)
        UDFReleaseResource(&(Vcb->VCBResource));

    return RC;

} // end UDFCloseFileInfoChain()
Exemple #8
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()
Exemple #9
0
NTSTATUS
UDFCloseAllXXXDelayedInDir(
    IN PVCB             Vcb,
    IN PUDF_FILE_INFO   FileInfo,
    IN BOOLEAN          System
    )
{
    PUDF_FILE_INFO*    PassedList = NULL;
    ULONG              PassedListSize = 0;
    PUDF_FILE_INFO*    FoundList = NULL;
    ULONG              FoundListSize = 0;
    NTSTATUS           RC;
    ULONG              i;
    BOOLEAN            ResAcq = FALSE;
    BOOLEAN            AcquiredVcb = FALSE;
    UDFNTRequiredFCB*  NtReqFcb;
    PUDF_FILE_INFO     CurFileInfo;
    PFE_LIST_ENTRY     CurListPtr;
    PFE_LIST_ENTRY*    ListPtrArray = NULL;

    _SEH2_TRY {

        KdPrint(("    UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
        // Acquire DelayedCloseResource
        UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
        ResAcq = TRUE;

        UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
        AcquiredVcb = TRUE;

        RC = UDFBuildTreeItemsList(Vcb, FileInfo,
                System ? UDFIsLastClose : UDFIsInDelayedCloseQueue,
                &PassedList, &PassedListSize, &FoundList, &FoundListSize);

        if(!NT_SUCCESS(RC)) {
            KdPrint(("    UDFBuildTreeItemsList(): error %x\n", RC));
            try_return(RC);
        }

        if(!FoundList || !FoundListSize) {
            try_return(RC = STATUS_SUCCESS);
        }

        // build array of referenced pointers
        ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY)));
        if(!ListPtrArray) {
            KdPrint(("    Can't alloc ListPtrArray for %x items\n", FoundListSize));
            try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
        }

        for(i=0;i<FoundListSize;i++) {

            _SEH2_TRY {
                
                CurFileInfo = FoundList[i];
                if(!CurFileInfo->ListPtr) {
                    CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY)));
                    if(!CurFileInfo->ListPtr) {
                        KdPrint(("    Can't alloc ListPtrEntry for items %x\n", i));
                        try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
                    }
                    CurFileInfo->ListPtr->FileInfo = CurFileInfo;
                    CurFileInfo->ListPtr->EntryRefCount = 0;
                }
                CurFileInfo->ListPtr->EntryRefCount++;
                ListPtrArray[i] = CurFileInfo->ListPtr;

            } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
                BrutePoint();
            } _SEH2_END;
        }

        UDFReleaseResource(&(Vcb->VCBResource));
        AcquiredVcb = FALSE;

        if(System) {
            // Remove from system queue
            PtrUDFFCB Fcb;
            IO_STATUS_BLOCK IoStatus;
            BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ?
                                     TRUE : FALSE;

            Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
            for(i=FoundListSize;i>0;i--) {
                UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
                AcquiredVcb = TRUE;
                _SEH2_TRY {

                    CurListPtr = ListPtrArray[i-1];
                    CurFileInfo = CurListPtr->FileInfo;
                    if(CurFileInfo &&
                       (Fcb = CurFileInfo->Fcb)) {
                        NtReqFcb = Fcb->NTRequiredFCB;
                        ASSERT((ULONG)NtReqFcb > 0x1000);
//                            ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000);
                        if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) &&
                            (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) {
                            MmPrint(("    CcFlushCache()\n"));
                            CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus);
                        }
                        if(NtReqFcb->SectionObject.ImageSectionObject) {
                            MmPrint(("    MmFlushImageSection()\n"));
                            MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite);
                        }
                        if(NtReqFcb->SectionObject.DataSectionObject) {
                            MmPrint(("    CcPurgeCacheSection()\n"));
                            CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
                        }
                    } else {
                        MmPrint(("    Skip item: deleted\n"));
                    }
                    CurListPtr->EntryRefCount--;
                    if(!CurListPtr->EntryRefCount) {
                        if(CurListPtr->FileInfo)
                            CurListPtr->FileInfo->ListPtr = NULL;
                        MyFreePool__(CurListPtr);
                    }
                } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
                    BrutePoint();
                } _SEH2_END;
                UDFReleaseResource(&(Vcb->VCBResource));
                AcquiredVcb = FALSE;
            }
            if(!NoDelayed)
                Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
        } else {
            // Remove from internal queue
            PtrUDFIrpContextLite NextIrpContextLite;

            for(i=FoundListSize;i>0;i--) {

                UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
                AcquiredVcb = TRUE;

                CurListPtr = ListPtrArray[i-1];
                CurFileInfo = CurListPtr->FileInfo;

                if(CurFileInfo &&
                   CurFileInfo->Fcb &&
                    (NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) {
                    RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
                    if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
//                            BrutePoint();
                        UDFGlobalData.DirDelayedCloseCount--;
                    } else {
                        UDFGlobalData.DelayedCloseCount--;
                    }
                    UDFDoDelayedClose(NextIrpContextLite);
                }
                CurListPtr->EntryRefCount--;
                if(!CurListPtr->EntryRefCount) {
                    if(CurListPtr->FileInfo)
                        CurListPtr->FileInfo->ListPtr = NULL;
                    MyFreePool__(CurListPtr);
                }
                UDFReleaseResource(&(Vcb->VCBResource));
                AcquiredVcb = FALSE;
            }
        }
        RC = STATUS_SUCCESS;

try_exit: NOTHING;

    } _SEH2_FINALLY {
Exemple #10
0
/*
    This routine walks through the tree to RootDir & kills all unreferenced
    structures....
    imho, Useful feature
 */
ULONG
UDFCleanUpFcbChain(
    IN PVCB Vcb,
    IN PUDF_FILE_INFO fi,
    IN ULONG TreeLength,
    IN BOOLEAN VcbAcquired
    )
{
    PtrUDFFCB      Fcb = NULL;
    PtrUDFFCB      ParentFcb = NULL;
    PUDF_FILE_INFO ParentFI;
    UDFNTRequiredFCB* NtReqFcb;
    ULONG CleanCode;
    LONG RefCount, ComRefCount;
    BOOLEAN Delete = FALSE;
    ULONG          ret_val = 0;

    ValidateFileInfo(fi);
    AdPrint(("UDFCleanUpFcbChain\n"));

    ASSERT(TreeLength);

    // we can't process Tree until we can acquire Vcb
    if(!VcbAcquired)
        UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);

    // cleanup parent chain (if any & unused)
    while(fi) {

        // acquire parent
        if((ParentFI = fi->ParentFile)) {
            ASSERT(fi->Fcb);
            ParentFcb = fi->Fcb->ParentFcb;
            ASSERT(ParentFcb);
            ASSERT(ParentFcb->NTRequiredFCB);
            UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
            UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE);
        } else {
            // we get to RootDir, it has no parent
            if(!VcbAcquired)
                UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE);
        }
        Fcb = fi->Fcb;
        ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);

        NtReqFcb = Fcb->NTRequiredFCB;
        ASSERT(NtReqFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB);

        // acquire current file/dir
        // we must assure that no more threads try to re-use this object
#ifdef UDF_DBG
        _SEH2_TRY {
#endif // UDF_DBG
            UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
            UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE);
#ifdef UDF_DBG
        } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
            BrutePoint();
            if(ParentFI) {
                UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
                UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
            } else {
                if(!VcbAcquired)
                    UDFReleaseResource(&(Vcb->VCBResource));
            }
            break;
        } _SEH2_END;
#endif // UDF_DBG
        ASSERT_REF((Fcb->ReferenceCount > fi->RefCount) || !TreeLength);
        // If we haven't pass through all files opened
        // in UDFCommonCreate before target file (TreeLength specfies
        // the number of such files) dereference them.
        // Otherwise we'll just check if the file has no references.
#ifdef UDF_DBG
        if(Fcb) {
            if(TreeLength) {
                ASSERT(Fcb->ReferenceCount);
                ASSERT(NtReqFcb->CommonRefCount);
                RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
                ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
            }
        } else {
            BrutePoint();
        }
        if(TreeLength)
            TreeLength--;
        ASSERT(Fcb->OpenHandleCount <= Fcb->ReferenceCount);
#else
        if(TreeLength) {
            RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
            ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
            TreeLength--;
        }
#endif

/*        if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) {
            AdPrint(("    %ws (%x)\n",
                       Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount));
        } else if (Fcb) {
            AdPrint(("    ??? (%x)\n",Fcb->ReferenceCount));
        } else {
            AdPrint(("    ??? (??)\n"));
        }*/
        // ...and delete if it has gone

        if(!RefCount && !Fcb->OpenHandleCount) {
            // no more references... current file/dir MUST DIE!!!
            BOOLEAN AutoInherited = UDFIsAStreamDir(fi) || UDFIsAStream(fi);

            if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
                // do nothing
            } else
#ifndef UDF_READ_ONLY_BUILD
            if(Delete) {
/*                if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
                    // set file size to zero (for UdfInfo package)
                    // we should not do this for directories
                    UDFResizeFile__(Vcb, fi, 0);
                }*/
                UDFReferenceFile__(fi);
                ASSERT(Fcb->ReferenceCount < fi->RefCount);
                UDFFlushFile__(Vcb, fi);
                UDFUnlinkFile__(Vcb, fi, TRUE);
                UDFCloseFile__(Vcb, fi);
                ASSERT(Fcb->ReferenceCount == fi->RefCount);
                Fcb->FCBFlags |= UDF_FCB_DELETED;
                Delete = FALSE;
            } else
#endif //UDF_READ_ONLY_BUILD
            if(!(Fcb->FCBFlags & UDF_FCB_DELETED)) {
                UDFFlushFile__(Vcb, fi);
            } else {
//                BrutePoint();
            }
#ifndef UDF_READ_ONLY_BUILD
            // check if we should try to delete Parent for the next time
            if(Fcb->FCBFlags & UDF_FCB_DELETE_PARENT)
                Delete = TRUE;
#endif //UDF_READ_ONLY_BUILD

            // remove references to OS-specific structures
            // to let UDF_INFO release FI & Co
            fi->Fcb = NULL;
            if(!ComRefCount) {
                // CommonFcb is also completly dereferenced
                // Kill it!
                fi->Dloc->CommonFcb = NULL;
            }

            if((CleanCode = UDFCleanUpFile__(Vcb, fi))) {
                // Check, if we can uninitialize & deallocate CommonFcb part
                // kill some cross links
                Fcb->FileInfo = NULL;
                // release allocated resources
                if(CleanCode & UDF_FREE_DLOC) {
                    // Obviously, it is a good time & place to release
                    // CommonFcb structure

//                    NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID;
                    // Unitialize byte-range locks support structure
                    FsRtlUninitializeFileLock(&(NtReqFcb->FileLock));
                    // Remove resources
                    UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
                    UDFReleaseResource(&(NtReqFcb->MainResource));
                    if(NtReqFcb->CommonFCBHeader.Resource) {
                        UDFDeleteResource(&(NtReqFcb->MainResource));
                        UDFDeleteResource(&(NtReqFcb->PagingIoResource));
                    }
                    NtReqFcb->CommonFCBHeader.Resource =
                    NtReqFcb->CommonFCBHeader.PagingIoResource = NULL;
                    UDFDeassignAcl(NtReqFcb, AutoInherited);
                    KdPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb));
#ifdef DBG
//                    NtReqFcb->FileObject->FsContext2 = NULL;
//                    ASSERT(NtReqFcb->FileObject);
/*                    if(NtReqFcb->FileObject) {
                        ASSERT(!NtReqFcb->FileObject->FsContext2);
                        NtReqFcb->FileObject->FsContext = NULL;
                        NtReqFcb->FileObject->SectionObjectPointer = NULL;
                    }*/
#endif //DBG
                    MyFreePool__(NtReqFcb);
                    ret_val |= UDF_CLOSE_NTREQFCB_DELETED;
                } else {
                    // we usually get here when the file has some opened links
                    UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
                    UDFReleaseResource(&(NtReqFcb->MainResource));
                }
                // remove some references & free Fcb structure
                Fcb->NTRequiredFCB = NULL;
                Fcb->ParentFcb = NULL;
                UDFCleanUpFCB(Fcb);
                MyFreePool__(fi);
                ret_val |= UDF_CLOSE_FCB_DELETED;
                // get pointer to parent FCB
                fi = ParentFI;
                // free old parent's resource...
                if(fi) {
                    UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
                    UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
                } else {
                    if(!VcbAcquired)
                        UDFReleaseResource(&(Vcb->VCBResource));
                }
            } else {
                // Stop cleaning up

                // Restore pointers
                fi->Fcb = Fcb;
                fi->Dloc->CommonFcb = NtReqFcb;
                // free all acquired resources
                UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
                UDFReleaseResource(&(NtReqFcb->MainResource));
                fi = ParentFI;
                if(fi) {
                    UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
                    UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
                } else {
                    if(!VcbAcquired)
                        UDFReleaseResource(&(Vcb->VCBResource));
                }
                // If we have dereferenced all parents 'associated'
                // with input file & current file is still in use
                // then it isn't worth walking down the tree
                // 'cause in this case all the rest files are also used
                if(!TreeLength)
                    break;
//                AdPrint(("Stop on referenced File/Dir\n"));
            }
        } else {
            // we get to referenced file/dir. Stop search & release resource
            UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
            UDFReleaseResource(&(NtReqFcb->MainResource));
            if(ParentFI) {
                UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB);
                UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource));
            } else {
                if(!VcbAcquired)
                    UDFReleaseResource(&(Vcb->VCBResource));
            }
            Delete = FALSE;
            if(!TreeLength)
                break;
            fi = ParentFI;
        }
    }
    if(fi) {
        Fcb = fi->Fcb;
        for(;TreeLength && fi;TreeLength--) {
            if(Fcb) {
                ParentFcb = Fcb->ParentFcb;
                ASSERT(Fcb->ReferenceCount);
                ASSERT(Fcb->NTRequiredFCB->CommonRefCount);
                ASSERT_REF(Fcb->ReferenceCount > fi->RefCount);
                UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
                UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount));
#ifdef UDF_DBG
            } else {
                BrutePoint();
#endif
            }
            Fcb = ParentFcb;
        }
    }
    if(!VcbAcquired)
        UDFReleaseResource(&(Vcb->VCBResource));
    return ret_val;

} // end UDFCleanUpFcbChain()
Exemple #11
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()