Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 98 lines (86 sloc) 2.5 KB
#!/bin/zsh
emulate zsh
usage(){
print 'usage: '$0:t' [-n] [-v] [-y] <fs>'
print -C2 - -n -v -y "just print what would happen; don't change anything" 'verbose' "don't ask before each operation"
}
#unset dry
#unset verbose
#unset yesall
for ((;;)) do
case $1 in
-n)
dry=1 ;;
-v)
# doesn't do anything right now
verbose=1 ;;
-y)
yesall=1 ;;
-*)
usage
exit 2 ;;
*) break ;;
esac
shift
done
if (( # != 1 )); then
usage
exit 2
fi
cksums=$(mktemp)
# checksum all files
# xdev don't cross filesystems
# links1 skip hard linked files
find $1 -xdev -type f -links 1 -print0 | xargs -0 md5sum > $cksums
# TODO: find hard links as well, but only reflink from them, not to them
sum=0
phy(){
filefrag -v $1 | fgrep 'ext logical physical' -A1 | tail -1 | tr -s ' ' . | cut -d. -f4
}
# all the files that have a duplicate
dup5s=$(sort $cksums | uniq -w 32 -d)
for md5 in $(cut -c 1-32 <<< $dup5s); do
# list of files with this checksum
files=$(grep $md5 $cksums | cut -c 35-)
f=(${(f)files})
unset files
# position in filesystem of one file
phy=$(phy $f[1])
# 0 probably means it doesn't have extents (kept with metadata)
if (( phy > 0 )); then
# if all files have same position, then already deduped or hard links
doit=0
for file in $f[2,-1]; do
if (( $(phy $file) != $phy )); then
doit=1
break
fi
done
if (( doit == 0 )); then
continue
fi
# show list of files to be deduped
print
print -l $f
if [[ -n $yesall ]] || read -q '?dedup (y/n)? '; then
for file in $f[2,-1]; do
p=$(phy $file)
if (( p != $phy )); then
# double-check ; contents may have changed by now
if cmp $file $f[1]; then
(( sum += $(du -sk $file | cut -f1) ))
if [[ -z $dry ]]; then
# guaranteed to be on same filesystem (-xdev), so inode will not change
/bin/cp --reflink=always --sparse=auto $f[1] $file
else
print reflink $f[1] $file
fi
else
print FALSE POSITIVE $file $f[1]
fi
fi
done
fi
fi
done
print $sum kilobytes saved
Jump to Line
Something went wrong with that request. Please try again.