def readlink(link): """ readlink(link) -> target Return a string representing the path to which the symbolic link points. """ handle = api.CreateFile( link, 0, 0, None, api.OPEN_EXISTING, api.FILE_FLAG_OPEN_REPARSE_POINT | api.FILE_FLAG_BACKUP_SEMANTICS, None, ) if handle == api.INVALID_HANDLE_VALUE: raise WindowsError() res = reparse.DeviceIoControl(handle, api.FSCTL_GET_REPARSE_POINT, None, 10240) bytes = create_string_buffer(res) p_rdb = cast(bytes, POINTER(api.REPARSE_DATA_BUFFER)) rdb = p_rdb.contents if not rdb.tag == api.IO_REPARSE_TAG_SYMLINK: raise RuntimeError("Expected IO_REPARSE_TAG_SYMLINK, but got %d" % rdb.tag) handle_nonzero_success(api.CloseHandle(handle)) return rdb.get_substitute_name()
def get_file_info(path): # open the file the same way CPython does in posixmodule.c desired_access = api.FILE_READ_ATTRIBUTES share_mode = 0 security_attributes = None creation_disposition = api.OPEN_EXISTING flags_and_attributes = (api.FILE_ATTRIBUTE_NORMAL | api.FILE_FLAG_BACKUP_SEMANTICS | api.FILE_FLAG_OPEN_REPARSE_POINT) template_file = None handle = api.CreateFile( path, desired_access, share_mode, security_attributes, creation_disposition, flags_and_attributes, template_file, ) if handle == api.INVALID_HANDLE_VALUE: raise WindowsError() info = api.BY_HANDLE_FILE_INFORMATION() res = api.GetFileInformationByHandle(handle, info) handle_nonzero_success(res) handle_nonzero_success(api.CloseHandle(handle)) return info
def get_symlink_target(link): """ get_symlink_target(link) -> target Return a string representing the path to which the symbolic link points. Similar to jaraco.windows.filesystem.readlink(link) except that opened file handle is closed properly, to prevent leak """ import jaraco.windows.api.filesystem as api import jaraco.windows.error as e from ctypes import (POINTER, cast, create_string_buffer) handle = api.CreateFile( link, 0, 0, None, api.OPEN_EXISTING, api.FILE_FLAG_OPEN_REPARSE_POINT | api.FILE_FLAG_BACKUP_SEMANTICS, None, ) if handle == api.INVALID_HANDLE_VALUE: raise WindowsError() res = api.DeviceIoControl(handle, api.FSCTL_GET_REPARSE_POINT, None, 10240) bytes = create_string_buffer(res) p_rdb = cast(bytes, POINTER(api.REPARSE_DATA_BUFFER)) rdb = p_rdb.contents e.handle_nonzero_success(api.CloseHandle(handle)) if not rdb.tag == api.IO_REPARSE_TAG_SYMLINK: raise RuntimeError("Expected IO_REPARSE_TAG_SYMLINK, but got %d" % rdb.tag) return rdb.get_print_name()
def get_final_path(path): r""" For a given path, determine the ultimate location of that path. Useful for resolving symlink targets. This functions wraps the GetFinalPathNameByHandle from the Windows SDK. Note, this function fails if a handle cannot be obtained (such as for C:\Pagefile.sys on a stock windows system). Consider using trace_symlink_target instead. """ desired_access = api.NULL share_mode = (api.FILE_SHARE_READ | api.FILE_SHARE_WRITE | api.FILE_SHARE_DELETE) security_attributes = api.LPSECURITY_ATTRIBUTES() # NULL pointer hFile = api.CreateFile( path, desired_access, share_mode, security_attributes, api.OPEN_EXISTING, api.FILE_FLAG_BACKUP_SEMANTICS, api.NULL, ) if hFile == api.INVALID_HANDLE_VALUE: raise WindowsError() buf_size = api.GetFinalPathNameByHandle(hFile, LPWSTR(), 0, api.VOLUME_NAME_DOS) handle_nonzero_success(buf_size) buf = create_unicode_buffer(buf_size) result_length = api.GetFinalPathNameByHandle(hFile, buf, len(buf), api.VOLUME_NAME_DOS) assert result_length < len(buf) handle_nonzero_success(result_length) handle_nonzero_success(api.CloseHandle(hFile)) return buf[:result_length]