[PYTHON] 파이썬에서 NTFS 연결 지점 만들기
PYTHON파이썬에서 NTFS 연결 지점 만들기
파이썬에서 NTFS 연결 지점을 만드는 방법이 있습니까? 접합 유틸리티를 호출 할 수 있지만 외부 도구에 의존하지 않는 것이 좋습니다.
해결법
-
==============================
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.예를 들어 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.5부터는 _winapi 모듈에 CreateJunction 함수가 있습니다.
파이썬 3.5부터는 _winapi 모듈에 CreateJunction 함수가 있습니다.
import _winapi _winapi.CreateJunction(source, target)
-
==============================
4.외부 도구에 의존하고 싶지는 않지만 특정 환경에 의존하지 마십시오. NTFS가 실행 중이라면 접합 유틸리티가있을 것이라고 가정 할 수 있다고 생각합니다.
외부 도구에 의존하고 싶지는 않지만 특정 환경에 의존하지 마십시오. NTFS가 실행 중이라면 접합 유틸리티가있을 것이라고 가정 할 수 있다고 생각합니다.
하지만, 외부 프로그램을 부르는 것이 아니라면 ctypes 자료가 매우 귀중하다는 것을 알았습니다. Python에서 Windows DLL을 직접 호출 할 수 있습니다. 그리고 요즘에는 표준 파이썬 릴리스에 있다고 확신합니다.
CreateJunction () (또는 Windows가 호출하는 API) API 호출이 어느 Windows DLL인지 파악하고 매개 변수를 설정하고 호출해야합니다. Microsoft는이를 잘 지원하지 않는 것으로 보입니다. SysInternals junction 프로그램이나 linkd 또는 다른 도구 중 하나를 해체하여 어떻게 수행하는지 확인할 수 있습니다.
나, 나는 꽤 게으르다, 나는 단지 외부 프로세스로서 접합을 호출 할 것이다 :-)
-
==============================
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
from https://stackoverflow.com/questions/1143260/create-ntfs-junction-point-in-python by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] pycharm에서 Conda 환경 사용 (0) | 2018.11.17 |
---|---|
[PYTHON] 데코레이터 클래스와 데코레이터 함수의 차이점 (0) | 2018.11.17 |
[PYTHON] 함수 이름에서 변수 이름 앞에 *와 **는 무엇을 의미합니까? [복제] (0) | 2018.11.17 |
[PYTHON] 파이썬에서 유니 코드 이스케이프 시퀀스가있는 유니 코드 텍스트 [duplicate] (0) | 2018.11.17 |
[PYTHON] 한 목록을 다른 파이썬으로 매핑하는 방법은 무엇입니까? [복제] (0) | 2018.11.17 |