NTSTATUS DokanCreateDiskDevice(__in PDRIVER_OBJECT DriverObject, __in ULONG MountId, __in PWCHAR MountPoint, __in PWCHAR UNCName, __in PWCHAR BaseGuid, __in PDOKAN_GLOBAL DokanGlobal, __in DEVICE_TYPE DeviceType, __in ULONG DeviceCharacteristics, __in BOOLEAN UseMountManager, __out PDokanDCB *Dcb) { WCHAR diskDeviceNameBuf[MAXIMUM_FILENAME_LENGTH]; WCHAR symbolicLinkNameBuf[MAXIMUM_FILENAME_LENGTH]; WCHAR mountPointBuf[MAXIMUM_FILENAME_LENGTH]; PDEVICE_OBJECT diskDeviceObject; PDEVICE_OBJECT volDeviceObject; PDokanDCB dcb; PDokanVCB vcb; UNICODE_STRING diskDeviceName; NTSTATUS status; BOOLEAN isNetworkFileSystem = (DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM); DOKAN_CONTROL dokanControl; // make DeviceName and SymboliLink if (isNetworkFileSystem) { #ifdef DOKAN_NET_PROVIDER RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_SYMBOLIC_LINK_NAME); #else RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_SYMBOLIC_LINK_NAME); RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); #endif } else { RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_DISK_DEVICE_NAME); RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_SYMBOLIC_LINK_NAME); RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); } RtlInitUnicodeString(&diskDeviceName, diskDeviceNameBuf); // // Create DeviceObject for the Disk Device // if (!isNetworkFileSystem) { status = IoCreateDeviceSecure(DriverObject, // DriverObject sizeof(DokanDCB), // DeviceExtensionSize &diskDeviceName, // DeviceName FILE_DEVICE_DISK, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &sddl, // Default SDDL String NULL, // Device Class GUID &diskDeviceObject); // DeviceObject } else { status = IoCreateDevice(DriverObject, // DriverObject sizeof(DokanDCB), // DeviceExtensionSize NULL, // DeviceName FILE_DEVICE_UNKNOWN, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &diskDeviceObject); // DeviceObject } if (!NT_SUCCESS(status)) { DDbgPrint(" %s failed: 0x%x\n", isNetworkFileSystem ? "IoCreateDevice(FILE_DEVICE_UNKNOWN)" : "IoCreateDeviceSecure(FILE_DEVICE_DISK)", status); return status; } // // Initialize the device extension. // dcb = diskDeviceObject->DeviceExtension; *Dcb = dcb; dcb->DeviceObject = diskDeviceObject; dcb->Global = DokanGlobal; dcb->Identifier.Type = DCB; dcb->Identifier.Size = sizeof(DokanDCB); dcb->MountId = MountId; dcb->DeviceType = FILE_DEVICE_DISK; dcb->DeviceCharacteristics = DeviceCharacteristics; KeInitializeEvent(&dcb->KillEvent, NotificationEvent, FALSE); // // Establish user-buffer access method. // diskDeviceObject->Flags |= DO_DIRECT_IO; // initialize Event and Event queue DokanInitIrpList(&dcb->PendingIrp); DokanInitIrpList(&dcb->PendingEvent); DokanInitIrpList(&dcb->NotifyEvent); KeInitializeEvent(&dcb->ReleaseEvent, NotificationEvent, FALSE); // "0" means not mounted dcb->Mounted = 0; ExInitializeResourceLite(&dcb->Resource); dcb->CacheManagerNoOpCallbacks.AcquireForLazyWrite = &DokanNoOpAcquire; dcb->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &DokanNoOpRelease; dcb->CacheManagerNoOpCallbacks.AcquireForReadAhead = &DokanNoOpAcquire; dcb->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &DokanNoOpRelease; dcb->UseMountManager = UseMountManager; if (wcscmp(MountPoint, L"") != 0) { RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, L"\\DosDevices\\"); if (wcslen(MountPoint) < 4) { mountPointBuf[12] = towupper(MountPoint[0]); mountPointBuf[13] = L':'; mountPointBuf[14] = L'\0'; if (isNetworkFileSystem) { dcb->UseMountManager = FALSE; } } else { dcb->UseMountManager = FALSE; RtlStringCchCatW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, MountPoint); } } else { RtlStringCchCopyW(mountPointBuf, MAXIMUM_FILENAME_LENGTH, L""); } dcb->DiskDeviceName = DokanAllocateUnicodeString(diskDeviceNameBuf); dcb->SymbolicLinkName = DokanAllocateUnicodeString(symbolicLinkNameBuf); dcb->MountPoint = DokanAllocateUnicodeString(mountPointBuf); if (UNCName != NULL) { dcb->UNCName = DokanAllocateUnicodeString(UNCName); } if (dcb->DiskDeviceName == NULL || dcb->SymbolicLinkName == NULL || dcb->MountPoint == NULL || (dcb->UNCName == NULL && UNCName != NULL)) { DDbgPrint(" Failed to allocate memory for device naming"); FreeDcbNames(dcb); ExDeleteResourceLite(&dcb->Resource); IoDeleteDevice(diskDeviceObject); return STATUS_INSUFFICIENT_RESOURCES; } DDbgPrint("DiskDeviceName: %wZ - SymbolicLinkName: %wZ - MountPoint: %wZ\n", dcb->DiskDeviceName, dcb->SymbolicLinkName, dcb->MountPoint); DDbgPrint(" IoCreateDevice DeviceType: %d\n", DeviceType); // Directly create volume device and init vcb here because it has strong // dependency with fs/disk // Otherwise we would have done this work when mounting the volume if (!isNetworkFileSystem) { status = IoCreateDevice(DriverObject, // DriverObject sizeof(DokanVCB), // DeviceExtensionSize NULL, // DeviceName DeviceType, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &volDeviceObject); // DeviceObject } else { status = IoCreateDeviceSecure(DriverObject, // DriverObject sizeof(DokanVCB), // DeviceExtensionSize &diskDeviceName, // DeviceName DeviceType, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &sddl, // Default SDDL String NULL, // Device Class GUID &volDeviceObject); // DeviceObject } if (!NT_SUCCESS(status)) { DDbgPrint(" IoCreateDevice failed: 0x%x\n", status); ExDeleteResourceLite(&dcb->Resource); IoDeleteDevice(diskDeviceObject); FreeDcbNames(dcb); return status; } vcb = volDeviceObject->DeviceExtension; vcb->Identifier.Type = VCB; vcb->Identifier.Size = sizeof(DokanVCB); vcb->DeviceObject = volDeviceObject; vcb->Dcb = dcb; dcb->Vcb = vcb; InitializeListHead(&vcb->NextFCB); InitializeListHead(&vcb->DirNotifyList); FsRtlNotifyInitializeSync(&vcb->NotifySync); ExInitializeFastMutex(&vcb->AdvancedFCBHeaderMutex); #if _WIN32_WINNT >= 0x0501 FsRtlSetupAdvancedHeader(&vcb->VolumeFileHeader, &vcb->AdvancedFCBHeaderMutex); #else if (DokanFsRtlTeardownPerStreamContexts) { FsRtlSetupAdvancedHeader(&vcb->VolumeFileHeader, &vcb->AdvancedFCBHeaderMutex); } #endif // // Create a symbolic link for userapp to interact with the driver. // status = IoCreateSymbolicLink(dcb->SymbolicLinkName, dcb->DiskDeviceName); if (!NT_SUCCESS(status)) { ExDeleteResourceLite(&dcb->Resource); IoDeleteDevice(diskDeviceObject); FreeDcbNames(dcb); DDbgPrint(" IoCreateSymbolicLink returned 0x%x\n", status); return status; } DDbgPrint("SymbolicLink: %wZ -> %wZ created\n", dcb->SymbolicLinkName, dcb->DiskDeviceName); // // Establish user-buffer access method. // volDeviceObject->Flags |= DO_DIRECT_IO; DokanInitVpb(diskDeviceObject->Vpb, diskDeviceObject, volDeviceObject); // Mark devices as initialized diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; volDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; ObReferenceObject(volDeviceObject); ObReferenceObject(diskDeviceObject); // DokanRegisterMountedDeviceInterface(diskDeviceObject, dcb); // Save to the global mounted list RtlZeroMemory(&dokanControl, sizeof(dokanControl)); RtlStringCchCopyW(dokanControl.DeviceName, sizeof(dokanControl.DeviceName) / sizeof(WCHAR), diskDeviceNameBuf); RtlStringCchCopyW(dokanControl.MountPoint, sizeof(dokanControl.MountPoint) / sizeof(WCHAR), mountPointBuf); dokanControl.Type = DeviceType; dokanControl.DeviceObject = volDeviceObject; InsertMountEntry(DokanGlobal, &dokanControl); dcb->Mounted = 1; if (dcb->UseMountManager) { status = DokanSendVolumeArrivalNotification(dcb->DiskDeviceName); if (!NT_SUCCESS(status)) { DDbgPrint(" DokanSendVolumeArrivalNotification failed: 0x%x\n", status); if (diskDeviceObject->Vpb) { diskDeviceObject->Vpb->DeviceObject = NULL; diskDeviceObject->Vpb->RealDevice = NULL; diskDeviceObject->Vpb->Flags = 0; } ExDeleteResourceLite(&dcb->Resource); IoDeleteDevice(diskDeviceObject); FreeDcbNames(dcb); return status; } } DokanCreateMountPoint(dcb); if (isNetworkFileSystem) { // Run FsRtlRegisterUncProvider in System thread. HANDLE handle; PKTHREAD thread; OBJECT_ATTRIBUTES objectAttribs; InitializeObjectAttributes(&objectAttribs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread( &handle, THREAD_ALL_ACCESS, &objectAttribs, NULL, NULL, (PKSTART_ROUTINE)DokanRegisterUncProvider, dcb); if (!NT_SUCCESS(status)) { DDbgPrint("PsCreateSystemThread failed: 0x%X\n", status); } else { ObReferenceObjectByHandle(handle, THREAD_ALL_ACCESS, NULL, KernelMode, &thread, NULL); ZwClose(handle); KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(thread); } } // DokanRegisterDeviceInterface(DriverObject, diskDeviceObject, dcb); return STATUS_SUCCESS; }
static VOID DokanControl(PDOKAN_CONTROL Control) { PMOUNT_ENTRY mountEntry; Control->Status = DOKAN_CONTROL_FAIL; switch (Control->Type) { case DOKAN_CONTROL_MOUNT: DbgPrintW(L"DokanControl Mount\n"); if (DokanControlMount(Control->MountPoint, Control->DeviceName)) { Control->Status = DOKAN_CONTROL_SUCCESS; InsertMountEntry(Control); } else { Control->Status = DOKAN_CONTROL_FAIL; } break; case DOKAN_CONTROL_UNMOUNT: DbgPrintW(L"DokanControl Unmount\n"); mountEntry = FindMountEntry(Control); if (mountEntry == NULL) { if (!wcslen(Control->MountPoint)) FindMountPoint(Control); DbgPrintW(L"DokanControl MountEntry not found. Try unmount '%s' force: %d\n", Control->MountPoint, Control->Option); if (Control->Option == DOKAN_CONTROL_OPTION_FORCE_UNMOUNT && DokanControlUnmount(Control->MountPoint)) { Control->Status = DOKAN_CONTROL_SUCCESS; break; } Control->Status = DOKAN_CONTROL_FAIL; break; } if (DokanControlUnmount(mountEntry->MountControl.MountPoint)) { Control->Status = DOKAN_CONTROL_SUCCESS; if (Control->DeviceName[0] == L'\0') { wcscpy_s(Control->DeviceName, sizeof(Control->DeviceName) / sizeof(WCHAR), mountEntry->MountControl.DeviceName); } RemoveMountEntry(mountEntry); } else { mountEntry->MountControl.Status = DOKAN_CONTROL_FAIL; Control->Status = DOKAN_CONTROL_FAIL; } break; case DOKAN_CONTROL_CHECK: { DbgPrint("DokanControl Check\n"); Control->Status = 0; } break; case DOKAN_CONTROL_FIND: { DbgPrintW(L"DokanControl Find\n"); DokanControlFind(Control); } break; case DOKAN_CONTROL_LIST: { DbgPrintW(L"DokanControl List\n"); DokanControlList(Control); } break; default: DbgPrintW(L"DokanControl UnknownType %u\n", Control->Type); } return; }
static VOID DokanControl(PDOKAN_CONTROL Control) { PMOUNT_ENTRY mountEntry; ULONG index = 0; DWORD written = 0; Control->Status = DOKAN_CONTROL_FAIL; switch (Control->Type) { case DOKAN_CONTROL_MOUNT: DbgPrintW(L"DokanControl Mount\n"); // if (DokanControlMount(Control->MountPoint, Control->DeviceName)) { Control->Status = DOKAN_CONTROL_SUCCESS; InsertMountEntry(Control); DbgPrintW(L"DriveLetter: %c, DeviceName %s\n", Control->MountPoint[0], Control->DeviceName); // } else { // Control->Status = DOKAN_CONTROL_FAIL; // } break; case DOKAN_CONTROL_UNMOUNT: DbgPrintW(L"DokanControl Unmount\n"); mountEntry = FindMountEntry(Control); if (mountEntry == NULL) { if (Control->Option == DOKAN_CONTROL_OPTION_FORCE_UNMOUNT ) { Control->Status = DOKAN_CONTROL_SUCCESS; break; } Control->Status = DOKAN_CONTROL_FAIL; break; } // if (DokanControlUnmount(mountEntry->MountControl.MountPoint)) { Control->Status = DOKAN_CONTROL_SUCCESS; if (wcslen(Control->DeviceName) == 0) { wcscpy_s(Control->DeviceName, sizeof(Control->DeviceName) / sizeof(WCHAR), mountEntry->MountControl.DeviceName); } RemoveMountEntry(mountEntry); // } else { // mountEntry->MountControl.Status = DOKAN_CONTROL_FAIL; // Control->Status = DOKAN_CONTROL_FAIL; // } break; case DOKAN_CONTROL_CHECK: { DbgPrint("DokanControl Check\n"); Control->Status = 0; } break; case DOKAN_CONTROL_FIND: { DbgPrintW(L"DokanControl Find\n"); DokanControlFind(Control); } break; case DOKAN_CONTROL_LIST: { DbgPrintW(L"DokanControl List\n"); DokanControlList(Control); } break; default: DbgPrintW(L"DokanControl UnknownType %u\n", Control->Type); } return; }