Minifilter获取文件打开路径异常:NTFS Junction场景不符合预期
问题根源分析
你遇到的问题核心在于FLT_FILE_NAME_ALLOW_QUERY_ON_REPARSE这个标志的作用——当你设置它时,FltGetFileNameInformation会等待系统完成重解析点的处理后再查询文件名,因此返回的是解析后的真实路径,而非用户最初打开文件时使用的原始路径。这和你依赖FLT_FILE_NAME_OPENED获取"打开时名称"的预期直接冲突了。
另外,NTFS junction的处理逻辑是:系统会先接收用户的原始打开请求(比如\Device\HarddiskVolume2\a\b\b.txt),处理重解析点后发起内部请求打开真实路径(\Device\HarddiskVolume2\b\b.txt),你的Post-Create回调实际触发的是这个内部请求,默认情况下拿到的自然是真实路径。
解决方案:获取重解析前的原始路径
要获取用户最初使用的打开路径,你需要使用FLT_FILE_NAME_REPARSE_ORIGINAL这个文件名类型标志,它专门用于获取重解析处理前的原始请求路径。结合回退逻辑处理非重解析场景,修改后的代码如下:
PFLT_FILE_NAME_INFORMATION pFNI = NULL; NTSTATUS Status; // 优先尝试获取重解析前的原始路径 Status = FltGetFileNameInformation( Data, FLT_FILE_NAME_REPARSE_ORIGINAL | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &pFNI ); if (NT_SUCCESS(Status)) { DBG_PRINT_INFO("Original opened path: '%wZ'", pFNI->Name); // 这里可以提取父目录路径用于查找配置文件 FltReleaseFileNameInformation(pFNI); pFNI = NULL; } else { // 非重解析场景,回退到常规的FLT_FILE_NAME_OPENED Status = FltGetFileNameInformation( Data, FLT_FILE_NAME_OPENED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &pFNI ); if (NT_SUCCESS(Status)) { DBG_PRINT_INFO("Opened path: '%wZ'", pFNI->Name); FltReleaseFileNameInformation(pFNI); pFNI = NULL; } else { DBG_PRINT_ERROR("FltGetFileNameInformation failed: %#x", Status); __leave; } }
关键注意事项
- 移除
FLT_FILE_NAME_ALLOW_QUERY_ON_REPARSE:这个标志会强制等待重解析完成,导致你无法拿到原始路径,必须从标志组合中移除。 - 释放文件名信息:每次调用
FltGetFileNameInformation成功后,务必调用FltReleaseFileNameInformation释放资源,避免内存泄漏(你原来的代码缺少这一步,需要补上)。 - 回退逻辑的必要性:
FLT_FILE_NAME_REPARSE_ORIGINAL仅在请求经过重解析处理时有效,非重解析场景下会返回失败,因此必须回退到FLT_FILE_NAME_OPENED保证兼容性。
这样修改后,当用户通过junction打开文件时,你就能拿到\Device\HarddiskVolume2\a\b\b.txt这个原始路径,进而正确找到父目录下的配置文件了。
内容的提问来源于stack exchange,提问作者Wade Brainerd




