Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I answered this in a <a href="https://stackoverflow.com/questions/1447575/symlinks-on-windows/7924557#7924557">similar question</a>, so I'll copy my answer to that below. Since writing that answer, I ended up writing a python-only (if you can call a module that uses ctypes python-only) module to creating, reading, and checking junctions which can be found in <a href="https://github.com/Juntalis/ntfslink-python/tree/master/ntfslink" rel="nofollow noreferrer">this folder</a>. Hope that helps.</p> <p>Also, unlike the answer that utilizes uses the <strong>CreateSymbolicLinkA</strong> API, the linked implementation should work on any Windows version that supports junctions. CreateSymbolicLinkA is only supported in Vista+.</p> <p><strong>Answer:</strong></p> <p><a href="https://github.com/juntalis/ntfslink-python" rel="nofollow noreferrer">python ntfslink extension</a></p> <p>Or if you want to use pywin32, you can use the previously stated method, and to read, use:</p> <pre><code>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) &amp; 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) &lt; 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) &gt; 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 &gt; 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() </code></pre> <p>Adjust the attributes in the CreateFile to your needs, but for a normal situation, it should work. Feel free to improve on it.</p> <p>It should also work for folder junctions if you use MOUNTPOINT instead of SYMBOLIC_LINK.</p> <p>You may way to check that</p> <pre><code>sys.getwindowsversion()[0] &gt;= 6 </code></pre> <p>if you put this into something you're releasing, since this form of symbolic link is only supported on Vista+.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload