// user assinged bigger buffer that is enough to return WriteEventContext NTSTATUS DokanEventWrite(__in PDEVICE_OBJECT DeviceObject, _Inout_ 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); DokanFreeIrpEntry(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 = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress); 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 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 DokanDispatchRead(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) /*++ Routine Description: This device control dispatcher handles read IRPs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PIO_STACK_LOCATION irpSp; PFILE_OBJECT fileObject; ULONG bufferLength; LARGE_INTEGER byteOffset; NTSTATUS status = STATUS_INVALID_PARAMETER; ULONG readLength = 0; PDokanCCB ccb; PDokanFCB fcb = NULL; PDokanVCB vcb; PVOID currentAddress = NULL; PEVENT_CONTEXT eventContext; ULONG eventLength; BOOLEAN fcbLocked = FALSE; BOOLEAN isPagingIo = FALSE; BOOLEAN isSynchronousIo = FALSE; BOOLEAN noCache = FALSE; __try { DDbgPrint("==> DokanRead\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; // // If this is a zero length read then return SUCCESS immediately. // if (irpSp->Parameters.Read.Length == 0) { DDbgPrint(" Parameters.Read.Length == 0 \n"); Irp->IoStatus.Information = 0; status = STATUS_SUCCESS; __leave; } if (irpSp->MinorFunction == IRP_MN_COMPLETE) { Irp->MdlAddress = NULL; status = STATUS_SUCCESS; __leave; } if (fileObject == NULL && Irp->MdlAddress != NULL) { DDbgPrint(" Reads by File System Recognizers\n"); currentAddress = MmGetSystemAddressForMdlNormalSafe(Irp->MdlAddress); if (currentAddress == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } // here we could return the bootsector. If we don't have one // the requested read lenght must be returned as requested readLength = irpSp->Parameters.Read.Length; 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_DEVICE_REQUEST; __leave; } bufferLength = irpSp->Parameters.Read.Length; if (irpSp->Parameters.Read.ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION && irpSp->Parameters.Read.ByteOffset.HighPart == -1) { // irpSp->Parameters.Read.ByteOffset == NULL don't need check? DDbgPrint("use FileObject ByteOffset\n"); byteOffset = fileObject->CurrentByteOffset; } else { byteOffset = irpSp->Parameters.Read.ByteOffset; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); DDbgPrint(" ByteCount:%lu ByteOffset:%I64d\n", bufferLength, byteOffset.QuadPart); if (bufferLength == 0) { status = STATUS_SUCCESS; readLength = 0; __leave; } // make a MDL for UserBuffer that can be used later on another thread // context if (Irp->MdlAddress == NULL) { status = DokanAllocateMdl(Irp, irpSp->Parameters.Read.Length); if (!NT_SUCCESS(status)) { __leave; } } ccb = fileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { DDbgPrint(" DOKAN_FILE_DIRECTORY %p\n", fcb); status = STATUS_INVALID_PARAMETER; __leave; } if (Irp->Flags & IRP_PAGING_IO) { isPagingIo = TRUE; } if (fileObject->Flags & FO_SYNCHRONOUS_IO) { isSynchronousIo = TRUE; } if (Irp->Flags & IRP_NOCACHE) { noCache = TRUE; } if (!isPagingIo && (fileObject->SectionObjectPointer != NULL) && (fileObject->SectionObjectPointer->DataSectionObject != NULL)) { ExAcquireResourceExclusiveLite(&fcb->PagingIoResource, TRUE); CcFlushCache(&fcb->SectionObjectPointers, &irpSp->Parameters.Read.ByteOffset, irpSp->Parameters.Read.Length, NULL); ExReleaseResourceLite(&fcb->PagingIoResource); } DokanFCBLockRO(fcb); fcbLocked = TRUE; // length of EventContext is sum of file name length and itself 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); if (isPagingIo) { DDbgPrint(" Paging IO\n"); eventContext->FileFlags |= DOKAN_PAGING_IO; } if (isSynchronousIo) { DDbgPrint(" Synchronous IO\n"); eventContext->FileFlags |= DOKAN_SYNCHRONOUS_IO; } if (noCache) { DDbgPrint(" Nocache\n"); eventContext->FileFlags |= DOKAN_NOCACHE; } // offset of file to read eventContext->Operation.Read.ByteOffset = byteOffset; // buffer size for read // user-mode file system application can return this size eventContext->Operation.Read.BufferLength = irpSp->Parameters.Read.Length; // copy the accessed file name eventContext->Operation.Read.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Read.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // // We now check whether we can proceed based on the state of // the file oplocks. // if (!FlagOn(Irp->Flags, IRP_PAGING_IO)) { // 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; } // // We have to check for read access according to the current // state of the file locks, and set FileSize from the Fcb. // // FsRtlCheckLockForReadAccess does not block. if (!FsRtlCheckLockForReadAccess(&fcb->FileLock, Irp)) { status = STATUS_FILE_LOCK_CONFLICT; __leave; } } // register this IRP to pending IPR list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { if(fcbLocked) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(Irp, status, readLength); DDbgPrint("<== DokanRead\n"); } return status; }
VOID DokanCompleteRead(__in PIRP_ENTRY IrpEntry, __in PEVENT_INFORMATION EventInfo) { PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; ULONG readLength = 0; ULONG bufferLen = 0; PVOID buffer = NULL; PDokanCCB ccb; PFILE_OBJECT fileObject; fileObject = IrpEntry->FileObject; ASSERT(fileObject != NULL); DDbgPrint("==> DokanCompleteRead %wZ\n", &fileObject->FileName); irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; ccb = fileObject->FsContext2; ASSERT(ccb != NULL); ccb->UserContext = EventInfo->Context; // DDbgPrint(" set Context %X\n", (ULONG)ccb->UserContext); // buffer which is used to copy Read info if (irp->MdlAddress) { // DDbgPrint(" use MDL Address\n"); buffer = MmGetSystemAddressForMdlNormalSafe(irp->MdlAddress); } else { // DDbgPrint(" use UserBuffer\n"); buffer = irp->UserBuffer; } // available buffer size bufferLen = irpSp->Parameters.Read.Length; DDbgPrint(" bufferLen %d, Event.BufferLen %d\n", bufferLen, EventInfo->BufferLength); // buffer is not specified or short of length if (bufferLen == 0 || buffer == NULL || bufferLen < EventInfo->BufferLength) { readLength = 0; status = STATUS_INSUFFICIENT_RESOURCES; } else { RtlZeroMemory(buffer, bufferLen); RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength); // read length which is actually read readLength = EventInfo->BufferLength; status = EventInfo->Status; if (NT_SUCCESS(status) && EventInfo->BufferLength > 0 && (fileObject->Flags & FO_SYNCHRONOUS_IO) && !(irp->Flags & IRP_PAGING_IO)) { // update current byte offset only when synchronous IO and not pagind IO fileObject->CurrentByteOffset.QuadPart = EventInfo->Operation.Read.CurrentByteOffset.QuadPart; DDbgPrint(" Updated CurrentByteOffset %I64d\n", fileObject->CurrentByteOffset.QuadPart); } } if (NT_SUCCESS(status)) { DDbgPrint(" STATUS_SUCCESS\n"); } else if (status == STATUS_INSUFFICIENT_RESOURCES) { DDbgPrint(" STATUS_INSUFFICIENT_RESOURCES\n"); } else if (status == STATUS_END_OF_FILE) { DDbgPrint(" STATUS_END_OF_FILE\n"); } else { DDbgPrint(" status = 0x%X\n", status); } DokanCompleteIrpRequest(irp, status, readLength); DDbgPrint("<== DokanCompleteRead\n"); }
VOID DokanCompleteDirectoryControl(__in PIRP_ENTRY IrpEntry, __in PEVENT_INFORMATION EventInfo) { PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_SUCCESS; ULONG info = 0; ULONG bufferLen = 0; PVOID buffer = NULL; DDbgPrint("==> DokanCompleteDirectoryControl\n"); irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; // buffer pointer which points DirecotryInfo if (irp->MdlAddress) { // DDbgPrint(" use MDL Address\n"); buffer = MmGetSystemAddressForMdlNormalSafe(irp->MdlAddress); } else { // DDbgPrint(" use UserBuffer\n"); buffer = irp->UserBuffer; } // usable buffer size bufferLen = irpSp->Parameters.QueryDirectory.Length; // DDbgPrint(" !!Returning DirecotyInfo!!\n"); // buffer is not specified or short of length if (bufferLen == 0 || buffer == NULL || bufferLen < EventInfo->BufferLength) { info = 0; status = STATUS_INSUFFICIENT_RESOURCES; } else { PDokanCCB ccb = IrpEntry->FileObject->FsContext2; // ULONG orgLen = irpSp->Parameters.QueryDirectory.Length; // // set the information recieved from user mode // ASSERT(buffer != NULL); RtlZeroMemory(buffer, bufferLen); // DDbgPrint(" copy DirectoryInfo\n"); RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength); DDbgPrint(" eventInfo->Directory.Index = %lu\n", EventInfo->Operation.Directory.Index); DDbgPrint(" eventInfo->BufferLength = %lu\n", EventInfo->BufferLength); DDbgPrint(" eventInfo->Status = %x (%lu)\n", EventInfo->Status, EventInfo->Status); // update index which specified n-th directory entry is returned // this should be locked before writing? ccb->Context = EventInfo->Operation.Directory.Index; ccb->UserContext = EventInfo->Context; // DDbgPrint(" set Context %X\n", (ULONG)ccb->UserContext); // written bytes // irpSp->Parameters.QueryDirectory.Length = EventInfo->BufferLength; status = EventInfo->Status; info = EventInfo->BufferLength; } if (IrpEntry->Flags & DOKAN_MDL_ALLOCATED) { DokanFreeMdl(irp); IrpEntry->Flags &= ~DOKAN_MDL_ALLOCATED; } DokanCompleteIrpRequest(irp, status, info); DDbgPrint("<== DokanCompleteDirectoryControl\n"); }