⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vdiskmp.c

📁 SCSI 的虚拟磁盘驱动 需要 windows DDK 很易懂的 DDK 文件结构
💻 C
📖 第 1 页 / 共 5 页
字号:
	Status = ZwQueryValueKey(DiskKeyHandle, &Str, KeyValuePartialInformation,
                                u.valueKeyPartialInf, BufferSize, &Length);
	if (NT_SUCCESS(Status) && (u.valueKeyPartialInf->Type == REG_DWORD))
		// Retrieve the value (in megabytes)
		*DiskSize = *(ULONG*)&(u.valueKeyPartialInf->Data);
	else
		// Use the default
		*DiskSize = 10;
    // Convert megabytes to sectors
	*DiskSize *= 2048;   // 2048 == (1024*1024/512)
    KdPrint(("VdiskReadRegistryParameters: Filename is %ls. \r\n  Size is %u sectors\r\n",    
                SzFileName, *DiskSize));
    // Query the read only value
    RtlInitUnicodeString(&Str, L"ReadOnly");
	Status = ZwQueryValueKey(DiskKeyHandle, &Str, KeyValuePartialInformation,
                                u.valueKeyPartialInf, BufferSize, &Length);
	if (NT_SUCCESS(Status) && (u.valueKeyPartialInf->Type == REG_DWORD))
		// Retrieve the value (in megabytes)
		*ReadOnly = *(ULONG*)&(u.valueKeyPartialInf->Data) ? TRUE : FALSE;
	else
		// Use the default
		*ReadOnly = FALSE;
    // Free buffer
    ExFreePool(u.buffer);
    // Close handle - it's not needed
    ZwClose(DiskKeyHandle);
    // Success
    return STATUS_SUCCESS;
} // end VdiskReadRegistryParameters()

///////////////////////////////////////////////////////////////////////////////
// Remove the Lun's path from Registry
//
static NTSTATUS VdiskRemoveLunFromRegistry(UCHAR TargetId, UCHAR LunId)
{
    OBJECT_ATTRIBUTES ObjectAttributes;
    NTSTATUS Status = STATUS_SUCCESS;
	UNICODE_STRING Str;
    HANDLE KeyHandle;
    PVOID Buffer;
    // Allocate buffer
    Buffer = ExAllocatePoolWithTag(PagedPool, (wcslen(szVdiskLunPath)+1)*sizeof(WCHAR), 'Den3');
    // Check status
    if (Buffer == NULL)
    {
        KdPrint(("VdiskRemoveLunFromRegistry: Can't allocate buffer!\r\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    // Format Registry path
    swprintf(Buffer, szVdiskLunPath, TargetId, LunId);
    // Open the key
    RtlInitUnicodeString(&Str, Buffer);
    InitializeObjectAttributes(&ObjectAttributes, &Str, OBJ_CASE_INSENSITIVE, NULL, NULL);
    Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
    if (!NT_SUCCESS(Status))
    {
        // Disk key is not exist
        KdPrint(("VdiskRemoveLunFromRegistry: Can't open disk key %ls! 0x%X\r\n", Buffer, Status));
        return Status;
    }
    // Delete the key
    Status = ZwDeleteKey(KeyHandle);
    if (!NT_SUCCESS(Status))
        KdPrint(("VdiskRemoveLunFromRegistry: Can't delete disk key %ls! 0x%X\r\n", Buffer, Status));
    else
        KdPrint(("VdiskRemoveLunFromRegistry: %ls\r\n", Buffer));
    ZwClose(KeyHandle);
    ExFreePool(Buffer);
	return Status;
}

///////////////////////////////////////////////////////////////////////////////
// Reads the file-disk parameters from the registry
// and start thread to process requests
//
static NTSTATUS VdiskInquiryLun(
    PVDISK_DEVICE_EXTENSION DeviceExtension, UCHAR TargetId, UCHAR LunId)
{
	NTSTATUS Status;
	KIRQL Irql;
	PVDISK_LUN_EXTENSION Lun = NULL;
    KEVENT Event;
	HANDLE ThreadHandle;
	VDISK_LUN_REQUEST Request;
    BOOLEAN ReadOnly = FALSE;
    KdPrint(("VdiskReadRegistryParameters enter...\r\r\n"));
    ASSERT(DeviceExtension);
    // LUN_EXTENSION allocated by VSPORT
    Lun = (PVDISK_LUN_EXTENSION)VsPortGetLogicalUnit(DeviceExtension, 0, TargetId, LunId);
    if (Lun == NULL)
    {
        // The device have disappeared
		KdPrint(("VdiskInquiryLun: the device has disappeared from under us\r\r\n"));
        return STATUS_INSUFFICIENT_RESOURCES;
	}
    // If it isn't first inquiry - do not need next processing
    if ((Lun->DeviceExtension == DeviceExtension) && (Lun->Sign == VDISK_LUN_SIGN))
    {
        // We must check Lun existence in the Registry
        // and remove it if it is not found
        WCHAR SzFileName[256];
        ULONG DiskSize;
        // If the worker thread isn't working then start it!
        if(Lun->Flags & VDISK_LUN_SHUTDOWN)
        {
            // Lun shutdowned
            KdPrint(("VdiskInquiryLun: LUN %X was shut down. Restart it.\r\n", Lun));
            // Check for thread
            ASSERT(Lun->Flags & VDISK_LUN_THREAD_FINISHED);
            // Un-shutdown Lun and restart system thread;
            Lun->Flags &= ~VDISK_LUN_SHUTDOWN;
            // Parameters in the Registry may have been changed - read
            // them again and start thread
            goto LunInitialization;
        }
        // Read data from the Registry for the LUN
        Status = VdiskReadRegistryParameters(TargetId, LunId, SzFileName, &DiskSize, &ReadOnly);
        if (!NT_SUCCESS(Status))
        {
            // Error read Registry. LUN will be destroyed.
            KdPrint(("VdiskInquiryLun: LUN %X will be destroyed\r\n", Lun));
            VdiskRemoveLunFromRegistry(TargetId, LunId);
            return Status;
        }
        // Compare the current values with the values in the LUN
        // and remove the device if the values are not equal
        if (
             // Compare the file names
             ( (wcslen(SzFileName) !=0) && wcscmp(Lun->SzFileName, SzFileName) ) ||
             // Compare the ReadOnly values (shutdown LUN if they are different)
             ( (BOOLEAN)(Lun->Flags & VDISK_LUN_READ_ONLY) ^ (BOOLEAN)ReadOnly )
            )
        {
            // Values are not equal. LUN will be destroyed.
            KdPrint(("VdiskInquiryLun: Registry was changed. Something goes wrong. LUN %X will be destroyed\r\n", Lun));
            return STATUS_UNSUCCESSFUL;
        }
        KdPrint(("VdiskInquiryLun: LUN %X checked in Registry Ok.\r\n", Lun));
        // Ok. Driver is quite satisfied with LUN state.
        return STATUS_SUCCESS;
    }
    //
	// From this point we create LUN
	//
#if DBG        
    KdPrint(("VdiskInquiryLun: Begin inquiries. Lun %X DeviceExtension 0x%X\r\n",
                Lun, DeviceExtension));
    if (((PVDISK_DEVICE_EXTENSION)DeviceExtension)->Luns[VdiskLun2Index(TargetId, LunId)] != NULL)
    {
        KdPrint(("VdiskInquiryLun: *** Strange! Lun (%d,%d) marked as created.\r\n",
                        TargetId, LunId));
    }
#endif
LunInitialization:
    // Zero LUN's structure
    RtlZeroMemory(Lun, sizeof (VDISK_LUN_EXTENSION));
    // Save signature to check 
    Lun->Sign = VDISK_LUN_SIGN;
    // Set this flag now. We must know thread state.
    Lun->Flags = VDISK_LUN_THREAD_FINISHED;
    // Save TargetId
    Lun->TargetId = TargetId;
    // Save LUN
    Lun->LunId = LunId;
    // Read data from the Registry for the LUN
    Status = VdiskReadRegistryParameters(TargetId, LunId, (PWSTR)Lun->SzFileName,
                                                                &Lun->DiskSize, &ReadOnly);
    if (!NT_SUCCESS(Status))
        // Error read Registry. LUN will not be created.
        return Status;
    // Set flag if needed
    if (ReadOnly)
        Lun->Flags |= VDISK_LUN_READ_ONLY;
    // Initialize the local event
	KeInitializeEvent(&Event, NotificationEvent, FALSE);
	// Initialize the queue
	InitializeListHead(&Lun->RequestQueue);
    // Initialize the lock
	KeInitializeSpinLock(&Lun->RequestQueueLock);
	// Lock acces to this LUN
    KeInitializeSpinLock(&Lun->SpinLock);
    // Initialize the event
	KeInitializeEvent(&Lun->RequestQueueEvent, NotificationEvent, FALSE);
    // Initialize the shutdown event
   	KeInitializeEvent(&Lun->ShutdownEvent, NotificationEvent, FALSE);
    // Save pointer to the DeviceExtension (thread must know it to complete request)
    Lun->DeviceExtension = DeviceExtension;
    // Start the system thread to execute requests
	Status = PsCreateSystemThread(&ThreadHandle, (ACCESS_MASK)0L, NULL, NULL, NULL,
                                    VdiskRequestThread, (PVOID)Lun);
    // Check status
	if (!NT_SUCCESS(Status))
    {
	    KdPrint(("VdiskInquiryLun: Can't create thread!\r\n"));
        goto NotCreated;
    }
    // Save the thread's object pointer to wait for shutdown
    // Don't need to save thread handle
	Status = ObReferenceObjectByHandle(ThreadHandle, (ACCESS_MASK)0, NULL, KernelMode, &Lun->ThreadObject, NULL);
	ZwClose(ThreadHandle);
    // Check status
	if (!NT_SUCCESS(Status))
    {
		KdPrint(("VdiskInquiryLun: Error in the ObReferenceObjectByHandle!\r\n"));
        // Signal the completion
        KeSetEvent((PKEVENT)(&Lun->ShutdownEvent), IO_NO_INCREMENT, FALSE);
        goto NotCreated;
	}
    // Submit the initialization request
    Request.RequestCode = VDISK_REQUEST_INIT;
	Request.ParamInitEvent = (ULONG)(&Event);
	(NTSTATUS)(Request.ParamInitStatus) = STATUS_SUCCESS;
    VdiskRequestSubmit(&Request, Lun);
    // Wait for completion of initializaton
	KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
	Status = Request.ParamInitStatus;
	if (!NT_SUCCESS(Status))
    {
		KdPrint(("VdiskInquiryLun: Initialization of file is failed 0x%X\r\n", Status));
		// Initialization failed
		// Wait for the thread to terminate
		KeWaitForSingleObject(Lun->ThreadObject, Executive, KernelMode, FALSE, NULL);
		ObDereferenceObject(Lun->ThreadObject);
NotCreated:
        // Mark it as not created
        Lun->DeviceExtension = NULL;
        return Status;
	}
    KdPrint(("VdiskInquiryLun: Lun (%u,%u) created\r\n", TargetId, LunId));
    // Clear this flag now. It means thread is working.
    Lun->Flags &= ~VDISK_LUN_THREAD_FINISHED;
    // Save pointer to the array. We will check it in the VdiskMpDestroyLun()
    DeviceExtension->Luns[VdiskLun2Index(TargetId, LunId)] = Lun;
    return STATUS_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////
// Process all SCSI disk operations
//
static VOID VdiskMpStartIo(PVOID DeviceExtension, PSCSI_REQUEST_BLOCK Srb)
{
	PVDISK_LUN_EXTENSION Lun = NULL;
    PVDISK_LUN_REQUEST Request;
    ULONG Start;
    ULONG MaxSector;
    USHORT BlockCount;
    UCHAR TargetId;
    UCHAR LunId;
    ASSERT(DeviceExtension);
    ASSERT(Srb);
    // Return selection timeout for is not existed devices
    Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
    TargetId = Srb->TargetId;
    LunId = Srb->Lun;
    if ((Srb->TargetId == INITIATOR_ID) || (Srb->PathId >= NUMBER_OF_BUSES))
    {
        // return selection timeout for is not existed devices
        KdPrint(("VdiskMpStartIo     : TargetId is wrong\r\n"));
        goto Failed;
    }
    // Extract the LUN extension - it is guaranteed to exist
	// Check if Lun is NULL - can be so if just removed by the DAD removal callback
	//	called by the protocol
    Lun = (PVDISK_LUN_EXTENSION)VsPortGetLogicalUnit(DeviceExtension, Srb->PathId, Srb->TargetId, Srb->Lun);
	if (Lun == NULL)
    {
		// The device have disappeared
		KdPrint(("VdiskMpStartIo     : the device have disappeared from under us\r\n"));
        goto Failed;
	}
    switch (Srb->Function) 
	{
#ifdef VSPORT_PNP
    case SRB_FUNCTION_VSPORT_WMI:
        // Process as a WMI SRB
        VdiskMpWmiStartIo(DeviceExtension, (PSCSI_WMI_REQUEST_BLOCK)Srb);
        return;
#endif
	case SRB_FUNCTION_SHUTDOWN:
    {
        IF_SCSI(KdPrint(("VdiskMpStartIo     : SRB_FUNCTION_SHUTDOWN Lun 0x%X\r\n", Lun));)
        // Process shutdown
        VdiskShutdownLun(Lun, FALSE);
        // Clear pointer 
        ((PVDISK_DEVICE_EXTENSION)DeviceExtension)->Luns[ 
            VdiskLun2Index(Lun->TargetId, Lun->LunId) ] = NULL;
        // Return SUCCESS
        Srb->SrbStatus = SRB_STATUS_SUCCESS;
        break;
    }
    case SRB_FUNCTION_RESET_BUS:
        IF_SCSI(KdPrint(("VdiskMpStartIo     : SRB_FUNCTION_RESET_BUS\r\n"));)
        // Reset bus.
        VdiskMpResetBus(DeviceExtension, 0);
        // Return success.
		Srb->SrbStatus = SRB_STATUS_SUCCESS;
		break;
	case SRB_FUNCTION_EXECUTE_SCSI:
        switch (Srb->Cdb[0])  
        {
        case SCSIOP_VERIFY:
            IF_SCSI(KdPrint(("VdiskMpStartIo     : SCSIOP_VERIFY\r\n"));)
        case SCSIOP_TEST_UNIT_READY:
            IF_SCSI(KdPrint(("VdiskMpStartIo     : SCSIOP_TEST_UNIT_READY\r\n"));)
            // Check Lun flags
            if ( Lun->Flags & VDISK_LUN_SHUTDOWN)
            {
                IF_SCSI(KdPrint(("VdiskMpStartIo     : Lun 0x%X shutdown.\r\n", Lun));)
                // Return sense data
                VdiskFillSenseData(&Lun->SenseData, Srb, SCSI_ADSENSE_NO_MEDIA_IN_DEVICE);
                break;
            }
            else
                // Return success.
    		    Srb->SrbStatus = SRB_STATUS_SUCCESS;
    		break;
        case SCSIOP_READ_CAPACITY:
        {
            // Device size in sectors
            ULONG Size = Lun->DiskSize>0?Lun->DiskSize-1:0;
            IF_SCSI(KdPrint(("VdiskMpStartIo     : SCSIOP_READ_CAPACITY Disk size is 0x%X\r\n", Size));)
            // Convert to big-endian
            // 0x00020000 is 0x00000200 (512) big-endian
            ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x00020000;
            ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = VdiskChangeBytes(Size);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -