转自:http://univasity.iteye.com/blog/860847

<!-- 发觉越是没事干,记忆越差,乘还记得点什么,记录下以备份 -->

继上一篇关于USN的探索,我们能对USN进行了简单的操作,但是有一样基本的东西却没有做到——我们还无法获取到USN记录的文件路径,而这恰恰是非常必要的。

<开始探索> 
typedef struct {
DWORD RecordLength; // 记录长度
WORD MajorVersion; // 主版本
WORD MinorVersion; // 次版本
DWORDLONG FileReferenceNumber; // 文件引用数
DWORDLONG ParentFileReferenceNumber; // 父目录引用数
USN Usn; // USN
LARGE_INTEGER TimeStamp; // 时间戳
DWORD Reason; // 原因
DWORD SourceInfo; // 源信息
DWORD SecurityId; // 安全
ID DWORD FileAttributes; // 文件属性
WORD FileNameLength; // 文件长度
WORD FileNameOffset; // penultimate of original version 2.0 < 文件名偏移 >
DWORD ExtraInfo1; // Hypothetically added in version 2.1
DWORD ExtraInfo2; // Hypothetically added in version 2.2
DWORD ExtraInfo3; // Hypothetically added in version 2.3
WCHAR FileName[1]; // variable length always at the end < 文件名第一位的指针 >
} USN_RECORD, *PUSN_RECORD;

这是每个USN记录的结构,通过这个结构我们能获取到的文件名和其他一些信息,但并不包含其所在的路径。

前面的文章中曾稍微提到过其中的FileReferenceNumber和 ParentFileReferenceNumber是关键。

是有这么一种方法,通过微软提供的NtQueryInformationFile 函数获取,具体实现如下:

Cpp代码  
  1. /// <summary>
  2. /// GetPathByFileReferenceNumber() 通过文件的映射ID获取文件路径.
  3. /// </summary>
  4. /// <param name="hVol">HANDLE对象,指向驱动盘
  5. /// </param>
  6. /// <param name="frn">文件的映射ID,包含在USN_RECORD中
  7. /// </param>
  8. /// <param name="pathBuffer">储存返回值的char*
  9. /// </param>
  10. /// <param name="bufferSize">指定返回值的长度
  11. /// </param>
  12. /// <returns>BOOL
  13. /// </returns>
  14. /// <remarks>
  15. /// 只支持NTFS3.0及以上的驱动盘,并且在Win7下运行该方法需要获取管理员权限
  16. /// </remarks>
  17. BOOL GetPathByFileReferenceNumber(__in HANDLE hVol, __in DWORDLONG frn, __out char* pathBuffer, __in int bufferSize)
  18. {
  19. BOOL result = FALSE;
  20. HANDLE hFile;
  21. //printf("frn: %I64x\n", frn);
  22. // 将FileReferenceNumber转为UNICODE_STR
  23. UNICODE_STRING fidstr;
  24. CoverFileReferenceNumberToFileIdStr(frn, &fidstr);
  25. //ULONG fid[2] = {0x00000892, 0x00020000};//{i.nFileIndexLow, i.nFileIndexHigh};
  26. //UNICODE_STRING fidstr = {8, 8, (PWSTR) fid};
  27. // 构建用于寻找的OBJECT_ATTRIBUTES
  28. OBJECT_ATTRIBUTES oa = {0};
  29. oa.Length = sizeof(OBJECT_ATTRIBUTES);
  30. oa.ObjectName = &fidstr;
  31. oa.RootDirectory = hVol;
  32. oa.Attributes = OBJ_CASE_INSENSITIVE;
  33. //InitializeObjectAttributes (&oa, &fidstr, OBJ_CASE_INSENSITIVE, d, NULL);
  34. IO_STATUS_BLOCK ioStatusBlock = {0};
  35. // 通过FILE_ID打开文件,获取文件句柄
  36. ULONG status = NtCreatefile(&hFile,
  37. FILE_GENERIC_READ,
  38. &oa,
  39. &ioStatusBlock,
  40. NULL,
  41. FILE_ATTRIBUTE_READONLY,
  42. FILE_SHARE_READ | FILE_SHARE_WRITE,
  43. FILE_OPEN,
  44. FILE_OPEN_BY_FILE_ID | FILE_OPEN_FOR_BACKUP_INTENT,
  45. NULL,
  46. 0);
  47. //printf("status: %X, handle: %x\n", status, hFile);
  48. //printf("error: %d, t: %x\n", GetLastError(), iosb);
  49. if(0==status){
  50. //FILE_NAME_INFORMATION* info = (FILE_NAME_INFORMATION*)malloc(BUF_LEN);
  51. //int allocSize = BUF_LEN;
  52. // 获取文件名称信息
  53. status = NtQueryInformationFile(hFile,
  54. &ioStatusBlock,
  55. info,
  56. allocSize,
  57. FileNameInformation);
  58. if(0==status){
  59. // 获取到的名字是wchar*, 将其转为char*
  60. int dwMinSize = (*info).FileNameLength;
  61. WideCharToMultiByte(CP_OEMCP,NULL,(*info).FileName,dwMinSize/2,pathBuffer,dwMinSize,NULL,FALSE);
  62. result = TRUE;
  63. }
  64. //free(info);
  65. CloseHandle(hFile);
  66. }
  67. return result;
  68. }
虽然这是不错的方法,但是太慢了,简单测试了一下,20W个文件要14秒多,一台机器何止如此少的文件数...远远达不到Everything的快速。
但是MSDN和网上我都翻遍了,毫无收获。 那难道真的还有其他方法?
<寻觅新思路>

于是我将手头所有的信息汇集起来,将信息都打印到文本上仔细地审查了一遍。

下面是一部分打印出来的信息:
***********************
<盘符>
文件名
FileReferenceNumber - 对应地址
ParentFileReferenceNumber - 对应地址

<C:\>
Program Files
frn:281474976710716 - C:\Program Files
pfrn:1407374883553285 - C:\

Common Files
frn:281474976710717 - C:\Program Files\Common Files
pfrn:281474976710716 - C:\Program Files

microsoft shared
frn:281474976710718 - C:\Program Files\Common Files\microsoft shared
pfrn:281474976710717 - C:\Program Files\Common Files

<D:\>
Program Files
frn:281474976710691 - D:\Program Files
pfrn:1407374883553285 - D:\

Thunder Network
frn:281474976710692 - D:\Program Files\Thunder Network
pfrn:281474976710691 - D:\Program Files

Thunder
frn:281474976710693 - D:\Program Files\Thunder Network\Thunder
pfrn:281474976710692 - D:\Program Files\Thunder Network

<E:\>
实况8中超风云秋风DIY版
frn:281474976710694 - E:\实况8中超风云秋风DIY版
pfrn:1407374883553285 - E:\

WE8.exe
frn:281474976710698 - E:\实况8中超风云秋风DIY版\WE8.exe
pfrn:281474976710694 - E:\实况8中超风云秋风DIY版

**********************
首先注意下加粗的地方,指向的路径是根目录(盘符),不难发现他们对应的ReferenceNumber都是一致的,经测试无论U盘,外置硬盘还是删了USN再建,我发现都是一致的,而且就是1407374883553285,不知会不会和机器本身有关,具体有待验证,不过我们还是得出一条结论:
<根目录的ReferenceNumber是一个与盘符无关的特定不变的数值——1407374883553285>

再具体看数据,以上面<E:\>的数据作为样例,整理如下: 
name                             frn                                     pfrn                              path
WE8.exe                        281474976710698       281474976710694      E:\实况8中超风云秋风DIY版\WE8.exe
实况8中超风云秋风DIY版    281474976710694       1407374883553285    E:\实况8中超风云秋风DIY版
E:                                 1407374883553285      /                                  E:\

前面3个信息是我们能通过USN直接获取的,path是我们要获取的。

而最后一行(1407374883553285 ->E:\ )是我们前面验证的。

基于这个,如果我们要获取"实况8中超风云秋风DIY版 "所在的路径,就可以根据他的pfrn(1407374883553285 )关联到E:\ ,然后一组合,“E:\ 实况8中超风云秋风DIY版 ”就出来了。如果是“WE8.exe ”呢?那就必须先获取“实况8中超风云秋风DIY版 ”的路径才能建立起来。

按这样的规律,只要我们能自上而下地建立起联系就能获取到所有文件的完整路径了。其实这就是一个树的结构。

<具体实现> 
为了能自上而下地建立起来,在我们读取USN的时候就要先做一些处理。

1.按每个目录属性的记录的frn作为key值,每个以该key作为pfrn的记录作为内容,构建一个哈希表(Hashtable<Long, Vector>)。

这样,当我们读取完所有记录后就会得到一个这样的哈希表结构:
key                               value
(目录属性)记录的frn         array{...}[pfrn为key值的记录]

2.给定一个首要条件,建立第一级关联
根据盘符名(如E:\)->1407374883553285,找到key=1407374883553285下的所有记录,将其路径逐一标记为"盘符+机身名字"

3.递归遍历,获取所有记录的路径
遍历已建立路径的每个记录,找到以该记录的frn为key值的元素,建立路径,如此来回反复。

最后就能建立起完整的路径表。当然这样的局限性就是需要先获取到所有的数据。

这里提供一个大概的参考:

Java代码  
  1. static final long rootFileReferenceNumber = Long.parseLong("1407374883553285");
  2. static final String EndSymbol = "\\";
  3. private Hashtable<Long, Vector> hashByPfrn; // 根据pfrn作为key值对记录进行分类储存
  4. private Hashtable<Long, String> hashPaths; // 用于辅助递归
  5. public static main(String[] args){
  6. for(所有USN记录){
  7. addData(.frn, .fileName, .pfrn, .filePath, .fileAttribute);
  8. }
  9. buildPath(rootFileReferenceNumber, "E:\\");
  10. }
  11. /**
  12. * 添加数据
  13. * @param frn
  14. * @param fileName
  15. * @param pfrn
  16. * @param filePath
  17. * @param fileAttribute
  18. */
  19. private void addData(long frn, String fileName, long pfrn, String filePath, int fileAttribute) {
  20. Vector<NtfsVolumeData> v = (Vector<NtfsVolumeData>) hashByPfrn.get(pfrn);
  21. NtfsVolumeData record = new NtfsVolumeData(frn, fileName, pfrn, filePath, fileAttribute);
  22. if (v == null) {
  23. v = new Vector<NtfsVolumeData>();
  24. v.add(record);
  25. hashByPfrn.put(pfrn, v);
  26. } else {
  27. v.add(record);
  28. }
  29. fileCounter++;
  30. }
  31. /**
  32. * 建立路径
  33. * @param rootKey
  34. * @param rootName
  35. */
  36. private void buildPath(long rootKey, String rootName) {
  37. hashPaths.clear();
  38. long key = rootKey;
  39. hashPaths.put(key, rootName);
  40. buildPath(key, hashPaths);
  41. }
  42. /**
  43. * 递归建立路径
  44. * @param key
  45. * @param hashPaths
  46. */
  47. private void buildPath(long key, Hashtable hashPaths) {
  48. // 获取到属于该key的记录
  49. Vector<NtfsVolumeData> records = (Vector<NtfsVolumeData>) hashByPfrn.get(key);
  50. if (records == null || records.size() <= 0) {
  51. return;
  52. }
  53. // 获取该key对应的路径
  54. String filePath = (String) hashPaths.get(key);
  55. // 设置路径
  56. for (NtfsVolumeData record : records) {
  57. record.setParentPath(filePath);
  58. /**
  59. * 对带有目录属性的记录
  60. */
  61. if (0 != (record.getFileAttributes() & UsnRecordAttributeValues.FILE_ATTRIBUTE_DIRECTORY)) {
  62. // 记录当前记录路径为新路径
  63. hashPaths.put(record.frn, record.getFullPath() + EndSymbol);
  64. // 再进一步搜索
  65. buildPath(record.frn, hashPaths);
  66. }
  67. }
  68. }

Everything研究之快速获取USN记录的文件路径相关推荐

  1. js获取用户选择的文件路径[曲线救国]

    JavaScript如何获取用户input[type=file]选择的文件路径呢? 首先,JavaScript本身是无法通过input[type=file]获取用户选择的文件路径的,这条路是行不通的. ...

  2. JavaGUI编程 -- Swing之Icon、ImageIcon标签获取当前类同一级文件路径的资源

    1. Swing之Icon.ImageIcon标签&获取当前类同一级文件路径的资源 1.1 Icon标签 这个是使用画笔画自己心怡的图标 示例: package GUI.Swing;impor ...

  3. 快速获取OpenCV库(Lib)文件下的所有文件的目录名~

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 OpenCV的VS配置中很重要的一步是配置链接器 ...

  4. android 获取uri的正确文件路径的办法

    有时会从其他的文件浏览器获取路径,这时根据路径去数据库取文件时会发现不成功,原因是由于android的文件浏览器太多,各自返回的路径不统一,而android本身的数据库中的路径是绝对路径,即" ...

  5. 获取resources目录下文件路径的九套功法

    文章目录 前述 功法一 功法二 功法三 功法四(重要) 功法五(重要) 功法六(重要) 功法七 功法八 功法九 前述 项目开发中,经常会有一些静态资源,被放置在resources目录下,随项目打包在一 ...

  6. android文件夹隐藏,Android – 快速获取隐藏图像和文件夹的方法

    我正在添加另一个答案 快速闪电 : – 在我的测试应用程序中以134微秒执行扫描. 使用ContentResolver : – 使用ContentResolver扫描包含.noMedia文件的所有隐藏 ...

  7. linux如何获取raw中的文件路径,如何使用Linux获取Touchscreen Rawdata的坐标

    我们有一个3米的微触摸显示屏.它通过usb连接到我的debian系统,并被识别为人机界面(hid).我正在尝试访问并推送实时信息-如果它被触及我想知道哪里(x,y)并通过netcat管道到另一台主机. ...

  8. linux如何获取raw中的文件路径,如何使用Linux获得Touchscreen Rawdata的坐标

    我们有一个3米的微触摸显示屏.它通过usb与我的debian系统相连,并被认为是人机界面(hid).我正在尝试访问并推送实时信息......如果它被触及我想知道哪里(x,y)并将它通过netcat传递 ...

  9. Mac下获取AppStore安装包文件路径

    本文介绍了Mac下如何找到AppStore下载的安装包路径,以及如何提取出来供以后使用的相关步骤,希望对大家有所帮助. 通过远在大洋彼岸的苹果服务器下载东西,确实有够慢啊!AppStore更甚:甚至都 ...

最新文章

  1. 鱼佬:从数据竞赛到工作!
  2. 欢迎大家观顾【图灵教育社区】
  3. 7:MD5、圆形图片、动态换肤
  4. 微服务可靠性设计--转
  5. Qt中为工程添加资源文件、给按钮添加图片
  6. Smalidea+IntelliJ IDEA/Android Studio无源码调试
  7. Linux的find -print 和 -print0区别:换行不换行
  8. Spring Boot实践教程(二):SpringApplication分析
  9. 2014 网选 5011 Game(Nim游戏,数学题)
  10. 《OOD启思录》—第2章2.6节角色与类
  11. VMware虚拟网络设置(NAT模式,桥接模式,仅主机模式设置),再也不用担心虚拟机连不上网了。
  12. 几种web报表打印方案的比较
  13. 从U盘安装windows/linux操作系统
  14. IATF16949认证辅导,IATF16949第六章容易发生的问题点及处理方案
  15. chrome最简单的多开方法
  16. Springboot毕设项目电商系统设计与实现t32la(java+VUE+Mybatis+Maven+Mysql)
  17. easyui教程 php,jQuery EasyUI 教程-Panel(面板)
  18. 【English】十一、一般疑问句
  19. @keyup.enter.native
  20. ibmx340服务器硬盘,IBM3850安装操作系统

热门文章

  1. 阿里云免费SSL证书续费步骤 TOMCAT
  2. iOS逆向-手把手教你写支付宝蚂蚁森林收集能量助手
  3. Web网站模板-餐厅饭店宣传响应式网站模板(HTML+CSS+JavaScript)
  4. gnuplot用C语言程序画图,gnuplot使用
  5. WPS 宣布将推出“WPS AI”
  6. 理解O(log2N)和O(Nlog2N)
  7. OpenGL基本图元的绘制
  8. ACM图灵奖现状以及得主及其分别分别的贡献
  9. 金蝶apusic9.0版本安装包
  10. 2kids学汉字 android,新2Kids学汉字