복붙노트

[PYTHON] 파이썬에서 NTFS 연결 지점 만들기

PYTHON

파이썬에서 NTFS 연결 지점 만들기

파이썬에서 NTFS 연결 지점을 만드는 방법이 있습니까? 접합 유틸리티를 호출 할 수 있지만 외부 도구에 의존하지 않는 것이 좋습니다.

해결법

  1. ==============================

    1.나는 비슷한 질문으로 이것을 대답 했으므로 아래에 그 대답을 복사하겠습니다. 그 대답을 작성한 이래로, 나는 python 전용 (ctypes python 전용 모듈을 호출 할 수 있다면) 모듈을 작성, 읽기 및이 폴더에서 찾을 수있는 교차점 검사에 이르기까지 작성했습니다. 희망이 도움이됩니다.

    나는 비슷한 질문으로 이것을 대답 했으므로 아래에 그 대답을 복사하겠습니다. 그 대답을 작성한 이래로, 나는 python 전용 (ctypes python 전용 모듈을 호출 할 수 있다면) 모듈을 작성, 읽기 및이 폴더에서 찾을 수있는 교차점 검사에 이르기까지 작성했습니다. 희망이 도움이됩니다.

    또한 CreateSymbolicLinkA API를 사용하는 대답과 달리 링크 된 구현은 접합을 지원하는 모든 Windows 버전에서 작동해야합니다. CreateSymbolicLinkA는 Vista +에서만 지원됩니다.

    대답:

    파이썬 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의 특성을 필요에 맞게 조정하십시오. 그러나 정상적인 상황에서는 작동해야합니다. 기분 전환하십시오.

    또한 SYMBOLIC_LINK 대신 MOUNTPOINT를 사용하면 폴더 접합에도 사용할 수 있습니다.

    그걸 확인하는 방법이 있겠지.

    sys.getwindowsversion()[0] >= 6
    

    이 형식의 심볼릭 링크는 Vista +에서만 지원되므로 릴리스 할 항목에 넣으면됩니다.

  2. ==============================

    2.예를 들어 python win32 API 모듈을 사용할 수 있습니다.

    예를 들어 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

  3. ==============================

    3.파이썬 3.5부터는 _winapi 모듈에 CreateJunction 함수가 있습니다.

    파이썬 3.5부터는 _winapi 모듈에 CreateJunction 함수가 있습니다.

    import _winapi
    _winapi.CreateJunction(source, target)
    
  4. ==============================

    4.외부 도구에 의존하고 싶지는 않지만 특정 환경에 의존하지 마십시오. NTFS가 실행 중이라면 접합 유틸리티가있을 것이라고 가정 할 수 있다고 생각합니다.

    외부 도구에 의존하고 싶지는 않지만 특정 환경에 의존하지 마십시오. NTFS가 실행 중이라면 접합 유틸리티가있을 것이라고 가정 할 수 있다고 생각합니다.

    하지만, 외부 프로그램을 부르는 것이 아니라면 ctypes 자료가 매우 귀중하다는 것을 알았습니다. Python에서 Windows DLL을 직접 호출 할 수 있습니다. 그리고 요즘에는 표준 파이썬 릴리스에 있다고 확신합니다.

    CreateJunction () (또는 Windows가 호출하는 API) API 호출이 어느 Windows DLL인지 파악하고 매개 변수를 설정하고 호출해야합니다. Microsoft는이를 잘 지원하지 않는 것으로 보입니다. SysInternals junction 프로그램이나 linkd 또는 다른 도구 중 하나를 해체하여 어떻게 수행하는지 확인할 수 있습니다.

    나, 나는 꽤 게으르다, 나는 단지 외부 프로세스로서 접합을 호출 할 것이다 :-)

  5. ==============================

    5.Charles에 의해 허용 된 답변을 기반으로, 여기에 기능 향상 (및 크로스 플랫폼) 버전 (Python 2.7 및 3.5+)이 추가되었습니다.

    Charles에 의해 허용 된 답변을 기반으로, 여기에 기능 향상 (및 크로스 플랫폼) 버전 (Python 2.7 및 3.5+)이 추가되었습니다.

    import os
    import struct
    import sys
    
    if sys.platform == "win32":
        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
    
    # These are defined in win32\lib\winnt.py, but with wrong values
    IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003  # Junction
    IO_REPARSE_TAG_SYMLINK = 0xA000000C
    
    def islink(path):
        """
        Cross-platform islink implementation.
    
        Supports Windows NT symbolic links and reparse points.
    
        """
        if sys.platform != "win32" or sys.getwindowsversion()[0] < 6:
            return os.path.islink(path)
        return bool(os.path.exists(path) and GetFileAttributes(path) &
                    FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT)
    
    
    def parse_reparse_buffer(buf):
        """ 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;
    
        """
        # See https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntifs/ns-ntifs-_reparse_data_buffer
    
        data = {'tag': struct.unpack('<I', buf[:4])[0],
                'data_length': struct.unpack('<H', buf[4:6])[0],
                'reserved': struct.unpack('<H', buf[6:8])[0]}
        buf = buf[8:]
    
        if data['tag'] in (IO_REPARSE_TAG_MOUNT_POINT, IO_REPARSE_TAG_SYMLINK):
            keys = ['substitute_name_offset',
                    'substitute_name_length',
                    'print_name_offset',
                    'print_name_length']
            if data['tag'] == IO_REPARSE_TAG_SYMLINK:
                keys.append('flags')
    
            # Parsing
            for k in keys:
                if k == 'flags':
                    fmt, sz = '<I', 4
                else:
                    fmt, sz = '<H', 2
                data[k] = struct.unpack(fmt, buf[:sz])[0]
                buf = buf[sz:]
    
        # Using the offset and lengths grabbed, we'll set the buffer.
        data['buffer'] = buf
    
        return data
    
    
    def readlink(path):
        """
        Cross-platform implenentation of readlink.
    
        Supports Windows NT symbolic links and reparse points.
    
        """
        if sys.platform != "win32":
            return os.readlink(path)
    
        # This wouldn't return true if the file didn't exist
        if not islink(path):
            # Mimic POSIX error
            raise OSError(22, 'Invalid argument', path)
    
        # Open the file correctly depending on the string type.
        if type(path) is type(u''):
            createfilefn = CreateFileW
        else:
            createfilefn = CreateFile
        # FILE_FLAG_OPEN_REPARSE_POINT alone is not enough if 'path'
        # is a symbolic link to a directory or a NTFS junction.
        # We need to set FILE_FLAG_BACKUP_SEMANTICS as well.
        # See https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilea
        handle = createfilefn(path, GENERIC_READ, 0, None, OPEN_EXISTING,
                              FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0)
    
        # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16 * 1024)
        buf = 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 is bigger than 0)
        if len(buf) < 9:
            return type(path)()
        # Parse and return our result.
        result = parse_reparse_buffer(buf)
        if result['tag'] in (IO_REPARSE_TAG_MOUNT_POINT, IO_REPARSE_TAG_SYMLINK):
            offset = result['substitute_name_offset']
            ending = offset + result['substitute_name_length']
            rpath = result['buffer'][offset:ending].decode('UTF-16-LE')
        else:
            rpath = result['buffer']
        if len(rpath) > 4 and rpath[0:4] == '\\??\\':
            rpath = rpath[4:]
        return rpath
    
  6. from https://stackoverflow.com/questions/1143260/create-ntfs-junction-point-in-python by cc-by-sa and MIT license