Подтвердить что ты не робот

Создание точки соединения NTFS в Python

Есть ли способ создать точку соединения NTFS в Python? Я знаю, что могу вызвать утилиту junction, но лучше не полагаться на внешние инструменты.

4b9b3361

Ответ 1

Я ответил на это в аналогичном вопросе, поэтому я скопирую свой ответ на это ниже. После написания этого ответа я закончил писать только python (если вы можете вызвать модуль, который использует только модуль ctypes python) для создания, чтения и проверки соединений, которые можно найти в эта папка. Надеюсь, что это поможет.

Кроме того, в отличие от ответа, который использует API CreateSymbolicLinkA, связанная реализация должна работать с любой версией Windows, поддерживающей соединения. CreateSymbolicLinkA поддерживается только в Vista +.

Ответ:

расширение 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 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 +.

Ответ 2

вы можете использовать python win32 API-модули, например.

import win32file

win32file.CreateSymbolicLink(srcDir, targetDir, 1)

см. http://docs.activestate.com/activepython/2.5/pywin32/win32file__CreateSymbolicLink_meth.html для более подробной информации

если вы тоже не хотите полагаться на это, вы всегда можете использовать ctypes и напрямую обращаться к CreateSymbolicLinl win32 API, который в любом случае является простым вызовом

вот пример вызова с использованием ctypes

import ctypes

kdll = ctypes.windll.LoadLibrary("kernel32.dll")

kdll.CreateSymbolicLinkA("d:\testdir", "d:\testdir_link", 1)

MSDN говорит Минимальный поддерживаемый клиент Windows Vista​​p >

Ответ 3

Так как у Python 3.5 есть функция CreateJunction в модуле _winapi.

import _winapi
_winapi.CreateJunction(source, target)

Ответ 4

Вы не хотите полагаться на внешние инструменты, но не против полагаться на конкретную среду? Я думаю, вы могли бы с уверенностью предположить, что если NTFS вы работаете, вероятно, там будет утилита соединения.

Но, если вы имеете в виду, что не хотите вызывать внешнюю программу, я нашел ctypes материал для быть неоценимым. Он позволяет вызывать Windows DLL напрямую из Python. И я уверен, что это в стандартных выпусках Python в наши дни.

Вам просто нужно выяснить, в какую Windows DLL вызывает вызов CreateJunction() (или любой другой вызов Windows) API, и настроить параметры и вызвать. Удачи вам в этом, Microsoft, похоже, не очень хорошо его поддерживает. Вы можете разобрать программу SysInternals junction или linkd или один из других инструментов, чтобы узнать, как они это делают.

Я, я довольно ленив, я бы назвал junction внешним процессом: -)