python读取路径太长_路径名太长,无法打开?

常规DOS路径限制为MAX_PATH(260)个字符,包括字符串的终止字符NUL。通过使用以\\?\前缀开头的扩展长度路径,可以超过此限制。此路径必须是完全限定的Unicode字符串,并且只能使用反斜杠作为路径分隔符。根据Microsoft的file system functionality comparison,最大扩展路径长度为32760个字符。单个文件或目录名最多可以包含255个字符(UDF文件系统为127个字符)。扩展的UNC路径也支持为\\?\UNC\server\share。

例如:import os

def winapi_path(dos_path, encoding=None):

if (not isinstance(dos_path, unicode) and

encoding is not None):

dos_path = dos_path.decode(encoding)

path = os.path.abspath(dos_path)

if path.startswith(u"\\\\"):

return u"\\\\?\\UNC\\" + path[2:]

return u"\\\\?\\" + path

path = winapi_path(os.path.join(u"JSONFiles",

item["category"],

item["action"],

item["source"],

fileName + ".json"))>>> path = winapi_path("C:\\Temp\\test.txt")

>>> print path

\\?\C:\Temp\test.txt

请参阅MSDN上的以下页面:

背景

Windows调用NT运行库函数RtlDosPathNameToRelativeNtPathName_U_WithStatus将DOS路径转换为本机NT路径。如果上面的路径在后面的函数上设置了断点,我们可以看到它如何处理以前缀\\?\开头的路径。Breakpoint 0 hit

ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus:

00007ff9`d1fb5880 4883ec58 sub rsp,58h

0:000> du @rcx

000000b4`52fc0f60 "\\?\C:\Temp\test.txt"

0:000> r rdx

rdx=000000b450f9ec18

0:000> pt

ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus+0x66:

00007ff9`d1fb58e6 c3 ret

结果将\\?\替换为NT DOS设备前缀\??\,并将字符串复制到本机^{}:0:000> dS b450f9ec18

000000b4`536b7de0 "\??\C:\Temp\test.txt"

如果使用//?/而不是\\?\,则路径仍限制为MAX_PATH个字符。如果太长,则RtlDosPathNameToRelativeNtPathName返回状态代码STATUS_NAME_TOO_LONG(0xc000106)。

如果使用\\?\作为前缀,但在路径的其余部分使用斜杠,则Windows不会为您将斜杠转换为反斜杠:Breakpoint 0 hit

ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus:

00007ff9`d1fb5880 4883ec58 sub rsp,58h

0:000> du @rcx

0000005b`c2ffbf30 "\\?\C:/Temp/test.txt"

0:000> r rdx

rdx=0000005bc0b3f068

0:000> pt

ntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus+0x66:

00007ff9`d1fb58e6 c3 ret

0:000> dS 5bc0b3f068

0000005b`c3066d30 "\??\C:/Temp/test.txt"

正斜杠是NT命名空间中的有效对象名字符。它由Microsoft文件系统保留,但您可以在其他命名的内核对象中使用正斜杠,这些对象存储在\BaseNamedObjects或\Sessions\[session number]\BaseNamedObjects中。另外,我不认为I/O管理器对设备和文件名中的保留字符强制执行策略。这取决于设备。也许有人有一个Windows设备,它实现了一个名称空间,允许在名称中使用正斜杠。至少可以创建包含正斜杠的DOS设备名。例如:>>> kernel32 = ctypes.WinDLL('kernel32')

>>> kernel32.DefineDosDeviceW(0, u'My/Device', u'C:\\Temp')

>>> os.path.exists(u'\\\\?\\My/Device\\test.txt')

True

你可能想知道\??意味着什么。这曾经是对象名称空间中DOS设备链接的实际目录,但从NT 5(或NT 4 w/Terminal Services)开始,这就变成了一个虚拟前缀。对象管理器通过首先检查目录\Sessions\0\DosDevices\[LOGON_SESSION_ID]中登录会话的DOS设备链接,然后检查目录\Global??中的系统范围的DOS设备链接来处理此前缀。

请注意,前者是登录会话,而不是Windows会话。登录会话目录都在Windows会话0的DosDevices目录下(即Vista+中的服务会话)。因此,如果您有用于非提升登录的映射驱动器,您将发现它在提升的命令提示符中不可用,因为提升的令牌实际上用于不同的登录会话。

DOS设备链接的一个例子是\Global??\C:=>\Device\HarddiskVolume2。在这种情况下,DOS C:驱动器实际上是指向HarddiskVolume2设备的符号链接。

以下是系统如何处理解析路径以打开文件的简要概述。假设我们调用WinAPI CreateFile,它将转换后的NT UNICODE_STRING存储在^{}结构中,并调用系统函数NtCreateFile。0:000> g

Breakpoint 1 hit

ntdll!NtCreateFile:

00007ff9`d2023d70 4c8bd1 mov r10,rcx

0:000> !obja @r8

Obja +000000b450f9ec58 at 000000b450f9ec58:

Name is \??\C:\Temp\test.txt

OBJ_CASE_INSENSITIVE

NtCreateFile调用I/O管理器函数^{},后者反过来调用未记录的对象管理器API ObOpenObjectByName。这是解析路径的工作。对象管理器以\??\C:\Temp\test.txt开头。然后它用\Global??\C:Temp\test.txt替换它。接下来它解析到C:符号链接,并且必须重新开始(重新解析)最终路径\Device\HarddiskVolume2\Temp\test.txt。

一旦对象管理器到达HarddiskVolume2设备对象,解析就传递给I/O管理器,它实现Device对象类型。I/O的ParseProcedure{}创建File对象和major function codeIRP_MJ_CREATE(打开/创建操作)的I/O Request Packet (IRP)由设备堆栈处理。这将通过^{}发送到设备驱动程序。如果设备实现重分析点(例如连接装入点、符号链接等),并且路径包含重分析点,则必须将解析的路径重新提交给对象管理器,以便从一开始就进行分析。

设备驱动程序将在遍历目录时使用进程标记(或者如果模拟则使用线程)的SeChangeNotifyPrivilege(几乎总是存在并启用)来绕过访问检查。但是,最终对设备和目标文件的访问必须由安全描述符来允许,该描述符通过^{}进行验证。除了像FAT32这样的简单文件系统不支持文件安全之外。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值