3

Is there a quick way/function to enum all hardlinks of a file? Something that directly gives me the paths of all hardlinks to a given file? On windows if that matters any.

I know about os.stat("foo.txt").st_nlink and about os.path.samefile(path1, path2).

Using these I can probably bodge together something to enumerate all hardlinks of a given file. Welcome to implementation suggestions tho.

martixy
  • 784
  • 1
  • 10
  • 26

1 Answers1

4

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)

  • 1
    It seems that the bug has been resolved, `win32file.FindFileNames(r'path\as\string')` works seamlessly. – mmj Mar 11 '21 at 10:27