// 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; }
NTSTATUS DokanDispatchFlush( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PVOID buffer; NTSTATUS status = STATUS_INVALID_PARAMETER; PDokanFCB fcb; PDokanCCB ccb; PDokanVCB vcb; PEVENT_CONTEXT eventContext; ULONG eventLength; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanFlush\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy file name to be flushed eventContext->Flush.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Flush.FileName, fcb->FileName.Buffer, fcb->FileName.Length); CcUninitializeCacheMap(fileObject, NULL, NULL); //fileObject->Flags &= FO_CLEANUP_COMPLETE; // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { // if status is not pending, must complete current IRPs if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } else { DDbgPrint(" STATUS_PENDING\n"); } DDbgPrint("<== DokanFlush\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanDispatchQueryInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; ULONG info = 0; ULONG eventLength; PEVENT_CONTEXT eventContext; BOOLEAN isNormalized = FALSE; // PAGED_CODE(); __try { DDbgPrint("==> DokanQueryInformation\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" FileInfoClass %d\n", irpSp->Parameters.QueryFile.FileInformationClass); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } DokanPrintFileName(fileObject); /* if (fileObject->FsContext2 == NULL && fileObject->FileName.Length == 0) { // volume open? status = STATUS_SUCCESS; __leave; }*/ vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } ccb = (PDokanCCB)fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); DokanFCBLockRO(fcb); switch (irpSp->Parameters.QueryFile.FileInformationClass) { case FileBasicInformation: DDbgPrint(" FileBasicInformation\n"); break; case FileInternalInformation: DDbgPrint(" FileInternalInformation\n"); break; case FileEaInformation: DDbgPrint(" FileEaInformation\n"); break; case FileStandardInformation: DDbgPrint(" FileStandardInformation\n"); break; case FileAllInformation: DDbgPrint(" FileAllInformation\n"); break; case FileAlternateNameInformation: DDbgPrint(" FileAlternateNameInformation\n"); break; case FileAttributeTagInformation: DDbgPrint(" FileAttributeTagInformation\n"); break; case FileCompressionInformation: DDbgPrint(" FileCompressionInformation\n"); break; case FileNormalizedNameInformation: DDbgPrint(" FileNormalizedNameInformation\n"); isNormalized = TRUE; case FileNameInformation: { PFILE_NAME_INFORMATION nameInfo; DDbgPrint(" FileNameInformation\n"); nameInfo = (PFILE_NAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(nameInfo != NULL); BOOLEAN isNetworkFileSystem = (vcb->Dcb->VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM); PUNICODE_STRING fileName = &fcb->FileName; USHORT length = fcb->FileName.Length; BOOLEAN doConcat = FALSE; if (isNetworkFileSystem) { if (fcb->FileName.Length == 0 || fcb->FileName.Buffer[0] != L'\\') { DDbgPrint(" NetworkFileSystem has no root folder. So return the " "full device name \n"); fileName = vcb->Dcb->DiskDeviceName; length = fileName->Length; } else { if (isNormalized) { DDbgPrint(" FullFileName should be returned \n"); fileName = vcb->Dcb->DiskDeviceName; length = fileName->Length + vcb->Dcb->DiskDeviceName->Length; doConcat = TRUE; } } } if (irpSp->Parameters.QueryFile.Length < sizeof(FILE_NAME_INFORMATION) + length) { info = irpSp->Parameters.QueryFile.Length; status = STATUS_BUFFER_OVERFLOW; } else { RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.QueryFile.Length); nameInfo->FileNameLength = fileName->Length; RtlCopyMemory(&nameInfo->FileName[0], fileName->Buffer, fileName->Length); if (doConcat) { DDbgPrint(" Concat the devicename with the filename to get the " "fullname of the file \n"); RtlStringCchCatW(nameInfo->FileName, NTSTRSAFE_MAX_CCH, fcb->FileName.Buffer); } info = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + length; status = STATUS_SUCCESS; } __leave; } break; case FileNetworkOpenInformation: DDbgPrint(" FileNetworkOpenInformation\n"); break; case FilePositionInformation: { PFILE_POSITION_INFORMATION posInfo; DDbgPrint(" FilePositionInformation\n"); if (irpSp->Parameters.QueryFile.Length < sizeof(FILE_POSITION_INFORMATION)) { status = STATUS_INFO_LENGTH_MISMATCH; } else { posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(posInfo != NULL); RtlZeroMemory(posInfo, sizeof(FILE_POSITION_INFORMATION)); if (fileObject->CurrentByteOffset.QuadPart < 0) { status = STATUS_INVALID_PARAMETER; } else { // set the current file offset posInfo->CurrentByteOffset = fileObject->CurrentByteOffset; info = sizeof(FILE_POSITION_INFORMATION); status = STATUS_SUCCESS; } } __leave; } break; case FileStreamInformation: DDbgPrint(" FileStreamInformation\n"); break; case FileStandardLinkInformation: DDbgPrint(" FileStandardLinkInformation\n"); break; case FileNetworkPhysicalNameInformation: DDbgPrint(" FileNetworkPhysicalNameInformation\n"); break; case FileRemoteProtocolInformation: DDbgPrint(" FileRemoteProtocolInformation\n"); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.QueryFile.FileInformationClass); break; } // if it is not treadted in swich case // calculate the length of EVENT_CONTEXT // sum of it's size and file name length eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); eventContext->Operation.File.FileInformationClass = irpSp->Parameters.QueryFile.FileInformationClass; // bytes length which is able to be returned eventContext->Operation.File.BufferLength = irpSp->Parameters.QueryFile.Length; // copy file name to EventContext from FCB eventContext->Operation.File.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.File.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to pending IPR list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (fcb) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, info); DDbgPrint("<== DokanQueryInformation\n"); } return status; }
NTSTATUS DokanDispatchWrite(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; NTSTATUS status = STATUS_INVALID_PARAMETER; PEVENT_CONTEXT eventContext; ULONG eventLength; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; PVOID buffer; BOOLEAN writeToEoF = FALSE; BOOLEAN isPagingIo = FALSE; BOOLEAN isNonCached = FALSE; BOOLEAN isSynchronousIo = FALSE; BOOLEAN fcbLocked = FALSE; __try { DDbgPrint("==> DokanWrite\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; // // If this is a zero length write then return SUCCESS immediately. // if (irpSp->Parameters.Write.Length == 0) { DDbgPrint(" Parameters.Write.Length == 0\n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_DEVICE_REQUEST; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { status = STATUS_INVALID_PARAMETER; __leave; } if (Irp->MdlAddress) { DDbgPrint(" use MdlAddress\n"); buffer = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress); } else { DDbgPrint(" use UserBuffer\n"); buffer = Irp->UserBuffer; } if (buffer == NULL) { DDbgPrint(" buffer == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } if (irpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1) { writeToEoF = TRUE; } if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } if (Irp->Flags & IRP_NOCACHE) { isNonCached = TRUE; } if (fileObject->Flags & FO_SYNCHRONOUS_IO) { isSynchronousIo = TRUE; } if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, writeToEoF ? NULL : &irpSp->Parameters.Write.ByteOffset, irpSp->Parameters.Write.Length, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, writeToEoF ? NULL : &irpSp->Parameters.Write.ByteOffset, irpSp->Parameters.Write.Length, FALSE); ExReleaseResourceLite(&fcb->PagingIoResource); } // Cannot write at end of the file when using paging IO if (writeToEoF && isPagingIo) { DDbgPrint(" writeToEoF & isPagingIo\n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } // the length of EventContext is sum of length to write and length of file // name DokanFCBLockRO(fcb); fcbLocked = TRUE; eventLength = sizeof(EVENT_CONTEXT) + irpSp->Parameters.Write.Length + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); // no more memory! if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // When the length is bigger than usual event notitfication buffer, // saves pointer in DiverContext to copy EventContext after allocating // more bigger memory. Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = eventContext; if (isPagingIo) { DDbgPrint(" Paging IO\n"); eventContext->FileFlags |= DOKAN_PAGING_IO; } if (isSynchronousIo) { DDbgPrint(" Synchronous IO\n"); eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO; } if (isNonCached) { DDbgPrint(" Nocache\n"); eventContext->FileFlags |= DOKAN_NOCACHE; } // offset of file to write eventContext->Operation.Write.ByteOffset = irpSp->Parameters.Write.ByteOffset; if (writeToEoF) { eventContext->FileFlags |= DOKAN_WRITE_TO_END_OF_FILE; DDbgPrint(" WriteOffset = end of file\n"); } if (isSynchronousIo && ((irpSp->Parameters.Write.ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) && (irpSp->Parameters.Write.ByteOffset.HighPart == -1))) { // NOTE: // http://msdn.microsoft.com/en-us/library/ms795960.aspx // Do not check IrpSp->Parameters.Write.ByteOffset.QuadPart == 0 // Probably the document is wrong. eventContext->Operation.Write.ByteOffset.QuadPart = fileObject->CurrentByteOffset.QuadPart; } // the size of buffer to write eventContext->Operation.Write.BufferLength = irpSp->Parameters.Write.Length; // the offset from the begining of structure // the contents to write will be copyed to this offset eventContext->Operation.Write.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, Operation.Write.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // adds last null char // copies the content to write to EventContext RtlCopyMemory((PCHAR)eventContext + eventContext->Operation.Write.BufferOffset, buffer, irpSp->Parameters.Write.Length); // copies file name eventContext->Operation.Write.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Write.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // When eventlength is less than event notification buffer, // returns it to user-mode using pending event. if (eventLength <= EVENT_CONTEXT_MAX_SIZE) { DDbgPrint(" Offset %d:%d, Length %d\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // EventContext is no longer needed, clear it Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; // // We now check whether we can proceed based on the state of // the file oplocks. // // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } } // register this IRP to IRP waiting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); // Resuests bigger memory // eventContext will be freed later using // Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] } else { // the length at lest file name can be stored ULONG requestContextLength = max( sizeof(EVENT_CONTEXT), eventContext->Operation.Write.BufferOffset); PEVENT_CONTEXT requestContext = AllocateEventContext(vcb->Dcb, Irp, requestContextLength, ccb); // no more memory! if (requestContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; DokanFreeEventContext(eventContext); __leave; } DDbgPrint(" Offset %d:%d, Length %d (request)\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // copies from begining of EventContext to the end of file name RtlCopyMemory(requestContext, eventContext, eventContext->Operation.Write.BufferOffset); // puts actual size of RequestContext requestContext->Length = requestContextLength; // requsts enough size to copy EventContext requestContext->Operation.Write.RequestLength = eventLength; // // We now check whether we can proceed based on the state of // the file oplocks. // // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, requestContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(requestContext); Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; DokanFreeEventContext(eventContext); } __leave; } } // regiters this IRP to IRP wainting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, requestContext, 0); } } __finally { if (fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanWrite\n"); } return status; }
NTSTATUS DokanQueryDirectory( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PFILE_OBJECT fileObject; PIO_STACK_LOCATION irpSp; PDokanVCB vcb; PDokanCCB ccb; PDokanFCB fcb; NTSTATUS status; PUNICODE_STRING searchPattern; ULONG eventLength; PEVENT_CONTEXT eventContext; ULONG index; BOOLEAN initial; ULONG flags = 0; irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } ccb = fileObject->FsContext2; if (ccb == NULL) { return STATUS_INVALID_PARAMETER; } ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (irpSp->Flags & SL_INDEX_SPECIFIED) { DDbgPrint(" index specified %d\n", irpSp->Parameters.QueryDirectory.FileIndex); } if (irpSp->Flags & SL_RETURN_SINGLE_ENTRY) { DDbgPrint(" return single entry"); } if (irpSp->Flags & SL_RESTART_SCAN) { DDbgPrint(" restart scan"); } if (irpSp->Parameters.QueryDirectory.FileName) { DDbgPrint(" pattern:%wZ\n", irpSp->Parameters.QueryDirectory.FileName); } switch (irpSp->Parameters.QueryDirectory.FileInformationClass) { case FileDirectoryInformation: DDbgPrint(" FileDirectoryInformation"); break; case FileFullDirectoryInformation: DDbgPrint(" FileFullDirectoryInformation"); break; case FileNamesInformation: DDbgPrint(" FileNamesInformation"); break; case FileBothDirectoryInformation: DDbgPrint(" FileBothDirectoryInformation"); break; case FileIdBothDirectoryInformation: DDbgPrint(" FileIdBothDirectoryInformation"); break; default: DDbgPrint(" unknown FileInfoClass %d\n", irpSp->Parameters.QueryDirectory.FileInformationClass); break; } // make a MDL for UserBuffer that can be used later on another thread context if (Irp->MdlAddress == NULL) { status = DokanAllocateMdl(Irp, irpSp->Parameters.QueryDirectory.Length); if (!NT_SUCCESS(status)) { return status; } flags = DOKAN_MDL_ALLOCATED; } // size of EVENT_CONTEXT is sum of its length and file name length eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; initial = (BOOLEAN)(ccb->SearchPattern == NULL && !(ccb->Flags & DOKAN_DIR_MATCH_ALL)); // this is an initial query if (initial) { DDbgPrint(" initial query"); // and search pattern is provided if (irpSp->Parameters.QueryDirectory.FileName) { // free current search pattern stored in CCB if (ccb->SearchPattern) ExFreePool(ccb->SearchPattern); // the size of search pattern ccb->SearchPatternLength = irpSp->Parameters.QueryDirectory.FileName->Length; ccb->SearchPattern = ExAllocatePool(ccb->SearchPatternLength + sizeof(WCHAR)); if (ccb->SearchPattern == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(ccb->SearchPattern, ccb->SearchPatternLength + sizeof(WCHAR)); // copy provided search pattern to CCB RtlCopyMemory(ccb->SearchPattern, irpSp->Parameters.QueryDirectory.FileName->Buffer, ccb->SearchPatternLength); } else { ccb->Flags |= DOKAN_DIR_MATCH_ALL; } } // if search pattern is provided, add the length of it to store pattern if (ccb->SearchPattern) { eventLength += ccb->SearchPatternLength; } eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } eventContext->Context = ccb->UserContext; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // index which specified index-1 th directory entry has been returned // this time, 'index'th entry should be returned index = 0; if (irpSp->Flags & SL_INDEX_SPECIFIED) { index = irpSp->Parameters.QueryDirectory.FileIndex; DDbgPrint(" using FileIndex %d\n", index); } else if (FlagOn(irpSp->Flags, SL_RESTART_SCAN)) { DDbgPrint(" SL_RESTART_SCAN"); index = 0; } else { index = (ULONG)ccb->Context; DDbgPrint(" ccb->Context %d\n", index); } eventContext->Directory.FileInformationClass = irpSp->Parameters.QueryDirectory.FileInformationClass; eventContext->Directory.BufferLength = irpSp->Parameters.QueryDirectory.Length; // length of buffer eventContext->Directory.FileIndex = index; // directory index which should be returned this time // copying file name(directory name) eventContext->Directory.DirectoryNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Directory.DirectoryName, fcb->FileName.Buffer, fcb->FileName.Length); // if search pattern is specified, copy it to EventContext if (ccb->SearchPatternLength) { PVOID searchBuffer; eventContext->Directory.SearchPatternLength = ccb->SearchPatternLength; eventContext->Directory.SearchPatternOffset = eventContext->Directory.DirectoryNameLength; searchBuffer = (PVOID)((SIZE_T)&eventContext->Directory.SearchPatternBase[0] + (SIZE_T)eventContext->Directory.SearchPatternOffset); RtlCopyMemory(searchBuffer, ccb->SearchPattern, ccb->SearchPatternLength); DDbgPrint(" ccb->SearchPattern %ws\n", ccb->SearchPattern); } status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags); return status; }
NTSTATUS DokanDispatchClose( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) /*++ Routine Description: This device control dispatcher handles create & close IRPs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb; PEVENT_CONTEXT eventContext; ULONG eventLength; PDokanFCB fcb; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanClose"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject is NULL"); status = STATUS_SUCCESS; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { if (fileObject->FsContext2) { ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); DDbgPrint(" Free CCB:%X\n", ccb); DokanFreeCCB(ccb); DokanFreeFCB(fcb); } status = STATUS_SUCCESS; __leave; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { //status = STATUS_INSUFFICIENT_RESOURCES; DDbgPrint(" eventContext == NULL"); DDbgPrint(" Free CCB:%X\n", ccb); DokanFreeCCB(ccb); DokanFreeFCB(fcb); status = STATUS_SUCCESS; __leave; } eventContext->Context = ccb->UserContext; DDbgPrint(" UserContext:%X\n", (ULONG)ccb->UserContext); // copy the file name to be closed eventContext->Close.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Close.FileName, fcb->FileName.Buffer, fcb->FileName.Length); DDbgPrint(" Free CCB:%X\n", ccb); DokanFreeCCB(ccb); DokanFreeFCB(fcb); // Close can not be pending status // don't register this IRP //status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext->SerialNumber, 0); // inform it to user-mode DokanEventNotification(&vcb->Dcb->NotifyEvent, eventContext); status = STATUS_SUCCESS; } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } DDbgPrint("<== DokanClose"); FsRtlExitFileSystem(); } return status; }
VOID DokanDeleteDeviceObject(__in PDokanDCB Dcb) { PDokanVCB vcb; DOKAN_CONTROL dokanControl; PMOUNT_ENTRY mountEntry = NULL; ASSERT(GetIdentifierType(Dcb) == DCB); vcb = Dcb->Vcb; if (Dcb->SymbolicLinkName == NULL) { DDbgPrint(" Symbolic Name already deleted, so go out here\n"); return; } RtlZeroMemory(&dokanControl, sizeof(dokanControl)); RtlCopyMemory(dokanControl.DeviceName, Dcb->DiskDeviceName->Buffer, Dcb->DiskDeviceName->Length); mountEntry = FindMountEntry(Dcb->Global, &dokanControl); if (mountEntry != NULL) { if (mountEntry->MountControl.Type == FILE_DEVICE_NETWORK_FILE_SYSTEM) { // Run FsRtlDeregisterUncProvider in System thread. HANDLE handle; PKTHREAD thread; OBJECT_ATTRIBUTES objectAttribs; NTSTATUS status; InitializeObjectAttributes(&objectAttribs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread( &handle, THREAD_ALL_ACCESS, &objectAttribs, NULL, NULL, (PKSTART_ROUTINE)DokanDeregisterUncProvider, 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); } } RemoveMountEntry(Dcb->Global, mountEntry); } else { DDbgPrint(" Cannot found associated mount entry.\n"); } DDbgPrint(" Delete Symbolic Name: %wZ\n", Dcb->SymbolicLinkName); IoDeleteSymbolicLink(Dcb->SymbolicLinkName); if (Dcb->MountedDeviceInterfaceName.Buffer != NULL) { IoSetDeviceInterfaceState(&Dcb->MountedDeviceInterfaceName, FALSE); RtlFreeUnicodeString(&Dcb->MountedDeviceInterfaceName); RtlInitUnicodeString(&Dcb->MountedDeviceInterfaceName, NULL); } if (Dcb->DiskDeviceInterfaceName.Buffer != NULL) { IoSetDeviceInterfaceState(&Dcb->DiskDeviceInterfaceName, FALSE); RtlFreeUnicodeString(&Dcb->DiskDeviceInterfaceName); RtlInitUnicodeString(&Dcb->DiskDeviceInterfaceName, NULL); } FreeDcbNames(Dcb); if (Dcb->DeviceObject->Vpb) { Dcb->DeviceObject->Vpb->DeviceObject = NULL; Dcb->DeviceObject->Vpb->RealDevice = NULL; Dcb->DeviceObject->Vpb->Flags = 0; } if (vcb != NULL) { DDbgPrint(" FCB allocated: %d\n", vcb->FcbAllocated); DDbgPrint(" FCB freed: %d\n", vcb->FcbFreed); DDbgPrint(" CCB allocated: %d\n", vcb->CcbAllocated); DDbgPrint(" CCB freed: %d\n", vcb->CcbFreed); // delete volDeviceObject DDbgPrint(" Delete Volume DeviceObject\n"); IoDeleteDevice(vcb->DeviceObject); } // delete diskDeviceObject DDbgPrint(" Delete Disk DeviceObject\n"); IoDeleteDevice(Dcb->DeviceObject); }
// start event dispatching NTSTATUS DokanEventStart( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { ULONG outBufferLen; ULONG inBufferLen; 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 DokanDispatchQueryInformation( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb; PDokanVCB vcb; ULONG info = 0; ULONG eventLength; PEVENT_CONTEXT eventContext; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanQueryInformation\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" FileInfoClass %d\n", irpSp->Parameters.QueryFile.FileInformationClass); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } DokanPrintFileName(fileObject); /* if (fileObject->FsContext2 == NULL && fileObject->FileName.Length == 0) { // volume open? status = STATUS_SUCCESS; __leave; }*/ vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } ccb = (PDokanCCB)fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); switch (irpSp->Parameters.QueryFile.FileInformationClass) { case FileBasicInformation: DDbgPrint(" FileBasicInformation\n"); break; case FileInternalInformation: DDbgPrint(" FileInternalInformation\n"); break; case FileEaInformation: DDbgPrint(" FileEaInformation\n"); break; case FileStandardInformation: DDbgPrint(" FileStandardInformation\n"); break; case FileAllInformation: DDbgPrint(" FileAllInformation\n"); break; case FileAlternateNameInformation: DDbgPrint(" FileAlternateNameInformation\n"); break; case FileAttributeTagInformation: DDbgPrint(" FileAttributeTagInformation\n"); break; case FileCompressionInformation: DDbgPrint(" FileCompressionInformation\n"); break; case FileNameInformation: { PFILE_NAME_INFORMATION nameInfo; DDbgPrint(" FileNameInformation\n"); if (irpSp->Parameters.QueryFile.Length < sizeof(FILE_NAME_INFORMATION) + fcb->FileName.Length) { status = STATUS_INSUFFICIENT_RESOURCES; } else { nameInfo = (PFILE_NAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(nameInfo != NULL); nameInfo->FileNameLength = fcb->FileName.Length; RtlCopyMemory(nameInfo->FileName, fcb->FileName.Buffer, fcb->FileName.Length); info = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + fcb->FileName.Length; status = STATUS_SUCCESS; } __leave; } break; case FileNetworkOpenInformation: DDbgPrint(" FileNetworkOpenInformation\n"); break; case FilePositionInformation: { PFILE_POSITION_INFORMATION posInfo; DDbgPrint(" FilePositionInformation\n"); if (irpSp->Parameters.QueryFile.Length < sizeof(FILE_POSITION_INFORMATION)) { status = STATUS_INFO_LENGTH_MISMATCH; } else { posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(posInfo != NULL); RtlZeroMemory(posInfo, sizeof(FILE_POSITION_INFORMATION)); if (fileObject->CurrentByteOffset.QuadPart < 0) { status = STATUS_INVALID_PARAMETER; } else { // set the current file offset posInfo->CurrentByteOffset = fileObject->CurrentByteOffset; info = sizeof(FILE_POSITION_INFORMATION); status = STATUS_SUCCESS; } } __leave; } break; case FileStreamInformation: DDbgPrint(" FileStreamInformation\n"); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.QueryFile.FileInformationClass); break; } // if it is not treadted in swich case // calculate the length of EVENT_CONTEXT // sum of it's size and file name length eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); eventContext->File.FileInformationClass = irpSp->Parameters.QueryFile.FileInformationClass; // bytes length which is able to be returned eventContext->File.BufferLength = irpSp->Parameters.QueryFile.Length; // copy file name to EventContext from FCB eventContext->File.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->File.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to pending IPR list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanQueryInformation\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DiskDeviceControl(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PIO_STACK_LOCATION irpSp; PDokanDCB dcb; PDokanVCB vcb; NTSTATUS status = STATUS_NOT_IMPLEMENTED; ULONG outputLength = 0; ULONG inputLength = 0; DOKAN_INIT_LOGGER(logger, DeviceObject->DriverObject, IRP_MJ_DEVICE_CONTROL); DDbgPrint(" => DokanDiskDeviceControl\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); dcb = DeviceObject->DeviceExtension; outputLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; inputLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; if (GetIdentifierType(dcb) != DCB) { PrintIdType(dcb); DDbgPrint(" Device is not dcb so go out here\n"); return STATUS_INVALID_PARAMETER; } if (IsDeletePending(DeviceObject)) { DDbgPrint(" Device object is pending for delete valid anymore\n"); return STATUS_DEVICE_REMOVED; } vcb = dcb->Vcb; if (IsUnmountPendingVcb(vcb)) { DDbgPrint(" Volume is unmounted so ignore dcb requests\n"); return STATUS_NO_SUCH_DEVICE; } DDbgPrint(" DiskDeviceControl Device name %wZ \n", dcb->DiskDeviceName); switch (irpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_DISK_GET_DRIVE_GEOMETRY: { PDISK_GEOMETRY diskGeometry; DDbgPrint(" IOCTL_DISK_GET_DRIVE_GEOMETRY\n"); if (outputLength < sizeof(DISK_GEOMETRY)) { Irp->IoStatus.Information = 0; status = STATUS_BUFFER_TOO_SMALL; break; } diskGeometry = (PDISK_GEOMETRY)Irp->AssociatedIrp.SystemBuffer; ASSERT(diskGeometry != NULL); DokanPopulateDiskGeometry(diskGeometry); Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); status = STATUS_SUCCESS; } break; case IOCTL_DISK_GET_LENGTH_INFO: { PGET_LENGTH_INFORMATION getLengthInfo; DDbgPrint(" IOCTL_DISK_GET_LENGTH_INFO\n"); if (outputLength < sizeof(GET_LENGTH_INFORMATION)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } getLengthInfo = (PGET_LENGTH_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(getLengthInfo != NULL); getLengthInfo->Length.QuadPart = 1024 * 1024 * 500; status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); } break; case IOCTL_DISK_GET_DRIVE_LAYOUT: case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: case IOCTL_DISK_GET_PARTITION_INFO: case IOCTL_DISK_GET_PARTITION_INFO_EX: { // Fake drive layout/partition information VOID *outputBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG ioctl = irpSp->Parameters.DeviceIoControl.IoControlCode; switch (ioctl) { case IOCTL_DISK_GET_DRIVE_LAYOUT: DDbgPrint(" IOCTL_DISK_GET_DRIVE_LAYOUT\n"); Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry[1]); break; case IOCTL_DISK_GET_DRIVE_LAYOUT_EX: DDbgPrint(" IOCTL_DISK_GET_DRIVE_LAYOUT_EX\n"); Irp->IoStatus.Information = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[1]); break; case IOCTL_DISK_GET_PARTITION_INFO: DDbgPrint(" IOCTL_DISK_GET_PARTITION_INFO\n"); Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION); break; case IOCTL_DISK_GET_PARTITION_INFO_EX: DDbgPrint(" IOCTL_DISK_GET_PARTITION_INFO_EX\n"); Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX); break; default: DDbgPrint(" unknown ioctl %d\n", ioctl); break; } if (outputLength < Irp->IoStatus.Information) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } RtlZeroMemory(outputBuffer, Irp->IoStatus.Information); // if we are getting the drive layout, then we need to start by // adding some of the non-partition stuff that says we have // exactly one partition available. if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT) { PDRIVE_LAYOUT_INFORMATION layout; layout = (PDRIVE_LAYOUT_INFORMATION)outputBuffer; layout->PartitionCount = 1; layout->Signature = 1; outputBuffer = (PVOID)(layout->PartitionEntry); ioctl = IOCTL_DISK_GET_PARTITION_INFO; } else if (ioctl == IOCTL_DISK_GET_DRIVE_LAYOUT_EX) { PDRIVE_LAYOUT_INFORMATION_EX layoutEx; layoutEx = (PDRIVE_LAYOUT_INFORMATION_EX)outputBuffer; layoutEx->PartitionStyle = PARTITION_STYLE_MBR; layoutEx->PartitionCount = 1; layoutEx->Mbr.Signature = 1; outputBuffer = (PVOID)(layoutEx->PartitionEntry); ioctl = IOCTL_DISK_GET_PARTITION_INFO_EX; } // NOTE: the local var 'ioctl' is now modified to either EX or // non-EX version. the local var 'systemBuffer' is now pointing // to the partition information structure. if (ioctl == IOCTL_DISK_GET_PARTITION_INFO) { PPARTITION_INFORMATION partitionInfo; partitionInfo = (PPARTITION_INFORMATION)outputBuffer; partitionInfo->RewritePartition = FALSE; partitionInfo->RecognizedPartition = FALSE; partitionInfo->PartitionType = PARTITION_ENTRY_UNUSED; partitionInfo->BootIndicator = FALSE; partitionInfo->HiddenSectors = 0; partitionInfo->StartingOffset.QuadPart = 0; partitionInfo->PartitionLength.QuadPart = DOKAN_DEFAULT_DISK_SIZE; // Partition size equels disk size here partitionInfo->PartitionNumber = 0; } else { PPARTITION_INFORMATION_EX partitionInfo; partitionInfo = (PPARTITION_INFORMATION_EX)outputBuffer; partitionInfo->PartitionStyle = PARTITION_STYLE_MBR; partitionInfo->RewritePartition = FALSE; partitionInfo->Mbr.RecognizedPartition = FALSE; partitionInfo->Mbr.PartitionType = PARTITION_ENTRY_UNUSED; partitionInfo->Mbr.BootIndicator = FALSE; partitionInfo->Mbr.HiddenSectors = 0; partitionInfo->StartingOffset.QuadPart = 0; partitionInfo->PartitionLength.QuadPart = DOKAN_DEFAULT_DISK_SIZE; // Partition size equels disk size here partitionInfo->PartitionNumber = 0; } status = STATUS_SUCCESS; } break; case IOCTL_DISK_IS_WRITABLE: DDbgPrint(" IOCTL_DISK_IS_WRITABLE\n"); status = IS_DEVICE_READ_ONLY(DeviceObject) ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_SUCCESS; break; case IOCTL_DISK_MEDIA_REMOVAL: DDbgPrint(" IOCTL_DISK_MEDIA_REMOVAL\n"); status = STATUS_SUCCESS; break; case IOCTL_STORAGE_MEDIA_REMOVAL: DDbgPrint(" IOCTL_STORAGE_MEDIA_REMOVAL\n"); status = STATUS_SUCCESS; break; case IOCTL_DISK_SET_PARTITION_INFO: DDbgPrint(" IOCTL_DISK_SET_PARTITION_INFO\n"); break; case IOCTL_DISK_VERIFY: DDbgPrint(" IOCTL_DISK_VERIFY\n"); break; case IOCTL_STORAGE_GET_HOTPLUG_INFO: { PSTORAGE_HOTPLUG_INFO hotplugInfo; DDbgPrint(" IOCTL_STORAGE_GET_HOTPLUG_INFO\n"); if (outputLength < sizeof(STORAGE_HOTPLUG_INFO)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } hotplugInfo = Irp->AssociatedIrp.SystemBuffer; hotplugInfo->Size = sizeof(STORAGE_HOTPLUG_INFO); hotplugInfo->MediaRemovable = 1; hotplugInfo->MediaHotplug = 1; hotplugInfo->DeviceHotplug = 1; hotplugInfo->WriteCacheEnableOverride = 0; status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); } break; case IOCTL_VOLUME_GET_GPT_ATTRIBUTES: { DDbgPrint(" IOCTL_VOLUME_GET_GPT_ATTRIBUTES\n"); PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION gptAttrInfo; if (outputLength < sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } // Set GPT read-only flag if device is not writable gptAttrInfo = Irp->AssociatedIrp.SystemBuffer; if (IS_DEVICE_READ_ONLY(DeviceObject)) gptAttrInfo->GptAttributes = GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY; Irp->IoStatus.Information = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION); status = STATUS_SUCCESS; } break; case IOCTL_STORAGE_CHECK_VERIFY: case IOCTL_DISK_CHECK_VERIFY: DDbgPrint(" IOCTL_STORAGE_CHECK_VERIFY\n"); status = STATUS_SUCCESS; break; case IOCTL_STORAGE_CHECK_VERIFY2: DDbgPrint(" IOCTL_STORAGE_CHECK_VERIFY2\n"); status = STATUS_SUCCESS; break; case IOCTL_STORAGE_QUERY_PROPERTY: DDbgPrint(" IOCTL_STORAGE_QUERY_PROPERTY\n"); PSTORAGE_PROPERTY_QUERY query = NULL; query = (PSTORAGE_PROPERTY_QUERY)Irp->AssociatedIrp.SystemBuffer; ASSERT(query != NULL); if (query->QueryType == PropertyExistsQuery) { if (query->PropertyId == StorageDeviceUniqueIdProperty) { PSTORAGE_DEVICE_UNIQUE_IDENTIFIER storage; DDbgPrint(" PropertyExistsQuery StorageDeviceUniqueIdProperty\n"); if (outputLength < sizeof(STORAGE_DEVICE_UNIQUE_IDENTIFIER)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } storage = Irp->AssociatedIrp.SystemBuffer; status = STATUS_SUCCESS; } else if (query->PropertyId == StorageDeviceWriteCacheProperty) { DDbgPrint(" PropertyExistsQuery StorageDeviceWriteCacheProperty\n"); status = STATUS_NOT_IMPLEMENTED; } else { DDbgPrint(" PropertyExistsQuery Unknown %d\n", query->PropertyId); status = STATUS_NOT_IMPLEMENTED; } } else if (query->QueryType == PropertyStandardQuery) { if (query->PropertyId == StorageDeviceProperty) { PSTORAGE_DEVICE_DESCRIPTOR storage; DDbgPrint(" PropertyStandardQuery StorageDeviceProperty\n"); if (outputLength < sizeof(STORAGE_DEVICE_DESCRIPTOR)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } storage = Irp->AssociatedIrp.SystemBuffer; status = STATUS_SUCCESS; } else if (query->PropertyId == StorageAdapterProperty) { DDbgPrint(" PropertyStandardQuery StorageAdapterProperty\n"); status = STATUS_NOT_IMPLEMENTED; } else { DDbgPrint(" PropertyStandardQuery Unknown %d\n", query->PropertyId); status = STATUS_ACCESS_DENIED; } } else { DDbgPrint(" Unknown query type %d\n", query->QueryType); status = STATUS_ACCESS_DENIED; } break; case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: { PMOUNTDEV_NAME mountdevName; PUNICODE_STRING deviceName = dcb->DiskDeviceName; DDbgPrint(" IOCTL_MOUNTDEV_QUERY_DEVICE_NAME\n"); if (outputLength < sizeof(MOUNTDEV_NAME)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); break; } mountdevName = (PMOUNTDEV_NAME)Irp->AssociatedIrp.SystemBuffer; ASSERT(mountdevName != NULL); /* NOTE: When Windows API GetVolumeNameForVolumeMountPoint is called, this IO control is called. Even if status = STATUS_SUCCESS, GetVolumeNameForVolumeMountPoint can returns error if it doesn't match cached data from mount manager (looks like). */ RtlZeroMemory(mountdevName, outputLength); mountdevName->NameLength = deviceName->Length; if (sizeof(USHORT) + mountdevName->NameLength <= outputLength) { RtlCopyMemory((PCHAR)mountdevName->Name, deviceName->Buffer, mountdevName->NameLength); Irp->IoStatus.Information = sizeof(USHORT) + mountdevName->NameLength; status = STATUS_SUCCESS; DDbgPrint(" DeviceName %wZ\n", deviceName); } else { Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); status = STATUS_BUFFER_OVERFLOW; } } break; case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: { PMOUNTDEV_UNIQUE_ID uniqueId; DDbgPrint(" IOCTL_MOUNTDEV_QUERY_UNIQUE_ID\n"); if (outputLength < sizeof(MOUNTDEV_UNIQUE_ID)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); break; } uniqueId = (PMOUNTDEV_UNIQUE_ID)Irp->AssociatedIrp.SystemBuffer; ASSERT(uniqueId != NULL); uniqueId->UniqueIdLength = dcb->DiskDeviceName->Length; if (sizeof(USHORT) + uniqueId->UniqueIdLength <= outputLength) { RtlCopyMemory((PCHAR)uniqueId->UniqueId, dcb->DiskDeviceName->Buffer, uniqueId->UniqueIdLength); Irp->IoStatus.Information = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + uniqueId->UniqueIdLength; status = STATUS_SUCCESS; DDbgPrint(" UniqueName %wZ\n", dcb->DiskDeviceName); break; } else { Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); status = STATUS_BUFFER_OVERFLOW; } } break; case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: { PMOUNTDEV_SUGGESTED_LINK_NAME linkName; DDbgPrint(" IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n"); if (outputLength < sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); break; } linkName = (PMOUNTDEV_SUGGESTED_LINK_NAME)Irp->AssociatedIrp.SystemBuffer; ASSERT(linkName != NULL); if (dcb->MountPoint != NULL && dcb->MountPoint->Length > 0) { if (IsMountPointDriveLetter(dcb->MountPoint) == STATUS_SUCCESS) { linkName->UseOnlyIfThereAreNoOtherLinks = FALSE; linkName->NameLength = dcb->MountPoint->Length; if (sizeof(USHORT) + linkName->NameLength <= outputLength) { DokanLogInfo(&logger, L"Returning suggested drive letter: %wZ", dcb->MountPoint); RtlCopyMemory((PCHAR)linkName->Name, dcb->MountPoint->Buffer, linkName->NameLength); Irp->IoStatus.Information = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name[0]) + linkName->NameLength; status = STATUS_SUCCESS; DDbgPrint(" LinkName %wZ (%d)\n", dcb->MountPoint, dcb->MountPoint->Length); break; } else { Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); status = STATUS_BUFFER_OVERFLOW; } } else { DDbgPrint(" MountPoint %wZ is not a drive\n", dcb->MountPoint); status = STATUS_NOT_FOUND; } } else { DDbgPrint(" MountPoint is NULL or undefined\n"); status = STATUS_NOT_FOUND; } DokanLogInfo(&logger, L"Suggested drive letter return status: %I32x", status); } break; case IOCTL_MOUNTDEV_LINK_CREATED: { PMOUNTDEV_NAME mountdevName = Irp->AssociatedIrp.SystemBuffer; DDbgPrint(" IOCTL_MOUNTDEV_LINK_CREATED\n"); status = STATUS_SUCCESS; if (!IsUnmountPending(DeviceObject) && mountdevName != NULL && mountdevName->NameLength > 0) { WCHAR *symbolicLinkNameBuf = ExAllocatePool((mountdevName->NameLength + 1) * sizeof(WCHAR)); if (symbolicLinkNameBuf == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(symbolicLinkNameBuf, (mountdevName->NameLength + 1) * sizeof(WCHAR)); RtlCopyMemory(symbolicLinkNameBuf, mountdevName->Name, mountdevName->NameLength); DDbgPrint(" MountDev Name: %ws\n", symbolicLinkNameBuf); DokanLogInfo(&logger, L"Link created: %s", symbolicLinkNameBuf); if (wcsncmp(symbolicLinkNameBuf, L"\\DosDevices\\", 12) == 0) { if (dcb->MountPoint != NULL && dcb->MountPoint->Length == 0) { ExFreePool(dcb->MountPoint); dcb->MountPoint = NULL; } if (!dcb->MountPoint || ((dcb->MountPoint->Length != mountdevName->NameLength || RtlCompareMemory(mountdevName->Name, dcb->MountPoint->Buffer, mountdevName->NameLength) != mountdevName->NameLength))) { DDbgPrint(" Update mount Point by %ws\n", symbolicLinkNameBuf); ExFreePool(dcb->MountPoint); dcb->MountPoint = DokanAllocateUnicodeString(symbolicLinkNameBuf); if (dcb->DiskDeviceName != NULL) { PMOUNT_ENTRY mountEntry; PDOKAN_CONTROL dokanControl = ExAllocatePool(sizeof(DOKAN_CONTROL)); if (dokanControl == NULL) { ExFreePool(symbolicLinkNameBuf); status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(dokanControl, sizeof(*dokanControl)); RtlCopyMemory(dokanControl->DeviceName, dcb->DiskDeviceName->Buffer, dcb->DiskDeviceName->Length); if (dcb->UNCName->Buffer != NULL && dcb->UNCName->Length > 0) { RtlCopyMemory(dokanControl->UNCName, dcb->UNCName->Buffer, dcb->UNCName->Length); } dokanControl->SessionId = dcb->SessionId; mountEntry = FindMountEntry(dcb->Global, dokanControl, TRUE); ExFreePool(dokanControl); if (mountEntry != NULL) { RtlStringCchCopyW(mountEntry->MountControl.MountPoint, MAXIMUM_FILENAME_LENGTH, symbolicLinkNameBuf); } else { DDbgPrint(" Cannot found associated MountEntry.\n"); } } else { DDbgPrint( " DiskDeviceName is null. Is device currently unmounted?\n"); } } else { DDbgPrint(" Mount Point match, no need to update it.\n"); } } else { DDbgPrint(" Mount Point is not DosDevices, ignored.\n"); } ExFreePool(symbolicLinkNameBuf); } else { DDbgPrint(" MountDev Name is undefined or unmounting in progress.\n"); } } break; case IOCTL_MOUNTDEV_LINK_DELETED: { PMOUNTDEV_NAME mountdevName = Irp->AssociatedIrp.SystemBuffer; DDbgPrint(" IOCTL_MOUNTDEV_LINK_DELETED\n"); status = STATUS_SUCCESS; if (dcb->UseMountManager) { if (mountdevName != NULL && mountdevName->NameLength > 0) { WCHAR *symbolicLinkNameBuf = ExAllocatePool((mountdevName->NameLength + 1) * sizeof(WCHAR)); if (symbolicLinkNameBuf == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(symbolicLinkNameBuf, (mountdevName->NameLength + 1) * sizeof(WCHAR)); RtlCopyMemory(symbolicLinkNameBuf, mountdevName->Name, mountdevName->NameLength); DDbgPrint(" MountDev Name: %ws\n", symbolicLinkNameBuf); if (dcb->MountPoint != NULL && dcb->MountPoint->Length > 0) { // If deleted mount point match user requested mount point, release // devices if (dcb->MountPoint->Length == mountdevName->NameLength && RtlCompareMemory(mountdevName->Name, dcb->MountPoint->Buffer, mountdevName->NameLength) == mountdevName->NameLength) { status = DokanEventRelease(vcb->DeviceObject, Irp); } else { DDbgPrint(" Deleted Mount Point doesn't match device excepted " "mount point.\n"); } } // Or, if no requested mount point, we assume the first deleted one // release devices else { status = DokanEventRelease(vcb->DeviceObject, Irp); } ExFreePool(symbolicLinkNameBuf); } else { DDbgPrint(" MountDev Name is undefined.\n"); } } else { DDbgPrint(" Mount Manager is not enabled for this device. Ignored.\n"); } } break; // case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY: // DDbgPrint(" IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY\n"); // break; case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: DDbgPrint(" IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n"); break; case IOCTL_VOLUME_ONLINE: DDbgPrint(" IOCTL_VOLUME_ONLINE\n"); status = STATUS_SUCCESS; break; case IOCTL_VOLUME_OFFLINE: DDbgPrint(" IOCTL_VOLUME_OFFLINE\n"); status = STATUS_SUCCESS; break; case IOCTL_VOLUME_READ_PLEX: DDbgPrint(" IOCTL_VOLUME_READ_PLEX\n"); break; case IOCTL_VOLUME_PHYSICAL_TO_LOGICAL: DDbgPrint(" IOCTL_VOLUME_PHYSICAL_TO_LOGICAL\n"); break; case IOCTL_VOLUME_IS_CLUSTERED: DDbgPrint(" IOCTL_VOLUME_IS_CLUSTERED\n"); break; case IOCTL_VOLUME_PREPARE_FOR_CRITICAL_IO: DDbgPrint(" IOCTL_VOLUME_PREPARE_FOR_CRITICAL_IO\n"); break; case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: { PVOLUME_DISK_EXTENTS volume; ULONG bufferLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; DDbgPrint(" IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS\n"); if (bufferLength < sizeof(VOLUME_DISK_EXTENTS)) { status = STATUS_INVALID_PARAMETER; Irp->IoStatus.Information = 0; break; } volume = Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(volume, sizeof(VOLUME_DISK_EXTENTS)); volume->NumberOfDiskExtents = 1; Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS); status = STATUS_SUCCESS; } break; case IOCTL_STORAGE_EJECT_MEDIA: { DDbgPrint(" IOCTL_STORAGE_EJECT_MEDIA\n"); DokanUnmount(dcb); status = STATUS_SUCCESS; } break; case IOCTL_REDIR_QUERY_PATH_EX: case IOCTL_REDIR_QUERY_PATH: { PQUERY_PATH_RESPONSE pathResp; BOOLEAN prefixOk = FALSE; if (dcb->UNCName != NULL && dcb->UNCName->Length > 0) { if (Irp->RequestorMode != KernelMode) { break; } WCHAR *lpPath = NULL; ULONG ulPath = 0; if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH) { PQUERY_PATH_REQUEST pathReq; DDbgPrint(" IOCTL_REDIR_QUERY_PATH\n"); if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST)) { status = STATUS_BUFFER_OVERFLOW; break; } // Always a METHOD_NEITHER IOCTL pathReq = (PQUERY_PATH_REQUEST) irpSp->Parameters.DeviceIoControl.Type3InputBuffer; DDbgPrint(" PathNameLength = %d\n", pathReq->PathNameLength); DDbgPrint(" SecurityContext = %p\n", pathReq->SecurityContext); DDbgPrint(" FilePathName = %.*ls\n", (unsigned int)(pathReq->PathNameLength / sizeof(WCHAR)), pathReq->FilePathName); lpPath = pathReq->FilePathName; ulPath = pathReq->PathNameLength / sizeof(WCHAR); if (pathReq->PathNameLength >= dcb->UNCName->Length / sizeof(WCHAR)) { prefixOk = (_wcsnicmp(pathReq->FilePathName, dcb->UNCName->Buffer, dcb->UNCName->Length / sizeof(WCHAR)) == 0); } } else { PQUERY_PATH_REQUEST_EX pathReqEx; DDbgPrint(" IOCTL_REDIR_QUERY_PATH_EX\n"); if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(QUERY_PATH_REQUEST_EX)) { status = STATUS_BUFFER_OVERFLOW; break; } // Always a METHOD_NEITHER IOCTL pathReqEx = (PQUERY_PATH_REQUEST_EX) irpSp->Parameters.DeviceIoControl.Type3InputBuffer; DDbgPrint(" pSecurityContext = %p\n", pathReqEx->pSecurityContext); DDbgPrint(" EaLength = %d\n", pathReqEx->EaLength); DDbgPrint(" pEaBuffer = %p\n", pathReqEx->pEaBuffer); DDbgPrint(" PathNameLength = %d\n", pathReqEx->PathName.Length); DDbgPrint(" FilePathName = %*ls\n", (unsigned int)(pathReqEx->PathName.Length / sizeof(WCHAR)), pathReqEx->PathName.Buffer); lpPath = pathReqEx->PathName.Buffer; ulPath = pathReqEx->PathName.Length / sizeof(WCHAR); if (pathReqEx->PathName.Length >= dcb->UNCName->Length) { prefixOk = (_wcsnicmp(pathReqEx->PathName.Buffer, dcb->UNCName->Buffer, dcb->UNCName->Length / sizeof(WCHAR)) == 0); } } unsigned int i = 1; for (; i < ulPath && i * sizeof(WCHAR) < dcb->UNCName->Length && !prefixOk; ++i) { if (_wcsnicmp(&lpPath[i], &dcb->UNCName->Buffer[i], 1) != 0) { break; } if ((i + 1) * sizeof(WCHAR) < dcb->UNCName->Length) { prefixOk = (dcb->UNCName->Buffer[i + 1] == L'\\'); } } if (!prefixOk) { status = STATUS_BAD_NETWORK_PATH; break; } for (; i < ulPath && i * sizeof(WCHAR) < dcb->UNCName->Length && prefixOk; ++i) { if (_wcsnicmp(&lpPath[i], &dcb->UNCName->Buffer[i], 1) != 0) { prefixOk = FALSE; } } if (!prefixOk) { status = STATUS_BAD_NETWORK_NAME; break; } pathResp = (PQUERY_PATH_RESPONSE)Irp->UserBuffer; pathResp->LengthAccepted = dcb->UNCName->Length; status = STATUS_SUCCESS; } } break; case IOCTL_STORAGE_GET_MEDIA_TYPES_EX: { PGET_MEDIA_TYPES mediaTypes = NULL; PDEVICE_MEDIA_INFO mediaInfo = NULL; //&mediaTypes->MediaInfo[0]; // We alway return only one media type DDbgPrint(" IOCTL_STORAGE_GET_MEDIA_TYPES_EX\n"); if (outputLength < sizeof(GET_MEDIA_TYPES)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = 0; break; } mediaTypes = (PGET_MEDIA_TYPES)Irp->AssociatedIrp.SystemBuffer; ASSERT(mediaTypes != NULL); mediaInfo = &mediaTypes->MediaInfo[0]; mediaTypes->DeviceType = FILE_DEVICE_VIRTUAL_DISK; mediaTypes->MediaInfoCount = 1; PDISK_GEOMETRY diskGeometry = ExAllocatePool(sizeof(DISK_GEOMETRY)); if (diskGeometry == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } RtlZeroMemory(diskGeometry, sizeof(*diskGeometry)); DokanPopulateDiskGeometry(diskGeometry); mediaInfo->DeviceSpecific.DiskInfo.MediaType = diskGeometry->MediaType; mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1; mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE); mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = diskGeometry->Cylinders.QuadPart; mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = diskGeometry->TracksPerCylinder; mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = diskGeometry->SectorsPerTrack; mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = diskGeometry->BytesPerSector; ExFreePool(diskGeometry); status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(GET_MEDIA_TYPES); } break; case IOCTL_STORAGE_GET_DEVICE_NUMBER: { PSTORAGE_DEVICE_NUMBER deviceNumber; DDbgPrint(" IOCTL_STORAGE_GET_DEVICE_NUMBER\n"); if (outputLength < sizeof(STORAGE_DEVICE_NUMBER)) { status = STATUS_BUFFER_TOO_SMALL; Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); break; } deviceNumber = (PSTORAGE_DEVICE_NUMBER)Irp->AssociatedIrp.SystemBuffer; ASSERT(deviceNumber != NULL); deviceNumber->DeviceType = FILE_DEVICE_VIRTUAL_DISK; if (vcb) { deviceNumber->DeviceType = vcb->DeviceObject->DeviceType; } deviceNumber->DeviceNumber = 0; // Always one volume only per disk device deviceNumber->PartitionNumber = (ULONG)-1; // Not partitionable Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); status = STATUS_SUCCESS; } break; default: PrintUnknownDeviceIoctlCode( irpSp->Parameters.DeviceIoControl.IoControlCode); status = STATUS_INVALID_DEVICE_REQUEST; break; } DDbgPrint(" <= DokanDiskDeviceControl\n"); return 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: //Remove for Dokan 2.x.x DDbgPrint(" IOCTL_KEEPALIVE\n"); if (IsFlagOn(vcb->Flags, VCB_MOUNTED)) { ExEnterCriticalRegionAndAcquireResourceExclusive(&dcb->Resource); DokanUpdateTimeout(&dcb->TickCount, DOKAN_KEEPALIVE_TIMEOUT_DEFAULT); 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; }
NTSTATUS DokanDispatchFileSystemControl( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION irpSp; PDokanVCB vcb; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanFileSystemControl\n"); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { status = STATUS_INVALID_PARAMETER; __leave; } irpSp = IoGetCurrentIrpStackLocation(Irp); switch(irpSp->MinorFunction) { case IRP_MN_KERNEL_CALL: DDbgPrint(" IRP_MN_KERNEL_CALL\n"); break; case IRP_MN_LOAD_FILE_SYSTEM: DDbgPrint(" IRP_MN_LOAD_FILE_SYSTEM\n"); break; case IRP_MN_MOUNT_VOLUME: { PVPB vpb; DDbgPrint(" IRP_MN_MOUNT_VOLUME\n"); if (irpSp->Parameters.MountVolume.DeviceObject != vcb->Dcb->DeviceObject) { DDbgPrint(" Not DokanDiskDevice\n"); status = STATUS_INVALID_PARAMETER; } vpb = irpSp->Parameters.MountVolume.Vpb; vpb->DeviceObject = vcb->DeviceObject; vpb->RealDevice = vcb->DeviceObject; vpb->Flags |= VPB_MOUNTED; vpb->VolumeLabelLength = wcslen(VOLUME_LABEL) * sizeof(WCHAR); RtlStringCchCopyW(vpb->VolumeLabel, sizeof(vpb->VolumeLabel) / sizeof(WCHAR), VOLUME_LABEL); vpb->SerialNumber = 0x19831116; status = STATUS_SUCCESS; } break; case IRP_MN_USER_FS_REQUEST: DDbgPrint(" IRP_MN_USER_FS_REQUEST\n"); status = DokanUserFsRequest(DeviceObject, Irp); break; case IRP_MN_VERIFY_VOLUME: DDbgPrint(" IRP_MN_VERIFY_VOLUME\n"); break; default: DDbgPrint(" unknown %d\n", irpSp->MinorFunction); status = STATUS_INVALID_PARAMETER; break; } } __finally { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); DDbgPrint("<== DokanFileSystemControl\n"); FsRtlExitFileSystem(); } return status; }
// start event dispatching NTSTATUS DokanEventStart(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { ULONG outBufferLen; ULONG inBufferLen; PIO_STACK_LOCATION irpSp; EVENT_START eventStart; PEVENT_DRIVER_INFO driverInfo; PDOKAN_GLOBAL dokanGlobal; PDokanDCB dcb; NTSTATUS status; DEVICE_TYPE deviceType; ULONG deviceCharacteristics = 0; WCHAR baseGuidString[64]; GUID baseGuid = DOKAN_BASE_GUID; UNICODE_STRING unicodeGuid; ULONG deviceNamePos; BOOLEAN useMountManager = FALSE; BOOLEAN mountGlobally = TRUE; BOOLEAN fileLockUserMode = FALSE; 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; } 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; } if (eventStart.Flags & DOKAN_EVENT_WRITE_PROTECT) { DDbgPrint(" DeviceCharacteristics |= FILE_READ_ONLY_DEVICE\n"); deviceCharacteristics |= FILE_READ_ONLY_DEVICE; } if (eventStart.Flags & DOKAN_EVENT_MOUNT_MANAGER) { DDbgPrint(" Using Mount Manager\n"); useMountManager = TRUE; } if (eventStart.Flags & DOKAN_EVENT_CURRENT_SESSION) { DDbgPrint(" Mounting on current session only\n"); mountGlobally = FALSE; } if (eventStart.Flags & DOKAN_EVENT_FILELOCK_USER_MODE) { DDbgPrint(" FileLock in User Mode\n"); fileLockUserMode = TRUE; } KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&dokanGlobal->Resource, TRUE); DOKAN_CONTROL dokanControl; RtlZeroMemory(&dokanControl, sizeof(dokanControl)); RtlStringCchCopyW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH, L"\\DosDevices\\"); if (wcslen(eventStart.MountPoint) == 1) { dokanControl.MountPoint[12] = towupper(eventStart.MountPoint[0]); dokanControl.MountPoint[13] = L':'; dokanControl.MountPoint[14] = L'\0'; } else { RtlStringCchCatW(dokanControl.MountPoint, MAXIMUM_FILENAME_LENGTH, eventStart.MountPoint); } DDbgPrint(" Checking for MountPoint %ls \n", dokanControl.MountPoint); PMOUNT_ENTRY foundEntry = FindMountEntry(dokanGlobal, &dokanControl, FALSE); if (foundEntry != NULL) { DDbgPrint(" MountPoint exists already %ls \n", dokanControl.MountPoint); driverInfo->DriverVersion = DOKAN_DRIVER_VERSION; driverInfo->Status = DOKAN_START_FAILED; Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); return STATUS_SUCCESS; } baseGuid.Data2 = (USHORT)(dokanGlobal->MountId & 0xFFFF) ^ baseGuid.Data2; baseGuid.Data3 = (USHORT)(dokanGlobal->MountId >> 16) ^ baseGuid.Data3; status = RtlStringFromGUID(&baseGuid, &unicodeGuid); if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); return status; } RtlZeroMemory(baseGuidString, sizeof(baseGuidString)); RtlStringCchCopyW(baseGuidString, sizeof(baseGuidString) / sizeof(WCHAR), unicodeGuid.Buffer); RtlFreeUnicodeString(&unicodeGuid); InterlockedIncrement((LONG *)&dokanGlobal->MountId); status = DokanCreateDiskDevice( DeviceObject->DriverObject, dokanGlobal->MountId, eventStart.MountPoint, eventStart.UNCName, baseGuidString, dokanGlobal, deviceType, deviceCharacteristics, mountGlobally, useMountManager, &dcb); if (!NT_SUCCESS(status)) { ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); return status; } dcb->FileLockInUserMode = fileLockUserMode; 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])); // Set the irp timeout in milliseconds // If the IrpTimeout is 0, we assume that the value was not changed dcb->IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT; if (eventStart.IrpTimeout > 0) { if (eventStart.IrpTimeout > DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX) { eventStart.IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT_RESET_MAX; } if (eventStart.IrpTimeout < DOKAN_IRP_PENDING_TIMEOUT) { eventStart.IrpTimeout = DOKAN_IRP_PENDING_TIMEOUT; } dcb->IrpTimeout = eventStart.IrpTimeout; } DDbgPrint(" DeviceName:%ws\n", driverInfo->DeviceName); dcb->UseAltStream = 0; if (eventStart.Flags & DOKAN_EVENT_ALTERNATIVE_STREAM_ON) { DDbgPrint(" ALT_STREAM_ON\n"); dcb->UseAltStream = 1; } DokanStartEventNotificationThread(dcb); ExReleaseResourceLite(&dokanGlobal->Resource); KeLeaveCriticalRegion(); IoVerifyVolume(dcb->DeviceObject, FALSE); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof(EVENT_DRIVER_INFO); DDbgPrint("<== DokanEventStart\n"); return Irp->IoStatus.Status; }
NTSTATUS DokanDispatchSetInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PIO_STACK_LOCATION irpSp; PVOID buffer; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; ULONG eventLength; PFILE_OBJECT targetFileObject; PEVENT_CONTEXT eventContext; BOOLEAN isPagingIo = FALSE; BOOLEAN fcbLocked = FALSE; PFILE_END_OF_FILE_INFORMATION pInfoEoF = NULL; vcb = DeviceObject->DeviceExtension; __try { DDbgPrint("==> DokanSetInformationn\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } ccb = (PDokanCCB)fileObject->FsContext2; ASSERT(ccb != NULL); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); buffer = Irp->AssociatedIrp.SystemBuffer; if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } fcb = ccb->Fcb; ASSERT(fcb != NULL); switch (irpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: DDbgPrint( " FileAllocationInformation %lld\n", ((PFILE_ALLOCATION_INFORMATION)buffer)->AllocationSize.QuadPart); break; case FileBasicInformation: DDbgPrint(" FileBasicInformation\n"); break; case FileDispositionInformation: DDbgPrint(" FileDispositionInformation\n"); break; case FileEndOfFileInformation: if ((fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { pInfoEoF = (PFILE_END_OF_FILE_INFORMATION)buffer; if (!MmCanFileBeTruncated(fileObject->SectionObjectPointer, &pInfoEoF->EndOfFile)) { status = STATUS_USER_MAPPED_FILE; __leave; } if (!isPagingIo) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); ExReleaseResourceLite(&fcb->PagingIoResource); } } DDbgPrint(" FileEndOfFileInformation %lld\n", ((PFILE_END_OF_FILE_INFORMATION)buffer)->EndOfFile.QuadPart); break; case FileLinkInformation: DDbgPrint(" FileLinkInformation\n"); break; case FilePositionInformation: { PFILE_POSITION_INFORMATION posInfo; posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(posInfo != NULL); DDbgPrint(" FilePositionInformation %lld\n", posInfo->CurrentByteOffset.QuadPart); fileObject->CurrentByteOffset = posInfo->CurrentByteOffset; status = STATUS_SUCCESS; __leave; } break; case FileRenameInformation: DDbgPrint(" FileRenameInformation\n"); /* Flush any opened files before doing a rename * of the parent directory or the specific file */ targetFileObject = irpSp->Parameters.SetFile.FileObject; if (targetFileObject) { DDbgPrint(" FileRenameInformation targetFileObject specified so perform flush\n"); PDokanCCB targetCcb = (PDokanCCB)targetFileObject->FsContext2; ASSERT(targetCcb != NULL); FlushAllCachedFcb(targetCcb->Fcb, targetFileObject); } FlushAllCachedFcb(fcb, fileObject); break; case FileValidDataLengthInformation: DDbgPrint(" FileValidDataLengthInformation\n"); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass); break; } // // when this IRP is not handled in swich case // // calcurate the size of EVENT_CONTEXT // it is sum of file name length and size of FileInformation DokanFCBLockRW(fcb); fcbLocked = TRUE; eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length + irpSp->Parameters.SetFile.Length; targetFileObject = irpSp->Parameters.SetFile.FileObject; if (targetFileObject) { DDbgPrint(" FileObject Specified %wZ\n", &(targetFileObject->FileName)); eventLength += targetFileObject->FileName.Length; } eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; eventContext->Operation.SetFile.FileInformationClass = irpSp->Parameters.SetFile.FileInformationClass; // the size of FileInformation eventContext->Operation.SetFile.BufferLength = irpSp->Parameters.SetFile.Length; // the offset from begining of structure to fill FileInfo eventContext->Operation.SetFile.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, Operation.SetFile.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // the last null char BOOLEAN isRenameOrLink = irpSp->Parameters.SetFile.FileInformationClass == FileRenameInformation || irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation; if (!isRenameOrLink) { // copy FileInformation RtlCopyMemory( (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset, Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length); } if (isRenameOrLink) { // We need to hanle FileRenameInformation separetly because the structure // of FILE_RENAME_INFORMATION // has HANDLE type field, which size is different in 32 bit and 64 bit // environment. // This cases problems when driver is 64 bit and user mode library is 32 // bit. PFILE_RENAME_INFORMATION renameInfo = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; PDOKAN_RENAME_INFORMATION renameContext = (PDOKAN_RENAME_INFORMATION)( (PCHAR)eventContext + eventContext->Operation.SetFile.BufferOffset); // This code assumes FILE_RENAME_INFORMATION and FILE_LINK_INFORMATION // have // the same typse and fields. ASSERT(sizeof(FILE_RENAME_INFORMATION) == sizeof(FILE_LINK_INFORMATION)); renameContext->ReplaceIfExists = renameInfo->ReplaceIfExists; renameContext->FileNameLength = renameInfo->FileNameLength; RtlCopyMemory(renameContext->FileName, renameInfo->FileName, renameInfo->FileNameLength); if (targetFileObject != NULL) { // if Parameters.SetFile.FileObject is specified, replase // FILE_RENAME_INFO's file name by // FileObject's file name. The buffer size is already adjusted. DDbgPrint(" renameContext->FileNameLength %d\n", renameContext->FileNameLength); DDbgPrint(" renameContext->FileName %ws\n", renameContext->FileName); RtlZeroMemory(renameContext->FileName, renameContext->FileNameLength); PFILE_OBJECT parentFileObject = targetFileObject->RelatedFileObject; if (parentFileObject != NULL) { RtlCopyMemory(renameContext->FileName, parentFileObject->FileName.Buffer, parentFileObject->FileName.Length); RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, L"\\"); RtlStringCchCatW(renameContext->FileName, NTSTRSAFE_MAX_CCH, targetFileObject->FileName.Buffer); renameContext->FileNameLength = targetFileObject->FileName.Length + parentFileObject->FileName.Length + sizeof(WCHAR); } else { RtlCopyMemory(renameContext->FileName, targetFileObject->FileName.Buffer, targetFileObject->FileName.Length); renameContext->FileNameLength = targetFileObject->FileName.Length; } } if (irpSp->Parameters.SetFile.FileInformationClass == FileRenameInformation) { DDbgPrint(" rename: %wZ => %ls, FileCount = %u\n", fcb->FileName, renameContext->FileName, (ULONG)fcb->FileCount); } } // copy the file name eventContext->Operation.SetFile.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.SetFile.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanSetInformation\n"); } return status; }
// user assinged bigger buffer that is enough to return WriteEventContext NTSTATUS DokanEventWrite( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; PIRP writeIrp; eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); DDbgPrint("==> DokanEventWrite [EventInfo #%X]\n", eventInfo->SerialNumber); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&vcb->Dcb->PendingIrp.ListLock, &oldIrql); // search corresponding write IRP through pending IRP list listHead = &vcb->Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { PIO_STACK_LOCATION writeIrpSp, eventIrpSp; PEVENT_CONTEXT eventContext; ULONG info = 0; NTSTATUS status; nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); // check whehter this is corresponding IRP //DDbgPrint("SerialNumber irpEntry %X eventInfo %X\n", irpEntry->SerialNumber, eventInfo->SerialNumber); if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } // do NOT free irpEntry here writeIrp = irpEntry->Irp; if (writeIrp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); ExFreePool(irpEntry); continue; } if (IoSetCancelRoutine(writeIrp, DokanIrpCancelRoutine) == NULL) { //if (IoSetCancelRoutine(writeIrp, NULL) != NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; continue; } writeIrpSp = irpEntry->IrpSp; eventIrpSp = IoGetCurrentIrpStackLocation(Irp); ASSERT(writeIrpSp != NULL); ASSERT(eventIrpSp != NULL); eventContext = (PEVENT_CONTEXT)writeIrp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT]; ASSERT(eventContext != NULL); // short of buffer length if (eventIrpSp->Parameters.DeviceIoControl.OutputBufferLength < eventContext->Length) { DDbgPrint(" EventWrite: STATUS_INSUFFICIENT_RESOURCE\n"); status = STATUS_INSUFFICIENT_RESOURCES; } else { PVOID buffer; //DDbgPrint(" EventWrite CopyMemory\n"); //DDbgPrint(" EventLength %d, BufLength %d\n", eventContext->Length, // eventIrpSp->Parameters.DeviceIoControl.OutputBufferLength); if (Irp->MdlAddress) buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); else buffer = Irp->AssociatedIrp.SystemBuffer; ASSERT(buffer != NULL); RtlCopyMemory(buffer, eventContext, eventContext->Length); info = eventContext->Length; status = STATUS_SUCCESS; } DokanFreeEventContext(eventContext); writeIrp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; // this IRP will be completed by caller function return Irp->IoStatus.Status; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); return STATUS_SUCCESS; }
NTSTATUS DokanDispatchSetInformation( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PIO_STACK_LOCATION irpSp; PVOID buffer; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb; PDokanVCB vcb; ULONG eventLength; PFILE_OBJECT targetFileObject; PEVENT_CONTEXT eventContext; //PAGED_CODE(); vcb = DeviceObject->DeviceExtension; __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanSetInformationn\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } ccb = (PDokanCCB)fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); buffer = Irp->AssociatedIrp.SystemBuffer; switch (irpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: DDbgPrint(" FileAllocationInformation %lld\n", ((PFILE_ALLOCATION_INFORMATION)buffer)->AllocationSize.QuadPart); break; case FileBasicInformation: DDbgPrint(" FileBasicInformation\n"); break; case FileDispositionInformation: DDbgPrint(" FileDispositionInformation\n"); break; case FileEndOfFileInformation: DDbgPrint(" FileEndOfFileInformation %lld\n", ((PFILE_END_OF_FILE_INFORMATION)buffer)->EndOfFile.QuadPart); break; case FileLinkInformation: DDbgPrint(" FileLinkInformation\n"); break; case FilePositionInformation: { PFILE_POSITION_INFORMATION posInfo; posInfo = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(posInfo != NULL); DDbgPrint(" FilePositionInformation %lld\n", posInfo->CurrentByteOffset.QuadPart); fileObject->CurrentByteOffset = posInfo->CurrentByteOffset; status = STATUS_SUCCESS; __leave; } break; case FileRenameInformation: DDbgPrint(" FileRenameInformation\n"); break; case FileValidDataLengthInformation: DDbgPrint(" FileValidDataLengthInformation\n"); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass); break; } // // when this IRP is not handled in swich case // // calcurate the size of EVENT_CONTEXT // it is sum of file name length and size of FileInformation eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length + irpSp->Parameters.SetFile.Length; targetFileObject = irpSp->Parameters.SetFile.FileObject; if (targetFileObject) { DDbgPrint(" FileObject Specified %wZ\n", &(targetFileObject->FileName)); eventLength += targetFileObject->FileName.Length; } eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; eventContext->SetFile.FileInformationClass = irpSp->Parameters.SetFile.FileInformationClass; // the size of FileInformation eventContext->SetFile.BufferLength = irpSp->Parameters.SetFile.Length; // the offset from begining of structure to fill FileInfo eventContext->SetFile.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, SetFile.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // the last null char // copy FileInformation RtlCopyMemory((PCHAR)eventContext + eventContext->SetFile.BufferOffset, Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.SetFile.Length); if (irpSp->Parameters.SetFile.FileInformationClass == FileRenameInformation || irpSp->Parameters.SetFile.FileInformationClass == FileLinkInformation) { // We need to hanle FileRenameInformation separetly because the structure of FILE_RENAME_INFORMATION // has HANDLE type field, which size is different in 32 bit and 64 bit environment. // This cases problems when driver is 64 bit and user mode library is 32 bit. PFILE_RENAME_INFORMATION renameInfo = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; PDOKAN_RENAME_INFORMATION renameContext = (PDOKAN_RENAME_INFORMATION)((PCHAR)eventContext + eventContext->SetFile.BufferOffset); // This code assumes FILE_RENAME_INFORMATION and FILE_LINK_INFORMATION have // the same typse and fields. ASSERT(sizeof(FILE_RENAME_INFORMATION) == sizeof(FILE_LINK_INFORMATION)); renameContext->ReplaceIfExists = renameInfo->ReplaceIfExists; renameContext->FileNameLength = renameInfo->FileNameLength; RtlCopyMemory(renameContext->FileName, renameInfo->FileName, renameInfo->FileNameLength); if (targetFileObject != NULL) { // if Parameters.SetFile.FileObject is specified, replase FILE_RENAME_INFO's file name by // FileObject's file name. The buffer size is already adjusted. DDbgPrint(" renameContext->FileNameLength %d\n", renameContext->FileNameLength); DDbgPrint(" renameContext->FileName %ws\n", renameContext->FileName); RtlZeroMemory(renameContext->FileName, renameContext->FileNameLength); RtlCopyMemory(renameContext->FileName, targetFileObject->FileName.Buffer, targetFileObject->FileName.Length); renameContext->FileNameLength = targetFileObject->FileName.Length; } } // copy the file name eventContext->SetFile.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->SetFile.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanSetInformation\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS RegisterPendingIrpMain( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp, __in ULONG SerialNumber, __in PIRP_LIST IrpList, __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 = ExAllocatePool(sizeof(IRP_ENTRY)); if (NULL == irpEntry) { return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(irpEntry, sizeof(IRP_ENTRY)); InitializeListHead(&irpEntry->ListEntry); irpEntry->SerialNumber = SerialNumber; irpEntry->FileObject = irpSp->FileObject; irpEntry->Dcb = DeviceObject->DeviceExtension; irpEntry->Irp = Irp; irpEntry->IrpSp = irpSp; irpEntry->IrpList = IrpList; 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); ExFreePool(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;; }
NTSTATUS DokanDispatchWrite( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; NTSTATUS status =STATUS_INVALID_PARAMETER; PEVENT_CONTEXT eventContext; ULONG eventLength; PDokanCCB ccb; PDokanFCB fcb; PDokanVCB vcb; PVOID buffer; ULONG bufferLength; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanWrite"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL"); status = STATUS_INVALID_PARAMETER; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (fcb->Flags & DOKAN_FILE_DIRECTORY) { status = STATUS_INVALID_PARAMETER; __leave; } if (irpSp->Parameters.Write.Length == 0) { status = STATUS_SUCCESS; __leave; } if (Irp->MdlAddress) { DDbgPrint(" use MdlAddress"); buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); } else { DDbgPrint(" use UserBuffer"); buffer = Irp->UserBuffer; } if (buffer == NULL) { DDbgPrint(" buffer == NULL"); status = STATUS_INVALID_PARAMETER; __leave; } // the length of EventContext is sum of length to write and length of file name eventLength = sizeof(EVENT_CONTEXT) + irpSp->Parameters.Write.Length + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); // no more memory! if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // When the length is bigger than usual event notitfication buffer, // saves pointer in DiverContext to copy EventContext after allocating // more bigger memory. Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = eventContext; if (Irp->Flags & IRP_PAGING_IO) { DDbgPrint(" Paging IO"); eventContext->FileFlags |= DOKAN_PAGING_IO; } if (fileObject->Flags & FO_SYNCHRONOUS_IO) { DDbgPrint(" Synchronous IO"); eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO; } // offset of file to write eventContext->Write.ByteOffset = irpSp->Parameters.Write.ByteOffset; if (irpSp->Parameters.Write.ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1) { eventContext->FileFlags |= DOKAN_WRITE_TO_END_OF_FILE; DDbgPrint(" WriteOffset = end of file"); } if ((fileObject->Flags & FO_SYNCHRONOUS_IO) && ((irpSp->Parameters.Write.ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION) && (irpSp->Parameters.Write.ByteOffset.HighPart == -1))) { // NOTE: // http://msdn.microsoft.com/en-us/library/ms795960.aspx // Do not check IrpSp->Parameters.Write.ByteOffset.QuadPart == 0 // Probably the document is wrong. eventContext->Write.ByteOffset.QuadPart = fileObject->CurrentByteOffset.QuadPart; } // the size of buffer to write eventContext->Write.BufferLength = irpSp->Parameters.Write.Length; // the offset from the begining of structure // the contents to write will be copyed to this offset eventContext->Write.BufferOffset = FIELD_OFFSET(EVENT_CONTEXT, Write.FileName[0]) + fcb->FileName.Length + sizeof(WCHAR); // adds last null char // copies the content to write to EventContext RtlCopyMemory((PCHAR)eventContext + eventContext->Write.BufferOffset, buffer, irpSp->Parameters.Write.Length); // copies file name eventContext->Write.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Write.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // When eventlength is less than event notification buffer, // returns it to user-mode using pending event. if (eventLength <= EVENT_CONTEXT_MAX_SIZE) { DDbgPrint(" Offset %d:%d, Length %d\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // EventContext is no longer needed, clear it Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; // register this IRP to IRP waiting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); // Resuests bigger memory // eventContext will be freed later using Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] } else { // the length at lest file name can be stored ULONG requestContextLength = max(sizeof(EVENT_CONTEXT), eventContext->Write.BufferOffset); PEVENT_CONTEXT requestContext = AllocateEventContext(vcb->Dcb, Irp, requestContextLength, ccb); // no more memory! if (requestContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = 0; DokanFreeEventContext(eventContext); __leave; } DDbgPrint(" Offset %d:%d, Length %d (request)\n", irpSp->Parameters.Write.ByteOffset.HighPart, irpSp->Parameters.Write.ByteOffset.LowPart, irpSp->Parameters.Write.Length); // copies from begining of EventContext to the end of file name RtlCopyMemory(requestContext, eventContext, eventContext->Write.BufferOffset); // puts actual size of RequestContext requestContext->Length = requestContextLength; // requsts enough size to copy EventContext requestContext->Write.RequestLength = eventLength; // regiters this IRP to IRP wainting list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, requestContext, 0); } } __finally { // if status of IRP is not pending, must complete current IRP if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } else { DDbgPrint(" STATUS_PENDING"); } DDbgPrint("<== DokanWrite"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanDispatchCleanup(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles Cleanup IRP. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb = NULL; PDokanFCB fcb = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; DOKAN_INIT_LOGGER(logger, DeviceObject->DriverObject, IRP_MJ_CLEANUP); __try { DDbgPrint("==> DokanCleanup\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); // Cleanup must be success in any case if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (vcb == NULL) { DDbgPrint(" No device extension\n"); status = STATUS_SUCCESS; __leave; } if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (fcb->IsKeepalive) { DokanFCBLockRW(fcb); BOOLEAN shouldUnmount = ccb->IsKeepaliveActive; if (shouldUnmount) { // Here we intentionally let the VCB-level flag stay set, because // there's no sense in having an opportunity for an "operation timeout // unmount" in this case. ccb->IsKeepaliveActive = FALSE; } DokanFCBUnlock(fcb); if (shouldUnmount) { if (IsUnmountPendingVcb(vcb)) { DokanLogInfo(&logger, L"Ignoring keepalive close because unmount is already in" L" progress."); } else { DokanLogInfo(&logger, L"Unmounting due to keepalive close."); DokanUnmount(vcb->Dcb); } } } if (fcb->BlockUserModeDispatch) { status = STATUS_SUCCESS; __leave; } FlushFcb(fcb, fileObject); DokanFCBLockRW(fcb); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; DokanFCBUnlock(fcb); __leave; } fileObject->Flags |= FO_CLEANUP_COMPLETE; eventContext->Context = ccb->UserContext; eventContext->FileFlags |= DokanCCBFlagsGet(ccb); // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy the filename to EventContext from ccb eventContext->Operation.Cleanup.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Cleanup.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); DokanFCBUnlock(fcb); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } // register this IRP to pending IRP list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanCleanup\n"); } return status; }
NTSTATUS DokanDispatchCleanup(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles Cleanup IRP. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb = NULL; PDokanFCB fcb = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; __try { DDbgPrint("==> DokanCleanup\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); // Cleanup must be success in any case if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (vcb == NULL) { DDbgPrint(" No device extension\n"); status = STATUS_SUCCESS; __leave; } if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); FlushFcb(fcb, fileObject); DokanFCBLockRW(fcb); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; DokanFCBUnlock(fcb); __leave; } fileObject->Flags |= FO_CLEANUP_COMPLETE; eventContext->Context = ccb->UserContext; eventContext->FileFlags |= DokanCCBFlagsGet(ccb); // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy the filename to EventContext from ccb eventContext->Operation.Cleanup.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Cleanup.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // FsRtlCheckOpLock is called with non-NULL completion routine - not blocking. status = FsRtlCheckOplock(DokanGetFcbOplock(fcb), Irp, eventContext, DokanOplockComplete, DokanPrePostIrp); DokanFCBUnlock(fcb); // // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted // to service an oplock break and we need to leave now. // if (status != STATUS_SUCCESS) { if (status == STATUS_PENDING) { DDbgPrint(" FsRtlCheckOplock returned STATUS_PENDING\n"); } else { DokanFreeEventContext(eventContext); } __leave; } // register this IRP to pending IRP list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanCleanup\n"); } return status; }
NTSTATUS DokanDispatchCreate( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) /*++ Routine Description: This device control dispatcher handles create & close IRPs. 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_INVALID_PARAMETER; PFILE_OBJECT fileObject; ULONG info = 0; PEPROCESS process; PUNICODE_STRING processImageName; PEVENT_CONTEXT eventContext; PFILE_OBJECT relatedFileObject; ULONG fileNameLength = 0; ULONG eventLength; PDokanFCB fcb; PDokanCCB ccb; PWCHAR fileName; BOOLEAN needBackSlashAfterRelatedFile = FALSE; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanCreate\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; relatedFileObject = fileObject->RelatedFileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DDbgPrint(" FileName:%wZ\n", &fileObject->FileName); vcb = DeviceObject->DeviceExtension; PrintIdType(vcb); if (GetIdentifierType(vcb) != VCB) { status = STATUS_SUCCESS; __leave; } dcb = vcb->Dcb; DDbgPrint(" IrpSp->Flags = %d\n", irpSp->Flags); if (irpSp->Flags & SL_CASE_SENSITIVE) { DDbgPrint(" IrpSp->Flags SL_CASE_SENSITIVE\n"); } if (irpSp->Flags & SL_FORCE_ACCESS_CHECK) { DDbgPrint(" IrpSp->Flags SL_FORCE_ACCESS_CHECK\n"); } if (irpSp->Flags & SL_OPEN_PAGING_FILE) { DDbgPrint(" IrpSp->Flags SL_OPEN_PAGING_FILE\n"); } if (irpSp->Flags & SL_OPEN_TARGET_DIRECTORY) { DDbgPrint(" IrpSp->Flags SL_OPEN_TARGET_DIRECTORY\n"); } if ((fileObject->FileName.Length > sizeof(WCHAR)) && (fileObject->FileName.Buffer[1] == L'\\') && (fileObject->FileName.Buffer[0] == L'\\')) { fileObject->FileName.Length -= sizeof(WCHAR); RtlMoveMemory(&fileObject->FileName.Buffer[0], &fileObject->FileName.Buffer[1], fileObject->FileName.Length); } if (relatedFileObject != NULL) { fileObject->Vpb = relatedFileObject->Vpb; } else { fileObject->Vpb = dcb->DeviceObject->Vpb; } if (relatedFileObject == NULL && fileObject->FileName.Length == 0) { DDbgPrint(" request for FS device\n"); if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) { status = STATUS_NOT_A_DIRECTORY; } else { SetFileObjectForVCB(fileObject, vcb); info = FILE_OPENED; status = STATUS_SUCCESS; } __leave; } if (fileObject->FileName.Length > sizeof(WCHAR) && fileObject->FileName.Buffer[fileObject->FileName.Length/sizeof(WCHAR)-1] == L'\\') { fileObject->FileName.Length -= sizeof(WCHAR); } fileNameLength = fileObject->FileName.Length; if (relatedFileObject) { fileNameLength += relatedFileObject->FileName.Length; if (fileObject->FileName.Length > 0 && fileObject->FileName.Buffer[0] == '\\') { DDbgPrint(" when RelatedFileObject is specified, the file name should be relative path\n"); status = STATUS_OBJECT_NAME_INVALID; __leave; } if (relatedFileObject->FileName.Length > 0 && relatedFileObject->FileName.Buffer[relatedFileObject->FileName.Length/sizeof(WCHAR)-1] != '\\') { needBackSlashAfterRelatedFile = TRUE; fileNameLength += sizeof(WCHAR); } } // don't open file like stream if (!dcb->UseAltStream && DokanUnicodeStringChar(&fileObject->FileName, L':') != -1) { DDbgPrint(" alternate stream\n"); status = STATUS_INVALID_PARAMETER; info = 0; __leave; } // this memory is freed by DokanGetFCB if needed // "+ sizeof(WCHAR)" is for the last NULL character fileName = ExAllocatePool(fileNameLength + sizeof(WCHAR)); if (fileName == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } RtlZeroMemory(fileName, fileNameLength + sizeof(WCHAR)); if (relatedFileObject != NULL) { DDbgPrint(" RelatedFileName:%wZ\n", &relatedFileObject->FileName); // copy the file name of related file object RtlCopyMemory(fileName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length); if (needBackSlashAfterRelatedFile) { ((PWCHAR)fileName)[relatedFileObject->FileName.Length/sizeof(WCHAR)] = '\\'; } // copy the file name of fileObject RtlCopyMemory((PCHAR)fileName + relatedFileObject->FileName.Length + (needBackSlashAfterRelatedFile? sizeof(WCHAR) : 0), fileObject->FileName.Buffer, fileObject->FileName.Length); } else { // if related file object is not specifed, copy the file name of file object RtlCopyMemory(fileName, fileObject->FileName.Buffer, fileObject->FileName.Length); } fcb = DokanGetFCB(vcb, fileName, fileNameLength); if (fcb == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (irpSp->Flags & SL_OPEN_PAGING_FILE) { fcb->AdvancedFCBHeader.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE; fcb->AdvancedFCBHeader.Flags2 &= ~FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS; } ccb = DokanAllocateCCB(dcb, fcb); if (ccb == NULL) { DokanFreeFCB(fcb); // FileName is freed here status = STATUS_INSUFFICIENT_RESOURCES; __leave; } fileObject->FsContext = &fcb->AdvancedFCBHeader; fileObject->FsContext2 = ccb; fileObject->PrivateCacheMap = NULL; fileObject->SectionObjectPointer = &fcb->SectionObjectPointers; //fileObject->Flags |= FILE_NO_INTERMEDIATE_BUFFERING; eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = 0; eventContext->FileFlags |= fcb->Flags; // copy the file name eventContext->Create.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Create.FileName, fcb->FileName.Buffer, fcb->FileName.Length); eventContext->Create.FileAttributes = irpSp->Parameters.Create.FileAttributes; eventContext->Create.CreateOptions = irpSp->Parameters.Create.Options; eventContext->Create.DesiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess; eventContext->Create.ShareAccess = irpSp->Parameters.Create.ShareAccess; // register this IRP to waiting IPR list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanCreate\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanDispatchQueryVolumeInformation(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { NTSTATUS status = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION irpSp; PVOID buffer; PFILE_OBJECT fileObject; PDokanVCB vcb; PDokanDCB dcb; PDokanCCB ccb; ULONG info = 0; ULONG RequiredLength; __try { DDbgPrint("==> DokanQueryVolumeInformation\n"); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } dcb = vcb->Dcb; if (!dcb->Mounted) { status = STATUS_VOLUME_DISMOUNTED; __leave; } irpSp = IoGetCurrentIrpStackLocation(Irp); buffer = Irp->AssociatedIrp.SystemBuffer; fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" FileName: %wZ\n", &fileObject->FileName); ccb = fileObject->FsContext2; // ASSERT(ccb != NULL); switch (irpSp->Parameters.QueryVolume.FsInformationClass) { case FileFsVolumeInformation: DDbgPrint(" FileFsVolumeInformation\n"); if (vcb->HasEventWait) { break; } DDbgPrint(" Still no threads for processing available\n"); PFILE_FS_VOLUME_INFORMATION FsVolInfo; ULONG VolumeLabelLength; if (irpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION)) { status = STATUS_BUFFER_OVERFLOW; __leave; } FsVolInfo = (PFILE_FS_VOLUME_INFORMATION)buffer; FsVolInfo->VolumeCreationTime.QuadPart = 0; FsVolInfo->VolumeSerialNumber = 0x19831116; VolumeLabelLength = (USHORT)wcslen(VOLUME_LABEL) * sizeof(WCHAR); FsVolInfo->VolumeLabelLength = VolumeLabelLength; /* We don't support ObjectId */ FsVolInfo->SupportsObjects = FALSE; RequiredLength = sizeof(FILE_FS_VOLUME_INFORMATION) + VolumeLabelLength - sizeof(WCHAR); if (irpSp->Parameters.QueryVolume.Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_VOLUME_INFORMATION); status = STATUS_BUFFER_OVERFLOW; __leave; } RtlCopyMemory(FsVolInfo->VolumeLabel, L"DOKAN", VolumeLabelLength); Irp->IoStatus.Information = RequiredLength; status = STATUS_SUCCESS; __leave; break; case FileFsLabelInformation: DDbgPrint(" FileFsLabelInformation\n"); break; case FileFsSizeInformation: DDbgPrint(" FileFsSizeInformation\n"); break; case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION device; DDbgPrint(" FileFsDeviceInformation\n"); device = (PFILE_FS_DEVICE_INFORMATION)Irp->AssociatedIrp.SystemBuffer; if (irpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { status = STATUS_BUFFER_TOO_SMALL; info = sizeof(FILE_FS_DEVICE_INFORMATION); __leave; } device->DeviceType = dcb->DeviceType; device->Characteristics = dcb->DeviceCharacteristics; status = STATUS_SUCCESS; info = sizeof(FILE_FS_DEVICE_INFORMATION); __leave; } break; case FileFsAttributeInformation: DDbgPrint(" FileFsAttributeInformation\n"); if (vcb->HasEventWait) { break; } DDbgPrint(" Still no threads for processing available\n"); PFILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo; if (irpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION)) { status = STATUS_BUFFER_OVERFLOW; __leave; } FsAttrInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Irp->AssociatedIrp.SystemBuffer; FsAttrInfo->FileSystemAttributes = FILE_SUPPORTS_HARD_LINKS | FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES; FsAttrInfo->MaximumComponentNameLength = 256; FsAttrInfo->FileSystemNameLength = 8; RequiredLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8 - sizeof(WCHAR); if (irpSp->Parameters.QueryVolume.Length < RequiredLength) { Irp->IoStatus.Information = sizeof(FILE_FS_ATTRIBUTE_INFORMATION); status = STATUS_BUFFER_OVERFLOW; __leave; } RtlCopyMemory(FsAttrInfo->FileSystemName, L"Dokan\0", 10); Irp->IoStatus.Information = RequiredLength; status = STATUS_SUCCESS; __leave; break; case FileFsControlInformation: DDbgPrint(" FileFsControlInformation\n"); break; case FileFsFullSizeInformation: DDbgPrint(" FileFsFullSizeInformation\n"); break; case FileFsObjectIdInformation: DDbgPrint(" FileFsObjectIdInformation\n"); break; case FileFsMaximumInformation: DDbgPrint(" FileFsMaximumInformation\n"); break; default: break; } if (irpSp->Parameters.QueryVolume.FsInformationClass == FileFsVolumeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsSizeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsAttributeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsFullSizeInformation) { ULONG eventLength = sizeof(EVENT_CONTEXT); PEVENT_CONTEXT eventContext; if (ccb && !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } // this memory must be freed in this {} eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, NULL); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (ccb) { eventContext->Context = ccb->UserContext; eventContext->FileFlags = ccb->Flags; // DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); } eventContext->Operation.Volume.FsInformationClass = irpSp->Parameters.QueryVolume.FsInformationClass; // the length which can be returned to user-mode eventContext->Operation.Volume.BufferLength = irpSp->Parameters.QueryVolume.Length; status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } } __finally { DokanCompleteIrpRequest(Irp, status, info); DDbgPrint("<== DokanQueryVolumeInformation\n"); } return status; }
NTSTATUS DokanDispatchLock(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb; PDokanFCB fcb; PDokanVCB vcb; PEVENT_CONTEXT eventContext; ULONG eventLength; __try { DDbgPrint("==> DokanLock\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); switch (irpSp->MinorFunction) { case IRP_MN_LOCK: DDbgPrint(" IRP_MN_LOCK\n"); break; case IRP_MN_UNLOCK_ALL: DDbgPrint(" IRP_MN_UNLOCK_ALL\n"); break; case IRP_MN_UNLOCK_ALL_BY_KEY: DDbgPrint(" IRP_MN_UNLOCK_ALL_BY_KEY\n"); break; case IRP_MN_UNLOCK_SINGLE: DDbgPrint(" IRP_MN_UNLOCK_SINGLE\n"); break; default: DDbgPrint(" unknown function : %d\n", irpSp->MinorFunction); break; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = ccb->UserContext; DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy file name to be locked eventContext->Operation.Lock.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Lock.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // parameters of Lock eventContext->Operation.Lock.ByteOffset = irpSp->Parameters.LockControl.ByteOffset; if (irpSp->Parameters.LockControl.Length != NULL) { eventContext->Operation.Lock.Length.QuadPart = irpSp->Parameters.LockControl.Length->QuadPart; } else { DDbgPrint(" LockControl.Length = NULL\n"); } eventContext->Operation.Lock.Key = irpSp->Parameters.LockControl.Key; // register this IRP to waiting IRP list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanLock\n"); } return status; }
NTSTATUS DokanEventRelease(__in PDEVICE_OBJECT DeviceObject) { PDokanDCB dcb; PDokanVCB vcb; PDokanFCB fcb; PDokanCCB ccb; PLIST_ENTRY fcbEntry, fcbNext, fcbHead; PLIST_ENTRY ccbEntry, ccbNext, ccbHead; NTSTATUS status = STATUS_SUCCESS; DDbgPrint("==> DokanEventRelease\n"); if (DeviceObject == NULL) { return STATUS_INVALID_PARAMETER; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } dcb = vcb->Dcb; DokanDeleteMountPoint(dcb); // ExAcquireResourceExclusiveLite(&dcb->Resource, TRUE); dcb->Mounted = 0; // ExReleaseResourceLite(&dcb->Resource); // search CCB list to complete not completed Directory Notification KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&vcb->Resource, TRUE); fcbHead = &vcb->NextFCB; for (fcbEntry = fcbHead->Flink; fcbEntry != fcbHead; fcbEntry = fcbNext) { fcbNext = fcbEntry->Flink; fcb = CONTAINING_RECORD(fcbEntry, DokanFCB, NextFCB); ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE); ccbHead = &fcb->NextCCB; for (ccbEntry = ccbHead->Flink; ccbEntry != ccbHead; ccbEntry = ccbNext) { ccbNext = ccbEntry->Flink; ccb = CONTAINING_RECORD(ccbEntry, DokanCCB, NextCCB); DDbgPrint(" NotifyCleanup ccb:%p, context:%X, filename:%wZ\n", ccb, (ULONG)ccb->UserContext, &fcb->FileName); FsRtlNotifyCleanup(vcb->NotifySync, &vcb->DirNotifyList, ccb); } ExReleaseResourceLite(&fcb->Resource); } ExReleaseResourceLite(&vcb->Resource); KeLeaveCriticalRegion(); ReleasePendingIrp(&dcb->PendingIrp); ReleasePendingIrp(&dcb->PendingEvent); DokanStopCheckThread(dcb); DokanStopEventNotificationThread(dcb); DokanDeleteDeviceObject(dcb); DDbgPrint("<== DokanEventRelease\n"); return status; }
NTSTATUS DokanDispatchDirectoryControl( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_NOT_IMPLEMENTED; PFILE_OBJECT fileObject; PIO_STACK_LOCATION irpSp; PDokanCCB ccb; PDokanVCB vcb; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanDirectoryControl"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" failed fileObject is NULL"); status = STATUS_INVALID_PARAMETER; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); if (irpSp->MinorFunction == IRP_MN_QUERY_DIRECTORY) { status = DokanQueryDirectory(DeviceObject, Irp); } else if( irpSp->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) { status = DokanNotifyChangeDirectory(DeviceObject, Irp); } else { DDbgPrint(" invalid minor function"); status = STATUS_INVALID_PARAMETER; } } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } DokanPrintNTStatus(status); DDbgPrint("<== DokanDirectoryControl"); FsRtlExitFileSystem(); } return status; }
// When user-mode file system application returns EventInformation, // search corresponding pending IRP and complete it NTSTATUS DokanCompleteIrp( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); //DDbgPrint("==> DokanCompleteIrp [EventInfo #%X]\n", eventInfo->SerialNumber); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } //DDbgPrint(" Lock IrpList.ListLock\n"); 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); // check whether this is corresponding IRP //DDbgPrint("SerialNumber irpEntry %X eventInfo %X\n", irpEntry->SerialNumber, eventInfo->SerialNumber); // this irpEntry must be freed in this if statement if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } RemoveEntryList(thisEntry); irp = irpEntry->Irp; if (irp == NULL) { // this IRP is already canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); ExFreePool(irpEntry); irpEntry = NULL; break; } if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; break; } // IRP is not canceled yet irpSp = irpEntry->IrpSp; ASSERT(irpSp != NULL); // IrpEntry is saved here for CancelRoutine // Clear it to prevent to be completed by CancelRoutine twice irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = NULL; KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); switch (irpSp->MajorFunction) { case IRP_MJ_DIRECTORY_CONTROL: DokanCompleteDirectoryControl(irpEntry, eventInfo); break; case IRP_MJ_READ: DokanCompleteRead(irpEntry, eventInfo); break; case IRP_MJ_WRITE: DokanCompleteWrite(irpEntry, eventInfo); break; case IRP_MJ_QUERY_INFORMATION: DokanCompleteQueryInformation(irpEntry, eventInfo); break; case IRP_MJ_QUERY_VOLUME_INFORMATION: DokanCompleteQueryVolumeInformation(irpEntry, eventInfo); break; case IRP_MJ_CREATE: DokanCompleteCreate(irpEntry, eventInfo); break; case IRP_MJ_CLEANUP: DokanCompleteCleanup(irpEntry, eventInfo); break; case IRP_MJ_LOCK_CONTROL: DokanCompleteLock(irpEntry, eventInfo); break; case IRP_MJ_SET_INFORMATION: DokanCompleteSetInformation(irpEntry, eventInfo); break; case IRP_MJ_FLUSH_BUFFERS: DokanCompleteFlush(irpEntry, eventInfo); break; default: DDbgPrint("Unknown IRP %d\n", irpSp->MajorFunction); // TODO: in this case, should complete this IRP break; } ExFreePool(irpEntry); irpEntry = NULL; return STATUS_SUCCESS; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); //DDbgPrint("<== AACompleteIrp [EventInfo #%X]\n", eventInfo->SerialNumber); // TODO: should return error return STATUS_SUCCESS; }
NTSTATUS DokanDispatchCleanup( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) /*++ Routine Description: This device control dispatcher handles Cleanup IRP. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; PDokanCCB ccb = NULL; PDokanFCB fcb = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanCleanup\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); // Cleanup must be success in any case if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_SUCCESS; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB || !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_SUCCESS; __leave; } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (fileObject->SectionObjectPointer != NULL && fileObject->SectionObjectPointer->DataSectionObject != NULL) { CcFlushCache(&fcb->SectionObjectPointers, NULL, 0, NULL); CcPurgeCacheSection(&fcb->SectionObjectPointers, NULL, 0, FALSE); CcUninitializeCacheMap(fileObject, NULL, NULL); } fileObject->Flags |= FO_CLEANUP_COMPLETE; eventContext->Context = ccb->UserContext; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); // copy the filename to EventContext from ccb eventContext->Cleanup.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Cleanup.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to pending IRP list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanCleanup\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanDispatchQueryVolumeInformation( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { NTSTATUS status = STATUS_INVALID_PARAMETER; PIO_STACK_LOCATION irpSp; PVOID buffer; PFILE_OBJECT fileObject; PDokanVCB vcb; PDokanDCB dcb; PDokanCCB ccb; ULONG info = 0; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanQueryVolumeInformation"); DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } dcb = vcb->Dcb; irpSp = IoGetCurrentIrpStackLocation(Irp); buffer = Irp->AssociatedIrp.SystemBuffer; fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL"); status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" FileName: %wZ\n", &fileObject->FileName); ccb = fileObject->FsContext2; // ASSERT(ccb != NULL); switch(irpSp->Parameters.QueryVolume.FsInformationClass) { case FileFsVolumeInformation: DDbgPrint(" FileFsVolumeInformation"); break; case FileFsLabelInformation: DDbgPrint(" FileFsLabelInformation"); break; case FileFsSizeInformation: DDbgPrint(" FileFsSizeInformation"); break; case FileFsDeviceInformation: { PFILE_FS_DEVICE_INFORMATION device; DDbgPrint(" FileFsDeviceInformation"); device = (PFILE_FS_DEVICE_INFORMATION)Irp->AssociatedIrp.SystemBuffer; if (irpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_DEVICE_INFORMATION)) { status = STATUS_BUFFER_TOO_SMALL; info = sizeof(FILE_FS_DEVICE_INFORMATION); __leave; } device->DeviceType = FILE_DEVICE_DISK;//dcb->DeviceType; device->Characteristics = dcb->DeviceCharacteristics; status = STATUS_SUCCESS; info = sizeof(FILE_FS_DEVICE_INFORMATION); __leave; } break; case FileFsAttributeInformation: DDbgPrint(" FileFsAttributeInformation"); break; case FileFsControlInformation: DDbgPrint(" FileFsControlInformation"); break; case FileFsFullSizeInformation: DDbgPrint(" FileFsFullSizeInformation"); break; case FileFsObjectIdInformation: DDbgPrint(" FileFsObjectIdInformation"); break; case FileFsMaximumInformation: DDbgPrint(" FileFsMaximumInformation"); break; default: break; } if (irpSp->Parameters.QueryVolume.FsInformationClass == FileFsVolumeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsSizeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsAttributeInformation || irpSp->Parameters.QueryVolume.FsInformationClass == FileFsFullSizeInformation) { ULONG eventLength = sizeof(EVENT_CONTEXT); PEVENT_CONTEXT eventContext; if (ccb && !DokanCheckCCB(vcb->Dcb, fileObject->FsContext2)) { status = STATUS_INVALID_PARAMETER; __leave; } // this memory must be freed in this {} eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, NULL); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (ccb) { eventContext->Context = ccb->UserContext; eventContext->FileFlags = ccb->Flags; //DDbgPrint(" get Context %X\n", (ULONG)ccb->UserContext); } eventContext->Volume.FsInformationClass = irpSp->Parameters.QueryVolume.FsInformationClass; // the length which can be returned to user-mode eventContext->Volume.BufferLength = irpSp->Parameters.QueryVolume.Length; status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanQueryVolumeInformation"); FsRtlExitFileSystem(); } return status; }