2009-07-17 9 views

Trả lời

7

Tôi đã trả lời câu hỏi này theo số similar question, vì vậy tôi sẽ sao chép câu trả lời của mình vào câu hỏi dưới đây. Kể từ khi viết câu trả lời đó, tôi đã kết thúc bằng cách viết một con trăn chỉ (nếu bạn có thể gọi một mô-đun sử dụng mô-đun chỉ python) để tạo, đọc và kiểm tra các nút có thể được tìm thấy trong this folder. Hy vọng rằng sẽ giúp.

Ngoài ra, không giống như câu trả lời sử dụng API CreateSymbolicLinkA, triển khai được liên kết sẽ hoạt động trên bất kỳ phiên bản Windows nào hỗ trợ nút giao. CreateSymbolicLinkA chỉ được hỗ trợ trong Vista +.

Trả lời:

python ntfslink extension

Hoặc nếu bạn muốn sử dụng PyWin32, bạn có thể sử dụng phương pháp đã nêu trước đây, và để đọc, sử dụng:

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() 

Điều chỉnh các thuộc tính trong CreateFile theo nhu cầu của bạn, nhưng đối với một tình huống bình thường, nó sẽ hoạt động. Cảm thấy tự do để cải thiện nó.

Nó cũng sẽ hoạt động đối với các liên kết thư mục nếu bạn sử dụng MOUNTPOINT thay vì SYMBOLIC_LINK.

Bạn có thể cách để kiểm tra xem

sys.getwindowsversion()[0] >= 6 

nếu bạn đặt này vào một cái gì đó bạn đang phát hành, kể từ khi hình thức liên kết tượng trưng chỉ được hỗ trợ trên Vista +.

+1

Lưu ý rằng tiện ích mở rộng ntfslink hiện bị hỏng theo Python3 – CharlesB

+0

Xem câu trả lời của tôi bên dưới cho Python> = 3.5 – CharlesB

0

Bạn không muốn dựa vào các công cụ bên ngoài nhưng bạn không ngại dựa vào môi trường cụ thể? Tôi nghĩ rằng bạn có thể giả định một cách an toàn rằng, nếu đó là NTFS bạn đang chạy trên, tiện ích giao lộ có thể sẽ ở đó.

Nhưng, nếu bạn muốn nói rằng bạn không muốn gọi ra một chương trình bên ngoài, tôi đã tìm thấy công cụ ctypes là vô giá. Nó cho phép bạn gọi Windows DLL trực tiếp từ Python. Và tôi khá chắc chắn nó trong bản phát hành Python chuẩn ngày nay.

Bạn chỉ cần tìm ra Windows DLL nào CreateJunction() (hoặc bất kỳ Windows nào gọi nó) API gọi là trong và thiết lập các tham số và cuộc gọi. Tốt nhất của may mắn với điều đó, Microsoft dường như không hỗ trợ nó rất tốt. Bạn có thể tháo rời chương trình SysInternals junction hoặc linkd hoặc một trong các công cụ khác để tìm hiểu cách thực hiện.

Me, tôi khá lười biếng, tôi chỉ muốn gọi junction như một quá trình mở :-)

+0

ctypes được bao gồm trong Python từ 2,5 trở đi. –

+3

Lệnh nối không tồn tại trên Vista và Win7. Nó được thay thế bởi mklink. –

+0

Nó tồn tại như một công cụ Sysinternals Junction. – Nux

8

bạn có thể sử dụng python module win32 API ví dụ

import win32file 

win32file.CreateSymbolicLink(srcDir, targetDir, 1) 

thấy http://docs.activestate.com/activepython/2.5/pywin32/win32file__CreateSymbolicLink_meth.html để biết thêm chi tiết

nếu bạn không muốn dựa vào điều đó quá, bạn luôn có thể sử dụng ctypes và trực tiếp gọi CreateSymbolicLinl win32 API, mà là anyway một cuộc gọi đơn giản

đây được ví dụ cuộc gọi sử dụng ctypes

import ctypes 

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

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

MSDN nói tối thiểu hỗ trợ khách hàng Windows Vista

012.
+2

Tôi nghĩ rằng các nút nối từ Win2K trở đi nhưng không chính thức (hoặc tốt) được hỗ trợ bởi MS, do sự khan hiếm tài liệu về cách thực hiện. Các liên kết tượng trưng mới trông tốt hơn rất nhiều, đặc biệt là kể từ khi bạn có thể làm chúng vào các tập tin và (tôi nghĩ) bây giờ họ có thể vượt qua các mạng. – paxdiablo

+1

có các nút giao là tập con của các liên kết tượng trưng –

+7

Các nút giao là _not_ một tập con của các liên kết tượng trưng. Các mối nối chỉ áp dụng cho các thư mục. Câu trả lời này là không chính xác và tạo ra một liên kết tượng trưng cho các tệp (chỉ hoạt động trên Vista trở lên) chứ không phải là một đường nối cho các thư mục (hoạt động trên NTFS trong Windows 2000) trở lên. Thật không may, không có cách thực sự dễ dàng để làm điều này trong Python. –

4

Vì Python 3.5 có chức năng CreateJunction trong mô-đun _winapi.

import _winapi 
_winapi.CreateJunction(source, target)