VOID DokanCompleteQueryVolumeInformation( __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; PDokanCCB ccb; //FsRtlEnterFileSystem(); DDbgPrint("==> DokanCompleteQueryVolumeInformation"); irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; ccb = IrpEntry->FileObject->FsContext2; //ASSERT(ccb != NULL); // does not save Context!! // ccb->UserContext = EventInfo->Context; // buffer which is used to copy VolumeInfo buffer = irp->AssociatedIrp.SystemBuffer; // available buffer size to inform bufferLen = irpSp->Parameters.QueryVolume.Length; // if buffer is invalid or short of length if (bufferLen == 0 || buffer == NULL || bufferLen < EventInfo->BufferLength) { info = 0; status = STATUS_INSUFFICIENT_RESOURCES; } else { // copy the information from user-mode to specified buffer ASSERT(buffer != NULL); RtlZeroMemory(buffer, bufferLen); RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength); // the written length info = EventInfo->BufferLength; status = EventInfo->Status; } irp->IoStatus.Status = status; irp->IoStatus.Information = info; IoCompleteRequest(irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); DDbgPrint("<== DokanCompleteQueryVolumeInformation"); //FsRtlExitFileSystem(); }
NTSTATUS DokanDispatchRequest( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp) { PIO_STACK_LOCATION irpSp; irpSp = IoGetCurrentIrpStackLocation(Irp); switch (irpSp->MajorFunction) { case IRP_MJ_CREATE: return DokanDispatchCreate(DeviceObject, Irp); case IRP_MJ_CLOSE: return DokanDispatchClose(DeviceObject, Irp); case IRP_MJ_READ: return DokanDispatchRead(DeviceObject, Irp); case IRP_MJ_WRITE: return DokanDispatchWrite(DeviceObject, Irp); case IRP_MJ_FLUSH_BUFFERS: return DokanDispatchFlush(DeviceObject, Irp); case IRP_MJ_QUERY_INFORMATION: return DokanDispatchQueryInformation(DeviceObject, Irp); case IRP_MJ_SET_INFORMATION: return DokanDispatchSetInformation(DeviceObject, Irp); case IRP_MJ_QUERY_VOLUME_INFORMATION: return DokanDispatchQueryVolumeInformation(DeviceObject, Irp); case IRP_MJ_SET_VOLUME_INFORMATION: return DokanDispatchSetVolumeInformation(DeviceObject, Irp); case IRP_MJ_DIRECTORY_CONTROL: return DokanDispatchDirectoryControl(DeviceObject, Irp); case IRP_MJ_FILE_SYSTEM_CONTROL: return DokanDispatchFileSystemControl(DeviceObject, Irp); case IRP_MJ_DEVICE_CONTROL: return DokanDispatchDeviceControl(DeviceObject, Irp); case IRP_MJ_LOCK_CONTROL: return DokanDispatchLock(DeviceObject, Irp); case IRP_MJ_CLEANUP: return DokanDispatchCleanup(DeviceObject, Irp); case IRP_MJ_SHUTDOWN: return DokanDispatchShutdown(DeviceObject, Irp); case IRP_MJ_QUERY_SECURITY: return DokanDispatchQuerySecurity(DeviceObject, Irp); case IRP_MJ_SET_SECURITY: return DokanDispatchSetSecurity(DeviceObject, Irp); #if (_WIN32_WINNT >= 0x0500) case IRP_MJ_PNP: return DokanDispatchPnp(DeviceObject, Irp); #endif //(_WIN32_WINNT >= 0x0500) default: DDbgPrint("DokanDispatchRequest: Unexpected major function: %xh\n", irpSp->MajorFunction); DokanCompleteIrpRequest(Irp, STATUS_DRIVER_INTERNAL_ERROR, 0); return STATUS_DRIVER_INTERNAL_ERROR; } }
// 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); DokanFreeIrpEntry(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; case IRP_MJ_QUERY_SECURITY: DokanCompleteQuerySecurity(irpEntry, eventInfo); break; case IRP_MJ_SET_SECURITY: DokanCompleteSetSecurity(irpEntry, eventInfo); break; default: DDbgPrint("Unknown IRP %d\n", irpSp->MajorFunction); // TODO: in this case, should complete this IRP break; } DokanFreeIrpEntry(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 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 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; }
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; vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { return STATUS_INVALID_PARAMETER; } dcb = vcb->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:%X, 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); return 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"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL"); 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"); } DDbgPrint("<== DokanFlush"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DokanCommonLockControl(__in PIRP Irp) { NTSTATUS Status = STATUS_SUCCESS; PDokanFCB Fcb; PDokanCCB Ccb; PFILE_OBJECT fileObject; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); DDbgPrint("==> DokanCommonLockControl\n"); PAGED_CODE(); fileObject = irpSp->FileObject; DokanPrintFileName(fileObject); Ccb = fileObject->FsContext2; if (Ccb == NULL || Ccb->Identifier.Type != CCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Fcb = Ccb->Fcb; if (Fcb == NULL || Fcb->Identifier.Type != FCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } // // If the file is not a user file open then we reject the request // as an invalid parameter // if (DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) { DDbgPrint(" DokanCommonLockControl -> STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } // // We check whether we can proceed // based on the state of the file oplocks. // #if (NTDDI_VERSION >= NTDDI_WIN8) // Fcb's AllocationSize is constant after creation. if (((IRP_MN_LOCK == irpSp->MinorFunction) && ((ULONGLONG)irpSp->Parameters.LockControl.ByteOffset.QuadPart < (ULONGLONG)Fcb->AdvancedFCBHeader.AllocationSize.QuadPart)) || ((IRP_MN_LOCK != irpSp->MinorFunction) && FsRtlAreThereWaitingFileLocks(&Fcb->FileLock))) { // // Check whether we can proceed based on the state of file oplocks if doing // an operation that interferes with oplocks. Those operations are: // // 1. Lock a range within the file's AllocationSize. // 2. Unlock a range when there are waiting locks on the file. This one // is not guaranteed to interfere with oplocks, but it could, as // unlocking this range might cause a waiting lock to be granted // within AllocationSize! // #endif // Dokan DokanOplockComplete sends the operation to user mode, which isn't // what we want to do // so now wait for the oplock to be broken (pass in NULL for the callback) // This may block and enter wait state. Status = FsRtlCheckOplock(DokanGetFcbOplock(Fcb), Irp, NULL /* EventContext */, NULL /*DokanOplockComplete*/, NULL); #if (NTDDI_VERSION >= NTDDI_WIN8) } #endif // If we were waiting for the callback, then STATUS_PENDING would be ok too if (Status == STATUS_SUCCESS) { // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock(&Fcb->FileLock, Irp, NULL); } DDbgPrint("<== DokanCommonLockControl\n"); return Status; }
NTSTATUS DokanOplockRequest(__in PIRP *pIrp) { NTSTATUS Status = STATUS_SUCCESS; ULONG FsControlCode; PDokanDCB Dcb; PDokanVCB Vcb; PDokanFCB Fcb = NULL; PDokanCCB Ccb; PFILE_OBJECT fileObject; PIRP Irp = *pIrp; ULONG OplockCount = 0; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); BOOLEAN AcquiredVcb = FALSE; #if (NTDDI_VERSION >= NTDDI_WIN7) PREQUEST_OPLOCK_INPUT_BUFFER InputBuffer = NULL; ULONG InputBufferLength; ULONG OutputBufferLength; #endif PAGED_CODE(); // // Save some references to make our life a little easier // FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; fileObject = IrpSp->FileObject; DokanPrintFileName(fileObject); Ccb = fileObject->FsContext2; if (Ccb == NULL || Ccb->Identifier.Type != CCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Fcb = Ccb->Fcb; if (Fcb == NULL || Fcb->Identifier.Type != FCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Vcb = Fcb->Vcb; if (Vcb == NULL || Vcb->Identifier.Type != VCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Dcb = Vcb->Dcb; #if (NTDDI_VERSION >= NTDDI_WIN7) // // Get the input & output buffer lengths and pointers. // if (FsControlCode == FSCTL_REQUEST_OPLOCK) { InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; InputBuffer = (PREQUEST_OPLOCK_INPUT_BUFFER)Irp->AssociatedIrp.SystemBuffer; OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; // // Check for a minimum length on the input and ouput buffers. // if ((InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER)) || (OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))) { DDbgPrint(" DokanOplockRequest STATUS_BUFFER_TOO_SMALL\n"); return STATUS_BUFFER_TOO_SMALL; } } // // If the oplock request is on a directory it must be for a Read or // Read-Handle // oplock only. // if ((DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) && ((FsControlCode != FSCTL_REQUEST_OPLOCK) || !FsRtlOplockIsSharedRequest(Irp))) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } #endif // // Use a try finally to free the Fcb/Vcb // try { // // We grab the Fcb exclusively for oplock requests, shared for oplock // break acknowledgement. // if ((FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_1) || (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) || (FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || (FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_REQUEST)) #endif ) { AcquiredVcb = ExAcquireResourceSharedLite(&(Fcb->Vcb->Resource), TRUE); #if (NTDDI_VERSION >= NTDDI_WIN7) if (!Dcb->FileLockInUserMode && FsRtlOplockIsSharedRequest(Irp)) { #else if (!Dcb->FileLockInUserMode && FsControlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { #endif // // Byte-range locks are only valid on files. // if (!DokanFCBFlagsIsSet(Fcb, DOKAN_FILE_DIRECTORY)) { // // Set OplockCount to nonzero if FsRtl denies access // based on current byte-range lock state. // #if (NTDDI_VERSION >= NTDDI_WIN8) OplockCount = (ULONG)!FsRtlCheckLockForOplockRequest( &Fcb->FileLock, &Fcb->AdvancedFCBHeader.AllocationSize); #elif (NTDDI_VERSION >= NTDDI_WIN7) OplockCount = (ULONG)FsRtlAreThereCurrentOrInProgressFileLocks(&Fcb->FileLock); #else OplockCount = (ULONG)FsRtlAreThereCurrentFileLocks(&Fcb->FileLock); #endif } } else { // Shouldn't be something like UncleanCount counter and not FileCount // here? OplockCount = Fcb->FileCount; } } else if ((FsControlCode == FSCTL_OPLOCK_BREAK_ACKNOWLEDGE) || (FsControlCode == FSCTL_OPBATCH_ACK_CLOSE_PENDING) || (FsControlCode == FSCTL_OPLOCK_BREAK_NOTIFY) || (FsControlCode == FSCTL_OPLOCK_BREAK_ACK_NO_2) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->Flags, REQUEST_OPLOCK_INPUT_FLAG_ACK)) #endif ) { #if (NTDDI_VERSION >= NTDDI_WIN7) } else if (FsControlCode == FSCTL_REQUEST_OPLOCK) { // // The caller didn't provide either REQUEST_OPLOCK_INPUT_FLAG_REQUEST or // REQUEST_OPLOCK_INPUT_FLAG_ACK on the input buffer. // DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; __leave; } else { #else } else { #endif DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); Status = STATUS_INVALID_PARAMETER; __leave; } // // Fail batch, filter, and handle oplock requests if the file is marked // for delete. // if (((FsControlCode == FSCTL_REQUEST_FILTER_OPLOCK) || (FsControlCode == FSCTL_REQUEST_BATCH_OPLOCK) #if (NTDDI_VERSION >= NTDDI_WIN7) || ((FsControlCode == FSCTL_REQUEST_OPLOCK) && FlagOn(InputBuffer->RequestedOplockLevel, OPLOCK_LEVEL_CACHE_HANDLE)) #endif ) && DokanFCBFlagsIsSet(Fcb, DOKAN_DELETE_ON_CLOSE)) { DDbgPrint(" DokanOplockRequest STATUS_DELETE_PENDING\n"); Status = STATUS_DELETE_PENDING; __leave; } // // Call the FsRtl routine to grant/acknowledge oplock. // Status = FsRtlOplockFsctrl(DokanGetFcbOplock(Fcb), Irp, OplockCount); // // Once we call FsRtlOplockFsctrl, we no longer own the IRP and we should // not complete it. // *pIrp = NULL; } finally {
NTSTATUS DokanCreateDiskDevice( __in PDRIVER_OBJECT DriverObject, __in ULONG MountId, __in PWCHAR BaseGuid, __in PDOKAN_GLOBAL DokanGlobal, __in DEVICE_TYPE DeviceType, __in ULONG DeviceCharacteristics, __out PDokanDCB* Dcb ) { WCHAR diskDeviceNameBuf[MAXIMUM_FILENAME_LENGTH]; WCHAR fsDeviceNameBuf[MAXIMUM_FILENAME_LENGTH]; WCHAR symbolicLinkNameBuf[MAXIMUM_FILENAME_LENGTH]; PDEVICE_OBJECT diskDeviceObject; PDEVICE_OBJECT fsDeviceObject; PDokanDCB dcb; PDokanVCB vcb; UNICODE_STRING diskDeviceName; NTSTATUS status; BOOLEAN isNetworkFileSystem = (DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM); // make DeviceName and SymboliLink if (isNetworkFileSystem) { #ifdef DOKAN_NET_PROVIDER RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCopyW(fsDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_SYMBOLIC_LINK_NAME); #else RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(fsDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_DEVICE_NAME); RtlStringCchCatW(fsDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_NET_SYMBOLIC_LINK_NAME); RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); #endif } else { RtlStringCchCopyW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_DISK_DEVICE_NAME); RtlStringCchCatW(diskDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(fsDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_FS_DEVICE_NAME); RtlStringCchCatW(fsDeviceNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); RtlStringCchCopyW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, DOKAN_SYMBOLIC_LINK_NAME); RtlStringCchCatW(symbolicLinkNameBuf, MAXIMUM_FILENAME_LENGTH, BaseGuid); } RtlInitUnicodeString(&diskDeviceName, diskDeviceNameBuf); // // make a DeviceObject for Disk Device // if (!isNetworkFileSystem) { status = IoCreateDeviceSecure( DriverObject, // DriverObject sizeof(DokanDCB), // DeviceExtensionSize &diskDeviceName, // DeviceName FILE_DEVICE_DISK, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &sddl, // Default SDDL String NULL, // Device Class GUID &diskDeviceObject); // DeviceObject } else { status = IoCreateDevice( DriverObject, // DriverObject sizeof(DokanDCB), // DeviceExtensionSize NULL, // DeviceName FILE_DEVICE_UNKNOWN, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &diskDeviceObject); // DeviceObject } if (!NT_SUCCESS(status)) { DDbgPrint(" IoCreateDevice (DISK_DEVICE) failed: 0x%x\n", status); return status; } DDbgPrint("DokanDiskDevice: %wZ created\n", &diskDeviceName); // // Initialize the device extension. // dcb = diskDeviceObject->DeviceExtension; *Dcb = dcb; dcb->DeviceObject = diskDeviceObject; dcb->Global = DokanGlobal; dcb->Identifier.Type = DCB; dcb->Identifier.Size = sizeof(DokanDCB); dcb->MountId = MountId; dcb->DeviceType = FILE_DEVICE_DISK; dcb->DeviceCharacteristics = DeviceCharacteristics; KeInitializeEvent(&dcb->KillEvent, NotificationEvent, FALSE); // // Establish user-buffer access method. // diskDeviceObject->Flags |= DO_DIRECT_IO; // initialize Event and Event queue DokanInitIrpList(&dcb->PendingIrp); DokanInitIrpList(&dcb->PendingEvent); DokanInitIrpList(&dcb->NotifyEvent); KeInitializeEvent(&dcb->ReleaseEvent, NotificationEvent, FALSE); // "0" means not mounted dcb->Mounted = 0; ExInitializeResourceLite(&dcb->Resource); dcb->CacheManagerNoOpCallbacks.AcquireForLazyWrite = &DokanNoOpAcquire; dcb->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &DokanNoOpRelease; dcb->CacheManagerNoOpCallbacks.AcquireForReadAhead = &DokanNoOpAcquire; dcb->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &DokanNoOpRelease; dcb->SymbolicLinkName = AllocateUnicodeString(symbolicLinkNameBuf); dcb->DiskDeviceName = AllocateUnicodeString(diskDeviceNameBuf); dcb->FileSystemDeviceName = AllocateUnicodeString(fsDeviceNameBuf); status = IoCreateDeviceSecure( DriverObject, // DriverObject sizeof(DokanVCB), // DeviceExtensionSize dcb->FileSystemDeviceName, // DeviceName DeviceType, // DeviceType DeviceCharacteristics, // DeviceCharacteristics FALSE, // Not Exclusive &sddl, // Default SDDL String NULL, // Device Class GUID &fsDeviceObject); // DeviceObject if (!NT_SUCCESS(status)) { DDbgPrint(" IoCreateDevice (FILE_SYSTEM_DEVICE) failed: 0x%x\n", status); IoDeleteDevice(diskDeviceObject); return status; } DDbgPrint("DokanFileSystemDevice: %wZ created\n", dcb->FileSystemDeviceName); vcb = fsDeviceObject->DeviceExtension; vcb->Identifier.Type = VCB; vcb->Identifier.Size = sizeof(DokanVCB); vcb->DeviceObject = fsDeviceObject; vcb->Dcb = dcb; dcb->Vcb = vcb; InitializeListHead(&vcb->NextFCB); InitializeListHead(&vcb->DirNotifyList); FsRtlNotifyInitializeSync(&vcb->NotifySync); ExInitializeFastMutex(&vcb->AdvancedFCBHeaderMutex); #if _WIN32_WINNT >= 0x0501 FsRtlSetupAdvancedHeader(&vcb->VolumeFileHeader, &vcb->AdvancedFCBHeaderMutex); #else if (DokanFsRtlTeardownPerStreamContexts) { FsRtlSetupAdvancedHeader(&vcb->VolumeFileHeader, &vcb->AdvancedFCBHeaderMutex); } #endif // // Establish user-buffer access method. // fsDeviceObject->Flags |= DO_DIRECT_IO; if (diskDeviceObject->Vpb) { // NOTE: This can be done by IoRegisterFileSystem + IRP_MN_MOUNT_VOLUME, // however that causes BSOD inside filter manager on Vista x86 after mount // (mouse hover on file). // Probably FS_FILTER_CALLBACKS.PreAcquireForSectionSynchronization is // not correctly called in that case. diskDeviceObject->Vpb->DeviceObject = fsDeviceObject; diskDeviceObject->Vpb->RealDevice = fsDeviceObject; diskDeviceObject->Vpb->Flags |= VPB_MOUNTED; diskDeviceObject->Vpb->VolumeLabelLength = (USHORT)wcslen(VOLUME_LABEL) * sizeof(WCHAR); RtlStringCchCopyW(diskDeviceObject->Vpb->VolumeLabel, sizeof(diskDeviceObject->Vpb->VolumeLabel) / sizeof(WCHAR), VOLUME_LABEL); diskDeviceObject->Vpb->SerialNumber = 0x19831116; } ObReferenceObject(fsDeviceObject); ObReferenceObject(diskDeviceObject); // // Create a symbolic link for userapp to interact with the driver. // status = IoCreateSymbolicLink(dcb->SymbolicLinkName, dcb->DiskDeviceName); if (!NT_SUCCESS(status)) { if (diskDeviceObject->Vpb) { diskDeviceObject->Vpb->DeviceObject = NULL; diskDeviceObject->Vpb->RealDevice = NULL; diskDeviceObject->Vpb->Flags = 0; } IoDeleteDevice(diskDeviceObject); IoDeleteDevice(fsDeviceObject); DDbgPrint(" IoCreateSymbolicLink returned 0x%x\n", status); return status; } DDbgPrint("SymbolicLink: %wZ -> %wZ created\n", dcb->SymbolicLinkName, dcb->DiskDeviceName); // Mark devices as initialized diskDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; fsDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; //IoRegisterFileSystem(fsDeviceObject); if (isNetworkFileSystem) { // Run FsRtlRegisterUncProvider in System thread. HANDLE handle; PKTHREAD thread; OBJECT_ATTRIBUTES objectAttribs; InitializeObjectAttributes( &objectAttribs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); status = PsCreateSystemThread(&handle, THREAD_ALL_ACCESS, &objectAttribs, NULL, NULL, (PKSTART_ROUTINE)DokanRegisterUncProvider, dcb); if (!NT_SUCCESS(status)) { DDbgPrint("PsCreateSystemThread failed: 0x%X\n", status); } else { ObReferenceObjectByHandle(handle, THREAD_ALL_ACCESS, NULL, KernelMode, &thread, NULL); ZwClose(handle); KeWaitForSingleObject(thread, Executive, KernelMode, FALSE, NULL); ObDereferenceObject(thread); } } //DokanRegisterMountedDeviceInterface(diskDeviceObject, dcb); dcb->Mounted = 1; //DokanSendVolumeArrivalNotification(&deviceName); //DokanRegisterDeviceInterface(DriverObject, diskDeviceObject, dcb); return STATUS_SUCCESS; }
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 = NULL; PDokanVCB vcb; PDokanDCB dcb; PEVENT_CONTEXT eventContext = NULL; ULONG eventLength; BOOLEAN completeIrp = TRUE; __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; } dcb = vcb->Dcb; 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); DokanFCBLockRW(fcb); if (dcb->FileLockInUserMode) { 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); } else { status = DokanCommonLockControl(Irp); completeIrp = FALSE; } } __finally { if(fcb) DokanFCBUnlock(fcb); if (completeIrp) { DokanCompleteIrpRequest(Irp, status, 0); } DDbgPrint("<== DokanLock\n"); } return status; }
NTSTATUS DokanSendIoContlToMountManager( __in PVOID InputBuffer, __in ULONG Length ) { NTSTATUS status; UNICODE_STRING mountManagerName; PFILE_OBJECT mountFileObject; PDEVICE_OBJECT mountDeviceObject; PIRP irp; KEVENT driverEvent; IO_STATUS_BLOCK iosb; DDbgPrint("=> DokanSnedIoContlToMountManager\n"); RtlInitUnicodeString(&mountManagerName, MOUNTMGR_DEVICE_NAME); status = IoGetDeviceObjectPointer( &mountManagerName, FILE_READ_ATTRIBUTES, &mountFileObject, &mountDeviceObject); if (!NT_SUCCESS(status)) { DDbgPrint(" IoGetDeviceObjectPointer failed: 0x%x\n", status); return status; } KeInitializeEvent(&driverEvent, NotificationEvent, FALSE); irp = IoBuildDeviceIoControlRequest( IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mountDeviceObject, InputBuffer, Length, NULL, 0, FALSE, &driverEvent, &iosb); if (irp == NULL) { DDbgPrint(" IoBuildDeviceIoControlRequest failed\n"); return STATUS_INSUFFICIENT_RESOURCES; } status = IoCallDriver(mountDeviceObject, irp); if (status == STATUS_PENDING) { KeWaitForSingleObject( &driverEvent, Executive, KernelMode, FALSE, NULL); } status = iosb.Status; ObDereferenceObject(mountFileObject); ObDereferenceObject(mountDeviceObject); if (NT_SUCCESS(status)) { DDbgPrint(" IoCallDriver success\n"); } else { DDbgPrint(" IoCallDriver faield: 0x%x\n", status); } DDbgPrint("<= DokanSendIoContlToMountManager\n"); return status; }
NTSTATUS DokanRegisterDeviceInterface( __in PDRIVER_OBJECT DriverObject, __in PDEVICE_OBJECT DeviceObject, __in PDokanDCB Dcb ) { PDEVICE_OBJECT pnpDeviceObject = NULL; NTSTATUS status; status = IoReportDetectedDevice( DriverObject, InterfaceTypeUndefined, 0, 0, NULL, NULL, FALSE, &pnpDeviceObject); if (NT_SUCCESS(status)) { DDbgPrint(" IoReportDetectedDevice success\n"); } else { DDbgPrint(" IoReportDetectedDevice failed: 0x%x\n", status); return status; } if (IoAttachDeviceToDeviceStack(pnpDeviceObject, DeviceObject) != NULL) { DDbgPrint(" IoAttachDeviceToDeviceStack success\n"); } else { DDbgPrint(" IoAttachDeviceToDeviceStack failed\n"); } status = IoRegisterDeviceInterface( pnpDeviceObject, &GUID_DEVINTERFACE_DISK, NULL, &Dcb->DiskDeviceInterfaceName); if (NT_SUCCESS(status)) { DDbgPrint(" IoRegisterDeviceInterface success: %wZ\n", &Dcb->DiskDeviceInterfaceName); } else { DDbgPrint(" IoRegisterDeviceInterface failed: 0x%x\n", status); return status; } status = IoSetDeviceInterfaceState(&Dcb->DiskDeviceInterfaceName, TRUE); if (NT_SUCCESS(status)) { DDbgPrint(" IoSetDeviceInterfaceState success\n"); } else { DDbgPrint(" IoSetDeviceInterfaceState failed: 0x%x\n", status); return status; } status = IoRegisterDeviceInterface( pnpDeviceObject, &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL, &Dcb->MountedDeviceInterfaceName); if (NT_SUCCESS(status)) { DDbgPrint(" IoRegisterDeviceInterface success: %wZ\n", &Dcb->MountedDeviceInterfaceName); } else { DDbgPrint(" IoRegisterDeviceInterface failed: 0x%x\n", status); return status; } status = IoSetDeviceInterfaceState(&Dcb->MountedDeviceInterfaceName, TRUE); if (NT_SUCCESS(status)) { DDbgPrint(" IoSetDeviceInterfaceState success\n"); } else { DDbgPrint(" IoSetDeviceInterfaceState failed: 0x%x\n", status); return status; } 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; }
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; }
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) { info = irpSp->Parameters.QueryFile.Length; status = STATUS_BUFFER_OVERFLOW; } 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->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 { DokanCompleteIrpRequest(Irp, status, info); DDbgPrint("<== DokanQueryInformation\n"); FsRtlExitFileSystem(); } return status; }
VOID NotificationLoop( __in PIRP_LIST PendingIrp, __in PIRP_LIST NotifyEvent ) { PDRIVER_EVENT_CONTEXT driverEventContext; PLIST_ENTRY listHead; PIRP_ENTRY irpEntry; LIST_ENTRY completeList; NTSTATUS status; KIRQL irpIrql; KIRQL notifyIrql; PIRP irp; ULONG eventLen; ULONG bufferLen; PVOID buffer; //DDbgPrint("=> NotificationLoop\n"); InitializeListHead(&completeList); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&PendingIrp->ListLock, &irpIrql); KeAcquireSpinLock(&NotifyEvent->ListLock, ¬ifyIrql); while (!IsListEmpty(&PendingIrp->ListHead) && !IsListEmpty(&NotifyEvent->ListHead)) { listHead = RemoveHeadList(&NotifyEvent->ListHead); driverEventContext = CONTAINING_RECORD( listHead, DRIVER_EVENT_CONTEXT, ListEntry); listHead = RemoveHeadList(&PendingIrp->ListHead); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); eventLen = driverEventContext->EventContext.Length; // ensure this eventIrp is not cancelled irp = irpEntry->Irp; if (irp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); DokanFreeIrpEntry(irpEntry); // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); continue; } if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); continue; } // available size that is used for event notification bufferLen = irpEntry->IrpSp->Parameters.DeviceIoControl.OutputBufferLength; // buffer that is used to inform Event buffer = irp->AssociatedIrp.SystemBuffer; // buffer is not specified or short of length if (bufferLen == 0 || buffer == NULL || bufferLen < eventLen) { DDbgPrint("EventNotice : STATUS_INSUFFICIENT_RESOURCES\n"); DDbgPrint(" bufferLen: %d, eventLen: %d\n", bufferLen, eventLen); // push back InsertTailList(&NotifyEvent->ListHead, &driverEventContext->ListEntry); // marks as STATUS_INSUFFICIENT_RESOURCES irpEntry->SerialNumber = 0; } else { // let's copy EVENT_CONTEXT RtlCopyMemory(buffer, &driverEventContext->EventContext, eventLen); // save event length irpEntry->SerialNumber = eventLen; if (driverEventContext->Completed) { KeSetEvent(driverEventContext->Completed, IO_NO_INCREMENT, FALSE); } ExFreePool(driverEventContext); } InsertTailList(&completeList, &irpEntry->ListEntry); } KeClearEvent(&NotifyEvent->NotEmpty); KeClearEvent(&PendingIrp->NotEmpty); KeReleaseSpinLock(&NotifyEvent->ListLock, notifyIrql); KeReleaseSpinLock(&PendingIrp->ListLock, irpIrql); while (!IsListEmpty(&completeList)) { listHead = RemoveHeadList(&completeList); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); irp = irpEntry->Irp; if (irpEntry->SerialNumber == 0) { irp->IoStatus.Information = 0; irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; } else { irp->IoStatus.Information = irpEntry->SerialNumber; irp->IoStatus.Status = STATUS_SUCCESS; } DokanFreeIrpEntry(irpEntry); IoCompleteRequest(irp, IO_NO_INCREMENT); } //DDbgPrint("<= NotificationLoop\n"); }
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; 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->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 // copy FileInformation RtlCopyMemory((PCHAR)eventContext + eventContext->Operation.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->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); RtlCopyMemory(renameContext->FileName, targetFileObject->FileName.Buffer, targetFileObject->FileName.Length); renameContext->FileNameLength = targetFileObject->FileName.Length; } } // copy the file name eventContext->Operation.SetFile.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.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 { DokanCompleteIrpRequest(Irp, status, 0); DDbgPrint("<== DokanSetInformation\n"); FsRtlExitFileSystem(); } return status; }
NTSTATUS DriverEntry(__in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING RegistryPath) /*++ Routine Description: This routine gets called by the system to initialize the driver. Arguments: DriverObject - the system supplied driver object. RegistryPath - the system supplied registry path for this driver. Return Value: NTSTATUS --*/ { NTSTATUS status; PFAST_IO_DISPATCH fastIoDispatch; FS_FILTER_CALLBACKS filterCallbacks; PDOKAN_GLOBAL dokanGlobal = NULL; UNREFERENCED_PARAMETER(RegistryPath); DDbgPrint("==> DriverEntry ver.%x, %s %s\n", DOKAN_DRIVER_VERSION, __DATE__, __TIME__); status = DokanCreateGlobalDiskDevice(DriverObject, &dokanGlobal); if (NT_ERROR(status)) { return status; } // // Set up dispatch entry points for the driver. // DriverObject->DriverUnload = DokanUnload; DriverObject->MajorFunction[IRP_MJ_CREATE] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_READ] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_WRITE] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_PNP] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = DokanBuildRequest; DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = DokanBuildRequest; fastIoDispatch = ExAllocatePool(sizeof(FAST_IO_DISPATCH)); if (!fastIoDispatch) { IoDeleteDevice(dokanGlobal->FsDiskDeviceObject); IoDeleteDevice(dokanGlobal->FsCdDeviceObject); IoDeleteDevice(dokanGlobal->DeviceObject); DDbgPrint(" ExAllocatePool failed"); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH)); fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); fastIoDispatch->FastIoCheckIfPossible = DokanFastIoCheckIfPossible; // fastIoDispatch->FastIoRead = DokanFastIoRead; fastIoDispatch->FastIoRead = FsRtlCopyRead; fastIoDispatch->FastIoWrite = FsRtlCopyWrite; fastIoDispatch->AcquireFileForNtCreateSection = DokanAcquireForCreateSection; fastIoDispatch->ReleaseFileForNtCreateSection = DokanReleaseForCreateSection; fastIoDispatch->MdlRead = FsRtlMdlReadDev; fastIoDispatch->MdlReadComplete = FsRtlMdlReadCompleteDev; fastIoDispatch->PrepareMdlWrite = FsRtlPrepareMdlWriteDev; fastIoDispatch->MdlWriteComplete = FsRtlMdlWriteCompleteDev; DriverObject->FastIoDispatch = fastIoDispatch; #if _WIN32_WINNT >= _WIN32_WINNT_WIN8 ExInitializeNPagedLookasideList(&DokanIrpEntryLookasideList, NULL, NULL, POOL_NX_ALLOCATION, sizeof(IRP_ENTRY), TAG, 0); #else ExInitializeNPagedLookasideList(&DokanIrpEntryLookasideList, NULL, NULL, 0, sizeof(IRP_ENTRY), TAG, 0); #endif #if _WIN32_WINNT < 0x0501 RtlInitUnicodeString(&functionName, L"FsRtlTeardownPerStreamContexts"); DokanFsRtlTeardownPerStreamContexts = MmGetSystemRoutineAddress(&functionName); #endif RtlZeroMemory(&filterCallbacks, sizeof(FS_FILTER_CALLBACKS)); // only be used by filter driver? filterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS); filterCallbacks.PreAcquireForSectionSynchronization = DokanFilterCallbackAcquireForCreateSection; status = FsRtlRegisterFileSystemFilterCallbacks(DriverObject, &filterCallbacks); if (!NT_SUCCESS(status)) { IoDeleteDevice(dokanGlobal->FsDiskDeviceObject); IoDeleteDevice(dokanGlobal->FsCdDeviceObject); IoDeleteDevice(dokanGlobal->DeviceObject); DDbgPrint(" FsRtlRegisterFileSystemFilterCallbacks returned 0x%x\n", status); return status; } if (!DokanLookasideCreate(&g_DokanCCBLookasideList, sizeof(DokanCCB))) { IoDeleteDevice(dokanGlobal->FsDiskDeviceObject); IoDeleteDevice(dokanGlobal->FsCdDeviceObject); IoDeleteDevice(dokanGlobal->DeviceObject); return STATUS_INSUFFICIENT_RESOURCES; } if (!DokanLookasideCreate(&g_DokanFCBLookasideList, sizeof(DokanFCB))) { IoDeleteDevice(dokanGlobal->FsDiskDeviceObject); IoDeleteDevice(dokanGlobal->FsCdDeviceObject); IoDeleteDevice(dokanGlobal->DeviceObject); ExDeleteLookasideListEx(&g_DokanCCBLookasideList); return STATUS_INSUFFICIENT_RESOURCES; } if (!DokanLookasideCreate(&g_DokanEResourceLookasideList, sizeof(ERESOURCE))) { IoDeleteDevice(dokanGlobal->FsDiskDeviceObject); IoDeleteDevice(dokanGlobal->FsCdDeviceObject); IoDeleteDevice(dokanGlobal->DeviceObject); ExDeleteLookasideListEx(&g_DokanCCBLookasideList); ExDeleteLookasideListEx(&g_DokanFCBLookasideList); return STATUS_INSUFFICIENT_RESOURCES; } DDbgPrint("<== DriverEntry\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; PEVENT_CONTEXT eventContext; PFILE_OBJECT relatedFileObject; ULONG fileNameLength = 0; ULONG eventLength; PDokanFCB fcb; PDokanCCB ccb; PWCHAR fileName; BOOLEAN needBackSlashAfterRelatedFile = FALSE; PAGED_CODE(); __try { 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) { DDbgPrint(" IdentifierType is not vcb\n"); 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 || relatedFileObject->FileName.Length == 0) && 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) { DDbgPrint(" Can't allocatePool for fileName\n"); 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) { DDbgPrint(" Was not able to get FCB for fileName %ls\n", fileName); 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) { DDbgPrint(" Was not able to allocate CCB\n"); DokanFreeFCB(fcb); // FileName is freed here status = STATUS_INSUFFICIENT_RESOURCES; __leave; } //remember FILE_DELETE_ON_CLOSE so than the file can be deleted in close for windows 8 if (irpSp->Parameters.Create.Options & FILE_DELETE_ON_CLOSE) { fcb->Flags |= DOKAN_DELETE_ON_CLOSE; DDbgPrint(" FILE_DELETE_ON_CLOSE is set so remember for delete in cleanup\n"); } else { fcb->Flags &= ~DOKAN_DELETE_ON_CLOSE; } 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) { DDbgPrint(" Was not able to allocate eventContext\n"); status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = 0; eventContext->FileFlags |= fcb->Flags; // copy the file name eventContext->Operation.Create.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Operation.Create.FileName, fcb->FileName.Buffer, fcb->FileName.Length); eventContext->Operation.Create.FileAttributes = irpSp->Parameters.Create.FileAttributes; eventContext->Operation.Create.CreateOptions = irpSp->Parameters.Create.Options; eventContext->Operation.Create.DesiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess; eventContext->Operation.Create.ShareAccess = irpSp->Parameters.Create.ShareAccess; // register this IRP to waiting IPR list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext, 0); } __finally { DokanCompleteIrpRequest(Irp, status, info); DDbgPrint("<== DokanCreate\n"); } 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\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; if (fileObject == NULL) { DDbgPrint(" fileObject is NULL\n"); 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\n"); 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\n"); FsRtlExitFileSystem(); } return status; }
VOID DokanCompleteCreate( __in PIRP_ENTRY IrpEntry, __in PEVENT_INFORMATION EventInfo ) { PIRP irp; PIO_STACK_LOCATION irpSp; NTSTATUS status; ULONG info; PDokanCCB ccb; PDokanFCB fcb; irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; DDbgPrint("==> DokanCompleteCreate\n"); ccb = IrpEntry->FileObject->FsContext2; ASSERT(ccb != NULL); fcb = ccb->Fcb; ASSERT(fcb != NULL); DDbgPrint(" FileName:%wZ\n", &fcb->FileName); ccb->UserContext = EventInfo->Context; //DDbgPrint(" set Context %X\n", (ULONG)ccb->UserContext); status = EventInfo->Status; info = EventInfo->Operation.Create.Information; switch (info) { case FILE_OPENED: DDbgPrint(" FILE_OPENED\n"); break; case FILE_CREATED: DDbgPrint(" FILE_CREATED\n"); break; case FILE_OVERWRITTEN: DDbgPrint(" FILE_OVERWRITTEN\n"); break; case FILE_DOES_NOT_EXIST: DDbgPrint(" FILE_DOES_NOT_EXIST\n"); break; case FILE_EXISTS: DDbgPrint(" FILE_EXISTS\n"); break; case FILE_SUPERSEDED: DDbgPrint(" FILE_SUPERSEDED\n"); break; default: DDbgPrint(" info = %d\n", info); break; } KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&fcb->Resource, TRUE); if (NT_SUCCESS(status) && (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE || EventInfo->Operation.Create.Flags & DOKAN_FILE_DIRECTORY)) { if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) { DDbgPrint(" FILE_DIRECTORY_FILE %p\n", fcb); } else { DDbgPrint(" DOKAN_FILE_DIRECTORY %p\n", fcb); } fcb->Flags |= DOKAN_FILE_DIRECTORY; } ExReleaseResourceLite(&fcb->Resource); KeLeaveCriticalRegion(); KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&ccb->Resource, TRUE); if (NT_SUCCESS(status)) { ccb->Flags |= DOKAN_FILE_OPENED; } ExReleaseResourceLite(&ccb->Resource); KeLeaveCriticalRegion(); if (NT_SUCCESS(status)) { if (info == FILE_CREATED) { if (fcb->Flags & DOKAN_FILE_DIRECTORY) { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_DIR_NAME, FILE_ACTION_ADDED); } else { DokanNotifyReportChange(fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED); } } } else { DDbgPrint(" IRP_MJ_CREATE failed. Free CCB:%p\n", ccb); DokanFreeCCB(ccb); DokanFreeFCB(fcb); } irp->IoStatus.Status = status; irp->IoStatus.Information = info; IoCompleteRequest(irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); DDbgPrint("<== DokanCompleteCreate\n"); }
VOID DokanCompleteQueryInformation(__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; PDokanCCB ccb; DDbgPrint("==> DokanCompleteQueryInformation\n"); irp = IrpEntry->Irp; irpSp = IrpEntry->IrpSp; ccb = IrpEntry->FileObject->FsContext2; ASSERT(ccb != NULL); ccb->UserContext = EventInfo->Context; // DDbgPrint(" set Context %X\n", (ULONG)ccb->UserContext); // where we shold copy FileInfo to buffer = irp->AssociatedIrp.SystemBuffer; // available buffer size bufferLen = irpSp->Parameters.QueryFile.Length; // buffer is not specifed or short of size if (bufferLen == 0 || buffer == NULL || bufferLen < EventInfo->BufferLength) { info = 0; status = STATUS_INSUFFICIENT_RESOURCES; } else { // // we write FileInfo from user mode // ASSERT(buffer != NULL); RtlZeroMemory(buffer, bufferLen); RtlCopyMemory(buffer, EventInfo->Buffer, EventInfo->BufferLength); // written bytes info = EventInfo->BufferLength; status = EventInfo->Status; if (NT_SUCCESS(status) && irpSp->Parameters.QueryFile.FileInformationClass == FileAllInformation) { PFILE_ALL_INFORMATION allInfo = (PFILE_ALL_INFORMATION)buffer; allInfo->PositionInformation.CurrentByteOffset = IrpEntry->FileObject->CurrentByteOffset; } } DokanCompleteIrpRequest(irp, status, info); DDbgPrint("<== DokanCompleteQueryInformation\n"); }
PDokanFCB DokanGetFCB( __in PDokanVCB Vcb, __in PWCHAR FileName, __in ULONG FileNameLength) { PLIST_ENTRY thisEntry, nextEntry, listHead; PDokanFCB fcb = NULL; ULONG pos; KeEnterCriticalRegion(); ExAcquireResourceExclusiveLite(&Vcb->Resource, TRUE); // search the FCB which is already allocated // (being used now) listHead = &Vcb->NextFCB; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { nextEntry = thisEntry->Flink; fcb = CONTAINING_RECORD(thisEntry, DokanFCB, NextFCB); if (fcb->FileName.Length == FileNameLength) { // FileNameLength in bytes for (pos = 0; pos < FileNameLength/sizeof(WCHAR); ++pos) { if (fcb->FileName.Buffer[pos] != FileName[pos]) break; } // we have the FCB which is already allocated and used if (pos == FileNameLength/sizeof(WCHAR)) break; } fcb = NULL; } // we don't have FCB if (fcb == NULL) { DDbgPrint(" Allocate FCB\n"); fcb = DokanAllocateFCB(Vcb); // no memory? if (fcb == NULL) { ExFreePool(FileName); ExReleaseResourceLite(&Vcb->Resource); KeLeaveCriticalRegion(); return NULL; } ASSERT(fcb != NULL); fcb->FileName.Buffer = FileName; fcb->FileName.Length = (USHORT)FileNameLength; fcb->FileName.MaximumLength = (USHORT)FileNameLength; // we already have FCB } else { // FileName (argument) is never used and must be freed ExFreePool(FileName); } InterlockedIncrement(&fcb->FileCount); ExReleaseResourceLite(&Vcb->Resource); KeLeaveCriticalRegion(); return fcb; }
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; DDbgPrint(" rename also done on fcb %wZ \n", &fcb->FileName); } } 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: { DDbgPrint(" DokanCompleteSetInformation Report FileRenameInformation"); DokanNotifyReportChange0(fcb, &oldFileName, DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_RENAMED_OLD_NAME); // free old file name ExFreePool(oldFileName.Buffer); DokanNotifyReportChange(fcb, DokanFCBFlagsIsSet(fcb, DOKAN_FILE_DIRECTORY) ? FILE_NOTIFY_CHANGE_DIR_NAME : 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 ReleaseTimeoutPendingIrp( __in PDokanDCB Dcb ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; LARGE_INTEGER tickCount; LIST_ENTRY completeList; PIRP irp; DDbgPrint("==> ReleaseTimeoutPendingIRP\n"); InitializeListHead(&completeList); ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&Dcb->PendingIrp.ListLock, &oldIrql); // when IRP queue is empty, there is nothing to do if (IsListEmpty(&Dcb->PendingIrp.ListHead)) { KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql); DDbgPrint(" IrpQueue is Empty\n"); return STATUS_SUCCESS; } KeQueryTickCount(&tickCount); // search timeout IRP through pending IRP list listHead = &Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); // this IRP is NOT timeout yet if (tickCount.QuadPart < irpEntry->TickCount.QuadPart) { break; } RemoveEntryList(thisEntry); DDbgPrint(" timeout Irp #%X\n", irpEntry->SerialNumber); irp = irpEntry->Irp; if (irp == NULL) { // this IRP has already been canceled ASSERT(irpEntry->CancelRoutineFreeMemory == FALSE); DokanFreeIrpEntry(irpEntry); continue; } // this IRP is not canceled yet if (IoSetCancelRoutine(irp, NULL) == NULL) { // Cancel routine will run as soon as we release the lock InitializeListHead(&irpEntry->ListEntry); irpEntry->CancelRoutineFreeMemory = TRUE; continue; } // 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; InsertTailList(&completeList, &irpEntry->ListEntry); } if (IsListEmpty(&Dcb->PendingIrp.ListHead)) { KeClearEvent(&Dcb->PendingIrp.NotEmpty); } KeReleaseSpinLock(&Dcb->PendingIrp.ListLock, oldIrql); while (!IsListEmpty(&completeList)) { listHead = RemoveHeadList(&completeList); irpEntry = CONTAINING_RECORD(listHead, IRP_ENTRY, ListEntry); irp = irpEntry->Irp; DokanCompleteIrpRequest(irp, STATUS_INSUFFICIENT_RESOURCES, 0); DokanFreeIrpEntry(irpEntry); } DDbgPrint("<== ReleaseTimeoutPendingIRP\n"); return STATUS_SUCCESS; }
VOID DokanIrpCancelRoutine( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PIRP_ENTRY irpEntry; ULONG serialNumber = 0; PIO_STACK_LOCATION irpSp; UNREFERENCED_PARAMETER(DeviceObject); DDbgPrint("==> DokanIrpCancelRoutine\n"); // Release the cancel spinlock IoReleaseCancelSpinLock(Irp->CancelIrql); irpEntry = Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY]; if (irpEntry != NULL) { PKSPIN_LOCK lock = &irpEntry->IrpList->ListLock; // Acquire the queue spinlock ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(lock, &oldIrql); irpSp = IoGetCurrentIrpStackLocation(Irp); ASSERT(irpSp != NULL); serialNumber = irpEntry->SerialNumber; RemoveEntryList(&irpEntry->ListEntry); // If Write is canceld before completion and buffer that saves writing // content is not freed, free it here if (irpSp->MajorFunction == IRP_MJ_WRITE) { PVOID eventContext = Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT]; if (eventContext != NULL) { DokanFreeEventContext(eventContext); } Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_EVENT] = NULL; } if (IsListEmpty(&irpEntry->IrpList->ListHead)) { //DDbgPrint(" list is empty ClearEvent\n"); KeClearEvent(&irpEntry->IrpList->NotEmpty); } irpEntry->Irp = NULL; if (irpEntry->CancelRoutineFreeMemory == FALSE) { InitializeListHead(&irpEntry->ListEntry); } else { DokanFreeIrpEntry(irpEntry); irpEntry = NULL; } Irp->Tail.Overlay.DriverContext[DRIVER_CONTEXT_IRP_ENTRY] = NULL; KeReleaseSpinLock(lock, oldIrql); } DDbgPrint(" canceled IRP #%X\n", serialNumber); DokanCompleteIrpRequest(Irp, STATUS_CANCELLED, 0); DDbgPrint("<== DokanIrpCancelRoutine\n"); return; }
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"); }
// 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((LONG*)&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; }
VOID DokanPrintToSysLog(__in PDRIVER_OBJECT DriverObject, __in UCHAR MajorFunctionCode, __in NTSTATUS MessageId, __in NTSTATUS Status, __in LPCTSTR Format, __in va_list Args) { NTSTATUS status = STATUS_SUCCESS; PIO_ERROR_LOG_PACKET packet = NULL; WCHAR *message = NULL; size_t messageCapacity = DOKAN_LOG_MAX_CHAR_COUNT; size_t messageCharCount = 0; size_t messageCharsWritten = 0; size_t packetCount = 0; size_t i = 0; UCHAR packetCharCount = 0; UCHAR packetSize = 0; __try { message = ExAllocatePool(sizeof(WCHAR) * messageCapacity); if (message == NULL) { DDbgPrint("Failed to allocate message of capacity %d\n", messageCapacity); __leave; } status = RtlStringCchVPrintfW(message, messageCapacity, Format, Args); if (status == STATUS_BUFFER_OVERFLOW) { // In this case we want to at least log what we can fit. DDbgPrint("Log message was larger than DOKAN_LOG_MAX_CHAR_COUNT." " Format: %S\n", Format); } else if (status != STATUS_SUCCESS) { DDbgPrint("Failed to generate log message with format: %S; status: %x\n", Format, status); __leave; } status = RtlStringCchLengthW(message, messageCapacity, &messageCharCount); if (status != STATUS_SUCCESS) { DDbgPrint("Failed to determine message length, status: %x\n", status); __leave; } packetCount = messageCharCount / DOKAN_LOG_MAX_PACKET_NONNULL_CHARS; if (messageCharCount % DOKAN_LOG_MAX_PACKET_NONNULL_CHARS != 0) { ++packetCount; } for (i = 0; i < packetCount; i++) { packetCharCount = (UCHAR)min(messageCharCount - messageCharsWritten, DOKAN_LOG_MAX_PACKET_NONNULL_CHARS); packetSize = sizeof(IO_ERROR_LOG_PACKET) + sizeof(WCHAR) * (packetCharCount + 1); packet = IoAllocateErrorLogEntry(DriverObject, packetSize); if (packet == NULL) { DDbgPrint("Failed to allocate packet of size %d\n", packetSize); __leave; } RtlZeroMemory(packet, packetSize); packet->MajorFunctionCode = MajorFunctionCode; packet->NumberOfStrings = 1; packet->StringOffset = (USHORT)((char *)&packet->DumpData[0] - (char *)packet); packet->ErrorCode = MessageId; packet->FinalStatus = Status; RtlCopyMemory(&packet->DumpData[0], message + messageCharsWritten, sizeof(WCHAR) * packetCharCount); IoWriteErrorLogEntry(packet); // Destroys packet. packet = NULL; messageCharsWritten += packetCharCount; } } __finally { if (message != NULL) { ExFreePool(message); } } }