在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似乎都没有特别讨论这个话题。还是我看错了?
答案 0 :(得分:38)
因为我很懒,所以我没有编写测试程序,而是使用优秀的Far Manager测试它,它处理长路径(长于MAX_PATH
)或特殊文件名({{1} ,},con
等等就好了。
我创建了一个完全包含255个字符的字符串(“12345678901234 ... 012345”)并开始创建嵌套目录。幸运的是,Far的“Make Directory”函数采用斜杠分隔的字符串来表示“创建嵌套目录”,所以我只需几步就可以通过在内部编辑器中准备一个带有一些复制和粘贴的字符串来完成它。
我能够创建的最长路径是 32739 个字符,从“C:\”开始计算(即它不包括由Far添加的“\\?\”)。尝试使用一个附加字符创建目录或文件时出现的错误是“文件名或扩展名太长。”。如果我尝试进入该目录,我会收到同样的错误。
编辑:在调试器中花了一些时间,这是在Win32 API级别上发生的事情:
prn
,字符串为“\\?\ C:\ 123 [...] 012345”
32744 宽字符长(不包括终止零)。CreateFileW
执行一些额外检查,将以null结尾的字符串转换为CreateFileW
(长度= 65488,MaximumLength = 65490)并准备UNICODE_STRING
结构。OBJECT_ATTRIBUTES
然后在CreateFileW
中调用NtCreateFile
,这只是ntdll.dll
指令的包装。syscall
返回 0xC0000106 (NtCreateFile
)。STATUS_NAME_TOO_LONG
)到Win32错误206(RtlNtStatusToDosError
)。 我没有费心去检查内核中发生了什么,但我想我也可以看一下。
EDIT2 :我运行了WinObj,发现我的系统ERROR_FILENAME_EXCED_RANGE
上是C:
的符号链接。此字符串长 23个字符。如果我们用它替换传递给\Device\HarddiskVolume1
的字符串中的\C:
,我们会得到32744 - 3 + 23 = 32764 个字符。与终止零一起,这需要65530个字节。仍然没有超出限制(0xFFFF = 65535),所以我想还有一些额外的东西,比如会话或命名空间名称。
EDIT3 :完成内核后:
NtCreateFile
来电NtCreateFile
IopCreateFile
来电IopCreateFile
ObOpenObjectByName
来电ObOpenObjectByName
ObpLookupObjectName
检查ObpLookupObjectName
(ObpDosDevicesShortNamePrefix
) - >成功"\??\"
和"C:"
"\1234..."
"C:"
ObpLookupDirectoryEntry
向其查询已查找的目录条目ObpParseSymbolicLink
_OBJECT_SYMBOLIC_LINK
== LinkTarget
和{{1 }} == 3)和名称的其余部分。然后做这样的事情(忠实地reproduced by ReactOS):
"\Device\HarddiskVolume1"
在我们的例子中,46 + 65476 = 65522(0xfff2)刚刚超过限制。
所以,神秘解决了(我希望!)。
P.S。在Windows 7 x64 SP1下测试的所有内容。