VOID DokanCompleteSetInformation(__in PIRP_ENTRY IrpEntry, __in PEVENT_INFORMATION EventInfo) { PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status; ULONG info = 0; PDokanCCB ccb; PDokanFCB fcb = NULL; UNICODE_STRING oldFileName; FILE_INFORMATION_CLASS infoClass; irp = IrpEntry->Irp; status = EventInfo->Status; __try { DDbgPrint("==> DokanCompleteSetInformation\n"); irpSp = IrpEntry->IrpSp; ccb = IrpEntry->FileObject->FsContext2; ASSERT(ccb != NULL); KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE); fcb = ccb->Fcb; ASSERT(fcb != NULL); DokanFCBLockRW(fcb); ccb->UserContext = EventInfo->Context; info = EventInfo->BufferLength; infoClass = irpSp->Parameters.SetFile.FileInformationClass; RtlZeroMemory(&oldFileName, sizeof(UNICODE_STRING)); if (NT_SUCCESS(status)) { if (infoClass == FileDispositionInformation) { if (EventInfo->Operation.Delete.DeleteOnClose) { if (!MmFlushImageSection(&fcb->SectionObjectPointers, MmFlushForDelete)) { DDbgPrint(" Cannot delete user mapped image\n"); status = STATUS_CANNOT_DELETE; } else { DokanCCBFlagsSetBit(ccb, DOKAN_DELETE_ON_CLOSE); DokanFCBFlagsSetBit(fcb, DOKAN_DELETE_ON_CLOSE); DDbgPrint(" FileObject->DeletePending = TRUE\n"); IrpEntry->FileObject->DeletePending = TRUE; } } else { DokanCCBFlagsClearBit(ccb, DOKAN_DELETE_ON_CLOSE); DokanFCBFlagsClearBit(fcb, DOKAN_DELETE_ON_CLOSE); DDbgPrint(" FileObject->DeletePending = FALSE\n"); IrpEntry->FileObject->DeletePending = FALSE; } } // if rename is executed, reassign the file name if (infoClass == FileRenameInformation) { PVOID buffer = NULL; // this is used to inform rename in the bellow switch case oldFileName.Buffer = fcb->FileName.Buffer; oldFileName.Length = (USHORT)fcb->FileName.Length; oldFileName.MaximumLength = (USHORT)fcb->FileName.Length; // copy new file name buffer = ExAllocatePool(EventInfo->BufferLength + sizeof(WCHAR)); if (buffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; ExReleaseResourceLite(&ccb->Resource); KeLeaveCriticalRegion(); __leave; } fcb->FileName.Buffer = buffer; ASSERT(fcb->FileName.Buffer != NULL); RtlZeroMemory(fcb->FileName.Buffer, EventInfo->BufferLength + sizeof(WCHAR)); RtlCopyMemory(fcb->FileName.Buffer, EventInfo->Buffer, EventInfo->BufferLength); fcb->FileName.Length = (USHORT)EventInfo->BufferLength; fcb->FileName.MaximumLength = (USHORT)EventInfo->BufferLength; } } ExReleaseResourceLite(&ccb->Resource); KeLeaveCriticalRegion(); if (NT_SUCCESS(status)) { switch (irpSp->Parameters.SetFile.FileInformationClass) { case FileAllocationInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; case FileBasicInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION, FILE_ACTION_MODIFIED); break; case FileDispositionInformation: if (IrpEntry->FileObject->DeletePending) { if (DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY)) { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_REMOVED); } else { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } } break; case FileEndOfFileInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; case FileLinkInformation: // TODO: should check whether this is a directory // TODO: should notify new link name // DokanNotifyReportChange(vcb, ccb, FILE_NOTIFY_CHANGE_FILE_NAME, // FILE_ACTION_ADDED); break; case FilePositionInformation: // this is never used break; case FileRenameInformation: { DokanNotifyReportChange0(fcb, &oldFileName, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_OLD_NAME); // free old file name ExFreePool(oldFileName.Buffer); DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_NEW_NAME); } break; case FileValidDataLengthInformation: DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); break; default: DDbgPrint(" unknown type:%d\n", irpSp->Parameters.SetFile.FileInformationClass); break; } } } __finally { if(fcb) DokanFCBUnlock(fcb); DokanCompleteIrpRequest(irp, status, info); DDbgPrint("<== DokanCompleteSetInformation\n"); } }
NTSTATUS DokanQueryDirectory(__in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PFILE_OBJECT fileObject; PIO_STACK_LOCATION irpSp; PDokanVCB vcb; PDokanCCB ccb; PDokanFCB fcb; NTSTATUS status; 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); 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\n"); } if (irpSp->Flags & SL_RESTART_SCAN) { DDbgPrint(" restart scan\n"); } if (irpSp->Parameters.QueryDirectory.FileName) { DDbgPrint(" pattern:%wZ\n", irpSp->Parameters.QueryDirectory.FileName); } switch (irpSp->Parameters.QueryDirectory.FileInformationClass) { case FileDirectoryInformation: DDbgPrint(" FileDirectoryInformation\n"); break; case FileIdFullDirectoryInformation: DDbgPrint(" FileIdFullDirectoryInformation\n"); break; case FileFullDirectoryInformation: DDbgPrint(" FileFullDirectoryInformation\n"); break; case FileNamesInformation: DDbgPrint(" FileNamesInformation\n"); break; case FileBothDirectoryInformation: DDbgPrint(" FileBothDirectoryInformation\n"); break; case FileIdBothDirectoryInformation: DDbgPrint(" FileIdBothDirectoryInformation\n"); 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; } fcb = ccb->Fcb; ASSERT(fcb != NULL); DokanFCBLockRO(fcb); // 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 && !(DokanCCBFlagsIsSet(ccb, DOKAN_DIR_MATCH_ALL))); // this is an initial query if (initial) { DDbgPrint(" initial query\n"); // 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) { DokanFCBUnlock(fcb); 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 { DokanCCBFlagsSetBit(ccb, 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) { DokanFCBUnlock(fcb); 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\n"); index = 0; } else { index = (ULONG)ccb->Context; DDbgPrint(" ccb->Context %d\n", index); } eventContext->Operation.Directory.FileInformationClass = irpSp->Parameters.QueryDirectory.FileInformationClass; eventContext->Operation.Directory.BufferLength = irpSp->Parameters.QueryDirectory.Length; // length of buffer eventContext->Operation.Directory.FileIndex = index; // directory index which should be returned this time // copying file name(directory name) eventContext->Operation.Directory.DirectoryNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Directory.DirectoryName, fcb->FileName.Buffer, fcb->FileName.Length); DokanFCBUnlock(fcb); // if search pattern is specified, copy it to EventContext if (ccb->SearchPatternLength && ccb->SearchPattern) { PVOID searchBuffer; eventContext->Operation.Directory.SearchPatternLength = ccb->SearchPatternLength; eventContext->Operation.Directory.SearchPatternOffset = eventContext->Operation.Directory.DirectoryNameLength; searchBuffer = (PVOID)( (SIZE_T)&eventContext->Operation.Directory.SearchPatternBase[0] + (SIZE_T)eventContext->Operation.Directory.SearchPatternOffset); RtlCopyMemory(searchBuffer, ccb->SearchPattern, ccb->SearchPatternLength); DDbgPrint(" ccb->SearchPattern %ws\n", ccb->SearchPattern); } status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, flags); return status; }