微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

内部文件path超过大约时会发生什么? 在Windows中有32767个字符?

在Windows中(假设从2000年开始),文件path的长度最多可以是大约32767个字符。 这个限制的存在是由于UNICODE_STRING在本地API中的内部处理(也在内核端,驱动等)。 到现在为止还挺好。 我知道这部分背后的理论。

限制的原因是UNICODE_STRING的Length和MaximumLength成员计算了Buffer的字节数,但它们本身是16位无符号整数。

我也知道为什么限制是一个近似而不是一个限制。 这主要是由于你的文件名(例如\.C:boot.ini )被parsing为它的本机forms(例如??C:boot.ini ),然后被parsing为前缀实际卷设备名称,然后是相对于该卷的path,例如DeviceHarddiskVolume2boot.ini 。

此外,从Windows资源pipe理器遇到(“ANSI”) MAX_PATH限制时的已知症状是假装某些版本的Windows中不存在的文件文件夹(可能会在某些点上得到修复)。

在Windows上的 Device PhysicalMemory上需要说明

我的C#winform需要检测其他应用程序进入/退出/运行全屏,更喜欢事件

Windows虚拟内存和内核模式

Android与其他Linux有什么不同?

LoadLibrary引用计数

但是,当我调用CreateFile() ,path看起来像\.C:...filename.ext ,而整个path没有这个对象pipe理器,I / Opipe理器和文件系统驱动程序级别会发生什么超出限制,但达到它,在我的电话kernel32.dll的CreateFile() , 然后得到扩大? …

对于这个话题,SDK和WDK都没有特别的唠叨。 还是我看错了部分?

大内存块分配和4K块

MSDN术语 – 预定义控件与控制过程的窗口过程

如何在Windows上找出哪个.c文件包含R内部的.c函数

Windows堆pipe理器 – 前端和后端分配器

如果某个进程需要分配多于2 GB的内存,将会发生什么情况?

因为我很懒,所以我没有编写测试程序,而是使用优秀的远程管理器(它处理诸如长路径(超过MAX_PATH )或特殊文件名( con , prn等))来测试它。

我做了一个正好255个字符的字符串(“12345678901234 … 012345”),并开始创建嵌套的目录。 幸运的是,Far的“Make Directory”函数需要一个斜杠分隔的字符串来表示“创建嵌套的目录”,所以我可以通过在内部编辑器中准备一个字符串并进行一些复制和粘贴操作来完成。

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

编辑 :花了一些时间在调试器,这里是什么发生在Win32 API级别:

我尝试创建一个字符超过限制的文件

Far用字符串“\? C: 123 [0123] 012345”调用CreateFileW ,这个字符串长32744个字节(不包括终止零)。

CreateFileW执行一些额外的检查,将以null结尾的字符串转换为UNICODE_STRING (Length = 65488,MaximumLength = 65490),并准备一个OBJECT_ATTRIBUTES结构体。

CreateFileW然后在ntdll.dll调用NtCreateFile ,这只是syscall指令的一个包装。

NtCreateFile返回0xC0000106 ( STATUS_NAME_TOO_LONG )。

该状态值然后被转换(使用RtlNtStatusTodosError )到Win32错误206( ERROR_FILENAME_EXCED_RANGE )。

我没有检查内核中发生了什么,但我想我也可以看看 。

编辑2 :我运行WinObj ,发现在我的系统C:是符号链接DeviceHarddiskVolume1 。 该字符串长23个字符 。 如果我们用它替换传递给NtCreateFile的字符串C:得到32744 – 3 + 23 = 32764个字符。 加上终止零,这需要65530字节。 仍然缺少限制(0xFFFF = 65535),所以我猜想还有一些额外的东西被添加,比如会话或者命名空间的名字。

编辑3 :通过内核后:

NtCreateFile调用IopCreateFile

IopCreateFile调用ObOpenObjectByName

ObOpenObjectByName调用ObpLookupObjectName

ObpLookupObjectName检查ObpDosDevicesShortNamePrefix ( "??" ) – >成功

它跳过前缀,并将剩余部分拆分为"C:"和"1234..."

它通过调用ObpLookupDirectoryEntry来解析"C:"

然后调用ObpParseSymbolicLink传递查找的目录条目( _OBJECT_SYMBOLIC_LINK与LinkTarget == "DeviceHarddiskVolume1"和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下测试的一切。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐