Eryk Sun <eryk...@gmail.com> added the comment:
Sample implementation: import os import msvcrt import win32file def samefile(f1, f2): """Test whether two paths refer to the same file or directory.""" s1 = os.stat(f1) s2 = os.stat(f2) return _common_same_file(f1, f2, s1, s2) def sameopenfile(fd1, fd2): """Test whether two file descriptors refer to the same file.""" s1 = os.fstat(fd1) s2 = os.fstat(fd2) return _common_same_file(fd1, fd2, s1, s2) def _common_same_file(f1, f2, s1, s2): if s1.st_ino != s2.st_ino or s1.st_dev != s2.st_dev: return False # (st_dev, st_ino) may be insufficient on its own. Use the final # NT path of each file to refine the comparison. p = _get_final_nt_paths([f1, f2]) # The stat result is unreliable if the volume serial number (st_dev) # or file ID (st_ino) is 0. if 0 in (s1.st_dev, s1.st_ino): if None in p: return False return p[0] == p[1] # A volume shadow copy has the same volume serial number as the # base volume. In this case, the device names have to be compared. d = _get_device_names(p) if any('volumeshadowcopy' in n for n in d if n): return d[0] == d[1] return True def _get_final_nt_paths(files): result = [] nt_normal = 0x2 # VOLUME_NAME_NT | FILE_NAME_NORMALIZED nt_opened = 0xA # VOLUME_NAME_NT | FILE_NAME_OPENED for f in files: p = None if f is not None: try: p = _getfinalpathname(f, nt_normal) except OSError: try: p = _getfinalpathname(f, nt_opened) except OSError: pass result.append(p) return result def _get_device_names(paths): # Look for "\Device\{device name}[\]". result = [] for p in paths: d = None if p is not None: q = p.split('\\', 3) if len(q) > 2 and q[1].lower() == 'device' and q[2]: d = q[2].lower() result.append(d) return result def _getfinalpathname(p, flags=0): try: if isinstance(p, int): h = msvcrt.get_osfhandle(p) else: h = win32file.CreateFile(p, 0, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_BACKUP_SEMANTICS, None) return win32file.GetFinalPathNameByHandle(h, flags) except win32file.error as e: strerror = e.strerror.rstrip('\r\n .') raise OSError(0, strerror, p, e.winerror) from None ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue46763> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com