def realpath(fpath): while islink(fpath): rpath = readlink(fpath) if rpath is None: return fpath if not os.path.isabs(rpath): rpath = os.path.abspath(os.path.join(os.path.dirname(fpath), rpath)) fpath = rpath return fpath
def realpath(fpath): while islink(fpath): rpath = readlink(fpath) if rpath is None: return fpath if not os.path.isabs(rpath): rpath = os.path.abspath( os.path.join(os.path.dirname(fpath), rpath)) fpath = rpath return fpath
def is_link_to(path, target): def normalize(path): return os.path.normcase(os.path.normpath(path)) return islink(path) and \ normalize(realpath(path)) == normalize(realpath(target))
def readlink(path): """ Windows readlink implementation. """ # This wouldn't return true if the file didn't exist, as far as I know. if not islink(path): if win32_verbose: print("readlink(%s): not a link." % path) return None # Open the file correctly depending on the string type. hfile = CreateFile(path, GENERIC_READ, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = DeviceIoControl(hfile, FSCTL_GET_REPARSE_POINT, None, 16384) CloseHandle(hfile) # Minimum possible length (assuming length of the target is bigger than 0) if not buffer or len(buffer) < 9: if win32_verbose: print("readlink(%s): no reparse buffer." % path) return None # Parse and return our result. # 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; # Only handle SymbolicLinkReparseBuffer (tag, dataLength, reserver, SubstituteNameOffset, SubstituteNameLength, PrintNameOffset, PrintNameLength, Flags) = struct.unpack(SymbolicLinkReparseFormat, buffer[:SymbolicLinkReparseSize]) # print tag, dataLength, reserver, SubstituteNameOffset, SubstituteNameLength start = SubstituteNameOffset + SymbolicLinkReparseSize actualPath = buffer[start:start + SubstituteNameLength].decode("utf-16") # This utf-16 string is null terminated index = actualPath.find("\0") if index > 0: actualPath = actualPath[:index] if actualPath.startswith("\\??\\"): # ASCII 92, 63, 63, 92 ret = actualPath[4:] # strip off leading junk else: ret = actualPath if win32_verbose: print("readlink(%s->%s->%s): index(null) = %d"%\ (path,repr(actualPath),repr(ret),index)) return ret
def readlink(path): """ Windows readlink implementation. """ # This wouldn't return true if the file didn't exist, as far as I know. if not islink(path): if win32_verbose: print("readlink(%s): not a link."%path) return None # Open the file correctly depending on the string type. hfile = CreateFile(path, GENERIC_READ, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT) # MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16384 = (16*1024) buffer = DeviceIoControl(hfile, FSCTL_GET_REPARSE_POINT, None, 16384) CloseHandle(hfile) # Minimum possible length (assuming length of the target is bigger than 0) if not buffer or len(buffer) < 9: if win32_verbose: print("readlink(%s): no reparse buffer."%path) return None # Parse and return our result. # 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; # Only handle SymbolicLinkReparseBuffer (tag, dataLength, reserver, SubstituteNameOffset, SubstituteNameLength, PrintNameOffset, PrintNameLength, Flags) = struct.unpack(SymbolicLinkReparseFormat, buffer[:SymbolicLinkReparseSize]) # print tag, dataLength, reserver, SubstituteNameOffset, SubstituteNameLength start = SubstituteNameOffset + SymbolicLinkReparseSize actualPath = buffer[start : start + SubstituteNameLength].decode("utf-16") # This utf-16 string is null terminated index = actualPath.find("\0") if index > 0: actualPath = actualPath[:index] if actualPath.startswith("\\??\\"): # ASCII 92, 63, 63, 92 ret = actualPath[4:] # strip off leading junk else: ret = actualPath if win32_verbose: print("readlink(%s->%s->%s): index(null) = %d"%\ (path,repr(actualPath),repr(ret),index)) return ret