Usage: $0 link-dir
Hashes a NUL-separated list of files on stdin into link-dir.
-Version: 0.20100522
+Version: 0.20101024
USAGE
}
}
# Garbage collection
-print STDERR "\nGarbage collection in '$link_dir'...";
+print STDERR "\nGarbage collection in '$link_dir'...\n";
chdir($link_dir) || die "chdir: $link_dir: $!";
-print STDERR "\nRemoving files with link count < 3 and temporary links...";
-system('find . -type f \( -links -3 -o -name ".*" \) -print0 | xargs -0rt rm -f') and die "system: exit status $?";
-print STDERR "\nRemoving empty directories...";
+
+my ($last_inode) = '';
+my @last_links;
+
+sub handle_gc_file {
+ my ($line) = @_;
+ my ($inode, $link) = ($line =~ /^(\S+) (.+)\0$/os);
+ $inode ||= '';
+ if ($inode ne $last_inode) {
+ my ($dev, $ino, $links) = ($last_inode =~ /^(\d+):(\d+):(\d+)$/os);
+ if (defined($links)) {
+ if ($links && $links == @last_links) {
+ print STDERR "rm -f @last_links\n";
+ for my $unlink (@last_links) {
+ unlink($unlink) or warn "unlink: $unlink: $!";
+ }
+ }
+ } else {
+ warn "Could not parse '$last_inode' in '$line'" unless $last_inode eq '';
+ }
+ @last_links = ();
+ }
+ $last_inode = $inode;
+ push(@last_links, $link);
+}
+
+print STDERR "Removing files contained entirely in '$link_dir'...\n";
+open(FIND, "find . -type f -printf '%D:%i:%n %p\\0' | sort -z --compress-program=gzip |") or die "open: find: $!";
+while (<FIND>) {
+ handle_gc_file($_);
+}
+handle_gc_file('');
+
+print STDERR "Removing empty directories...\n";
system("find . -type d -empty -print0 | xargs -0rt rmdir -p --ignore-fail-on-non-empty") and die "system: exit status $?";
-print STDERR "\nDone.\n";
+print STDERR "Done.\n";
exit(0);