当前位置: 首页 > 面试题库 >

在Python中创建NTFS交接点

巫马昆琦
2023-03-14
问题内容

有没有一种方法可以在Python中创建NTFS交接点?我知道我可以调用该junction实用程序,但是最好不要依赖外部工具。


问题答案:

我在类似的问题中回答了这个问题,因此将我的回答复制到下面的内容中。自从写出答案以来,我最终编写了一个纯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 function
SYMBOLIC_LINK = 'symbolic'
MOUNTPOINT = 'mountpoint'
GENERIC = 'generic'

def islink(fpath):
    """ Windows islink implementation. """
    if GetFileAttributes(fpath) & REPARSE_FOLDER:
        return True
    return False


def 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 buffer

def 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) == unicode 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 rpath

def 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 fpath


def 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 +上受支持。



 类似资料:
  • 问题内容: 我有一个日志文件,其中使用python记录了一些测试命令及其状态(通过/失败)。现在,我希望测试命令不应写为简单文本,而应写为超链接。这样,当我单击它们时,将打开另一个链接到它们的文件。 例如: 现在,我希望写在logfile.log中的CommandName应该是文件TestCommand.log的超链接,以便当我单击CommandName时,文件TestCommand.log会打开

  • 问题内容: 我有一个数据块,当前为n元组列表,但格式相当灵活,我想附加到Postgres表中-在这种情况下,每个n元组都对应于数据库中的一行。 到目前为止,我一直在做的工作是将所有内容都写入CSV文件,然后使用postgres的COPY将所有内容批量加载到数据库中。这可行,但不是最佳选择,我希望能够直接从python进行所有操作。python中是否有一种方法可以在Postgres中复制COPY类型

  • 问题内容: 我正在寻找一种在python中动态创建html文件的方法。我正在编写画廊脚本,该脚本在目录中进行迭代,收集文件元数据。然后,我打算使用此数据基于html自动创建图片库。事情很简单,只是一张图片表。 我真的不认为手动写入文件是最好的方法,并且代码可能很长。那么,有没有更好的方法可以做到这一点,可能是html特定的? 问题答案: 我认为,如果我对您的理解正确,那么您可以在此处看到“使用Py

  • 问题内容: 这个问题不是为了讨论是否需要单例设计模式,是否是反模式,还是针对任何宗教战争,而是要讨论如何以最pythonic的方式在Python中最好地实现此模式。在这种情况下,我定义“最pythonic”表示它遵循“最小惊讶原则”。 我有多个将成为单例的类(我的用例用于记录器,但这并不重要)。当我可以简单地继承或修饰时,我不希望增加gumph来使几个类杂乱无章。 最佳方法: 方法1:装饰器 优点

  • 问题内容: 我正在使用Redis通过Redis-py客户端库存储两个数据库:0和1 。我想为每个数据库创建两个连接。目前,我正在这样做: 但是,我似乎找不到从连接创建Redis对象的方法。 我在这里犯一个菜鸟错误吗? 问题答案: 您真的不应该那样创建连接。让我引用redis-py文档。 在后台,redis- py使用连接池来管理与Redis服务器的连接。默认情况下,您创建的每个Redis实例将依次

  • 问题内容: 我想创建一种秒表,当分钟数达到20分钟时,会弹出一个对话框,该对话框不是问题。但是我的分钟变量在此代码中没有增加。 问题答案: 您可以使用以下方法真正简化整个程序: