VOID DokanNotifyReportChange0(__in PDokanFCB Fcb, __in PUNICODE_STRING FileName, __in ULONG FilterMatch, __in ULONG Action) { USHORT nameOffset; DDbgPrint("==> DokanNotifyReportChange %wZ\n", FileName); ASSERT(Fcb != NULL); ASSERT(FileName != NULL); if (DokanUnicodeStringChar(FileName, L':') != -1) { //FileStream //Convert file action to stream action switch (Action) { case FILE_ACTION_ADDED: Action = FILE_ACTION_ADDED_STREAM; break; case FILE_ACTION_REMOVED: Action = FILE_ACTION_REMOVED_STREAM; break; case FILE_ACTION_MODIFIED: Action = FILE_ACTION_MODIFIED_STREAM; break; default: break; } //Convert file flag to stream flag if (FlagOn(FilterMatch, FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME)) SetFlag(FilterMatch, FILE_NOTIFY_CHANGE_STREAM_NAME); if (FlagOn(FilterMatch, FILE_NOTIFY_CHANGE_SIZE)) SetFlag(FilterMatch, FILE_NOTIFY_CHANGE_STREAM_SIZE); if (FlagOn(FilterMatch, FILE_NOTIFY_CHANGE_LAST_WRITE)) SetFlag(FilterMatch, FILE_NOTIFY_CHANGE_STREAM_WRITE); //Cleanup file flag converted ClearFlag(FilterMatch, ~(FILE_NOTIFY_CHANGE_STREAM_NAME | FILE_NOTIFY_CHANGE_STREAM_SIZE | FILE_NOTIFY_CHANGE_STREAM_WRITE)); } nameOffset = (USHORT)(FileName->Length / sizeof(WCHAR) - 1); // search the last "\" and then calculate the Offset in bytes nameOffset = (USHORT)(DokanSearchWcharinUnicodeStringWithUlong( FileName, L'\\', (ULONG)nameOffset, 1)); nameOffset *= sizeof(WCHAR); // Offset is in bytes FsRtlNotifyFullReportChange(Fcb->Vcb->NotifySync, &Fcb->Vcb->DirNotifyList, (PSTRING)FileName, nameOffset, NULL, // StreamName NULL, // NormalizedParentName FilterMatch, Action, NULL); // TargetContext DDbgPrint("<== DokanNotifyReportChange\n"); }
NTSTATUS DokanDispatchCreate( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) /*++ Routine Description: This device control dispatcher handles create & close IRPs. Arguments: DeviceObject - Context for the activity. Irp - The device control argument block. Return Value: NTSTATUS --*/ { PDokanVCB vcb; PDokanDCB dcb; PIO_STACK_LOCATION irpSp; NTSTATUS status = STATUS_INVALID_PARAMETER; PFILE_OBJECT fileObject; ULONG info = 0; PEPROCESS process; PUNICODE_STRING processImageName; PEVENT_CONTEXT eventContext; PFILE_OBJECT relatedFileObject; ULONG fileNameLength = 0; ULONG eventLength; PDokanFCB fcb; PDokanCCB ccb; PWCHAR fileName; BOOLEAN needBackSlashAfterRelatedFile = FALSE; PAGED_CODE(); __try { FsRtlEnterFileSystem(); DDbgPrint("==> DokanCreate\n"); irpSp = IoGetCurrentIrpStackLocation(Irp); fileObject = irpSp->FileObject; relatedFileObject = fileObject->RelatedFileObject; if (fileObject == NULL) { DDbgPrint(" fileObject == NULL\n"); status = STATUS_INVALID_PARAMETER; __leave; } DDbgPrint(" ProcessId %lu\n", IoGetRequestorProcessId(Irp)); DDbgPrint(" FileName:%wZ\n", &fileObject->FileName); vcb = DeviceObject->DeviceExtension; PrintIdType(vcb); if (GetIdentifierType(vcb) != VCB) { status = STATUS_SUCCESS; __leave; } dcb = vcb->Dcb; DDbgPrint(" IrpSp->Flags = %d\n", irpSp->Flags); if (irpSp->Flags & SL_CASE_SENSITIVE) { DDbgPrint(" IrpSp->Flags SL_CASE_SENSITIVE\n"); } if (irpSp->Flags & SL_FORCE_ACCESS_CHECK) { DDbgPrint(" IrpSp->Flags SL_FORCE_ACCESS_CHECK\n"); } if (irpSp->Flags & SL_OPEN_PAGING_FILE) { DDbgPrint(" IrpSp->Flags SL_OPEN_PAGING_FILE\n"); } if (irpSp->Flags & SL_OPEN_TARGET_DIRECTORY) { DDbgPrint(" IrpSp->Flags SL_OPEN_TARGET_DIRECTORY\n"); } if ((fileObject->FileName.Length > sizeof(WCHAR)) && (fileObject->FileName.Buffer[1] == L'\\') && (fileObject->FileName.Buffer[0] == L'\\')) { fileObject->FileName.Length -= sizeof(WCHAR); RtlMoveMemory(&fileObject->FileName.Buffer[0], &fileObject->FileName.Buffer[1], fileObject->FileName.Length); } if (relatedFileObject != NULL) { fileObject->Vpb = relatedFileObject->Vpb; } else { fileObject->Vpb = dcb->DeviceObject->Vpb; } if (relatedFileObject == NULL && fileObject->FileName.Length == 0) { DDbgPrint(" request for FS device\n"); if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) { status = STATUS_NOT_A_DIRECTORY; } else { SetFileObjectForVCB(fileObject, vcb); info = FILE_OPENED; status = STATUS_SUCCESS; } __leave; } if (fileObject->FileName.Length > sizeof(WCHAR) && fileObject->FileName.Buffer[fileObject->FileName.Length/sizeof(WCHAR)-1] == L'\\') { fileObject->FileName.Length -= sizeof(WCHAR); } fileNameLength = fileObject->FileName.Length; if (relatedFileObject) { fileNameLength += relatedFileObject->FileName.Length; if (fileObject->FileName.Length > 0 && fileObject->FileName.Buffer[0] == '\\') { DDbgPrint(" when RelatedFileObject is specified, the file name should be relative path\n"); status = STATUS_OBJECT_NAME_INVALID; __leave; } if (relatedFileObject->FileName.Length > 0 && relatedFileObject->FileName.Buffer[relatedFileObject->FileName.Length/sizeof(WCHAR)-1] != '\\') { needBackSlashAfterRelatedFile = TRUE; fileNameLength += sizeof(WCHAR); } } // don't open file like stream if (!dcb->UseAltStream && DokanUnicodeStringChar(&fileObject->FileName, L':') != -1) { DDbgPrint(" alternate stream\n"); status = STATUS_INVALID_PARAMETER; info = 0; __leave; } // this memory is freed by DokanGetFCB if needed // "+ sizeof(WCHAR)" is for the last NULL character fileName = ExAllocatePool(fileNameLength + sizeof(WCHAR)); if (fileName == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } RtlZeroMemory(fileName, fileNameLength + sizeof(WCHAR)); if (relatedFileObject != NULL) { DDbgPrint(" RelatedFileName:%wZ\n", &relatedFileObject->FileName); // copy the file name of related file object RtlCopyMemory(fileName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length); if (needBackSlashAfterRelatedFile) { ((PWCHAR)fileName)[relatedFileObject->FileName.Length/sizeof(WCHAR)] = '\\'; } // copy the file name of fileObject RtlCopyMemory((PCHAR)fileName + relatedFileObject->FileName.Length + (needBackSlashAfterRelatedFile? sizeof(WCHAR) : 0), fileObject->FileName.Buffer, fileObject->FileName.Length); } else { // if related file object is not specifed, copy the file name of file object RtlCopyMemory(fileName, fileObject->FileName.Buffer, fileObject->FileName.Length); } fcb = DokanGetFCB(vcb, fileName, fileNameLength); if (fcb == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } if (irpSp->Flags & SL_OPEN_PAGING_FILE) { fcb->AdvancedFCBHeader.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE; fcb->AdvancedFCBHeader.Flags2 &= ~FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS; } ccb = DokanAllocateCCB(dcb, fcb); if (ccb == NULL) { DokanFreeFCB(fcb); // FileName is freed here status = STATUS_INSUFFICIENT_RESOURCES; __leave; } fileObject->FsContext = &fcb->AdvancedFCBHeader; fileObject->FsContext2 = ccb; fileObject->PrivateCacheMap = NULL; fileObject->SectionObjectPointer = &fcb->SectionObjectPointers; //fileObject->Flags |= FILE_NO_INTERMEDIATE_BUFFERING; eventLength = sizeof(EVENT_CONTEXT) + fcb->FileName.Length; eventContext = AllocateEventContext(vcb->Dcb, Irp, eventLength, ccb); if (eventContext == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; __leave; } eventContext->Context = 0; eventContext->FileFlags |= fcb->Flags; // copy the file name eventContext->Create.FileNameLength = fcb->FileName.Length; RtlCopyMemory(eventContext->Create.FileName, fcb->FileName.Buffer, fcb->FileName.Length); eventContext->Create.FileAttributes = irpSp->Parameters.Create.FileAttributes; eventContext->Create.CreateOptions = irpSp->Parameters.Create.Options; eventContext->Create.DesiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess; eventContext->Create.ShareAccess = irpSp->Parameters.Create.ShareAccess; // register this IRP to waiting IPR list status = DokanRegisterPendingIrp(DeviceObject, Irp, eventContext); } __finally { if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); DokanPrintNTStatus(status); } DDbgPrint("<== DokanCreate\n"); FsRtlExitFileSystem(); } return status; }