2009-07-17 13 views

答えて

7

私はこれをsimilar questionで回答しました。その答えを以下にコピーします。その答えを書いて以来、私は、this folderにあるジャンクションを作成、読み込み、チェックするためにpython専用(ctypes python専用モジュールを呼び出すことができれば)のモジュールを作成しました。希望が役立ちます。

また、CreateSymbolicLinkA APIを使用する回答とは異なり、リンクされた実装は接合点をサポートするすべてのWindowsバージョンで動作するはずです。 CreateSymbolicLinkAはVista +でのみサポートされています。

回答:

python ntfslink extension

それとも、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 

いることを確認する方法。

+1

ntfslink拡張機能は現在Python3で壊れていることに注意してください。 – CharlesB

+0

Python> = 3.5 – CharlesB

0

外部ツールに頼りたくはありませんが、特定の環境に頼っても構いませんか?私はあなたが安全にそれを仮定することができると思う、それはあなたが実行しているNTFSの場合、接合ユーティリティがおそらくそこになります。

しかし、あなたが外部のプログラムに電話したくないという場合は、ctypesのものが非常に貴重であることがわかりました。 Pythonから直接Windows DLLを呼び出すことができます。そして、私はそれが現在の標準のPythonリリースにあることを確信しています。

CreateJunction()(またはWindowsが呼び出すもの)のAPI DLLがどのWindows DLLに入っているか把握して、パラメータと呼び出しを設定するだけです。 Microsoftはこれをうまくサポートしていないようです。 SysInternals junctionプログラムまたはlinkdまたは他のツールの1つを逆アセンブルして、その動作を調べることができます。

私は、私はかなり怠け者、私はちょうどあなたがモジュールなどのpythonのWin32 APIを使用することができます

+0

ctypesはPython 2.5以降に含まれています。 –

+3

VistaとWin7ではjunctionコマンドが存在しません。 mklinkに置き換えられました。 –

+0

Sysinternalsツールジャンクションとして存在します。 – Nux

8

:-)外部プロセスとしてjunctionを呼びたいですあなたもそれに依存したくない場合は

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

をサポートすると言うが使用されています
+2

私はジャンクションはWin2K以降であったと思いますが、 MSがサポートしています。新しいシンボリックリンクは、特にあなたがそれらをファイルにすることができ、ネットワークを横断できるようになって以来、はるかに優れています。 – paxdiablo

+1

yesジャンクションはシンボリックリンクのサブセットです –

+7

ジャンクションはシンボリックリンクのサブセットではありません。ジャンクションはディレクトリにのみ適用されます。この回答は間違っており、ディレクトリ(Windows 2000ではNTFSで動作)のジャンクションではなく、ファイルのシンボリックリンク(Vista以上でのみ動作します)を作成します。残念ながら、Pythonでこれを行う簡単な方法はありません。 –

4

_winapiモジュールには、CreateJunctionの機能があります。

import _winapi 
_winapi.CreateJunction(source, target) 
関連する問題