Break all hardlinks within a folder

hardlinkunix

I have a folder which contains a certain number of files which have hard links (in the same folder or somewhere else), and I want to de-hardlink these files, so they become independant, and changes to their contents won't affect any other file (their link count becomes 1).

Below, I give a solution which basically copies each hard link to another location, then move it back in place.

However this method seems rather crude and error-prone, so I'd like to know if there is some command which will de-hardlink a file for me.

Crude answer :

Find files which have hard links (Edit: To also find sockets etc. that have hardlinks, use find -not -type d -links +1) :

find      -type f -links +1 # files only
find -not -type d -links +1 # files, sockets etc.

A crude method to de-hardlink a file (copy it to another location, and move it back) :
Edit: As Celada said, it's best to do a cp -p below, to avoid loosing timestamps and permissions. Edit: Create a temporary directory and copy to a file under it, instead of overwriting a temp file, it minimizes the risk to overwrite some data, though the mv command is still risky (thanks @Tobu). Edit: Try to create the temporary directory in the same filesystem (@MikkoRantalainen).

# This is unhardlink.sh
set -e
for i in "$@"; do
  temp="$(mktemp -d -- "${i%/*}/hardlnk-XXXXXXXX")"
  [ -e "$temp" ] && cp -ip "$i" "$temp/tempcopy" && mv "$temp/tempcopy" "$i" && rmdir "$temp"
done

So, to un-hardlink all hard links (Edit: changed -type f to -not -type d, see above) :

find -not -type d -links +1 -print0 | xargs -0 unhardlink.sh

Best Answer

There is room for improvement in your script, for example adding a -p option to the cp command so that permissions and timestamps will be preserved across the unhardlink operation, and you could add some error handling so that the temp file is deleted in case of an error, but the basic idea of your solution is the only one that will work. To unhardlink a file you have to copy it and then move the copy back over the original name. There is no "less crude" solution, and this solution has race conditions in case another process is accessing the file at the same time.

Related Topic