NTSTATUS DokanResetPendingIrpTimeout( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; ULONG timeout; // in milisecond DDbgPrint("==> ResetPendingIrpTimeout\n"); eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); timeout = eventInfo->ResetTimeout.Timeout; if (DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX < timeout) { timeout = DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&vcb->Dcb->PendingIrp.ListLock, &oldIrql); // search corresponding IRP through pending IRP list listHead = &vcb->Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { PIRP irp; PIO_STACK_LOCATION irpSp; nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } DokanUpdateTimeout(&irpEntry->TickCount, timeout); break; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); DDbgPrint("<== ResetPendingIrpTimeout\n"); return STATUS_SUCCESS; }
NTSTATUS RegisterPendingIrpMain( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in ULONG SerialNumber, __in PIRP_LIST IrpList, __in ULONG Flags, __in ULONG CheckMount ) { PIRP_ENTRY irpEntry; PIO_STACK_LOCATION irpSp; KIRQL oldIrql; //DDbgPrint("==> DokanRegisterPendingIrpMain\n"); if (GetIdentifierType(DeviceObject->DeviceExtension) == VCB) { PDokanVCB vcb = DeviceObject->DeviceExtension; if (CheckMount && !vcb->Dcb->Mounted) { DDbgPrint(" device is not mounted\n"); return STATUS_INSUFFICIENT_RESOURCES; } } irpSp = IoGetCurrentIrpStackLocation(Irp); // Allocate a record and save all the event context. irpEntry = DokanAllocateIrpEntry(); if (NULL == irpEntry) { DDbgPrint(" can't allocate IRP_ENTRY\n"); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(irpEntry, sizeof(IRP_ENTRY)); InitializeListHead(&irpEntry->ListEntry); irpEntry->SerialNumber = SerialNumber; irpEntry->FileObject = irpSp->FileObject; irpEntry->Irp = Irp; irpEntry->IrpSp = irpSp; irpEntry->IrpList = IrpList; irpEntry->Flags = Flags; DokanUpdateTimeout(&irpEntry->TickCount, DOKAN_IRP_PENDING_TIMEOUT); //DDbgPrint(" Lock IrpList.ListLock\n"); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&IrpList->ListLock, &oldIrql); IoSetCancelRoutine(Irp, DokanIrpCancelRoutine); if (Irp->Cancel) { if (IoSetCancelRoutine(Irp, NULL) != NULL) { //DDbgPrint(" Release IrpList.ListLock %d\n", __LINE__); KeReleaseSpinLock(&IrpList->ListLock, oldIrql); DokanFreeIrpEntry(irpEntry); return STATUS_CANCELLED; } } IoMarkIrpPending(Irp); InsertTailList(&IrpList->ListHead, &irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = FALSE; // save the pointer in order to be accessed by cancel routine Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = irpEntry; KeSetEvent(&IrpList->NotEmpty, IO_NO_INCREMENT, FALSE); //DDbgPrint(" Release IrpList.ListLock\n"); KeReleaseSpinLock(&IrpList->ListLock, oldIrql); //DDbgPrint("<== DokanRegisterPendingIrpMain\n"); return STATUS_PENDING;; }
// start event dispatching NTSTATUS DokanEventStart( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { ULONG outBufferLen; ULONG inBufferLen; PVOID buffer; PIO_STACK_LOCATION irpSp; EVENT_START eventStart; PEVENT_DRIVER_INFO driverInfo; PDOKAN_GLOBAL dokanGlobal; PDokanDCB dcb; NTSTATUS status; DEVICE_TYPE deviceType; ULONG deviceCharacteristics; WCHAR baseGuidString[64]; GUID baseGuid = DOKAN_BASE_GUID; UNICODE_STRING unicodeGuid; ULONG deviceNamePos; DDbgPrint("==> DokanEventStart\n"); dokanGlobal = DeviceObject->DeviceExtension; if (GetIdentifierType(dokanGlobal) != DGL) { return STATUS_INVALID_PARAMETER; } irpSp = IoGetCurrentIrpStackLocation(Irp); outBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; inBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; if (outBufferLen != sizeof(EVENT_DRIVER_INFO) || inBufferLen != sizeof(EVENT_START)) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(&eventStart, Irp->AssociatedIrp.SystemBuffer, sizeof(EVENT_START)); driverInfo = Irp->AssociatedIrp.SystemBuffer; if (eventStart.UserVersion != DOKAN_DRIVER_VERSION) { driverInfo->DriverVersion = DOKAN_DRIVER_VERSION; driverInfo->Status = DOKAN_START_FAILED; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); return STATUS_SUCCESS; } deviceCharacteristics = FILE_DEVICE_IS_MOUNTED; switch (eventStart.DeviceType) { case DOKAN_DISK_FILE_SYSTEM: deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; break; case DOKAN_NETWORK_FILE_SYSTEM: deviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; deviceCharacteristics |= FILE_REMOTE_DEVICE; break; default: DDbgPrint(" Unknown device type: %d\n", eventStart.DeviceType); deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; } if (eventStart.Flags & DOKAN_EVENT_REMOVABLE) { DDbgPrint(" DeviceCharacteristics |= FILE_REMOVABLE_MEDIA\n"); deviceCharacteristics |= FILE_REMOVABLE_MEDIA; } baseGuid.Data2 = (USHORT)(dokanGlobal->MountId & 0xFFFF) ^ baseGuid.Data2; baseGuid.Data3 = (USHORT)(dokanGlobal->MountId >> 16) ^ baseGuid.Data3; status = RtlStringFromGUID(&baseGuid, &unicodeGuid); if (!NT_SUCCESS(status)) { return status; } RtlZeroMemory(baseGuidString, sizeof(baseGuidString)); RtlStringCchCopyW(baseGuidString, sizeof(baseGuidString) / sizeof(WCHAR), unicodeGuid.Buffer); RtlFreeUnicodeString(&unicodeGuid); InterlockedIncrement(&dokanGlobal->MountId); KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&dokanGlobal->Resource, TRUE); status = DokanCreateDiskDevice( DeviceObject->DriverObject, dokanGlobal->MountId, baseGuidString, dokanGlobal, deviceType, deviceCharacteristics, &dcb); if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); return status; } DDbgPrint(" MountId:%d\n", dcb->MountId); driverInfo->DeviceNumber = dokanGlobal->MountId; driverInfo->MountId = dokanGlobal->MountId; driverInfo->Status = DOKAN_MOUNTED; driverInfo->DriverVersion = DOKAN_DRIVER_VERSION; // SymbolicName is \\DosDevices\\Global\\Volume{D6CC17C5-1734-4085-BCE7-964F1E9F5DE9} // Finds the last '\' and copy into DeviceName. // DeviceName is \Volume{D6CC17C5-1734-4085-BCE7-964F1E9F5DE9} deviceNamePos = dcb->SymbolicLinkName->Length / sizeof(WCHAR) - 1; for (; dcb->SymbolicLinkName->Buffer[deviceNamePos] != L'\\'; --deviceNamePos) ; RtlStringCchCopyW(driverInfo->DeviceName, sizeof(driverInfo->DeviceName) / sizeof(WCHAR), &(dcb->SymbolicLinkName->Buffer[deviceNamePos])); DDbgPrint(" DeviceName:%ws\n", driverInfo->DeviceName); DokanUpdateTimeout(&dcb->TickCount, DOKAN_KEEPALIVE_TIMEOUT); dcb->UseAltStream = 0; if (eventStart.Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) { DDbgPrint(" ALT_STREAM_ON\n"); dcb->UseAltStream = 1; } dcb->UseKeepAlive = 0; if (eventStart.Flags & DOKAN_EVENT_KEEP_ALIVE_ON) { DDbgPrint(" KEEP_ALIVE_ON\n"); dcb->UseKeepAlive = 1; } dcb->Mounted = 1; DokanStartEventNotificationThread(dcb); DokanStartCheckThread(dcb); ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); DDbgPrint("<== DokanEventStart\n"); return Irp->IoStatus.Status; }
NTSTATUS DokanDispatchDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles IOCTLs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PDokanDCB dcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_NOT_IMPLEMENTED; ULONG controlCode = 0; ULONG outputLength = 0; // {DCA0E0A5-D2CA-4f0f-8416-A6414657A77A} // GUID dokanGUID = { 0xdca0e0a5, 0xd2ca, 0x4f0f, { 0x84, 0x16, 0xa6, 0x41, // 0x46, 0x57, 0xa7, 0x7a } }; __try { Irp->IoStatus.Information = 0; irpSp = IoGetCurrentIrpStackLocation(Irp); outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; controlCode = irpSp->Parameters.DeviceIoControl.IoControlCode; if (controlCode != IOCTL_EVENT_WAIT && controlCode != IOCTL_EVENT_INFO && controlCode != IOCTL_KEEPALIVE) { DDbgPrint("==> DokanDispatchIoControl\n"); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); } if (DeviceObject->DriverObject == NULL || DeviceObject->ReferenceCount < 0) { status = STATUS_DEVICE_DOES_NOT_EXIST; __leave; } vcb = DeviceObject->DeviceExtension; PrintIdType(vcb); if (GetIdentifierType(vcb) == DGL) { status = GlobalDeviceControl(DeviceObject, Irp); __leave; } else if (GetIdentifierType(vcb) == DCB) { status = DiskDeviceControlWithLock(DeviceObject, Irp); __leave; } else if (GetIdentifierType(vcb) != VCB) { status = STATUS_INVALID_PARAMETER; __leave; } dcb = vcb->Dcb; switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_EVENT_WAIT: DDbgPrint(" IOCTL_EVENT_WAIT\n"); status = DokanRegisterPendingIrpForEvent(DeviceObject, Irp); break; case IOCTL_EVENT_INFO: // DDbgPrint(" IOCTL_EVENT_INFO\n"); status = DokanCompleteIrp(DeviceObject, Irp); break; case IOCTL_EVENT_RELEASE: DDbgPrint(" IOCTL_EVENT_RELEASE\n"); status = DokanEventRelease(DeviceObject, Irp); break; case IOCTL_EVENT_WRITE: DDbgPrint(" IOCTL_EVENT_WRITE\n"); status = DokanEventWrite(DeviceObject, Irp); break; case IOCTL_KEEPALIVE: DDbgPrint(" IOCTL_KEEPALIVE\n"); if (IsFlagOn(vcb->Flags, VCB_MOUNTED)) { ExEnterCriticalRegionAndAcquireResourceExclusive(&dcb->Resource); DokanUpdateTimeout(&dcb->TickCount, DOKAN_KEEPALIVE_TIMEOUT); ExReleaseResourceAndLeaveCriticalRegion(&dcb->Resource); status = STATUS_SUCCESS; } else { DDbgPrint(" device is not mounted\n"); status = STATUS_INSUFFICIENT_RESOURCES; } break; case IOCTL_RESET_TIMEOUT: status = DokanResetPendingIrpTimeout(DeviceObject, Irp); break; case IOCTL_GET_ACCESS_TOKEN: status = DokanGetAccessToken(DeviceObject, Irp); break; default: { ULONG baseCode = DEVICE_TYPE_FROM_CTL_CODE( irpSp->Parameters.DeviceIoControl.IoControlCode); status = STATUS_NOT_IMPLEMENTED; // In case of IOCTL_STORAGE_BASE or IOCTL_DISK_BASE OR // FILE_DEVICE_NETWORK_FILE_SYSTEM or MOUNTDEVCONTROLTYPE ioctl type, pass // to DiskDeviceControl to avoid code duplication // TODO: probably not the best way to pass down Irp... if (baseCode == IOCTL_STORAGE_BASE || baseCode == IOCTL_DISK_BASE || baseCode == FILE_DEVICE_NETWORK_FILE_SYSTEM || baseCode == MOUNTDEVCONTROLTYPE) { status = DiskDeviceControlWithLock(dcb->DeviceObject, Irp); } if (status == STATUS_NOT_IMPLEMENTED) { PrintUnknownDeviceIoctlCode( irpSp->Parameters.DeviceIoControl.IoControlCode); } } break; } // switch IoControlCode } __finally { if (status != STATUS_PENDING) { if (IsDeletePending(DeviceObject)) { DDbgPrint(" DeviceObject is invalid, so prevent BSOD"); status = STATUS_DEVICE_REMOVED; } DokanCompleteIrpRequest(Irp, status, Irp->IoStatus.Information); } if (controlCode != IOCTL_EVENT_WAIT && controlCode != IOCTL_EVENT_INFO && controlCode != IOCTL_KEEPALIVE) { DokanPrintNTStatus(status); DDbgPrint("<== DokanDispatchIoControl\n"); } } return status; }
// start event dispatching NTSTATUS DokanEventStart( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { ULONG outBufferLen; ULONG inBufferLen; PVOID buffer; PIO_STACK_LOCATION irpSp; EVENT_START eventStart; PEVENT_DRIVER_INFO driverInfo; PDOKAN_GLOBAL dokanGlobal; PDokanDCB dcb; NTSTATUS status; DEVICE_TYPE deviceType; ULONG deviceCharacteristics; DDbgPrint("==> DokanEventStart\n"); dokanGlobal = DeviceObject->DeviceExtension; if (GetIdentifierType(dokanGlobal) != DGL) { return STATUS_INVALID_PARAMETER; } irpSp = IoGetCurrentIrpStackLocation(Irp); outBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; inBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; if (outBufferLen != sizeof(EVENT_DRIVER_INFO) || inBufferLen != sizeof(EVENT_START)) { return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory(&eventStart, Irp->AssociatedIrp.SystemBuffer, sizeof(EVENT_START)); driverInfo = Irp->AssociatedIrp.SystemBuffer; if (eventStart.UserVersion != DOKAN_VERSION) { driverInfo->DriverVersion = DOKAN_VERSION; driverInfo->Status = DOKAN_START_FAILED; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); return STATUS_SUCCESS; } deviceCharacteristics = FILE_DEVICE_IS_MOUNTED; switch (eventStart.DeviceType) { case DOKAN_DISK_FILE_SYSTEM: deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; break; case DOKAN_NETWORK_FILE_SYSTEM: deviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM; deviceCharacteristics |= FILE_REMOTE_DEVICE; break; default: DDbgPrint(" Unknown device type: %d\n", eventStart.DeviceType); deviceType = FILE_DEVICE_DISK_FILE_SYSTEM; } if (eventStart.Flags & DOKAN_EVENT_REMOVABLE) { DDbgPrint(" DeviceCharacteristics |= FILE_REMOVABLE_MEDIA\n"); deviceCharacteristics |= FILE_REMOVABLE_MEDIA; } KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&dokanGlobal->Resource, TRUE); status = DokanCreateDiskDevice( DeviceObject->DriverObject, dokanGlobal->MountId, dokanGlobal, deviceType, deviceCharacteristics, &dcb); if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); return status; } DDbgPrint(" MountId:%d\n", dcb->MountId); driverInfo->DeviceNumber = dokanGlobal->MountId; driverInfo->MountId = dokanGlobal->MountId; driverInfo->Status = DOKAN_MOUNTED; driverInfo->DriverVersion = DOKAN_VERSION; dcb->Mounted = eventStart.DriveLetter; DokanUpdateTimeout(&dcb->TickCount, DOKAN_KEEPALIVE_TIMEOUT); dcb->UseAltStream = 0; if (eventStart.Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) { DDbgPrint(" ALT_STREAM_ON\n"); dcb->UseAltStream = 1; } dcb->UseKeepAlive = 0; if (eventStart.Flags & DOKAN_EVENT_KEEP_ALIVE_ON) { DDbgPrint(" KEEP_ALIVE_ON\n"); dcb->UseKeepAlive = 1; } DokanStartEventNotificationThread(dcb); DokanStartCheckThread(dcb); ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); InterlockedIncrement(&dokanGlobal->MountId); DDbgPrint("<== DokanEventStart\n"); return Irp->IoStatus.Status; }