当文件路径超过大约时,内部会发生什么。 Windows中32767个字符?

时间:2013-03-07 02:42:30

标签: windows winapi internals

在Windows(假设2000以后)中,文件路径的长度最多约为32767个字符。由于本机API(也在内核端,驱动程序等)中使用UNICODE_STRING进行内部处理,因此存在此限制。到现在为止还挺好。我知道那部分背后的理论。

限制的原因是Length的{​​{1}}和MaximumLength成员计算UNICODE_STRING中的字节数,但是16位无符号整数本身

我也知道为什么限制是近似而不是设定限制。这主要是由于您的文件名(例如Buffer)如何被解析为其原生形式(例如\\.\C:\boot.ini),然后是由实际卷设备作为前缀的东西名称,然后是相对于该卷的路径,例如\??\C:\boot.ini

此外,从Windows资源管理器中,达到(“ANSI”)\Device\HarddiskVolume2\boot.ini限制时的已知症状是假装某些版本的Windows中不存在文件或文件夹(可能在某些时候已得到修复)。

但是当我使用类似MAX_PATH的路径调用CreateFile()时,对象管理器,I / O管理器和文件系统驱动程序级别会发生什么 路径超出限制,但到达,在我致电\\.\C:\...\filename.ext的{​​{1}}和然后扩大了吗? ...

SDK和WDK似乎都没有特别讨论这个话题。还是我看错了?

1 个答案:

答案 0 :(得分:38)

因为我很懒,所以我没有编写测试程序,而是使用优秀的Far Manager测试它,它处理长路径(长于MAX_PATH)或特殊文件名({{1} ,},con等等就好了。

我创建了一个完全包含255个字符的字符串(“12345678901234 ... 012345”)并开始创建嵌套目录。幸运的是,Far的“Make Directory”函数采用斜杠分隔的字符串来表示“创建嵌套目录”,所以我只需几步就可以通过在内部编辑器中准备一个带有一些复制和粘贴的字符串来完成它。

我能够创建的最长路径是 32739 个字符,从“C:\”开始计算(即它不包括由Far添加的“\\?\”)。尝试使用一个附加字符创建目录或文件时出现的错误是“文件名或扩展名太长。”。如果我尝试进入该目录,我会收到同样的错误。

编辑:在调试器中花了一些时间,这是在Win32 API级别上发生的事情:

  1. 我尝试创建一个字符超出限制
  2. 的文件
  3. 远程调用prn,字符串为“\\?\ C:\ 123 [...] 012345” 32744 宽字符长(不包括终止零)。
  4. CreateFileW执行一些额外检查,将以null结尾的字符串转换为CreateFileW(长度= 65488,MaximumLength = 65490)并准备UNICODE_STRING结构。
  5. OBJECT_ATTRIBUTES然后在CreateFileW中调用NtCreateFile,这只是ntdll.dll指令的包装。
  6. syscall返回 0xC0000106 NtCreateFile)。
  7. 然后将该状态值转换(使用STATUS_NAME_TOO_LONG)到Win32错误206(RtlNtStatusToDosError)。
  8. 我没有费心去检查内核中发生了什么,但我想我也可以看一下

    EDIT2 :我运行了WinObj,发现我的系统ERROR_FILENAME_EXCED_RANGE上是C:的符号链接。此字符串长 23个字符。如果我们用它替换传递给\Device\HarddiskVolume1的字符串中的\C:,我们会得到32744 - 3 + 23 = 32764 个字符。与终止零一起,这需要65530个字节。仍然没有超出限制(0xFFFF = 65535),所以我想还有一些额外的东西,比如会话或命名空间名称。

    EDIT3 :完成内核后:

    1. NtCreateFile来电NtCreateFile
    2. IopCreateFile来电IopCreateFile
    3. ObOpenObjectByName来电ObOpenObjectByName
    4. ObpLookupObjectName检查ObpLookupObjectNameObpDosDevicesShortNamePrefix) - >成功
    5. 它会跳过前缀并将剩余部分拆分为"\??\""C:"
    6. 通过调用"\1234..."
    7. 解析"C:"
    8. 然后调用 ObpLookupDirectoryEntry 向其查询已查找的目录条目ObpParseSymbolicLink _OBJECT_SYMBOLIC_LINK == LinkTarget和{{1 }} == 3)和名称的其余部分。
    9. 然后做这样的事情(忠实地reproduced by ReactOS):

      "\Device\HarddiskVolume1"

      在我们的例子中,46 + 65476 = 65522(0xfff2)刚刚超过限制。

      所以,神秘解决了(我希望!)。

    10. P.S。在Windows 7 x64 SP1下测试的所有内容。