1

我目前正在使用以下 P/Invoke 签名来获取常规 Windows 文件的短文件名:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetShortPathName([MarshalAs(UnmanagedType.LPTStr)] string path,
                                          [MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath,
                                          int shortPathLength);

目前 - 它工作没有任何问题,但我注意到一些相当奇怪的事情:
我知道 Windows 使用以下短文件名约定:

将名称剪切为 6 个字符(不带扩展名)
附加波浪号( ~)
附加一个表示匹配索引的无符号整数(从 1 开始)
附加原始文件扩展名

因此,文件名C:\abcdefghijklmn.txt应该可以在短名称下访问C:\abcdefg~1.txt(这工作得很好。)

现在奇怪的部分:我最近在我的音乐目录中执行了一个小的搜索,以查找特定的音频文件。结果是这样的:

.\Rammstein & Tatu - Moscow.mp3
.\Rammstein - Asche zu Asche.mp3
.\Rammstein - Der Meister.mp3
.\Rammstein - Du Hast.mp3
.\Rammstein - Eifersucht.mp3
.\Rammstein - Feuer Frei.mp3
.\Rammstein - Führe Mich.mp3
.\Rammstein - Haifisch.mp3
...

并以简写形式进行相同的搜索:

.\RA8E17~1.MP3
.\RA23A6~1.MP3
.\RAMMST~1.MP3
.\RA0CAE~1.MP3
.\RAMMST~2.MP3
.\RAMMST~3.MP3
.\RAMMST~4.MP3
.\RA6BAA~1.MP3
...

我的问题是:为什么 Windows 会在波浪号(比如RA23A6or RA0CAE)之前生成这样的“随机”前缀?

4

2 回答 2

10

微软没有记录这一点,但维基百科有:

8.3 文件名

尽管从 LFN 创建 8.3 名称没有强制算法,但 Windows 使用以下约定:

1.如果 LFN 是 8.3 大写,则磁盘上根本不会存储 LFN。

  • 例子:TEXTFILE.TXT

2.如果LFN是8.3大小写混合,LFN将存储大小写混合名称,而8.3名称将是它的大写版本。

  • 示例:TextFile.Txt变成TEXTFILE.TXT.

3.如果文件名包含 8.3 名称中不允许的字符(包括按惯例但 API 不允许的空格)或任何部分太长,则名称将被去除无效字符,例如空格和额外句点。其他字符如+改为下划线_和大写。然后将剥离的名称截断为其基本名称的前 6 个字母,后跟一个波浪号,后跟一个数字,然后是句点.,然后是扩展名的前 3 个字符。

  • 示例:TextFile1.Mine.txt成为TEXTFI~1.TXT(或TEXTFI~2.TXT,应该TEXTFI~1.TXT已经存在)。ver +1.2.text变成VER_12~1.TEX.

4.从 Windows 2000 开始,如果至少有 4 个文件或文件夹在其短名称中具有相同的前 6 个字符,则剥离的 LFN 将被截断为基本名称的前 2 个字母(如果基本名称只有 1,则截断为 1字母),后跟 4 个从文件名的未记录哈希派生的十六进制数字,后跟波浪号,后跟单个数字,后跟句.点,后跟扩展名的前 3 个字符。

  • 示例:TextFile.Mine.txt变成TE021F~1.TXT.

正如 Joey 提到的,文件名的未记录哈希已被反向工程

于 2015-07-20T21:08:13.583 回答
3

这是因为使用计数器和前缀的非常原始的方案仅适用于一定数量的文件。随着文件数量的增加,Windows 切换到更短的前缀和散列。有人实际上对哈希进行了逆向工程,并给出了一些解释:

如果您不知道 8.3 文件名是如何工作的,这里有一个简短的介绍。

  • 除了将文件名与扩展名分开的句点之外的所有句点都被删除 - a.testing.file.bat 变成了 attestingfile.bat。
  • 某些特殊字符(如 +)会变成下划线,而其他字符则被删除。文件名是大写的。1+2+3 Hello World.exe 变成 1_2_3HELLOWORLD.EXE。
  • 文件扩展名被截断为 3 个字符,并且(如果超过 8 个字符)文件名被截断为 6 个字符,后跟 ~1。SomeStuff.aspx 变成了 SOMEST~1.ASP。
  • 如果这些会导致冲突,则使用 ~2,然后是 ~3 和 ~4。
  • 而不是去~5,文件名被截断为 2 个字符,替换为长文件名的十六进制校验和 - SomeStuff.aspx 变成 SOBC84~1.ASP,其中 BC84 是(以前-) 未记录的校验和函数。
于 2015-07-20T21:12:36.653 回答