因为我很懒,所以我没有编写测试程序,而是使用出色的Far Manager对其进行了测试,该管理器可以处理长路径(长于MAX_PATH
)或特殊文件名(con
等prn
)。
我创建了一个正好 255 个字符的字符串(“12345678901234...012345”)并开始创建嵌套目录。幸运的是,Far 的“制作目录”函数采用斜杠分隔的字符串来表示“创建嵌套目录”,因此我只需几个步骤即可通过在内部编辑器中准备一个字符串并进行一些复制和粘贴来完成它。
我能够创建的最长路径是32739 个字符,从“C:\”开始计算(即不包括 Far 添加的“\\?\”)。尝试创建仅包含一个附加字符的目录或文件时出现的错误是“文件名或扩展名太长。 ”。如果我尝试进入该目录,我会得到同样的错误。
编辑:在调试器中花了一些时间,这是在 Win32 API 级别上发生的事情:
- 我尝试创建一个字符超过限制的文件
CreateFileW
使用字符串 "\\?\C:\123[...]012345" 进行远调用,该字符串长32744 个宽字符(不包括终止零)。
CreateFileW
做一些额外的检查,将 null 终止的字符串转换为UNICODE_STRING
(Length=65488, MaximumLength=65490) 并准备一个OBJECT_ATTRIBUTES
结构。
CreateFileW
然后调用NtCreateFile
in ntdll.dll
,这只是syscall
指令的包装。
NtCreateFile
返回0xC0000106 ( STATUS_NAME_TOO_LONG
)。
- 然后将该状态值转换(使用
RtlNtStatusToDosError
)为 Win32 错误 206 ( ERROR_FILENAME_EXCED_RANGE
)。
我没有费心检查内核中发生了什么,但我想我也可以看看。
EDIT2:我运行WinObj 并发现在我的系统C:
上是一个指向\Device\HarddiskVolume1
. 该字符串长度为23 个字符。如果我们用它替换\C:
传递给的字符串中的NtCreateFile
,我们得到 32744 - 3 + 23 = 32764 个字符。与终止零一起,这需要 65530 个字节。仍然没有达到限制(0xFFFF=65535),所以我想还有一些额外的东西被添加了,比如会话或命名空间名称。
EDIT3:通过内核后:
NtCreateFile
来电IopCreateFile
IopCreateFile
来电ObOpenObjectByName
ObOpenObjectByName
来电ObpLookupObjectName
ObpLookupObjectName
检查ObpDosDevicesShortNamePrefix
( "\??\"
) -> 成功
- 它跳过前缀并将剩余部分拆分为
"C:"
和"\1234..."
- 它
"C:"
通过调用来解决ObpLookupDirectoryEntry
- 然后它调用
ObpParseSymbolicLink
将查找的目录条目(_OBJECT_SYMBOLIC_LINK
带有LinkTarget
=="\Device\HarddiskVolume1"
和DosDeviceDriveIndex
== 3)和名称的其余部分传递给它。
然后它会做这样的事情(由 ReactOS 忠实复制):
TargetPath = &SymlinkObject->LinkTarget;
TempLength = TargetPath->Length;
TotalLength = TempLength + RemainingName->Length;
if (LengthUsed > 0xFFF0)
return STATUS_NAME_TOO_LONG;
在我们的例子中,46 + 65476 = 65522 (0xfff2) 刚好高于限制。
所以在那里,谜团解开了(我希望!)。
PS 在 Windows 7 x64 SP1 下测试的所有内容。