Ejemplo n.º 1
0
/*
    This routine initializes DirIndex array
 */
PDIR_INDEX_HDR
UDFDirIndexAlloc(
    IN uint_di i
    )
{
    uint_di j,k;
    PDIR_INDEX_HDR hDirNdx;
    PDIR_INDEX_ITEM* FrameList;

    if(!i)
        return NULL;
#ifdef UDF_LIMIT_DIR_SIZE
    if(i>UDF_DIR_INDEX_FRAME)
        return NULL;
#endif //UDF_LIMIT_DIR_SIZE

    j = i >> UDF_DIR_INDEX_FRAME_SH;
    i &= (UDF_DIR_INDEX_FRAME-1);

    hDirNdx = (PDIR_INDEX_HDR)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, sizeof(DIR_INDEX_HDR)+(j+(i!=0))*sizeof(PDIR_INDEX_ITEM), MEM_DIR_HDR_TAG);
    if(!hDirNdx) return NULL;
    RtlZeroMemory(hDirNdx, sizeof(DIR_INDEX_HDR));

    FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
    for(k=0; k<j; k++, FrameList++) {
        (*FrameList) = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG);
        if(!(*FrameList)) {
free_hdi:
            // item pointet by FrameList is NULL, it could not be allocated
            while(k) {
                k--;
                FrameList--;
                MyFreePool__(*FrameList);
            }
            MyFreePool__(hDirNdx);
            return NULL;
        }
        RtlZeroMemory((*FrameList), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM));
    }
    if(i) {
        (*FrameList) = (PDIR_INDEX_ITEM)MyAllocatePoolTag__(UDF_DIR_INDEX_MT, AlignDirIndex(i)*sizeof(DIR_INDEX_ITEM), MEM_DIR_NDX_TAG);
        if(!(*FrameList))
            goto free_hdi;
        RtlZeroMemory((*FrameList), i*sizeof(DIR_INDEX_ITEM));
    }

    hDirNdx->FrameCount = j+(i!=0);
    hDirNdx->LastFrameCount = i ? i : UDF_DIR_INDEX_FRAME;

    return hDirNdx;
} // UDFDirIndexAlloc()
Ejemplo n.º 2
0
/*
    This routine releases DirIndex array
 */
void
UDFDirIndexFree(
    PDIR_INDEX_HDR hDirNdx
    )
{
    uint32 k;
    PDIR_INDEX_ITEM* FrameList;

    FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
    if(!hDirNdx) return;
    for(k=0; k<hDirNdx->FrameCount; k++, FrameList++) {
        if(*FrameList) MyFreePool__(*FrameList);
    }
    MyFreePool__(hDirNdx);
} // UDFDirIndexFree();
Ejemplo n.º 3
0
VOID
UDFDoDelayedClose(
    IN PtrUDFIrpContextLite    NextIrpContextLite
    )
{
    PtrUDFIrpContext   IrpContext;

    AdPrint(("  UDFDoDelayedClose\n"));
    UDFInitializeIrpContextFromLite(&IrpContext,NextIrpContextLite);
    IrpContext->Fcb->IrpContextLite = NULL;
    MyFreePool__(NextIrpContextLite);
    IrpContext->Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
    UDFCommonClose(IrpContext,NULL);
} // end UDFDoDelayedClose()
Ejemplo n.º 4
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()
Ejemplo n.º 5
0
/*

Routine Description:
    This routine performs the verify volume operation.  It is responsible for
    either completing of enqueuing the input Irp.

Arguments:
    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/
NTSTATUS
UDFVerifyVolume(
    IN PIRP Irp
    )
{
    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
    PVPB Vpb = IrpSp->Parameters.VerifyVolume.Vpb;
    PVCB Vcb = (PVCB)IrpSp->Parameters.VerifyVolume.DeviceObject->DeviceExtension;
    PVCB NewVcb = NULL;
    IO_STATUS_BLOCK Iosb;
    ULONG MediaChangeCount = 0;
    NTSTATUS RC;
    ULONG Mode;
    BOOLEAN UnsafeIoctl = (Vcb->VCBFlags & UDF_VCB_FLAGS_UNSAFE_IOCTL) ? TRUE : FALSE;

    //  Update the real device in the IrpContext from the Vpb.  There was no available
    //  file object when the IrpContext was created.
    //    IrpContext->RealDevice = Vpb->RealDevice;
    KdPrint(("UDFVerifyVolume:\n"));

    //  Acquire shared global access, the termination handler for the
    //  following try statement will free the access.

    UDFAcquireResourceShared(&(UDFGlobalData.GlobalDataResource),TRUE);
    UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);

    _SEH2_TRY {

        KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
        // Check if the real device still needs to be verified.  If it doesn't
        // then obviously someone beat us here and already did the work
        // so complete the verify irp with success.  Otherwise reenable
        // the real device and get to work.
        if( !(Vpb->RealDevice->Flags & DO_VERIFY_VOLUME) &&
            ((Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_LOCKED) && !UnsafeIoctl) ) {
            KdPrint(("UDFVerifyVolume: STATUS_SUCCESS (1)\n"));
            try_return(RC = STATUS_SUCCESS);
        }
        Vcb->VCBFlags &= ~UDF_VCB_FLAGS_UNSAFE_IOCTL;
        // Verify that there is a disk here.
        RC = UDFPhSendIOCTL( IOCTL_STORAGE_CHECK_VERIFY,
                                 Vcb->TargetDeviceObject,
                                 NULL,0,
                                 &MediaChangeCount,sizeof(ULONG),
                                 TRUE,&Iosb );

        if(!NT_SUCCESS( RC )) {
            // If we will allow a raw mount then return WRONG_VOLUME to
            // allow the volume to be mounted by raw.
            if(FlagOn( IrpSp->Flags, SL_ALLOW_RAW_MOUNT )) {
                KdPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (1)\n"));
                RC = STATUS_WRONG_VOLUME;
            }

            if(UDFIsRawDevice(RC)) {
                KdPrint(("UDFVerifyVolume: STATUS_WRONG_VOLUME (2)\n"));
                RC = STATUS_WRONG_VOLUME;
            }
            try_return( RC );
        }

        if(Iosb.Information != sizeof(ULONG)) {
            // Be safe about the count in case the driver didn't fill it in
            MediaChangeCount = 0;
        }

        KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
        KdPrint(("UDFVerifyVolume: MediaChangeCount=%x, Vcb->MediaChangeCount=%x, UnsafeIoctl=%x\n",
            MediaChangeCount, Vcb->MediaChangeCount, UnsafeIoctl));
        // Verify that the device actually saw a change. If the driver does not
        // support the MCC, then we must verify the volume in any case.
        if(MediaChangeCount == 0 ||
            (Vcb->MediaChangeCount != MediaChangeCount) ||
           UnsafeIoctl ) {

            KdPrint(("UDFVerifyVolume: compare\n"));

            NewVcb = (PVCB)MyAllocatePool__(NonPagedPool,sizeof(VCB));
            if(!NewVcb)
                try_return(RC=STATUS_INSUFFICIENT_RESOURCES);
            RtlZeroMemory(NewVcb,sizeof(VCB));

            NewVcb->TargetDeviceObject = Vcb->TargetDeviceObject;
            NewVcb->Vpb = Vpb;

            // Set the removable media flag based on the real device's
            // characteristics
            if(Vpb->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) {
                UDFSetFlag( NewVcb->VCBFlags, UDF_VCB_FLAGS_REMOVABLE_MEDIA );
            }

            RC = UDFGetDiskInfo(NewVcb->TargetDeviceObject,NewVcb);
            if(!NT_SUCCESS(RC)) try_return(RC);
            // Prevent modification attempts durring Verify
            NewVcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY |
                                UDF_VCB_FLAGS_MEDIA_READ_ONLY;
            // Compare physical parameters (phase 1)
            KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
            RC = UDFCompareVcb(Vcb,NewVcb, TRUE);
            if(!NT_SUCCESS(RC)) try_return(RC);

            if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
                Vcb->MountPhErrorCount > MOUNT_ERR_THRESHOLD ) {
                KdPrint(("UDFVerifyVolume: it was very BAD volume. Do not perform Logical check\n"));
                goto skip_logical_check;
            }
            // Initialize internal cache
            // in *** READ ONLY *** mode
            Mode = WCACHE_MODE_ROM;

            RC = WCacheInit__(&(NewVcb->FastCache),
                              UDFGlobalData.WCacheMaxFrames,
                              UDFGlobalData.WCacheMaxBlocks,
                              NewVcb->WriteBlockSize,
                              5, NewVcb->BlockSizeBits,
                              UDFGlobalData.WCacheBlocksPerFrameSh,
                              0/*NewVcb->FirstLBA*/, NewVcb->LastPossibleLBA, Mode,
                                  /*WCACHE_CACHE_WHOLE_PACKET*/ 0 |
                                  (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) |
                                  WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS, // speed up mount on bad disks
                              UDFGlobalData.WCacheFramesToKeepFree,
                              UDFTWrite, UDFTRead,
#ifdef UDF_ASYNC_IO
                          UDFTWriteAsync, UDFTReadAsync,
#else  //UDF_ASYNC_IO
                          NULL, NULL,
#endif //UDF_ASYNC_IO
                              UDFIsBlockAllocated, UDFUpdateVAT,
                              UDFWCacheErrorHandler);
            if(!NT_SUCCESS(RC)) try_return(RC);

            KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
            RC = UDFGetDiskInfoAndVerify(NewVcb->TargetDeviceObject,NewVcb);
            KdPrint(("  NewVcb->NSRDesc=%x\n", NewVcb->NSRDesc));
            if(!NT_SUCCESS(RC)) {
                if((Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
                   (NewVcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) &&
                   !(NewVcb->NSRDesc & VRS_ISO9660_FOUND)) {
                    KdPrint(("UDFVerifyVolume: both are RAW -> remount\n", Vcb->Modified));
                    RC = STATUS_SUCCESS;
                    goto skip_logical_check;
                }
                if(RC == STATUS_UNRECOGNIZED_VOLUME) {
                    try_return(RC = STATUS_WRONG_VOLUME);
                }
                try_return(RC);
            }

            WCacheChFlags__(&(Vcb->FastCache),
                            WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet
                            WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS);  // let user retry request on Bad Blocks

            NewVcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED;
            // Compare logical parameters (phase 2)
            KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
            RC = UDFCompareVcb(Vcb,NewVcb, FALSE);
            if(!NT_SUCCESS(RC)) try_return(RC);
            // We have unitialized WCache, so it is better to
            // force MOUNT_VOLUME call
            if(!WCacheIsInitialized__(&(Vcb->FastCache)))
                try_return(RC = STATUS_WRONG_VOLUME);

skip_logical_check:;

        }

        KdPrint(("UDFVerifyVolume: compared\n"));
        KdPrint(("UDFVerifyVolume: Modified=%d\n", Vcb->Modified));
        if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_LOCKED)) {
            KdPrint(("UDFVerifyVolume: set UDF_VCB_FLAGS_VOLUME_MOUNTED\n"));
            Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_MOUNTED;
            Vcb->SoftEjectReq = FALSE;
        }
        UDFClearFlag( Vpb->RealDevice->Flags, DO_VERIFY_VOLUME );

try_exit: NOTHING;

    } _SEH2_FINALLY {

        // Update the media change count to note that we have verified the volume
        // at this value
        Vcb->MediaChangeCount = MediaChangeCount;

        // If we got the wrong volume, mark the Vcb as not mounted.
        if(RC == STATUS_WRONG_VOLUME) {
            KdPrint(("UDFVerifyVolume: clear UDF_VCB_FLAGS_VOLUME_MOUNTED\n"));
            Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
            Vcb->WriteSecurity = FALSE;
//            ASSERT(!(Vcb->EjectWaiter));
            if(Vcb->EjectWaiter) {
                UDFReleaseResource(&(Vcb->VCBResource));
                UDFStopEjectWaiter(Vcb);
                UDFAcquireResourceExclusive(&(Vcb->VCBResource),TRUE);
            }
        } else
        if(NT_SUCCESS(RC) &&
           (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)){
            BOOLEAN CacheInitialized = FALSE;
            KdPrint(("    !!! VerifyVolume - QUICK REMOUNT !!!\n"));
            // Initialize internal cache
            CacheInitialized = WCacheIsInitialized__(&(Vcb->FastCache));
            if(!CacheInitialized) {
                Mode = WCACHE_MODE_ROM;
                RC = WCacheInit__(&(Vcb->FastCache),
                                  Vcb->WCacheMaxFrames,
                                  Vcb->WCacheMaxBlocks,
                                  Vcb->WriteBlockSize,
                                  5, Vcb->BlockSizeBits,
                              Vcb->WCacheBlocksPerFrameSh,
                              0/*Vcb->FirstLBA*/, Vcb->LastPossibleLBA, Mode,
                                  /*WCACHE_CACHE_WHOLE_PACKET*/ 0 |
                                  (Vcb->DoNotCompareBeforeWrite ? WCACHE_DO_NOT_COMPARE : 0) |
                                  (Vcb->CacheChainedIo ? WCACHE_CHAINED_IO : 0),
                              Vcb->WCacheFramesToKeepFree,
//                              UDFTWrite, UDFTRead,
                              UDFTWriteVerify, UDFTReadVerify,
#ifdef UDF_ASYNC_IO
                                  UDFTWriteAsync, UDFTReadAsync,
#else  //UDF_ASYNC_IO
                                  NULL, NULL,
#endif //UDF_ASYNC_IO
                                  UDFIsBlockAllocated, UDFUpdateVAT,
                                  UDFWCacheErrorHandler);
            }
            if(NT_SUCCESS(RC)) {
                if(!Vcb->VerifyCtx.VInited) {
                    RC = UDFVInit(Vcb);
                }
            }
            if(NT_SUCCESS(RC)) {

                if(!CacheInitialized) {
                    if(!(Vcb->VCBFlags & UDF_VCB_FLAGS_MEDIA_READ_ONLY)) {
                        if(!Vcb->CDR_Mode) {
                            if((Vcb->TargetDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
                               CdrwMediaClassEx_IsRAM(Vcb->MediaClassEx)) {
                                KdPrint(("UDFMountVolume: RAM mode\n"));
                                Mode = WCACHE_MODE_RAM;
                            } else {
                                KdPrint(("UDFMountVolume: RW mode\n"));
                                Mode = WCACHE_MODE_RW;
                            }
        /*                    if(FsDeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
                            } else {
                                Vcb->WriteSecurity = TRUE;
                            }*/
                        } else {
                            Mode = WCACHE_MODE_R;
                        }
                    }
                    WCacheSetMode__(&(Vcb->FastCache), Mode);

                    WCacheChFlags__(&(Vcb->FastCache),
                                    WCACHE_CACHE_WHOLE_PACKET, // enable cache whole packet
                                    WCACHE_MARK_BAD_BLOCKS | WCACHE_RO_BAD_BLOCKS);  // let user retry request on Bad Blocks
                }
                // we can't record ACL on old format disks
                if(!UDFNtAclSupported(Vcb)) {
                    Vcb->WriteSecurity = FALSE;
                    Vcb->UseExtendedFE = FALSE;
                }
                KdPrint(("UDFVerifyVolume: try start EjectWaiter\n"));
                RC = UDFStartEjectWaiter(Vcb);
                if(!NT_SUCCESS(RC)) {
                    KdPrint(("UDFVerifyVolume: start EjectWaiter failed\n"));
                    Vcb->VCBFlags &= ~UDF_VCB_FLAGS_VOLUME_MOUNTED;
                    Vcb->WriteSecurity = FALSE;
                }
            }
        }

        if(NewVcb) {
            // Release internal cache
            KdPrint(("UDFVerifyVolume: delete NewVcb\n"));
            WCacheFlushAll__(&(NewVcb->FastCache),NewVcb);
            WCacheRelease__(&(NewVcb->FastCache));

            ASSERT(!(NewVcb->EjectWaiter));
            // Waiter thread should be already stopped
            // if MediaChangeCount have changed
            ASSERT(!(Vcb->EjectWaiter));

            UDFCleanupVCB(NewVcb);
            MyFreePool__(NewVcb);
        }
        UDFReleaseResource(&(Vcb->VCBResource));
        UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
    } _SEH2_END;

    // Complete the request if no exception.
    Irp->IoStatus.Information = 0;

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

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

    return RC;
} // end UDFVerifyVolume ()
Ejemplo n.º 6
0
/*
    Thisd routine truncates DirIndex array
 */
OSSTATUS
UDFDirIndexTrunc(
    IN PDIR_INDEX_HDR* _hDirNdx,
    IN uint_di d // decrement
    )
{
    uint_di j,k;

    if(d > UDF_DIR_INDEX_FRAME) {
        OSSTATUS status;
        while(d) {
            k = (d > UDF_DIR_INDEX_FRAME) ? UDF_DIR_INDEX_FRAME : d;
            if(!OS_SUCCESS(status = UDFDirIndexTrunc(_hDirNdx, k))) {
                return status;
            }
            d -= k;
        }
        return STATUS_SUCCESS;
    }

    PDIR_INDEX_HDR hDirNdx = *_hDirNdx;
    PDIR_INDEX_ITEM* FrameList;

    j = UDF_DIR_INDEX_FRAME+hDirNdx->LastFrameCount-d;
    FrameList = (PDIR_INDEX_ITEM*)(hDirNdx+1);
    k = hDirNdx->FrameCount-1;

    if(j <= UDF_DIR_INDEX_FRAME) {
        // free last frame
        if(!k && (j < 2)) {
            // someone tries to trunc. residual entries...
            return STATUS_INVALID_PARAMETER;
        }
        MyFreePool__(FrameList[k]);
        FrameList[k] = NULL;
        hDirNdx->LastFrameCount = UDF_DIR_INDEX_FRAME;
        hDirNdx->FrameCount--;
        // Truncate new last frame
        if(!MyReallocPool__((int8*)(FrameList[k-1]), UDF_DIR_INDEX_FRAME*sizeof(DIR_INDEX_ITEM),
                       (int8**)(&(FrameList[k-1])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) )
            return STATUS_INSUFFICIENT_RESOURCES;
        hDirNdx->LastFrameCount = j;
        // Truncate header
        if(!MyReallocPool__((int8*)hDirNdx, sizeof(DIR_INDEX_HDR) + (k+1)*sizeof(PDIR_INDEX_ITEM),
                       (int8**)(&hDirNdx), sizeof(DIR_INDEX_HDR) + k*sizeof(PDIR_INDEX_ITEM) ) )
            return STATUS_INSUFFICIENT_RESOURCES;

        (*_hDirNdx) = hDirNdx;

    } else {

        j -= UDF_DIR_INDEX_FRAME;
        if(!k && (j < 2)) {
            // someone tries to trunc. residual entries...
            return STATUS_INVALID_PARAMETER;
        }
        
        if(!MyReallocPool__((int8*)(FrameList[k]), AlignDirIndex(hDirNdx->LastFrameCount)*sizeof(DIR_INDEX_ITEM),
                       (int8**)(&(FrameList[k])), AlignDirIndex(j)*sizeof(DIR_INDEX_ITEM) ) )
            return STATUS_INSUFFICIENT_RESOURCES;
        hDirNdx->LastFrameCount = j;
    }
    return STATUS_SUCCESS;
} // end UDFDirIndexTrunc()
Ejemplo n.º 7
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()
Ejemplo n.º 8
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 {
Ejemplo n.º 9
0
NTSTATUS
UDFBuildTreeItemsList(
    IN PVCB               Vcb,
    IN PUDF_FILE_INFO     FileInfo,
    IN PCHECK_TREE_ITEM   CheckItemProc,
    IN PUDF_FILE_INFO**   PassedList,
    IN PULONG             PassedListSize,
    IN PUDF_FILE_INFO**   FoundList,
    IN PULONG             FoundListSize
    )
{
    PDIR_INDEX_HDR     hDirNdx;
    PUDF_FILE_INFO     SDirInfo;
    ULONG              i;

    KdPrint(("    UDFBuildTreeItemsList():\n"));
    if(!(*PassedList) || !(*FoundList)) {

        (*PassedList) = (PUDF_FILE_INFO*)
            MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
        if(!(*PassedList))
            return STATUS_INSUFFICIENT_RESOURCES;
        (*PassedListSize) = 0;

        (*FoundList) = (PUDF_FILE_INFO*)
            MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
        if(!(*FoundList)) {
            MyFreePool__(*PassedList);
            *PassedList = NULL;
            return STATUS_INSUFFICIENT_RESOURCES;
        }
        (*FoundListSize) = 0;
    }

    // check if already passed
    for(i=0;i<(*PassedListSize);i++) {
        if( ((*PassedList)[i]) == FileInfo )
            return STATUS_SUCCESS;
    }
    // remember passed object
    // we should not proceed linked objects twice
    (*PassedListSize)++;
    if( !((*PassedListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
        if(!MyReallocPool__((PCHAR)(*PassedList), (*PassedListSize)*sizeof(PUDF_FILE_INFO),
                         (PCHAR*)PassedList, ((*PassedListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_FILE_INFO))) {
            return STATUS_INSUFFICIENT_RESOURCES;
        }
    }
    (*PassedList)[(*PassedListSize)-1] = FileInfo;

    // check if this object matches our conditions
    if(CheckItemProc(FileInfo)) {
        // remember matched object
        (*FoundListSize)++;
        if( !((*FoundListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
            if(!MyReallocPool__((PCHAR)(*FoundList), (*FoundListSize)*sizeof(PUDF_DATALOC_INFO),
                             (PCHAR*)FoundList, ((*FoundListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_DATALOC_INFO))) {
                return STATUS_INSUFFICIENT_RESOURCES;
            }
        }
        (*FoundList)[(*FoundListSize)-1] = FileInfo;
    }

    // walk through SDir (if any)
    if((SDirInfo = FileInfo->Dloc->SDirInfo))
        UDFBuildTreeItemsList(Vcb, SDirInfo, CheckItemProc,
                 PassedList, PassedListSize, FoundList, FoundListSize);

    // walk through subsequent objects (if any)
    if((hDirNdx = FileInfo->Dloc->DirIndex)) {

        // scan DirIndex
        UDF_DIR_SCAN_CONTEXT ScanContext;
        PDIR_INDEX_ITEM DirNdx;
        PUDF_FILE_INFO CurFileInfo;

        if(UDFDirIndexInitScan(FileInfo, &ScanContext, 2)) {
            while((DirNdx = UDFDirIndexScan(&ScanContext, &CurFileInfo))) {
                if(!CurFileInfo)
                    continue;
                UDFBuildTreeItemsList(Vcb, CurFileInfo, CheckItemProc,
                         PassedList, PassedListSize, FoundList, FoundListSize);
            }
        }

    }
    return STATUS_SUCCESS;
} // end UDFBuildTreeItemsList()
Ejemplo n.º 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()