On Windows, enumeration of hardlinks to any given file is facilitated by the FindFirstFileName, FindNextFileName, and FindClose trio. Fortunately, pywin32 wraps these for us in a single call:
import win32file
hardlinks = win32file.FindFileNames(r'path\as\string')
Less fortunately, FindFileNames()
only accepts string input and leaves a trailing null on each path returned (bug reported here). We can easily make up for this and return more helpful pathlib.Path
objects while we're at it:
import os
from pathlib import Path
from typing import Union, List
from win32file import FindFileNames
def enumerate_hardlinks(path: Union[bytes, str, Path]) -> List[Path]:
def strip_null(p):
return p[:-1] if p.endswith('\x00') else p
# Convert possible path representations to a string.
path = os.fsdecode(os.fspath(path))
return [Path(strip_null(n)) for n in FindFileNames(path)]
To verify output, you can also enumerate all hardlinks to a file using fsutil from both Windows CMD and PowerShell:
>fsutil hardlink list C:\Users\name\1st
\Users\name\1st
\Users\name\2nd
\Users\name\3rd
Where 1st
, 2nd
, & 3rd
are all hardlinks to the same file.
(Tested using Python 3.8 and pywin32 v227)