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; // PVOID buffer; NTSTATUS status = STATUS_INVALID_PARAMETER; ULONG readLength = 0; PDokanCCB ccb; PDokanFCB fcb; PDokanVCB vcb; PEVENT_CONTEXT eventContext; ULONG eventLength; //PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanRead"); 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; } 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"); byteOffset = fileObject->CurrentByteOffset; } else { byteOffset = irpSp->Parameters.Read.ByteOffset; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); DDbgPrint(" ByteCount:%d ByteOffset:%d\n", bufferLength, byteOffset); 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 (fcb->Flags & DOKAN_FILE_DIRECTORY) { DDbgPrint(" DOKAN_FILE_DIRECTORY %p\n", fcb); status = STATUS_INVALID_PARAMETER; __leave; } // 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 (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; } if (Irp->Flags & IRP_NOCACHE) { DDbgPrint(" Nocache"); eventContext->FileFlags |= DOKAN_NOCACHE; } // offset of file to read eventContext->Read.ByteOffset = byteOffset; // buffer size for read // user-mode file system application can return this size eventContext->Read.BufferLength = irpSp->Parameters.Read.Length; // copy the accessed file name eventContext->Read.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Read.FileName, fcb->FileName.Buffer, fcb->FileName.Length); // register this IRP to pending IPR list and make it pending status status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { // if IRP status is not pending, must complete current IRP if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = readLength; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } else { DDbgPrint(" STATUS_PENDING"); } DDbgPrint("<== DokanRead"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanDispatchQuerySecurity( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_NOT_IMPLEMENTED; PFILE_OBJECT fileObject; ULONG info = 0; ULONG bufferLength; SECURITY_DESCRIPTOR dummySecurityDesc; ULONG descLength; PSECURITY_DESCRIPTOR securityDesc; PSECURITY_INFORMATION securityInfo; PDokanFCB fcb; PDokanDCB dcb; PDokanVCB vcb; PDokanCCB ccb; ULONG eventLength; PEVENT_CONTEXT eventContext; ULONG flags = 0; __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanQuerySecurity\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) { DbgPrint(" DeviceExtension != VCB\n"); status = STATUS_INVALID_PARAMETER; __leave; } dcb = vcb->Dcb; DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DokanPrintFileName(fileObject); ccb = fileObject->FsContext2; if (ccb == NULL) { DDbgPrint(" ccb == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } fcb = ccb->Fcb; bufferLength = irpSp->Parameters.QuerySecurity.Length; securityInfo = &irpSp->Parameters.QuerySecurity.SecurityInformation; if (*securityInfo & OWNER_SECURITY_INFORMATION) { DDbgPrint(" OWNER_SECURITY_INFORMATION\n"); } if (*securityInfo & GROUP_SECURITY_INFORMATION) { DDbgPrint(" GROUP_SECURITY_INFORMATION\n"); } if (*securityInfo & DACL_SECURITY_INFORMATION) { DDbgPrint(" DACL_SECURITY_INFORMATION\n"); } if (*securityInfo & SACL_SECURITY_INFORMATION) { DDbgPrint(" SACL_SECURITY_INFORMATION\n"); } if (*securityInfo & LABEL_SECURITY_INFORMATION) { DDbgPrint(" LABEL_SECURITY_INFORMATION\n"); } eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (Irp->UserBuffer != NULL && bufferLength > 0) { // make a MDL for UserBuffer that can be used later on another thread context if (Irp->MdlAddress == NULL) { status = DokanAllocateMdl(Irp, bufferLength); if (!NT_SUCCESS(status)) { ExFreePool(eventContext); __leave; } flags = DOKAN_MDL_ALLOCATED; } } eventContext->Context = ccb->UserContext; eventContext->Security.SecurityInformation = *securityInfo; eventContext->Security.BufferLength = bufferLength; eventContext->Security.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Security.FileName, fcb->FileName.Buffer, fcb->FileName.Length); status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanQuerySecurity\n"); FsRtlExitFileSystem(); } 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; }
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; }