2

I would like to know if it is possible identify whether a file (or link) is a hardlink or not, on Linux. For instance, If I created:

dd if=/dev/urandom bs=1024 count=10000 of=file_10MB conv=notrunc
ln file_10MB file_10MB_link1

I would like to create a check function, that could be used like this:

if is_hardlink("file_10MB_link1"):
    pass

How can I use Python to check if a file is a hardlink?

not2qubit
  • 14,531
  • 8
  • 95
  • 135
uilianries
  • 3,363
  • 15
  • 28

4 Answers4

9

I believe you're looking for "files which have a link count greater than 1"

for that you can use:

def more_than_one_link(filename):
    os.stat(filename).st_nlink > 1
anthony sottile
  • 61,815
  • 15
  • 148
  • 207
  • I think he wants a function that will be true for `file_10MB_link1` but false for `file_10MB`. Checking the link count won't do that, since they'll both return `st_nlink == 2` – Barmar Apr 17 '20 at 21:34
  • @Barmar there's no such thing -- they are the same inode – anthony sottile Apr 17 '20 at 21:35
  • I know, that's what I said in my answer. – Barmar Apr 17 '20 at 21:36
  • I appreciate your answers, but like @Barmar said, I need to identify a hardlink, not counting the nodes, otherwise, I'll need to check each file for every folder. Seems like there is no good option for that case, so I'll accept the code. Thanks a lot! – uilianries Apr 18 '20 at 00:54
  • 1
    Are you trying to find out if it's a hard link to a specific file? You can check the device and inode numbers to see if they're the same. – Barmar Apr 18 '20 at 01:12
  • I see, that's I'm looking for! – uilianries Apr 19 '20 at 00:57
3

No, it's not possible. There's nothing that distinguishes the original file from the hard link. They're just two names that refer to the same inode number, which represents the file contents.

You can use the code in Anthony Sottile's answer to tell if the file has multiple links to it, but you can't tell which is the original.

Barmar
  • 741,623
  • 53
  • 500
  • 612
2

The answer is that that it depends on the filesystem and (exact) OS you are using. For example, if you are using NTFS (although unlikely in a native Linux context) it allows for a wide range of NTFS specific features including hardlinks and junctions. So while in Windows they use link numbers for hardlinks, Linux OS use inodes.

You would need specific kernel drivers or a forensic OS to be able to read all those, as normal Linux are using only inodes, and would need to be counted and time-stamp analyzed to decide what is the original file vs. a later created hardlink(s).

As python can create both hardlinks and softlinks via:

os.link()    # Create a hard link
os.symlink() # Create a symbolic link

(TL;DR the long docs above) there should be a way for you to check the link type, although it may require quite a bit of disc processing (searching and comparing).

For the exact detection check the built-in os functions, explained in this answer.
[islink(), parse_reparse_buffer(), readlink()]

For all other details on how Windows are making links, please see the excellent web page about the Link Shell Extensions tool.

Either way, you could also use the ctypes python libraries for accessing the Windows API, but would require substantial coding. You may learn a lot more about this here.

not2qubit
  • 14,531
  • 8
  • 95
  • 135
2

TL;DR: here is how you do it:

import os
def are_hardlinked(f1, f2):
    if not (os.path.isfile(f1) and os.path.isfile(f2)):
        return False
    return os.path.samefile(f1, f2) or (os.stat(f1).st_ino == os.stat(f2).st_ino)

For linux, by definition, they are hardlinked if they point to the same inode, so comparing st_ino will do.

For windows, first decide what a window respective of a hardlink is ;), then go from there:)... However, it is possible for all reasonable definitions os.path.samefile(f1, f2) will cover you.

ntg
  • 12,950
  • 7
  • 74
  • 95
  • This is only comparing 2 files, so how would you determine and find the *other* file, if you only know one? – not2qubit May 02 '23 at 17:15