我在类似的问题中回答了这个问题,因此将我的回答复制到下面的内容中。自从写出答案以来,我最终编写了一个纯Python(如果您可以调用仅使用ctypes
python的模块)模块来创建,读取和检查可在此文件夹中找到的联结。希望能有所帮助。
另外,与使用 CreateSymboliclinkA API的答案不同,链接的实现应在任何支持联结的Windows版本上都可以使用。仅在Vista
+中支持CreateSymboliclinkA。
回答:
python ntfslink扩展
或者,如果您想使用pywin32,则可以使用前面提到的方法,并阅读以下内容:
from win32file import *from winioctlcon import FSCTL_GET_REPARSE_POINT__all__ = ['islink', 'readlink']# Win32file doesn't seem to have this attribute.FILE_ATTRIBUTE_REPARSE_POINT = 1024# To make things easier.REPARSE_FOLDER = (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT)# For the parse_reparse_buffer functionSYMBOLIC_link = 'symbolic'MOUNTPOINT = 'mountpoint'GENERIC = 'generic'def islink(fpath): """ Windows islink implementation. """ if GetFileAttributes(fpath) & REPARSE_FOLDER: return True return Falsedef parse_reparse_buffer(original, reparse_type=SYMBOLIC_link): """ Implementing the below in Python: typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymboliclinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIOnNAME; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; """ # Size of our data types SZULONG = 4 # sizeof(ULONG) SZUSHORT = 2 # sizeof(USHORT) # Our structure. # Probably a better way to iterate a dictionary in a particular order, # but I was in a hurry, unfortunately, so I used pkeys. buffer = { 'tag' : SZULONG, 'data_length' : SZUSHORT, 'reserved' : SZUSHORT, SYMBOLIC_link : { 'substitute_name_offset' : SZUSHORT, 'substitute_name_length' : SZUSHORT, 'print_name_offset' : SZUSHORT, 'print_name_length' : SZUSHORT, 'flags' : SZULONG, 'buffer' : u'', 'pkeys' : [ 'substitute_name_offset', 'substitute_name_length', 'print_name_offset', 'print_name_length', 'flags', ] }, MOUNTPOINT : { 'substitute_name_offset' : SZUSHORT, 'substitute_name_length' : SZUSHORT, 'print_name_offset' : SZUSHORT, 'print_name_length' : SZUSHORT, 'buffer' : u'', 'pkeys' : [ 'substitute_name_offset', 'substitute_name_length', 'print_name_offset', 'print_name_length', ] }, GENERIC : { 'pkeys' : [], 'buffer': '' } } # Header stuff buffer['tag'] = original[:SZULONG] buffer['data_length'] = original[SZULONG:SZUSHORT] buffer['reserved'] = original[SZULONG+SZUSHORT:SZUSHORT] original = original[8:] # Parsing k = reparse_type for c in buffer[k]['pkeys']: if type(buffer[k][c]) == int: sz = buffer[k][c] bytes = original[:sz] buffer[k][c] = 0 for b in bytes: n = ord(b) if n: buffer[k][c] += n original = original[sz:] # Using the offset and length's grabbed, we'll set the buffer. buffer[k]['buffer'] = original return bufferdef readlink(fpath): """ Windows readlink implementation. """ # This wouldn't return true if the file didn't exist, as far as I know. if not islink(fpath): return None # Open the file correctly depending on the string type. handle = CreateFileW(fpath, GENERIC_READ, 0, None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, 0) if type(fpath) == unipre else CreateFile(fpath, GENERIC_READ, 0, None, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, 0) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, None, 16*1024) # Above will return an ugly string (byte array), so we'll need to parse it. # But first, we'll close the handle to our file so we're not locking it anymore. CloseHandle(handle) # Minimum possible length (assuming that the length of the target is bigger than 0) if len(buffer) < 9: return None # Parse and return our result. result = parse_reparse_buffer(buffer) offset = result[SYMBOLIC_link]['substitute_name_offset'] ending = offset + result[SYMBOLIC_link]['substitute_name_length'] rpath = result[SYMBOLIC_link]['buffer'][offset:ending].replace('x00','') if len(rpath) > 4 and rpath[0:4] == '\??\': rpath = rpath[4:] return rpathdef realpath(fpath): from os import path while islink(fpath): rpath = readlink(fpath) if not path.isabs(rpath): rpath = path.abspath(path.join(path.dirname(fpath), rpath)) fpath = rpath return fpathdef example(): from os import system, unlink system('cmd.exe /c echo Hello World > test.txt') system('mklink test-link.txt test.txt') print 'Islink: %s' % islink('test-link.txt') print 'Readlink: %s' % readlink('test-link.txt') print 'RealPath: %s' % realpath('test-link.txt') unlink('test-link.txt') unlink('test.txt')if __name__=='__main__': example()
根据需要调整CreateFile中的属性,但是在正常情况下,它应该可以工作。随时进行改进。
如果您使用MOUNTPOINT而不是SYMBOLIC_link,它也适用于文件夹联结。
您可能会检查
sys.getwindowsversion()[0] >= 6
如果将此内容放到要发布的内容中,因为这种形式的符号链接仅在Vista +上受支持。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)