NTSTATUS GenerateFileName(IN PFLT_INSTANCE Instance, IN PFILE_OBJECT FileObject, IN PFLT_CALLBACK_DATA CallbackData, IN FLT_FILE_NAME_OPTIONS NameOptions, OUT PBOOLEAN CacheFileNameInformation, OUT PFLT_NAME_CONTROL FileName ) //上层的minifilter过滤驱动的名字请求进行处理 { NTSTATUS Status = STATUS_UNSUCCESSFUL; PFILE_OBJECT StreamObject = FileObject; PFLT_FILE_NAME_INFORMATION FileNameInformation = NULL; BOOLEAN bEncryptResource = FALSE; PFCB Fcb = FileObject->FsContext; PCCB Ccb = FileObject->FsContext2; FsRtlEnterFileSystem(); try { if(IsMyFakeFcb(FileObject)) { ExAcquireResourceSharedLite(Fcb->EncryptResource,TRUE); bEncryptResource = TRUE; if(BooleanFlagOn(Fcb->FcbState,SCB_STATE_SHADOW_CLOSE) || Ccb->StreamFileInfo.StreamObject == NULL) { try_return (Status = STATUS_FILE_DELETED); } else { StreamObject = Ccb->StreamFileInfo.StreamObject; } } ClearFlag(NameOptions,FLT_FILE_NAME_REQUEST_FROM_CURRENT_PROVIDER); if(FlagOn(NameOptions,FLT_FILE_NAME_NORMALIZED)) { ClearFlag(NameOptions,FLT_FILE_NAME_NORMALIZED); SetFlag(NameOptions,FLT_FILE_NAME_OPENED); } if (CallbackData) { PFILE_OBJECT TemFileObject = CallbackData->Iopb->TargetFileObject; CallbackData->Iopb->TargetFileObject = StreamObject; FltSetCallbackDataDirty(CallbackData); Status = FltGetFileNameInformation(CallbackData,NameOptions, &FileNameInformation); CallbackData->Iopb->TargetFileObject = TemFileObject; FltClearCallbackDataDirty(CallbackData); } else { Status = FltGetFileNameInformationUnsafe(StreamObject,Instance, NameOptions, &FileNameInformation); } if(!NT_SUCCESS(Status)) { try_return (Status); } Status = FltCheckAndGrowNameControl(FileName, FileNameInformation->Name.Length); if(!NT_SUCCESS(Status)) { try_return (Status); } RtlCopyUnicodeString(&FileName->Name, &FileNameInformation->Name); if(FileNameInformation != NULL) { FltReleaseFileNameInformation(FileNameInformation); } Status = STATUS_SUCCESS; try_exit: NOTHING; } finally { if(bEncryptResource) { ExReleaseResourceLite( Fcb->EncryptResource ); } } FsRtlExitFileSystem(); 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; }