2009-07-17 7 views

Répondre

7

J'ai répondu à cela dans un similar question, donc je vais copier ma réponse ci-dessous. Depuis l'écriture de cette réponse, j'ai fini par écrire un module python seulement (si vous pouvez appeler un module qui utilise ctypes python seulement) pour créer, lire et vérifier les jonctions qui peuvent être trouvées dans this folder. J'espère que cela pourra aider.

De même, contrairement à la réponse qui utilise l'API CreateSymbolicLinkA, l'implémentation liée doit fonctionner sur n'importe quelle version de Windows prenant en charge les jonctions. CreateSymbolicLinkA est uniquement pris en charge dans Vista +.

Réponse:

python ntfslink extension

Ou si vous voulez utiliser pywin32, vous pouvez utiliser la méthode précédemment indiqué, et à lire, utilisez:

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

Adjust les attributs le CreateFile à vos besoins, mais pour une situation normale, cela devrait fonctionner. N'hésitez pas à améliorer cela.

Il devrait également fonctionner pour les jonctions de dossiers si vous utilisez MOUNTPOINT au lieu de SYMBOLIC_LINK.

Vous peut ainsi vérifier que

sys.getwindowsversion()[0] >= 6 

si vous mettez cela en quelque chose que vous libérer, car cette forme de lien symbolique est uniquement prise en charge sur Vista +.

+1

Notez que l'extension ntfslink est actuellement cassée sous Python3 – CharlesB

+0

Voir ma réponse ci-dessous pour Python> = 3.5 – CharlesB

0

Vous ne voulez pas compter sur des outils externes, mais cela ne vous dérange pas de dépendre de l'environnement spécifique? Je pense que vous pouvez sans risque supposer que, si c'est NTFS que vous exécutez, l'utilitaire de jonction sera probablement là. Mais, si vous voulez dire que vous préférez ne pas appeler à un programme externe, j'ai trouvé que les choses ctypes sont inestimables. Il vous permet d'appeler des DLL Windows directement depuis Python. Et je suis sûr que c'est dans les versions standard de Python de nos jours.

Vous devez juste savoir quelle DLL Windows est l'appel API CreateJunction() (ou quel que soit l'appel Windows) et configurer les paramètres et appeler. Bonne chance avec ça, Microsoft ne semble pas très bien le supporter. Vous pourrait désassembler le programme SysInternals junction ou linkd ou l'un des autres outils pour savoir comment ils le font.

Moi, je suis assez paresseux, je voudrais simplement appeler junction comme un processus externe :-)

+0

ctypes est inclus dans Python à partir de la version 2.5. –

+3

La commande de jonction n'existe pas sur Vista et Win7. Il a été remplacé par mklink. –

+0

Il existe sous la forme d'une jonction d'outil Sysinternals. – Nux

8

vous pouvez utiliser des modules API python win32 par exemple

import win32file 

win32file.CreateSymbolicLink(srcDir, targetDir, 1) 

voir http://docs.activestate.com/activepython/2.5/pywin32/win32file__CreateSymbolicLink_meth.html pour plus de détails

si vous ne voulez pas compter sur cela aussi, vous pouvez toujours utiliser ctypes et appelez directement CreateSymbolicLinl API win32, ce qui est quand même un simple appel

ici est appel à l'aide par exemple ctypes

import ctypes 

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

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

MSDN dit client pris en charge minimum Windows Vista

+2

Je pense que les jonctions étaient à partir de Win2K, mais pas officiellement (ou bien) soutenu par MS, compte tenu de la rareté des docs sur la façon de le faire. Les nouveaux liens symboliques semblent beaucoup mieux, d'autant plus que vous pouvez les faire vers des fichiers et (je pense) qu'ils peuvent maintenant traverser des réseaux. – paxdiablo

+1

oui les jonctions sont un sous-ensemble de liens symboliques –

+7

Les jonctions sont _not_ un sous-ensemble de liens symboliques. Les jonctions ne s'appliquent qu'aux répertoires. Cette réponse est incorrecte et crée un lien symbolique pour les fichiers (qui ne fonctionne que sur Vista et au-dessus) plutôt qu'une jonction pour les répertoires (qui fonctionne sur NTFS sous Windows 2000) et plus. Malheureusement, il n'y a pas vraiment de moyen facile de le faire en Python. –

4

Depuis Python 3.5, il y a une fonction CreateJunction dans le module _winapi.

import _winapi 
_winapi.CreateJunction(source, target) 
Questions connexes