在Python中创建NTFS交接点

在Python中创建NTFS交接点,第1张

在Python中创建NTFS交接点

我在类似的问题中回答了这个问题,因此将我的回答复制到下面的内容中。自从写出答案以来,我最终编写了一个纯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 +上受支持。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5630493.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存