static _fileContext* _getOrSetContext ( PFLT_CALLBACK_DATA Data ) { NTSTATUS status = STATUS_SUCCESS; _fileContext* context = NULL; _fileContext* oldContext = NULL; status = FltGetFileContext( Data->Iopb->TargetInstance, Data->Iopb->TargetFileObject, &context ); if( STATUS_NOT_FOUND == status ) { status = FltAllocateContext( g_filter, FLT_FILE_CONTEXT, sizeof( _fileContext ), NonPagedPool, (PFLT_CONTEXT*)&context ); if( STATUS_SUCCESS == status ) { context->isNew = FALSE; context->isDelete = FALSE; context->isChanged = FALSE; context->isRead = FALSE; context->lastWritePid = 0; context->lastReadPid = 0; status = FltSetFileContext( Data->Iopb->TargetInstance, Data->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, context, &oldContext ); if( STATUS_FLT_CONTEXT_ALREADY_DEFINED == status ) { FltReleaseContext( (PFLT_CONTEXT)context ); context = oldContext; } else if( STATUS_SUCCESS != status ) { FltReleaseContext( (PFLT_CONTEXT)context ); context = NULL; } } } if( NULL_CONTEXT == context ) { context = NULL; } return context; }
VOID FLTAPI UcaTransactionContextCleanupCallback(_In_ PUCA_TRANSACTION_CONTEXT TransactionContext, _In_ FLT_CONTEXT_TYPE ContextType) { PUCA_DELETE_NOTIFY DeleteNotify = NULL; UNREFERENCED_PARAMETER(ContextType); PAGED_CODE(); __debugbreak(); ASSERT(ContextType == FLT_TRANSACTION_CONTEXT); if (TransactionContext->Resource != NULL) { FltAcquireResourceExclusive( TransactionContext->Resource ); while (!IsListEmpty( &TransactionContext->DeleteNotifyList)) { // Remove every UCA_DELETE_NOTIFY, releasing their corresponding // FLT_FILE_NAME_INFORMATION objects and freeing pool used by them DeleteNotify = CONTAINING_RECORD(RemoveHeadList(&TransactionContext->DeleteNotifyList), UCA_DELETE_NOTIFY, Links); FltReleaseContext(DeleteNotify->StreamContext); ExFreePoolWithTag(DeleteNotify, UCA_ERESOURCE_POOL_TAG); } FltReleaseResource(TransactionContext->Resource); // Delete and free the DeleteNotifyList synchronization resource. ExDeleteResourceLite(TransactionContext->Resource); ExFreePoolWithTag(TransactionContext->Resource, UCA_ERESOURCE_POOL_TAG); } }
NTSTATUS CtxCreateStreamHandleContext ( __deref_out PSTREAMHANDLE_CONTEXT *StreamHandleContext ) /*++ Routine Description: This routine creates a new stream context Arguments: StreamContext - Returns the stream context Return Value: Status --*/ { NTSTATUS status; PSTREAMHANDLE_CONTEXT streamHandleContext; PAGED_CODE(); // // Allocate a stream context // status = FltAllocateContext( g_FileFltContext.FileFltHandle, FLT_STREAMHANDLE_CONTEXT, STREAMHANDLE_CONTEXT_SIZE, NonPagedPool, &streamHandleContext ); if (!NT_SUCCESS( status )) { return status; } // // Initialize the newly created context // RtlZeroMemory( streamHandleContext, STREAMHANDLE_CONTEXT_SIZE ); streamHandleContext->Resource = FsAllocateResource(); if(streamHandleContext->Resource == NULL) { FltReleaseContext( streamHandleContext ); return STATUS_INSUFFICIENT_RESOURCES; } ExInitializeResourceLite( streamHandleContext->Resource ); *StreamHandleContext = streamHandleContext; return STATUS_SUCCESS; }
NTSTATUS iCtx_CreateStreamContext ( __in PFLT_RELATED_OBJECTS FltObjects, __deref_out PSTREAM_CONTEXT *StreamContext ) /*++ Routine Description: This routine creates a new stream context Arguments: StreamContext - Returns the stream context Return Value: Status --*/ { NTSTATUS status; PSTREAM_CONTEXT streamContext; PAGED_CODE(); status = FltAllocateContext( FltObjects->Filter, FLT_STREAM_CONTEXT, STREAM_CONTEXT_SIZE, NonPagedPool, &streamContext ); if (!NT_SUCCESS( status )) { return status; } // Initialize the newly created context RtlZeroMemory( streamContext, STREAM_CONTEXT_SIZE ); streamContext->Resource = ExAllocatePoolWithTag( NonPagedPool, sizeof( ERESOURCE ),RESOURCE_TAG ); if(streamContext->Resource == NULL) { FltReleaseContext( streamContext ); return STATUS_INSUFFICIENT_RESOURCES; } ExInitializeResourceLite( streamContext->Resource ); KeInitializeSpinLock(&streamContext->Resource1) ; *StreamContext = streamContext; return STATUS_SUCCESS; }
/*++ Routine Description: This routine creates a new stream context Arguments: StreamContext - Returns the stream context Return Value: Status --*/ NTSTATUS CtxCreateStreamHandleContext ( __deref_out PCTX_STREAMHANDLE_CONTEXT *StreamHandleContext ) { NTSTATUS status; PCTX_STREAMHANDLE_CONTEXT streamHandleContext; PAGED_CODE(); // // Allocate a stream context // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Allocating stream handle context \n") ); status = FltAllocateContext( Globals.Filter, FLT_STREAMHANDLE_CONTEXT, CTX_STREAMHANDLE_CONTEXT_SIZE, PagedPool, &streamHandleContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to allocate stream handle context with status 0x%x \n", status) ); return status; } // // Initialize the newly created context // RtlZeroMemory( streamHandleContext, CTX_STREAMHANDLE_CONTEXT_SIZE ); streamHandleContext->Resource = CtxAllocateResource(); if(streamHandleContext->Resource == NULL) { FltReleaseContext( streamHandleContext ); return STATUS_INSUFFICIENT_RESOURCES; } ExInitializeResourceLite( streamHandleContext->Resource ); *StreamHandleContext = streamHandleContext; return STATUS_SUCCESS; }
NTSTATUS UcaGetOrAllocContext(_In_ PFLT_INSTANCE Instance, _In_ PVOID Target, _In_ FLT_CONTEXT_TYPE ContextType, _In_ BOOLEAN CreateIfNotFound, _Outptr_ PFLT_CONTEXT *Context) { PFLT_CONTEXT OldContext; NTSTATUS Status; *Context = NULL; /* Try to get the existing context */ Status = UcaGetContext(Instance, Target, ContextType, Context); if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) return Status; /* Check if we need to allocate a new context */ if (Status == STATUS_NOT_FOUND && CreateIfNotFound) { /* Allocate a new context */ Status = UcaAllocateContext(ContextType, Context); if (!NT_SUCCESS(Status)) return Status; /* Set the new context */ Status = UcaSetContext(Instance, Target, ContextType, *Context, &OldContext); if (!NT_SUCCESS(Status)) { /* Something went wrong, free the context */ FltReleaseContext(*Context); /* Check if a context was already set */ if (Status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) { /* We're racing with some other call which managed to set the context before us. We will return that context instead */ *Context = OldContext; Status = STATUS_SUCCESS; } else { *Context = NULL; } } } return Status; }
VOID NPInstanceTeardownStart ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_TEARDOWN_FLAGS Flags ) { NTSTATUS status = STATUS_SUCCESS; PVOLUME_CONTEXT context = NULL; UNREFERENCED_PARAMETER( Flags ); PAGED_CODE(); PT_DBG_PRINT( PTDBG_TRACE_ROUTINES, ("minifilter1!NPInstanceTeardownStart: Entered\n") ); status = FltGetVolumeContext(FltObjects->Filter, FltObjects->Volume, &context); if( NT_SUCCESS(status) && context->Name.Buffer != NULL) DbgPrint("[%wZ]\n", &context->Name); FltReleaseContext( context ); }
NTSTATUS FmmIsImplicitVolumeLock( _In_ PFLT_CALLBACK_DATA Cbd, _Out_ PBOOLEAN IsLock ) /*++ Routine Description: This routine determines if an open is a implcit volume lock. Arguments Cbd - Supplies a pointer to the callbackData which declares the requested operation. IsLock - Supplies a pointer to a user allocated boolean which is used to tell the user wheather the operation is an implied volume lock. Return Value: Returns STATUS_SUCCESS if the the function determined wheather or not the operation was a volume lock. On STATUS_SUCCESS it is safe to check IsLock to get the answer. Otherwise, the check failed and we dont know if it is a lock or not. STATUS_INVALID_PARAMETER indicates that the volume's file system type is unrecognized by the check function. This is an error code. --*/ { NTSTATUS status = STATUS_SUCCESS; PFMM_INSTANCE_CONTEXT instanceContext = NULL; USHORT shareAccess; ACCESS_MASK prevAccess; PAGED_CODE(); // // Get the instance context so we know // which file system we are attached to. // status = FltGetInstanceContext( Cbd->Iopb->TargetInstance, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmIsImplicitVolumeLock -> Failed to get instance context.\n") ); goto FmmIsImplicitVolumeLockCleanup; } FLT_ASSERT( instanceContext != NULL ); // // Now check to see if the open is an implied volume lock // on this filesystem. // shareAccess = Cbd->Iopb->Parameters.Create.ShareAccess; prevAccess = Cbd->Iopb->Parameters.Create.SecurityContext->DesiredAccess; switch (instanceContext->FilesystemType) { case FLT_FSTYPE_REFS: *IsLock = ((!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && (BooleanFlagOn( prevAccess,(FILE_WRITE_DATA | FILE_APPEND_DATA) ))); status = STATUS_SUCCESS; break; case FLT_FSTYPE_NTFS: *IsLock = ((!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE)) && (BooleanFlagOn( prevAccess,(FILE_WRITE_DATA | FILE_APPEND_DATA) ))); status = STATUS_SUCCESS; break; case FLT_FSTYPE_FAT: *IsLock = (!BooleanFlagOn( shareAccess, FILE_SHARE_WRITE | FILE_SHARE_DELETE)); status = STATUS_SUCCESS; break; default: status = STATUS_INVALID_PARAMETER; break; } FmmIsImplicitVolumeLockCleanup: if (instanceContext != NULL ) { FltReleaseContext( instanceContext ); } return status; }
FLT_PREOP_CALLBACK_STATUS CtxPreClose ( _Inout_ PFLT_CALLBACK_DATA Cbd, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext ) { PCTX_STREAM_CONTEXT streamContext = NULL; NTSTATUS status; BOOLEAN streamContextCreated; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPreClose -> Enter (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // Get the stream context // status = CtxFindOrCreateStreamContext(Cbd, FALSE, // do not create if one does not exist &streamContext, &streamContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPreClose -> Failed to find stream context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPreCloseCleanup; } DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPreClose -> Getting stream context for file (Cbd = %p, FileObject = %p, StreamContext = %p. StreamContextCreated = %x)\n", Cbd, FltObjects->FileObject, streamContext, streamContextCreated) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamContext->Resource); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPreClose -> Old info in stream context for file(Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Update the close count in the context // streamContext->CloseCount++; DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPreClose -> New info in stream context for file (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamContext->Resource); CtxPreCloseCleanup: // // Release the references we have acquired // if (streamContext != NULL) { FltReleaseContext( streamContext ); } DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPreClose -> Exit (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // It doesn't make sense to fail the cleanup - so ignore any errors we may // encounter and return success // return FLT_PREOP_SUCCESS_NO_CALLBACK; }
VOID CtxInstanceTeardownComplete ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_TEARDOWN_FLAGS Flags ) /*++ Routine Description: This routine is called at the end of instance teardown. Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance and its associated volume. Flags - Reason why this instance is been deleted. Return Value: None. --*/ { PCTX_INSTANCE_CONTEXT instanceContext; NTSTATUS status; UNREFERENCED_PARAMETER( Flags ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance teardown complete started (Instance = %p)\n", FltObjects->Instance) ); DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Getting instance context (Volume = %p, Instance = %p)\n", FltObjects->Volume, FltObjects->Instance) ); status = FltGetInstanceContext( FltObjects->Instance, &instanceContext ); if (NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Instance teardown for volume %wZ (Volume = %p, Instance = %p, InstanceContext = %p)\n", &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance, instanceContext) ); // // Here the filter may perform any teardown of its own structures associated // with this instance. // // The filter should not free memory or synchronization objects allocated to // objects within the instance context. That should be performed in the // cleanup callback for the instance context // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing instance context %p for volume %wZ (Volume = %p, Instance = %p)\n", instanceContext, &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance) ); FltReleaseContext( instanceContext ); } else { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to get instance context (Volume = %p, Instance = %p Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); } DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance teardown complete ended (Instance = %p)\n", FltObjects->Instance) ); }
NTSTATUS CtxInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) /*++ Routine Description: This routine is called whenever a new instance is created on a volume. This gives us a chance to decide if we need to attach to this volume or not. Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance and its associated volume. Flags - Flags describing the reason for this attach request. Return Value: STATUS_SUCCESS - attach STATUS_FLT_DO_NOT_ATTACH - do not attach --*/ { PCTX_INSTANCE_CONTEXT instanceContext = NULL; NTSTATUS status = STATUS_SUCCESS; ULONG volumeNameLength; #if __NDAS_FS_MINI__ ULONG propertyLengthReturned; UNICODE_STRING ntfs; UNICODE_STRING ndasNtfs; UNICODE_STRING fat; UNICODE_STRING ndasFat; PNETDISK_PARTITION netdiskPartition; NETDISK_ENABLE_MODE netdiskEnableMode; #endif #if __LFS__ ULONG propertyLengthReturned; BOOLEAN result; UNICODE_STRING ntfs; UNICODE_STRING ndasNtfs; UNICODE_STRING fat; UNICODE_STRING ndasFat; PENABLED_NETDISK enabledNetdisk; NETDISK_ENABLE_MODE netdiskEnableMode; #endif UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeDeviceType ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); PAGED_CODE(); #if __NDAS_FS_MINI__ DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup started FltObjects = %p\n", FltObjects) ); #endif DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup started (Volume = %p, Instance = %p)\n", FltObjects->Volume, FltObjects->Instance) ); // // Allocate and initialize the context for this volume // // // Allocate the instance context // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Allocating instance context (Volume = %p, Instance = %p)\n", FltObjects->Volume, FltObjects->Instance) ); status = FltAllocateContext( FltObjects->Filter, FLT_INSTANCE_CONTEXT, CTX_INSTANCE_CONTEXT_SIZE, NonPagedPool, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to allocate instance context (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } #if __NDAS_FS_MINI__ RtlZeroMemory( instanceContext, sizeof(CTX_INSTANCE_CONTEXT) ); status = FltGetVolumeProperties( FltObjects->Volume, NULL, 0, &propertyLengthReturned ); DebugTrace( DEBUG_TRACE_INSTANCES, ("[MiniSpy]: IRP_MJ_VOLUME_MOUNT FltGetVolumeProperties, status = %x, propertyLengthReturned = %d\n", status, propertyLengthReturned) ); instanceContext->VolumeProperties = ExAllocatePoolWithTag( PagedPool, propertyLengthReturned, CTX_VOLUME_PROPERTY_TAG ); status = FltGetVolumeProperties( FltObjects->Volume, instanceContext->VolumeProperties, propertyLengthReturned, &propertyLengthReturned ); DebugTrace( DEBUG_TRACE_INSTANCES, ("[MiniSpy]: FltGetVolumeProperties, status = %x, propertyLengthReturned = %d\n", status, propertyLengthReturned) ); if( !NT_SUCCESS( status )) { status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } DebugTrace( DEBUG_TRACE_INSTANCES, ("[MiniSpy]: FltGetVolumeProperties, DeviceType = %d " "FileSystemDriverName = %wZ\n" "FileSystemDeviceName = %wZ " "RealDeviceName = %wZ\n", instanceContext->VolumeProperties->DeviceType, &instanceContext->VolumeProperties->FileSystemDriverName, &instanceContext->VolumeProperties->FileSystemDeviceName, &instanceContext->VolumeProperties->RealDeviceName) ); RtlInitUnicodeString( &ntfs, L"\\Ntfs" ); RtlInitUnicodeString( &ndasNtfs, NDAS_NTFS_DEVICE_NAME ); RtlInitUnicodeString( &fat, L"\\Fat" ); RtlInitUnicodeString( &ndasFat, NDAS_FAT_DEVICE_NAME ); if (!(RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ntfs, TRUE) || RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE) || RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &fat, TRUE) || RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE))) { status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } status = FltGetDeviceObject( FltObjects->Volume, &instanceContext->DeviceObject ); if (!NT_SUCCESS(status)) { status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } status = FltGetDiskDeviceObject( FltObjects->Volume, &instanceContext->DiskDeviceObject ); if (!NT_SUCCESS(status)) { status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } DebugTrace( DEBUG_TRACE_INSTANCES, ("DeviceObject = %p, DiskDeviceObject = %p\n", instanceContext->DeviceObject, instanceContext->DiskDeviceObject) ); if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE) && !GlobalLfs.NdasFatRwSupport && !GlobalLfs.NdasFatRoSupport || RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE) && !GlobalLfs.NdasNtfsRwSupport && !GlobalLfs.NdasNtfsRoSupport) { NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE)) { status = NetdiskManager_PreMountVolume( GlobalLfs.NetdiskManager, GlobalLfs.NdasFatRwIndirect ? TRUE : FALSE, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.DeviceObject, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.Vpb->RealDevice, &netdiskPartition, &netdiskEnableMode ); } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE)) { status = NetdiskManager_PreMountVolume( GlobalLfs.NetdiskManager, GlobalLfs.NdasNtfsRwIndirect ? TRUE : FALSE, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.DeviceObject, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.Vpb->RealDevice, &netdiskPartition, &netdiskEnableMode ); } else { status = NetdiskManager_PreMountVolume( GlobalLfs.NetdiskManager, FALSE, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.DeviceObject, instanceContext->DiskDeviceObject, //pIrpSp->Parameters.MountVolume.Vpb->RealDevice, &netdiskPartition, &netdiskEnableMode ); } SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("NetdiskManager_IsNetdiskPartition status = %x\n", status) ); if (!NT_SUCCESS(status)) { if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE) || RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE)) { NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } switch (netdiskEnableMode) { case NETDISK_READ_ONLY: if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &fat, TRUE)) { if (GlobalLfs.NdasFatRoSupport) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE)) { if (!GlobalLfs.NdasFatRoSupport) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ntfs, TRUE)) { if (GlobalLfs.NdasNtfsRoSupport) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE)) { if (!GlobalLfs.NdasNtfsRoSupport) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else { NDASFS_ASSERT( FALSE ); } break; case NETDISK_SECONDARY: case NETDISK_PRIMARY: case NETDISK_SECONDARY2PRIMARY: if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &fat, TRUE)) { if (GlobalLfs.NdasFatRwSupport && FlagOn(netdiskPartition->EnabledNetdisk->NetdiskInformation.EnabledFeatures, NDASFEATURE_SIMULTANEOUS_WRITE)) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE)) { if (!(GlobalLfs.NdasFatRwSupport && FlagOn(netdiskPartition->EnabledNetdisk->NetdiskInformation.EnabledFeatures, NDASFEATURE_SIMULTANEOUS_WRITE))) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ntfs, TRUE)) { if (GlobalLfs.NdasNtfsRwSupport && FlagOn(netdiskPartition->EnabledNetdisk->NetdiskInformation.EnabledFeatures, NDASFEATURE_SIMULTANEOUS_WRITE)) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE)) { if (!(GlobalLfs.NdasNtfsRwSupport && FlagOn(netdiskPartition->EnabledNetdisk->NetdiskInformation.EnabledFeatures, NDASFEATURE_SIMULTANEOUS_WRITE))) { NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, netdiskPartition, netdiskEnableMode, FALSE, 0, NULL, NULL ); NDASFS_ASSERT( FALSE ); status = STATUS_FLT_DO_NOT_ATTACH; goto CtxInstanceSetupCleanup; } } else { NDASFS_ASSERT( FALSE ); } break; default: NDASFS_ASSERT( FALSE ); break; } LfsReference( &GlobalLfs ); ExInitializeFastMutex( &instanceContext->LfsDeviceExt.FastMutex ); instanceContext->LfsDeviceExt.ReferenceCount = 1; InitializeListHead( &instanceContext->LfsDeviceExt.LfsQListEntry ); instanceContext->LfsDeviceExt.Flags = LFS_DEVICE_FLAG_INITIALIZING; instanceContext->LfsDeviceExt.FileSpyDeviceObject = NULL; instanceContext->LfsDeviceExt.InstanceContext = instanceContext; FltReferenceContext( instanceContext->LfsDeviceExt.InstanceContext ); instanceContext->LfsDeviceExt.NetdiskPartition = netdiskPartition; instanceContext->LfsDeviceExt.NetdiskEnabledMode = netdiskEnableMode; instanceContext->LfsDeviceExt.FilteringMode = LFS_NO_FILTERING; instanceContext->LfsDeviceExt.DiskDeviceObject = instanceContext->DiskDeviceObject; instanceContext->LfsDeviceExt.MountVolumeDeviceObject = instanceContext->DiskDeviceObject; SPY_LOG_PRINT( SPYDEBUG_ERROR, ("FileSpy!CtxInstanceSetup: instanceContext->LfsDeviceExt.DiskDeviceObject = %p\n", instanceContext->LfsDeviceExt.DiskDeviceObject) ); ExInterlockedInsertTailList( &GlobalLfs.LfsDeviceExtQueue, &instanceContext->LfsDeviceExt.LfsQListEntry, &GlobalLfs.LfsDeviceExtQSpinLock ); if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ntfs, TRUE)) { instanceContext->LfsDeviceExt.FileSystemType = LFS_FILE_SYSTEM_NTFS; } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasNtfs, TRUE)) { instanceContext->LfsDeviceExt.FileSystemType = LFS_FILE_SYSTEM_NDAS_NTFS; } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &fat, TRUE)) { instanceContext->LfsDeviceExt.FileSystemType = LFS_FILE_SYSTEM_FAT; } else if (RtlEqualUnicodeString(&instanceContext->VolumeProperties->FileSystemDeviceName, &ndasFat, TRUE)) { instanceContext->LfsDeviceExt.FileSystemType = LFS_FILE_SYSTEM_NDAS_FAT; } else { NDASFS_ASSERT( FALSE ); } NetdiskManager_PostMountVolume( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode, TRUE, instanceContext->LfsDeviceExt.FileSystemType, &instanceContext->LfsDeviceExt, &instanceContext->LfsDeviceExt.NetdiskPartitionInformation ); switch (netdiskEnableMode) { case NETDISK_READ_ONLY: instanceContext->LfsDeviceExt.FilteringMode = LFS_READONLY; break; case NETDISK_SECONDARY: instanceContext->LfsDeviceExt.FilteringMode = LFS_SECONDARY; break; case NETDISK_PRIMARY: case NETDISK_SECONDARY2PRIMARY: instanceContext->LfsDeviceExt.FilteringMode = LFS_PRIMARY; break; default: ASSERT( LFS_BUG ); break; } SetFlag( instanceContext->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_MOUNTING ); ASSERT( instanceContext->DiskDeviceObject->Vpb->DeviceObject ); instanceContext->LfsDeviceExt.Vpb = instanceContext->LfsDeviceExt.DiskDeviceObject->Vpb; // Vpb will be changed in IrpSp Why ? instanceContext->LfsDeviceExt.BaseVolumeDeviceObject = instanceContext->LfsDeviceExt.Vpb->DeviceObject; switch (instanceContext->LfsDeviceExt.FilteringMode) { case LFS_READONLY: { // // We don't support cache purging yet. // SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("LfsFsControlMountVolumeComplete: READONLY newDevExt->LfsDeviceExt = %p " "newDevExt->LfsDeviceExt.FileSystemType = %d\n", &instanceContext->LfsDeviceExt, instanceContext->LfsDeviceExt.FileSystemType) ); instanceContext->LfsDeviceExt.AttachedToDeviceObject = instanceContext->DeviceObject; //NULL; //instanceContext->NLExtHeader.AttachedToDeviceObject; NetdiskManager_MountVolumeComplete( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode, status, instanceContext->LfsDeviceExt.AttachedToDeviceObject ); status = SpyFsControlReadonlyMountVolumeComplete( &instanceContext->LfsDeviceExt ); break; } case LFS_PRIMARY: { instanceContext->LfsDeviceExt.AttachedToDeviceObject = instanceContext->DeviceObject; //NULL; //instanceContext->NLExtHeader.AttachedToDeviceObject; ASSERT( instanceContext->LfsDeviceExt.AttachedToDeviceObject ); NetdiskManager_MountVolumeComplete( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode, status, instanceContext->LfsDeviceExt.AttachedToDeviceObject ); SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("LfsFsControlMountVolumeComplete: LFS_PRIMARY newDevExt->LfsDeviceExt = %p " "newDevExt->LfsDeviceExt.FileSystemType = %d\n", &instanceContext->LfsDeviceExt, instanceContext->LfsDeviceExt.FileSystemType) ); status = STATUS_SUCCESS; break; } case LFS_SECONDARY: { instanceContext->LfsDeviceExt.AttachedToDeviceObject = instanceContext->DeviceObject; //NULL; //instanceContext->NLExtHeader.AttachedToDeviceObject; NetdiskManager_MountVolumeComplete( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode, status, instanceContext->LfsDeviceExt.AttachedToDeviceObject ); SPY_LOG_PRINT( LFS_DEBUG_LFS_INFO, ("CtxInstanceSetup: LFS_SECONDARY newDevExt->LfsDeviceExt = %p " "newDevExt->LfsDeviceExt.FileSystemType = %d\n", &instanceContext->LfsDeviceExt, instanceContext->LfsDeviceExt.FileSystemType) ); status = SpyFsControlSecondaryMountVolumeComplete( &instanceContext->LfsDeviceExt ); if (instanceContext->LfsDeviceExt.FilteringMode == LFS_SECONDARY_TO_PRIMARY) { NetdiskManager_ChangeMode( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, &instanceContext->LfsDeviceExt.NetdiskEnabledMode ); } break; } default: NDASFS_ASSERT( FALSE ); NetdiskManager_MountVolumeComplete( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode, status, NULL ); status = STATUS_SUCCESS; break; } // // We completed initialization of this device object, so now // clear the initializing flag. // if (status == STATUS_SUCCESS) { ClearFlag( instanceContext->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_INITIALIZING ); ClearFlag( instanceContext->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_MOUNTING ); SetFlag( instanceContext->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_MOUNTED ); } else { NTSTATUS status2; NDASFS_ASSERT( FALSE ); // // Queue an event to notify user applications // XevtQueueVolumeInvalidOrLocked( -1, instanceContext->LfsDeviceExt.NetdiskPartitionInformation.NetdiskInformation.SlotNo, instanceContext->LfsDeviceExt.NetdiskPartitionInformation.NetdiskInformation.UnitDiskNo ); // // Try to unplug // status2 = NetdiskManager_UnplugNetdisk( GlobalLfs.NetdiskManager, instanceContext->LfsDeviceExt.NetdiskPartition, instanceContext->LfsDeviceExt.NetdiskEnabledMode ); ASSERT( NT_SUCCESS(status2) ); } #endif // // Get the NT volume name length // status = FltGetVolumeName( FltObjects->Volume, NULL, &volumeNameLength ); if( !NT_SUCCESS( status ) && (status != STATUS_BUFFER_TOO_SMALL) ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Unexpected failure in FltGetVolumeName. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } // // Allocate a string big enough to take the volume name // instanceContext->VolumeName.MaximumLength = (USHORT) volumeNameLength; status = CtxAllocateUnicodeString( &instanceContext->VolumeName ); if( !NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to allocate volume name string. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } // // Get the NT volume name // status = FltGetVolumeName( FltObjects->Volume, &instanceContext->VolumeName, &volumeNameLength ); if( !NT_SUCCESS( status ) ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Unexpected failure in FltGetVolumeName. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } instanceContext->Instance = FltObjects->Instance; instanceContext->Volume = FltObjects->Volume; // // Set the instance context. // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Setting instance context %p for volume %wZ (Volume = %p, Instance = %p)\n", instanceContext, &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance) ); status = FltSetInstanceContext( FltObjects->Instance, FLT_SET_CONTEXT_KEEP_IF_EXISTS, instanceContext, NULL ); if( !NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to set instance context for volume %wZ (Volume = %p, Instance = %p, Status = 0x%08X)\n", &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } CtxInstanceSetupCleanup: #if __NDAS_FS_MINI__ if (status != STATUS_SUCCESS) { if (instanceContext->DiskDeviceObject) { ObDereferenceObject( instanceContext->DiskDeviceObject ); instanceContext->DiskDeviceObject = NULL; } if (instanceContext->DeviceObject) { ObDereferenceObject( instanceContext->DeviceObject ); instanceContext->DeviceObject = NULL; } if (instanceContext->VolumeProperties) { ExFreePoolWithTag( instanceContext->VolumeProperties, CTX_VOLUME_PROPERTY_TAG ); instanceContext->VolumeProperties = NULL; } if (FlagOn(instanceContext->LfsDeviceExt.Flags, LFS_DEVICE_FLAG_INITIALIZING)) { LfsDeviceExt_Dereference( &instanceContext->LfsDeviceExt ); } } #endif // // If FltAllocateContext suceeded then we MUST release the context, // irrespective of whether FltSetInstanceContext suceeded or not. // // FltAllocateContext increments the ref count by one. // A successful FltSetInstanceContext increments the ref count by one // and also associates the context with the file system object // // FltReleaseContext decrements the ref count by one. // // When FltSetInstanceContext succeeds, calling FltReleaseContext will // leave the context with a ref count of 1 corresponding to the internal // reference to the context from the file system structures // // When FltSetInstanceContext fails, calling FltReleaseContext will // leave the context with a ref count of 0 which is correct since // there is no reference to the context from the file system structures // if ( instanceContext != NULL ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing instance context %p (Volume = %p, Instance = %p)\n", instanceContext, FltObjects->Volume, FltObjects->Instance) ); FltReleaseContext( instanceContext ); } if (NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup complete (Volume = %p, Instance = %p). Filter will attach to the volume.\n", FltObjects->Volume, FltObjects->Instance) ); } else { DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup complete (Volume = %p, Instance = %p). Filter will not attach to the volume.\n", FltObjects->Volume, FltObjects->Instance) ); } return status; }
/*++ Routine Description: This routine creates a stream handle context for the target stream handle. Optionally, if the context already exists, this routine replaces it with the new context and releases the old context Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. ReplaceIfExists - Supplies if the stream handle context must be replaced if already present StreamContext - Returns the stream context ContextReplaced - Returns if an existing context was replaced Return Value: Status --*/ NTSTATUS CtxCreateOrReplaceStreamHandleContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN ReplaceIfExists, __deref_out PCTX_STREAMHANDLE_CONTEXT *StreamHandleContext, __out_opt PBOOLEAN ContextReplaced ) { NTSTATUS status; PCTX_STREAMHANDLE_CONTEXT streamHandleContext; PCTX_STREAMHANDLE_CONTEXT oldStreamHandleContext; PAGED_CODE(); *StreamHandleContext = NULL; if (ContextReplaced != NULL) *ContextReplaced = FALSE; // // Create a stream context // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Creating stream handle context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateStreamHandleContext( &streamHandleContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Set the new context we just allocated on the file object // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Setting stream context %p (FileObject = %p, Instance = %p, ReplaceIfExists = %x)\n", streamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance, ReplaceIfExists) ); status = FltSetStreamHandleContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, ReplaceIfExists ? FLT_SET_CONTEXT_REPLACE_IF_EXISTS : FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamHandleContext, &oldStreamHandleContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream handle context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing stream handle context %p (FileObject = %p, Instance = %p)\n", streamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( streamHandleContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // We will reach here only if we have failed with STATUS_FLT_CONTEXT_ALREADY_DEFINED // and we can fail with that code only if the context already exists and we have used // the FLT_SET_CONTEXT_KEEP_IF_EXISTS flag ASSERT( ReplaceIfExists == FALSE ); // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Stream context already defined. Retaining old stream context %p (FileObject = %p, Instance = %p)\n", oldStreamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamHandleContext = oldStreamHandleContext; status = STATUS_SUCCESS; } else { // // FltSetStreamContext has suceeded. The new context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // // However, if we have replaced an existing context then we need to // release the old context so as to decrement the ref count on it. // // Note that the memory allocated to the objects within the context // will be freed in the context cleanup and must not be done here. // if ( ReplaceIfExists && oldStreamHandleContext != NULL) { DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing old stream handle context %p (FileObject = %p, Instance = %p)\n", oldStreamHandleContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( oldStreamHandleContext ); if (ContextReplaced != NULL) *ContextReplaced = TRUE; } } *StreamHandleContext = streamHandleContext; return status; }
NTSTATUS CtxCreateOrReplaceStreamHandleContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN ReplaceIfExists, __deref_out PSTREAMHANDLE_CONTEXT *StreamHandleContext, __out_opt PBOOLEAN ContextReplaced ) /*++ Routine Description: This routine creates a stream handle context for the target stream handle. Optionally, if the context already exists, this routine replaces it with the new context and releases the old context Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. ReplaceIfExists - Supplies if the stream handle context must be replaced if already present StreamContext - Returns the stream context ContextReplaced - Returns if an existing context was replaced Return Value: Status --*/ { NTSTATUS status; PSTREAMHANDLE_CONTEXT streamHandleContext; PSTREAMHANDLE_CONTEXT oldStreamHandleContext; PAGED_CODE(); *StreamHandleContext = NULL; if (ContextReplaced != NULL) *ContextReplaced = FALSE; // // Create a stream context // status = CtxCreateStreamHandleContext( &streamHandleContext ); if (!NT_SUCCESS( status )) { return status; } // // Set the new context we just allocated on the file object // status = FltSetStreamHandleContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, ReplaceIfExists ? FLT_SET_CONTEXT_REPLACE_IF_EXISTS : FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamHandleContext, &oldStreamHandleContext ); if (!NT_SUCCESS( status )) { // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // FltReleaseContext( streamHandleContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // return status; } // // We will reach here only if we have failed with STATUS_FLT_CONTEXT_ALREADY_DEFINED // and we can fail with that code only if the context already exists and we have used // the FLT_SET_CONTEXT_KEEP_IF_EXISTS flag ASSERT( ReplaceIfExists == FALSE ); // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamHandleContext = oldStreamHandleContext; status = STATUS_SUCCESS; } else { // // FltSetStreamContext has suceeded. The new context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // // However, if we have replaced an existing context then we need to // release the old context so as to decrement the ref count on it. // // Note that the memory allocated to the objects within the context // will be freed in the context cleanup and must not be done here. // if ( ReplaceIfExists && oldStreamHandleContext != NULL) { streamHandleContext->TaskState = oldStreamHandleContext->TaskState; FltReleaseContext( oldStreamHandleContext ); if (ContextReplaced != NULL) *ContextReplaced = TRUE; } } *StreamHandleContext = streamHandleContext; return status; }
NTSTATUS CtxFindOrCreateFileContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __in_opt PUNICODE_STRING FileName, __deref_out PCTX_FILE_CONTEXT *FileContext, __out_opt PBOOLEAN ContextCreated ) /*++ Routine Description: This routine finds the file context for the target file. Optionally, if the context does not exist this routing creates a new one and attaches the context to the file. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the file context must be created if missing FileName - Supplies the file name FileContext - Returns the file context ContextCreated - Returns if a new context was created Return Value: Status --*/ { NTSTATUS status; PCTX_FILE_CONTEXT fileContext; PCTX_FILE_CONTEXT oldFileContext; PAGED_CODE(); *FileContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // // First try to get the file context. // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Trying to get file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltGetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &fileContext ); // // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context // if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // // Create a file context // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Creating file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateFileContext( FileName, &fileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Set the new context we just allocated on the file object // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Setting file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltSetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, fileContext, &oldFileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // We release the context here because FltSetFileContext failed // // If FltSetFileContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( fileContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetFileContext failed for a reason other than the context already // existing on the file. So the object now does not have any context set // on it. So we return failure to the caller. // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n", oldFileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // fileContext = oldFileContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *FileContext = fileContext; return status; }
NTSTATUS NcGenerateFileName ( _In_ PFLT_INSTANCE Instance, _In_ PFILE_OBJECT FileObject, _In_opt_ PFLT_CALLBACK_DATA Data, _In_ FLT_FILE_NAME_OPTIONS NameOptions, _Out_ PBOOLEAN CacheFileNameInformation, _Inout_ PFLT_NAME_CONTROL OutputNameControl ) { // // Status vars // NTSTATUS Status; // // State lookup vars // BOOLEAN Opened = (BOOLEAN)(FileObject->FsContext != NULL); // True if file object is opened. BOOLEAN ReturnShortName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_SHORT); // True if the user is requesting short name BOOLEAN ReturnOpenedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_OPENED); // True if user is requesting opened name. BOOLEAN ReturnNormalizedName = (BOOLEAN)(FltGetFileNameFormat(NameOptions) == FLT_FILE_NAME_NORMALIZED); // True if user is requesting normalized name. BOOLEAN IgnoreCase; FLT_FILE_NAME_OPTIONS NameQueryMethod = FltGetFileNameQueryMethod( NameOptions ); FLT_FILE_NAME_OPTIONS NameFlags = FLT_VALID_FILE_NAME_FLAGS & NameOptions; // // File name information // PFLT_FILE_NAME_INFORMATION LowerNameInfo = NULL; // File name as reported by lower name provider. Will always be down real mapping. PFLT_FILE_NAME_INFORMATION ShortInfo = NULL; // We will use ShortInfo to store the short name if needed. // // Contexts // PNC_INSTANCE_CONTEXT InstanceContext = NULL; // // Overlap // NC_PATH_OVERLAP RealOverlap; UNICODE_STRING RealRemainder = EMPTY_UNICODE_STRING; // // Temp storage // UNICODE_STRING MungedName = EMPTY_UNICODE_STRING; // // Temp pointer // PUNICODE_STRING Name = NULL; // Pointer to the name we are going to use. PAGED_CODE(); FLT_ASSERT( IoGetTopLevelIrp() == NULL ); // // This should never happen, but let's be safe. // if (!ReturnShortName && !ReturnOpenedName && !ReturnNormalizedName) { FLT_ASSERT( FALSE ); Status = STATUS_NOT_SUPPORTED; goto NcGenerateFileNameCleanup; } RealOverlap.EntireFlags = 0; // // To prevent infinite recursion, calls to FltGetFileNameInformation // from generate file name callbacks should not target current provider. // ClearFlag( NameFlags, FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER ); // // Fetch the instance context. // Status = FltGetInstanceContext( Instance, &InstanceContext ); if (!NT_SUCCESS( Status )) { goto NcGenerateFileNameCleanup; } // // We need to know what the name provider under us thinks the file is called. // If the caller wants the normalized name we query that, otherwise we query // the opened name because we have to compare the full path of the file vs. // the real mapping to determine if the file is mapped. // Status = NcGetFileNameInformation( Data, FileObject, Instance, (ReturnNormalizedName ? FLT_FILE_NAME_NORMALIZED : FLT_FILE_NAME_OPENED) | NameQueryMethod | NameFlags, &LowerNameInfo ); if (!NT_SUCCESS( Status )) { goto NcGenerateFileNameCleanup; } Status = FltParseFileNameInformation( LowerNameInfo ); if (!NT_SUCCESS( Status )) { goto NcGenerateFileNameCleanup; } // // Issues With Pre-open path: // // 1) Poison name cache below name provider: // If a filter above a name provider calls FltGetFileNameInformation on a // file object in his precreate callback, fltmgr will call the name // provider's generate name callback before the name provider's pre create // callback is invoked. Name providers by their nature change names in their // pre-create. Because the name provider has not had the opportunity to // modify the name yet, we need to make sure that fltmgr does not cache the name we // return below us, so we set the FLT_FILE_NAME_DO_NOT_CACHE flag. // //TODO: TRY TO GET ACROSS THAT THIS IS A NAME CHANGER PROBLEM, NOT ALL NAME PROVIDERS NEED TO. // if (!Opened) { SetFlag( NameFlags, FLT_FILE_NAME_DO_NOT_CACHE ); if (Data) { // // NT supports case sensitive and non-case sensitive naming in file systems. // This is handled on a per-open basis. Weather an open is case senstive is // determined by the FO_OPENED_CASE_SENSITIVE flag on the file object. // In pre-create the SL_CASE_SENSITIVE flag on the create IRP specifies the mode. // // If this is on an unopened FileObject, it had better be pre-create so we know // how to process the operation. If we are queried on an unopened FileObject // at any other time we have no way to handle the request. // FLT_ASSERT( Data->Iopb->MajorFunction == IRP_MJ_CREATE || Data->Iopb->MajorFunction == IRP_MJ_NETWORK_QUERY_OPEN ); IgnoreCase = !BooleanFlagOn( Data->Iopb->OperationFlags, SL_CASE_SENSITIVE ); } else { // // If people do unsafe queries on preopened IOs, we cannot // determine if the open is case sensitive or not. // So we cannot determine if this open is down the mapping. // fail. // FLT_ASSERT( FALSE ); Status = STATUS_INVALID_PARAMETER; goto NcGenerateFileNameCleanup; } } else { // // After a file has been opened, the case sensitivity is stored in the file object. // IgnoreCase = !BooleanFlagOn( FileObject->Flags, FO_OPENED_CASE_SENSITIVE ); } // // Calculate the overlap with the real mapping. // NcComparePath( &LowerNameInfo->Name, &InstanceContext->Mapping.RealMapping, &RealRemainder, IgnoreCase, TRUE, &RealOverlap ); // // Whether we munge depends on what name is requested. // if (ReturnOpenedName || ReturnNormalizedName) { if (Opened && RealOverlap.InMapping) { // // We munge the opened name if it overlaps with the real mapping. // The returned path will be down the user mapping. // Status = NcConstructPath( &InstanceContext->Mapping.UserMapping, &RealRemainder, TRUE, &MungedName); if (!NT_SUCCESS( Status )) { goto NcGenerateFileNameCleanup; } Name = &MungedName; } else { // // We return the queried result if the path is not in the // mapping. // Name = &LowerNameInfo->Name; } } else if (ReturnShortName) { // // Note that unlike opened names, a query for a shortname only returns // the final component, not the full path. // // TODO: Assert not preopen if (RealOverlap.Match) { // // The opened path is the mapping path. // This means that if we queried the filesystem // he would return the wrong path. // // Luckily, we can just use the mapping. // Name = &InstanceContext->Mapping.UserMapping.ShortNamePath.FinalComponentName; } else { // // We have to query below us to get the short name. // Status = NcGetFileNameInformation( Data, FileObject, Instance, FLT_FILE_NAME_SHORT | NameQueryMethod | NameFlags, &ShortInfo ); if (!NT_SUCCESS( Status )) { goto NcGenerateFileNameCleanup; } Status = FltParseFileNameInformation( ShortInfo ); if (!NT_SUCCESS(Status)) { goto NcGenerateFileNameCleanup; } // // Set name to returned name. // Name = &ShortInfo->Name; } } FLT_ASSERT( Name != NULL ); // // Try to grow the namechanger's record to accommodate the result. // Status = FltCheckAndGrowNameControl( OutputNameControl, Name->Length ); if (NT_SUCCESS( Status )) { // // Copy the new name into the buffer. // RtlCopyUnicodeString( &OutputNameControl->Name, Name ); *CacheFileNameInformation = TRUE; } NcGenerateFileNameCleanup: if (LowerNameInfo != NULL) { FltReleaseFileNameInformation( LowerNameInfo ); } if (ShortInfo != NULL) { FltReleaseFileNameInformation( ShortInfo ); } if (InstanceContext != NULL) { FltReleaseContext( InstanceContext ); } if (MungedName.Buffer != NULL) { ExFreePoolWithTag( MungedName.Buffer, NC_GENERATE_NAME_TAG ); } return Status; }
static NTSTATUS UcaAllocateContext(_In_ FLT_CONTEXT_TYPE ContextType, _Outptr_ PFLT_CONTEXT *Context) { PUCA_TRANSACTION_CONTEXT TransactionContext; NTSTATUS Status; PAGED_CODE(); switch (ContextType) { case FLT_STREAM_CONTEXT: /* Allocate stream context */ Status = FltAllocateContext(DriverData.FilterHandle, FLT_STREAM_CONTEXT, sizeof(UCA_STREAM_CONTEXT), UCA_CONTEXT_POOL_TYPE, Context); if (NT_SUCCESS(Status)) { RtlZeroMemory(*Context, sizeof(UCA_STREAM_CONTEXT)); FltInitializePushLock(&((PUCA_STREAM_CONTEXT)*Context)->Lock); } break; case FLT_FILE_CONTEXT: /* Allocate file context */ Status = FltAllocateContext(DriverData.FilterHandle, FLT_FILE_CONTEXT, sizeof(UCA_STREAM_CONTEXT), UCA_CONTEXT_POOL_TYPE, Context); if (NT_SUCCESS(Status)) { RtlZeroMemory(*Context, sizeof(UCA_STREAM_CONTEXT)); FltInitializePushLock(&((PUCA_STREAM_CONTEXT)*Context)->Lock); } break; case FLT_TRANSACTION_CONTEXT: /* Allocate transaction context */ Status = FltAllocateContext(DriverData.FilterHandle, FLT_TRANSACTION_CONTEXT, sizeof(UCA_TRANSACTION_CONTEXT), UCA_CONTEXT_POOL_TYPE, Context); if (NT_SUCCESS(Status)) { TransactionContext = (PUCA_TRANSACTION_CONTEXT)*Context; /* Zero the memory */ RtlZeroMemory(TransactionContext, sizeof(UCA_TRANSACTION_CONTEXT)); /* Initialize the notify list */ InitializeListHead(&TransactionContext->DeleteNotifyList); /* The resource needs to be in NPP */ TransactionContext->Resource = (PERESOURCE)ExAllocatePoolWithTag(NonPagedPool, sizeof(ERESOURCE), UCA_ERESOURCE_POOL_TAG); if (TransactionContext->Resource == NULL) { FltReleaseContext(TransactionContext); return STATUS_INSUFFICIENT_RESOURCES; } /* Initialize the lock */ ExInitializeResourceLite(TransactionContext->Resource); } break; case FLT_INSTANCE_CONTEXT: /* Allocate instance context */ Status = FltAllocateContext(DriverData.FilterHandle, FLT_INSTANCE_CONTEXT, sizeof(UCA_INSTANCE_CONTEXT), UCA_CONTEXT_POOL_TYPE, Context); if (NT_SUCCESS(Status)) { RtlZeroMemory(*Context, sizeof(UCA_INSTANCE_CONTEXT)); } break; default: Status = STATUS_INVALID_PARAMETER; break; } return Status; }
NTSTATUS CtxInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) /*++ Routine Description: This routine is called whenever a new instance is created on a volume. This gives us a chance to decide if we need to attach to this volume or not. Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance and its associated volume. Flags - Flags describing the reason for this attach request. Return Value: STATUS_SUCCESS - attach STATUS_FLT_DO_NOT_ATTACH - do not attach --*/ { PCTX_INSTANCE_CONTEXT instanceContext = NULL; NTSTATUS status = STATUS_SUCCESS; ULONG volumeNameLength; UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeDeviceType ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup started (Volume = %p, Instance = %p)\n", FltObjects->Volume, FltObjects->Instance) ); // // Allocate and initialize the context for this volume // // // Allocate the instance context // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Allocating instance context (Volume = %p, Instance = %p)\n", FltObjects->Volume, FltObjects->Instance) ); status = FltAllocateContext( FltObjects->Filter, FLT_INSTANCE_CONTEXT, CTX_INSTANCE_CONTEXT_SIZE, NonPagedPool, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to allocate instance context (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } // // Get the NT volume name length // status = FltGetVolumeName( FltObjects->Volume, NULL, &volumeNameLength ); if( !NT_SUCCESS( status ) && (status != STATUS_BUFFER_TOO_SMALL) ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Unexpected failure in FltGetVolumeName. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } // // Allocate a string big enough to take the volume name // instanceContext->VolumeName.MaximumLength = (USHORT) volumeNameLength; status = CtxAllocateUnicodeString( &instanceContext->VolumeName ); if( !NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to allocate volume name string. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } // // Get the NT volume name // status = FltGetVolumeName( FltObjects->Volume, &instanceContext->VolumeName, &volumeNameLength ); if( !NT_SUCCESS( status ) ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: Unexpected failure in FltGetVolumeName. (Volume = %p, Instance = %p, Status = 0x%x)\n", FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } instanceContext->Instance = FltObjects->Instance; instanceContext->Volume = FltObjects->Volume; // // Set the instance context. // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Setting instance context %p for volume %wZ (Volume = %p, Instance = %p)\n", instanceContext, &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance) ); status = FltSetInstanceContext( FltObjects->Instance, FLT_SET_CONTEXT_KEEP_IF_EXISTS, instanceContext, NULL ); if( !NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCES | DEBUG_TRACE_ERROR, ("[Ctx]: Failed to set instance context for volume %wZ (Volume = %p, Instance = %p, Status = 0x%08X)\n", &instanceContext->VolumeName, FltObjects->Volume, FltObjects->Instance, status) ); goto CtxInstanceSetupCleanup; } CtxInstanceSetupCleanup: // // If FltAllocateContext suceeded then we MUST release the context, // irrespective of whether FltSetInstanceContext suceeded or not. // // FltAllocateContext increments the ref count by one. // A successful FltSetInstanceContext increments the ref count by one // and also associates the context with the file system object // // FltReleaseContext decrements the ref count by one. // // When FltSetInstanceContext succeeds, calling FltReleaseContext will // leave the context with a ref count of 1 corresponding to the internal // reference to the context from the file system structures // // When FltSetInstanceContext fails, calling FltReleaseContext will // leave the context with a ref count of 0 which is correct since // there is no reference to the context from the file system structures // if ( instanceContext != NULL ) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing instance context %p (Volume = %p, Instance = %p)\n", instanceContext, FltObjects->Volume, FltObjects->Instance) ); FltReleaseContext( instanceContext ); } if (NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup complete (Volume = %p, Instance = %p). Filter will attach to the volume.\n", FltObjects->Volume, FltObjects->Instance) ); } else { DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance setup complete (Volume = %p, Instance = %p). Filter will not attach to the volume.\n", FltObjects->Volume, FltObjects->Instance) ); } return status; }
FLT_PREOP_CALLBACK_STATUS NcEnumerateDirectory ( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Flt_CompletionContext_Outptr_ PVOID *CompletionContext ) /*++ Routine Description: Routine is invoked when a directory enumeration is issued by the user. Arguments: Data - Pointer to the filter CallbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The context for the completion routine for this operation. Return Value: The return value is the Status of the operation. --*/ { //TODO WE SHOULD CONSIDER MOVING THIS TO POST BECAUSE NTFS WILL TAKE CARE // OF SYNC. FLT_PREOP_CALLBACK_STATUS ReturnValue; NTSTATUS Status; PNC_INSTANCE_CONTEXT InstanceContext = NULL; PNC_STREAM_HANDLE_CONTEXT HandleContext = NULL; PNC_DIR_QRY_CONTEXT DirCtx = NULL; PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; NC_PATH_OVERLAP RealOverlap; NC_PATH_OVERLAP UserOverlap; BOOLEAN Reset = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RESTART_SCAN ); BOOLEAN FirstQuery; BOOLEAN Single = BooleanFlagOn( Data->Iopb->OperationFlags, SL_RETURN_SINGLE_ENTRY ); BOOLEAN IgnoreCase = !BooleanFlagOn( FltObjects->FileObject->Flags, FO_OPENED_CASE_SENSITIVE ); FILE_INFORMATION_CLASS InformationClass = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass; PVOID UserBuffer; ULONG BufferSize; //size for user and system buffers. BOOLEAN Unlock = FALSE; //Vars for moving data into user buffer. ULONG NumEntriesCopied; ULONG UserBufferOffset; ULONG LastEntryStart; BOOLEAN MoreRoom; PNC_CACHE_ENTRY NextEntry; DIRECTORY_CONTROL_OFFSETS Offsets; BOOLEAN FoundStructureOffsets; UNREFERENCED_PARAMETER( CompletionContext ); PAGED_CODE(); FLT_ASSERT( IoGetTopLevelIrp() == NULL ); FoundStructureOffsets = NcDetermineStructureOffsets( &Offsets, InformationClass ); if (!FoundStructureOffsets) { Status = STATUS_INVALID_PARAMETER; ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } // // Get our instance context. // Status = FltGetInstanceContext( FltObjects->Instance, &InstanceContext ); if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } // // Get the directory's name. // Status = NcGetFileNameInformation( Data, NULL, NULL, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_DEFAULT, &FileNameInformation ); if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } Status = FltParseFileNameInformation( FileNameInformation ); if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } // // See if the directory is parent of either mapping. // NcComparePath( &FileNameInformation->Name, &InstanceContext->Mapping.UserMapping, NULL, IgnoreCase, TRUE, &UserOverlap ); NcComparePath( &FileNameInformation->Name, &InstanceContext->Mapping.RealMapping, NULL, IgnoreCase, TRUE, &RealOverlap ); if (!(UserOverlap.Parent || RealOverlap.Parent )) { // // We are not interested in this directory // because it is not the parent of either // mapping. This means we can just passthrough. // Status = STATUS_SUCCESS; ReturnValue = FLT_PREOP_SUCCESS_NO_CALLBACK; goto NcEnumerateDirectoryCleanup; } Status = NcStreamHandleContextAllocAndAttach( FltObjects->Filter, FltObjects->Instance, FltObjects->FileObject, &HandleContext ); if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } FLT_ASSERT( HandleContext != NULL ); DirCtx = &HandleContext->DirectoryQueryContext; _Analysis_assume_( DirCtx != NULL ); // // Before looking at the context, we have to acquire the lock. // NcLockStreamHandleContext( HandleContext ); Unlock = TRUE; // // We don't allow multiple outstanding enumeration requests on // a single handle. // // TODO: This needs to change. // if (DirCtx->EnumerationOutstanding) { Status = STATUS_UNSUCCESSFUL; ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } DirCtx->EnumerationOutstanding = TRUE; // // Now drop the lock. We're protected by the EnumerationOutstanding // flag; nobody else can muck with the enumeration context structure. // NcUnlockStreamHandleContext( HandleContext ); Unlock = FALSE; // // Now we need to initialize or clear the cache and query options. // Status = NcStreamHandleContextEnumSetup( DirCtx, InstanceContext, &Offsets, Data, FltObjects, UserOverlap, &FirstQuery ); if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } // // Prepare to populate the user buffer. // UserBuffer = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer; BufferSize = Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length; // // Lets copy data into the user buffer. // NumEntriesCopied = 0; UserBufferOffset = 0; do { // // If there is no cache entry, populate it. // if (DirCtx->Cache.Buffer == NULL) { Status = NcPopulateCacheEntry( FltObjects->Instance, FltObjects->FileObject, Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length, Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass, Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileName, Reset, &DirCtx->Cache); // // We only want to reset the cache once. // Reset = FALSE; // // There was a problem populating cache, pass up to user. // if (!NT_SUCCESS( Status )) { ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } } NextEntry = NcDirEnumSelectNextEntry( DirCtx, &Offsets, IgnoreCase ); if (NextEntry == NULL) { // // There are no more entries. // break; } if (NcSkipName( &Offsets, DirCtx, RealOverlap, &InstanceContext->Mapping, IgnoreCase )) { // // This entry is the real mapping path. That means we have to mask it... // We will say there is more room and continue. // MoreRoom = TRUE; } else { // // We are keeping this entry! // try { LastEntryStart = UserBufferOffset; UserBufferOffset = NcCopyDirEnumEntry( UserBuffer, UserBufferOffset, BufferSize, NextEntry, &Offsets, &MoreRoom ); } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { Status = STATUS_INVALID_USER_BUFFER; ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } if (MoreRoom) { NumEntriesCopied++; } }// end of "we are copying entry" } while (MoreRoom && (Single ? (NumEntriesCopied < 1) : TRUE)); if (NumEntriesCopied > 0) { // // Now we know what the last entry in the user buffer is going to be. // Set its NextEntryOffset to 0, so that the user knows its the last element. // try { NcSetNextEntryOffset( Add2Ptr(UserBuffer, LastEntryStart), &Offsets, TRUE ); } except (NcExceptionFilter( GetExceptionInformation(), TRUE )) { Status = STATUS_INVALID_USER_BUFFER; ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; } } // // We finished copying data. // ReturnValue = FLT_PREOP_COMPLETE; if (NumEntriesCopied == 0) { if (FirstQuery) { Status = STATUS_NO_SUCH_FILE; } else { Status = STATUS_NO_MORE_FILES; } } else { Status = STATUS_SUCCESS; } ReturnValue = FLT_PREOP_COMPLETE; goto NcEnumerateDirectoryCleanup; NcEnumerateDirectoryCleanup: if (ReturnValue == FLT_PREOP_COMPLETE) { // // We need to write back results of query. // Data->IoStatus.Status = Status; if (NT_SUCCESS( Status )) { //success Data->IoStatus.Information = UserBufferOffset; } else { //failure Data->IoStatus.Information = 0; } } if (InstanceContext != NULL) { FltReleaseContext( InstanceContext ); } if (DirCtx != NULL) { if (!Unlock) { NcLockStreamHandleContext( HandleContext ); Unlock = TRUE; } FLT_ASSERT( DirCtx->EnumerationOutstanding ); DirCtx->EnumerationOutstanding = FALSE; NcUnlockStreamHandleContext( HandleContext ); Unlock = FALSE; FltReleaseContext( HandleContext ); } FLT_ASSERT( !Unlock ); if (FileNameInformation != NULL) { FltReleaseFileNameInformation( FileNameInformation ); } return ReturnValue; }
NTSTATUS UcaGetVolumeGuidName(_In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_ PUNICODE_STRING VolumeGuidName) { PUCA_INSTANCE_CONTEXT InstanceContext = NULL; NTSTATUS Status; //PAGED_CODE(); /* Get the instance context, or create one if none exists */ Status = UcaGetOrAllocContext(FltObjects->Instance, NULL, FLT_INSTANCE_CONTEXT, TRUE, (PFLT_CONTEXT *)&InstanceContext); if (!NT_SUCCESS(Status)) return Status; /* Check if we've already cached the volume guid in a previous call */ if (InstanceContext->VolumeGuidName.Buffer == NULL) { UNICODE_STRING TempString; ULONG RequiredBytes; /* Get the required buffer for the string, plug an extra one for a trailing backslash */ RequiredBytes = UCA_VOLUME_GUID_NAME_SIZE * sizeof(WCHAR) + sizeof(WCHAR); /* Set the string data */ TempString.Length = 0; TempString.MaximumLength = (USHORT)RequiredBytes; /* Allocate some memory to hold the target */ TempString.Buffer = (PWCH)ExAllocatePoolWithTag(PagedPool, RequiredBytes, UCA_POOL_TAG); if (TempString.Buffer == NULL) { FltReleaseContext(InstanceContext); return STATUS_INSUFFICIENT_RESOURCES; } /* Now get the volume guid name */ Status = FltGetVolumeGuidName(FltObjects->Volume, &TempString, NULL); if (!NT_SUCCESS(Status)) { TRACE_ERROR(TraceHandle, "FltGetVolumeGuidName returned %X", Status); ExFreePoolWithTag(TempString.Buffer, UCA_POOL_TAG); FltReleaseContext(InstanceContext); return Status; } /* Add the trailing backslash */ RtlAppendUnicodeToString(&TempString, L"\\"); /* Set the SourceGuidName to the TempString. * It's okay to set Length and MaximumLength with no synchronization * because those will always be the same value */ InstanceContext->VolumeGuidName.Length = TempString.Length; InstanceContext->VolumeGuidName.MaximumLength = TempString.MaximumLength; /* Setting the buffer, however, requires some synchronization, * because another thread might be attempting to do the same, * and even though they're exactly the same string, they're * different allocations (buffers) so if the other thread we're * racing with manages to set the buffer before us, we need to * free our temporary string buffer */ InterlockedCompareExchangePointer(&InstanceContext->VolumeGuidName.Buffer, TempString.Buffer, NULL); if (InstanceContext->VolumeGuidName.Buffer != TempString.Buffer) { /* We didn't manage to set the buffer, so free the TempString buffer */ ExFreePoolWithTag(TempString.Buffer, UCA_POOL_TAG); } } /* Copy the guid name to the caller */ RtlCopyUnicodeString(VolumeGuidName, &InstanceContext->VolumeGuidName); /* We're done with the instance context */ FltReleaseContext(InstanceContext); return Status; }
NTSTATUS NPInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) { NTSTATUS status = STATUS_SUCCESS; PVOLUME_CONTEXT context = NULL; ULONG retLen; UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES)+512]; PFLT_VOLUME_PROPERTIES volProp = (PFLT_VOLUME_PROPERTIES)volPropBuffer; PDEVICE_OBJECT devObj = NULL; UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeDeviceType ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); PAGED_CODE(); PT_DBG_PRINT( PTDBG_TRACE_ROUTINES, ("minifilter1!NPInstanceSetup: Entered\n") ); try { // Allocate a volume context structure. status = FltAllocateContext( FltObjects->Filter, FLT_VOLUME_CONTEXT, sizeof(VOLUME_CONTEXT), NonPagedPool, &context ); if( !NT_SUCCESS(status) ) leave; // Get the volume properties, so I can get a sector size status = FltGetVolumeProperties( FltObjects->Volume, volProp, sizeof(volPropBuffer), &retLen ); if( !NT_SUCCESS(status) ) leave; // Get sector size ASSERT((volProp->SectorSize == 0) || (volProp->SectorSize >= MIN_SECTOR_SIZE)); context->SectorSize = max(volProp->SectorSize, MIN_SECTOR_SIZE); // Get device object, so I can get disk name context->Name.Buffer = NULL; status = FltGetDiskDeviceObject( FltObjects->Volume, &devObj ); if( !NT_SUCCESS(status) ) leave; status = IoVolumeDeviceToDosName( devObj, &context->Name); if( !NT_SUCCESS(status) ) leave; // Set the context status = FltSetVolumeContext( FltObjects->Volume, FLT_SET_CONTEXT_KEEP_IF_EXISTS, context, NULL ); DbgPrint("minifilter1!NPInstanceSetup: [%wZ 0x%04x/0x%04x]\n", &context->Name, context->SectorSize, volProp->SectorSize); DbgPrint("[%wZ - %wZ - %wZ]\n", &volProp->FileSystemDriverName, &volProp->FileSystemDeviceName, &volProp->RealDeviceName); if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED ) { status = STATUS_SUCCESS; } } finally { // Always release the context. If the set failed, it will free the // context. If not, it will remove the reference added by the set. // Note that the name buffer in the context will get freed by the // NPCleanupVolumeContext() routine. if(context) FltReleaseContext( context ); if(devObj) ObDereferenceObject( devObj ); } return status; }
FLT_POSTOP_CALLBACK_STATUS CtxPostSetInfo ( _Inout_ PFLT_CALLBACK_DATA Cbd, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_opt_ PVOID CbdContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) { PCTX_INSTANCE_CONTEXT instanceContext = NULL; PCTX_FILE_CONTEXT fileContext = NULL; PCTX_STREAM_CONTEXT streamContext = NULL; PCTX_STREAMHANDLE_CONTEXT streamHandleContext = NULL; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; NTSTATUS status; BOOLEAN streamContextCreated, fileContextCreated, streamHandleContextReplaced; UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CbdContext ); // // The pre-operation callback will return FLT_PREOP_SYNCHRONIZE if it needs a // post operation callback. In this case, the Filter Manager will call the // minifilter's post-operation callback in the context of the pre-operation // thread, at IRQL <= APC_LEVEL. This allows the post-operation code to be // pagable and also allows it to access paged data // PAGED_CODE(); DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostSetInfo -> Enter (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // Initialize defaults // status = STATUS_SUCCESS; // // If the SetInfo has failed, do nothing // if (!NT_SUCCESS( Cbd->IoStatus.Status )) { goto CtxPostSetInfoCleanup; } // // Get the instance context for the target instance // DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Trying to get instance context (TargetInstance = %p, Cbd = %p, FileObject = %p)\n", Cbd->Iopb->TargetInstance, Cbd, FltObjects->FileObject) ); status = FltGetInstanceContext( Cbd->Iopb->TargetInstance, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS | DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostSetInfo -> Failed to get instance context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_INSTANCE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Instance context info for volume %wZ (Cbd = %p, FileObject = %p, InstanceContext = %p) \n\tVolumeName = %wZ \n\tInstance = %p \n\tVolume = %p\n", &instanceContext->VolumeName, Cbd, FltObjects->FileObject, instanceContext, &instanceContext->VolumeName, &instanceContext->Instance, &instanceContext->Volume) ); // // Get the directory name // status = FltGetFileNameInformation( Cbd, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to get file name information (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Get the stream context // status = CtxFindOrCreateStreamContext(Cbd, FALSE, // do not create if one does not exist &streamContext, &streamContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find stream context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Getting stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p. StreamContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, streamContextCreated) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamContext->Resource); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Old info in stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Update the file name in the context // status = CtxUpdateNameInStreamContext( &nameInfo->Name, streamContext); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> New info in stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to update name in stream context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Create or replace a stream handle context // status = CtxCreateOrReplaceStreamHandleContext(Cbd, TRUE, &streamHandleContext, &streamHandleContextReplaced); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find or create stream handle context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Creating/Replacing stream handle context for file %wZ (Cbd = %p, FileObject = %p StreamHandleContext = %p, StreamHandleContextReplaced = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, streamHandleContextReplaced) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamHandleContext->Resource); // // Update the file name in the context // status = CtxUpdateNameInStreamHandleContext( &nameInfo->Name, streamHandleContext); DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Stream handle context info for file %wZ (Cbd = %p, FileObject = %p, StreamHandleContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, &streamHandleContext->FileName) ); // // Relinquish write acccess to the context // CtxReleaseResource( streamHandleContext->Resource ); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to update name in stream handle context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } // // Get the file context // status = CtxFindOrCreateFileContext( Cbd, FALSE, // do not create if one does not exist NULL, &fileContext, &fileContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because file contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Failed to find file context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostSetInfoCleanup; } DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> Getting file context for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p. FileContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, fileContextCreated) ); DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostSetInfo -> File context info for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, &fileContext->FileName) ); CtxPostSetInfoCleanup: // // Release the references we have acquired // if (instanceContext != NULL) { FltReleaseContext( instanceContext ); } if (fileContext != NULL) { FltReleaseContext( fileContext ); } if (streamContext != NULL) { FltReleaseContext( streamContext ); } if (streamHandleContext != NULL) { FltReleaseContext( streamHandleContext ); } if (nameInfo != NULL) { FltReleaseFileNameInformation( nameInfo ); } if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostSetInfo -> Failed with status 0x%x \n", status) ); // // It doesn't make sense to udate Cbd->IoStatus.Status on failure since the // file system has suceesfully completed the operation // } DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostSetInfo -> Exit (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); return FLT_POSTOP_FINISHED_PROCESSING; }
NTSTATUS FmmSetMetadataOpenTriggerFileObject ( __inout PFLT_CALLBACK_DATA Cbd ) /*++ Routine Description: This routine sets the MetadataOpenTriggerFileObject in the instance context to the file object of the volume that triggered the release of the metadata file references. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. Return Value: Status Note: This routine takes care of the synchronization needed to access the metadata file object and handle --*/ { NTSTATUS status = STATUS_SUCCESS; PFMM_INSTANCE_CONTEXT instanceContext = NULL; PAGED_CODE(); // // Get the instance context // status = FltGetInstanceContext( Cbd->Iopb->TargetInstance, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmSetMetadataOpenTriggerFileObject -> Failed to get instance context.\n") ); goto FmmSetMetadataOpenTriggerFileObjectCleanup; } // // Acquire exclusive access to the instance context // FmmAcquireResourceExclusive( &instanceContext->MetadataResouce ); if (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION)) { // // If this instance context is in a transition state, it implies that // the instance context lock has been released while sending an operation // down to the file system. The reason for doing so is to prevent a potential // deadlock if an underlying filter sends an IO to the top of the filter // stack while we are holding the resource // // We have managed to acquire this resource in this state of transition. // It would be incorrect to use or modify the instance context in any way // in this situation. So we simply let go. // status = STATUS_FILE_LOCK_CONFLICT; DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmSetMetadataOpenTriggerFileObject -> Failed to get exclusive access to instance context since it is in a state of transition.\n") ); } else { DebugTrace( DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmSetMetadataOpenTriggerFileObject -> Setting MetadataOpenTriggerFileObject to %p (OldValue = %p).\n", Cbd->Iopb->TargetFileObject, instanceContext->MetadataOpenTriggerFileObject) ); // // Save the volume file object as the trigger file object // ASSERT((instanceContext->MetadataOpenTriggerFileObject == NULL) || (instanceContext->MetadataOpenTriggerFileObject == Cbd->Iopb->TargetFileObject)); instanceContext->MetadataOpenTriggerFileObject = Cbd->Iopb->TargetFileObject; } // // Relinquish exclusive access to the instance context // FmmReleaseResource( &instanceContext->MetadataResouce); FmmSetMetadataOpenTriggerFileObjectCleanup: // // Release the references we have acquired // if (instanceContext != NULL) { FltReleaseContext( instanceContext ); } return status;; }
FLT_POSTOP_CALLBACK_STATUS CtxPostCreate ( _Inout_ PFLT_CALLBACK_DATA Cbd, _In_ PCFLT_RELATED_OBJECTS FltObjects, _Inout_opt_ PVOID CbdContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) { PCTX_FILE_CONTEXT fileContext = NULL; PCTX_STREAM_CONTEXT streamContext = NULL; PCTX_STREAMHANDLE_CONTEXT streamHandleContext = NULL; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; UNICODE_STRING fileName; NTSTATUS status; BOOLEAN fileContextCreated, streamContextCreated, streamHandleContextReplaced; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( CbdContext ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostCreate -> Enter (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); // // Initialize defaults // status = STATUS_SUCCESS; // // If the Create has failed, do nothing // if (!NT_SUCCESS( Cbd->IoStatus.Status )) { goto CtxPostCreateCleanup; } // // Get the file name // status = FltGetFileNameInformation( Cbd, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to get name information (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // Find or create a stream context // status = CtxFindOrCreateStreamContext(Cbd, TRUE, &streamContext, &streamContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create stream context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Getting/Creating stream context for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p. StreamContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, streamContextCreated) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive(streamContext->Resource); // // Increment the create count // streamContext->CreateCount++; // // Update the file name in the context // status = CtxUpdateNameInStreamContext( &nameInfo->Name, streamContext); DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Stream context info for file %wZ (Cbd = %p, FileObject = %p, StreamContext = %p) \n\tName = %wZ \n\tCreateCount = %x \n\tCleanupCount = %x, \n\tCloseCount = %x\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamContext, &streamContext->FileName, streamContext->CreateCount, streamContext->CleanupCount, streamContext->CloseCount) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to update name in stream context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // Create or replace a stream handle context // status = CtxCreateOrReplaceStreamHandleContext(Cbd, TRUE, &streamHandleContext, &streamHandleContextReplaced); if (!NT_SUCCESS( status )) { // // This failure will most likely be because stream contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create stream handle context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Creating/Replacing stream handle context for file %wZ (Cbd = %p, FileObject = %p StreamHandleContext = %p, StreamHandleContextReplaced = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, streamHandleContextReplaced) ); // // Acquire write acccess to the context // CtxAcquireResourceExclusive( streamHandleContext->Resource ); // // Update the file name in the context // status = CtxUpdateNameInStreamHandleContext( &nameInfo->Name, streamHandleContext); DebugTrace( DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Stream handle context info for file %wZ (Cbd = %p, FileObject = %p, StreamHandleContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, streamHandleContext, &streamHandleContext->FileName) ); // // Relinquish write acccess to the context // CtxReleaseResource(streamHandleContext->Resource); // // Quit on failure after we have given up // the resource // if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAMHANDLE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to update name in stream handle context for file %wZ (Cbd = %p, FileObject = %p)\n", &nameInfo->Name, Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } // // After FltParseFileNameInformation, nameInfo->Name also // contains the stream name. We need only the filename and do // not want to include the stream name in the file context // fileName.Buffer = nameInfo->Name.Buffer; fileName.Length = nameInfo->Name.Length - nameInfo->Stream.Length; fileName.MaximumLength = fileName.Length; // // Find or create a file context // status = CtxFindOrCreateFileContext( Cbd, TRUE, &fileName, &fileContext, &fileContextCreated); if (!NT_SUCCESS( status )) { // // This failure will most likely be because file contexts are not supported // on the object we are trying to assign a context to or the object is being // deleted // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Failed to find or create file context (Cbd = %p, FileObject = %p)\n", Cbd, FltObjects->FileObject) ); goto CtxPostCreateCleanup; } DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> Getting/Creating file context for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p. FileContextCreated = %x)\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, fileContextCreated) ); DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: CtxPostCreate -> File context info for file %wZ (Cbd = %p, FileObject = %p, FileContext = %p) \n\tName = %wZ\n", &nameInfo->Name, Cbd, FltObjects->FileObject, fileContext, &fileContext->FileName) ); CtxPostCreateCleanup: // // Release the references we have acquired // if (nameInfo != NULL) { FltReleaseFileNameInformation( nameInfo ); } if (fileContext != NULL) { FltReleaseContext( fileContext ); } if (streamContext != NULL) { FltReleaseContext( streamContext ); } if (streamHandleContext != NULL) { FltReleaseContext( streamHandleContext ); } if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR, ("[Ctx]: CtxPostCreate -> Failed with status 0x%x \n", status) ); // // It doesn't make sense to udate Cbd->IoStatus.Status on failure since the // file system has successfully completed the operation // } DebugTrace( DEBUG_TRACE_ALL_IO, ("[Ctx]: CtxPostCreate -> Exit (Cbd = %p, FileObject = %p, Status = 0x%x)\n", Cbd, FltObjects->FileObject, Cbd->IoStatus.Status) ); return FLT_POSTOP_FINISHED_PROCESSING; }
NTSTATUS FmmIsMetadataOpen ( __inout PFLT_CALLBACK_DATA Cbd, __out BOOLEAN* MetadataOpen ) /*++ Routine Description: This routine returns if the metadata file is open on the specified instance. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. MetadataOpen - Returns if the metadata file is open Return Value: Status Note: This routine takes care of the synchronization needed to access the metadata file object and handle --*/ { NTSTATUS status = STATUS_SUCCESS; PFMM_INSTANCE_CONTEXT instanceContext = NULL; // // Get the instance context // status = FltGetInstanceContext( Cbd->Iopb->TargetInstance, &instanceContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmIsMetadataOpen -> Failed to get instance context.\n") ); goto FmmIsMetadataOpenCleanup; } // // Acquire exclusive access to the instance context // FmmAcquireResourceShared( &instanceContext->MetadataResouce ); if (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION)) { // // If this instance context is in a transition state, it implies that // the instance context lock has been released while sending an operation // down to the file system. The reason for doing so is to prevent a potential // deadlock if an underlying filter sends an IO to the top of the filter // stack while we are holding the resource // // We have managed to acquire this resource in this state of transition. // It would be incorrect to use or modify the instance context in any way // in this situation. So we simply let go. // status = STATUS_FILE_LOCK_CONFLICT; DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS, ("[Fmm]: FmmIsMetadataOpen -> Failed to get exclusive access to instance context since it is in a state of transition.\n") ); } else { // // Return if the metadata is opened // *MetadataOpen = BooleanFlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ); // // Sanity - verify that this flag is reflecting the correct state of the metadata file // ASSERT ( (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ) && (instanceContext->MetadataFileObject != NULL) && (instanceContext->MetadataHandle != NULL)) || (!FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_METADATA_OPENED ) && (instanceContext->MetadataFileObject == NULL) && (instanceContext->MetadataHandle == NULL)) ); } // // Relinquish exclusive access to the instance context // FmmReleaseResource( &instanceContext->MetadataResouce); FmmIsMetadataOpenCleanup: // // Release the references we have acquired // if (instanceContext != NULL) { FltReleaseContext( instanceContext ); } return status; }
/*++ Routine Description: 这个函数查找目标流的流上下文。 This routine finds the stream context for the target stream. Optionally, if the context does not exist this routing creates a new one and attaches the context to the stream. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the stream must be created if missing StreamContext - Returns the stream context ContextCreated - Returns if a new context was created Return Value: Status --*/ NTSTATUS CtxFindOrCreateStreamContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __deref_out PCTX_STREAM_CONTEXT *StreamContext, __out_opt PBOOLEAN ContextCreated ) { NTSTATUS status; PCTX_STREAM_CONTEXT streamContext; PCTX_STREAM_CONTEXT oldStreamContext; PAGED_CODE(); *StreamContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // // First try to get the stream context. // DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Trying to get stream context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltGetStreamContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &streamContext ); // // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context // if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // // Create a stream context // DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Creating stream context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateStreamContext( &streamContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Set the new context we just allocated on the file object // DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Setting stream context %p (FileObject = %p, Instance = %p)\n", streamContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltSetStreamContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamContext, &oldStreamContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Releasing stream context %p (FileObject = %p, Instance = %p)\n", streamContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( streamContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set stream context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // DebugTrace( DEBUG_TRACE_STREAM_CONTEXT_OPERATIONS, ("[Ctx]: Stream context already defined. Retaining old stream context %p (FileObject = %p, Instance = %p)\n", oldStreamContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamContext = oldStreamContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *StreamContext = streamContext; return status; }
VOID CtxInstanceTeardownStart ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_TEARDOWN_FLAGS Flags ) /*++ Routine Description: This routine is called at the start of instance teardown. Arguments: FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance and its associated volume. Flags - Reason why this instance is been deleted. Return Value: None. --*/ { #if __NDAS_FS_MINI__ NTSTATUS status; PCTX_INSTANCE_CONTEXT instanceContext = NULL; #endif UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Flags ); PAGED_CODE(); DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance teardown start started (Instance = %p)\n", FltObjects->Instance) ); DebugTrace( DEBUG_TRACE_INSTANCES, ("[Ctx]: Instance teardown start ended (Instance = %p)\n", FltObjects->Instance) ); #if __NDAS_FS_MINI__ status = FltGetInstanceContext( FltObjects->Instance, &instanceContext ); NDASFS_ASSERT( status == STATUS_SUCCESS ); if (status == STATUS_SUCCESS) { LfsCleanupMountedDevice( &instanceContext->LfsDeviceExt ); if (instanceContext->DiskDeviceObject) { ObDereferenceObject( instanceContext->DiskDeviceObject ); instanceContext->DiskDeviceObject = NULL; } if (instanceContext->DeviceObject) { ObDereferenceObject( instanceContext->DeviceObject ); instanceContext->DeviceObject = NULL; } if (instanceContext->VolumeProperties) { ExFreePoolWithTag( instanceContext->VolumeProperties, CTX_VOLUME_PROPERTY_TAG ); instanceContext->VolumeProperties = NULL; } FltReleaseContext( instanceContext ); } #endif }
/*++ Routine Description: 这个函数找到目标文件的文件上下文。 如果上下文不存在,这个函数创建一个新的文件上下文附加在该文件上。 This routine finds the file context for the target file. Optionally, if the context does not exist this routing creates a new one and attaches the context to the file. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the file context must be created if missing FileName - Supplies the file name FileContext - Returns the file context ContextCreated - Returns if a new context was created Return Value: Status --*/ NTSTATUS CtxFindOrCreateFileContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __in_opt PUNICODE_STRING FileName, __deref_out PCTX_FILE_CONTEXT *FileContext, __out_opt PBOOLEAN ContextCreated ) { NTSTATUS status; PCTX_FILE_CONTEXT fileContext; PCTX_FILE_CONTEXT oldFileContext; PAGED_CODE(); *FileContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // 首先,尝试获取文件上下文。 // First try to get the file context. DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Trying to get file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltGetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &fileContext ); // 如果调用失败是因为上下文不存在,并且用户想创建一个新的话,那么就创建一个 // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // 创建一个文件上下文 // Create a file context DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Creating file context (FileObject = %p, Instance = %p)\n", Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = CtxCreateFileContext( FileName, &fileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to create file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // 将新建的上下文设置到文件对象上 // Set the new context we just allocated on the file object DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Setting file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); status = FltSetFileContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, fileContext, &oldFileContext ); if (!NT_SUCCESS( status )) { DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // 由于FltSetFileContext()调用失败,释放上下文 // We release the context here because FltSetFileContext failed // // 如果FltSetFileContext()成功,这个上下文会返回给调用者。 // 调用者使用这个上下文,当使用完毕之后释放它。 // If FltSetFileContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Releasing file context %p (FileObject = %p, Instance = %p)\n", fileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); FltReleaseContext( fileContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetFileContext failed for a reason other than the context already // existing on the file. So the object now does not have any context set // on it. So we return failure to the caller. DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: Failed to set file context with status 0x%x != STATUS_FLT_CONTEXT_ALREADY_DEFINED. (FileObject = %p, Instance = %p)\n", status, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); return status; } // 竞争条件。 // Race condition. Someone has set a context after we queried it. // Use the already set context instead DebugTrace( DEBUG_TRACE_FILE_CONTEXT_OPERATIONS, ("[Ctx]: File context already defined. Retaining old file context %p (FileObject = %p, Instance = %p)\n", oldFileContext, Cbd->Iopb->TargetFileObject, Cbd->Iopb->TargetInstance) ); // // Return the existing context. Note that the new context that we allocated has already been // realeased above. fileContext = oldFileContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *FileContext = fileContext; return status; }
NTSTATUS CtxFindOrCreateStreamHandleContext ( __in PFLT_CALLBACK_DATA Cbd, __in BOOLEAN CreateIfNotFound, __deref_out PSTREAMHANDLE_CONTEXT *StreamHandleContext, __out_opt PBOOLEAN ContextCreated ) /*++ Routine Description: This routine finds the stream context for the target stream. Optionally, if the context does not exist this routing creates a new one and attaches the context to the stream. Arguments: Cbd - Supplies a pointer to the callbackData which declares the requested operation. CreateIfNotFound - Supplies if the stream must be created if missing StreamContext - Returns the stream context ContextCreated - Returns if a new context was created Return Value: Status --*/ { NTSTATUS status; PSTREAMHANDLE_CONTEXT streamHandleContext; PSTREAMHANDLE_CONTEXT oldStreamHandleContext; PAGED_CODE(); *StreamHandleContext = NULL; if (ContextCreated != NULL) *ContextCreated = FALSE; // // First try to get the stream context. // status = FltGetStreamHandleContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, &streamHandleContext ); // // If the call failed because the context does not exist // and the user wants to creat a new one, the create a // new context // if (!NT_SUCCESS( status ) && (status == STATUS_NOT_FOUND) && CreateIfNotFound) { // // Create a stream context // status = CtxCreateStreamHandleContext( &streamHandleContext ); if (!NT_SUCCESS( status )) { return status; } // // Set the new context we just allocated on the file object // status = FltSetStreamContext( Cbd->Iopb->TargetInstance, Cbd->Iopb->TargetFileObject, FLT_SET_CONTEXT_KEEP_IF_EXISTS, streamHandleContext, &oldStreamHandleContext ); if (!NT_SUCCESS( status )) { // // We release the context here because FltSetStreamContext failed // // If FltSetStreamContext succeeded then the context will be returned // to the caller. The caller will use the context and then release it // when he is done with the context. // FltReleaseContext( streamHandleContext ); if (status != STATUS_FLT_CONTEXT_ALREADY_DEFINED) { // // FltSetStreamContext failed for a reason other than the context already // existing on the stream. So the object now does not have any context set // on it. So we return failure to the caller. // return status; } // // Race condition. Someone has set a context after we queried it. // Use the already set context instead // // // Return the existing context. Note that the new context that we allocated has already been // realeased above. // streamHandleContext = oldStreamHandleContext; status = STATUS_SUCCESS; } else { if (ContextCreated != NULL) *ContextCreated = TRUE; } } *StreamHandleContext = streamHandleContext; return status; }
NTSTATUS PtInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) { PDEVICE_OBJECT devObj = NULL; PVOLUME_CONTEXT ctx = NULL; PFILE_FS_SIZE_INFORMATION VolumeBuffer = NULL; NTSTATUS status = STATUS_SUCCESS; ULONG retLen; PUNICODE_STRING workingName; USHORT size; IO_STATUS_BLOCK IoStatus; UCHAR volPropBuffer[sizeof(FLT_VOLUME_PROPERTIES)+512]; PFLT_VOLUME_PROPERTIES volProp = (PFLT_VOLUME_PROPERTIES)volPropBuffer; PAGED_CODE(); UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeDeviceType ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); try { //我们在卷上下文中保存扇区大小跟一个资源,用卷上下文完成vcb的工作 status = FltAllocateContext( FltObjects->Filter, FLT_VOLUME_CONTEXT, sizeof(VOLUME_CONTEXT), NonPagedPool, &ctx ); if (!NT_SUCCESS(status)) { leave; } status = FltGetVolumeProperties( FltObjects->Volume, volProp, sizeof(volPropBuffer), &retLen ); if (!NT_SUCCESS(status)) { leave; } ASSERT((volProp->SectorSize == 0) || (volProp->SectorSize >= MIN_SECTOR_SIZE)); if(volProp->SectorSize > MAX_SECTOR_SIZE) { DbgPrint("不支持这么大的扇区的磁盘 %d \n",volProp->SectorSize ); status = STATUS_UNSUCCESSFUL; leave; } ctx->SectorSize = max(volProp->SectorSize ,MIN_SECTOR_SIZE); ctx->VolResource = X70FsdAllocateResource(); ctx->DeviceType = volProp->DeviceType; VolumeBuffer = FltAllocatePoolAlignedWithTag(FltObjects->Instance,NonPagedPool,sizeof(FILE_FS_SIZE_INFORMATION),'clu'); if(VolumeBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } status = FltQueryVolumeInformation( FltObjects->Instance, &IoStatus, VolumeBuffer, sizeof(FILE_FS_SIZE_INFORMATION), FileFsSizeInformation ); if (NT_SUCCESS(status)) { ctx->SectorsPerAllocationUnit = VolumeBuffer->SectorsPerAllocationUnit; } else { ctx->SectorsPerAllocationUnit = 1; //网络设备会返回失败。 } FltIsVolumeWritable(FltObjects->Volume,&ctx->IsWritable ); status = FltSetVolumeContext( FltObjects->Volume, FLT_SET_CONTEXT_KEEP_IF_EXISTS, ctx, NULL ); if (status == STATUS_FLT_CONTEXT_ALREADY_DEFINED) { status = STATUS_SUCCESS; } } finally { if (ctx != NULL) { FltReleaseContext( ctx ); } if(VolumeBuffer != NULL) { FltFreePoolAlignedWithTag(FltObjects->Instance,VolumeBuffer,'clu'); } } return status; }
static FLT_POSTOP_CALLBACK_STATUS FileCreateFilterPostCallback ( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags ) { FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING; KLOCK_QUEUE_HANDLE hMutex = { 0 }; PFLT_FILE_NAME_INFORMATION fileInfo = NULL; RU32 pid = 0; RU64 ts = 0; RU32 createOptions = 0; RU32 createDispositions = 0; _fileContext* context = NULL; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); // We only care about user mode for now. if( UserMode != Data->RequestorMode || STATUS_SUCCESS != Data->IoStatus.Status ) { return status; } if( FILE_CREATED == Data->IoStatus.Information ) { pid = (RU32)FltGetRequestorProcessId( Data ); ts = rpal_time_getLocal(); if( !NT_SUCCESS( FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &fileInfo ) ) ) { rpal_debug_kernel( "Failed to get file name info" ); fileInfo = NULL; } else { //rpal_debug_kernel( "NEW: %wZ", fileInfo->Name ); } if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isNew = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex ); g_files[ g_nextFile ].pid = pid; g_files[ g_nextFile ].ts = ts; g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID; g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_ADDED; if( NULL != fileInfo ) { copyUnicodeStringToBuffer( &fileInfo->Name, g_files[ g_nextFile ].path ); FltReleaseFileNameInformation( fileInfo ); } g_nextFile++; if( g_nextFile == _NUM_BUFFERED_FILES ) { g_nextFile = 0; } KeReleaseInStackQueuedSpinLock( &hMutex ); } createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF; createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24; if( IS_FLAG_ENABLED( createOptions, FILE_DELETE_ON_CLOSE ) ) { if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isDelete = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } } return status; }