Subject: Re: undoing the side effects of tar

From: [email-masked] (Randal L. Schwartz)
Date: Wed, 1 Apr 1992 15:49:54 GMT

In article <[email-masked]>, tal@Warren (Tom Limoncelli) writes:
| I used tar to copy a very large (800meg) directory tree and now I have
| to undo some of the side effects of SunOS 4.1.1 tar.  Has anyone
| written Perl programs to do the following:
| 
| 1 -- Re-hole files.  Tar expands holes in files.  Yes, I know that gnu
| tar doesn't have this problem but gnu tar core dumped when I tried to
| copy this hierarchy for some reason.  Has anyone written a program that
| finds files that would be candidates for re-holeing?  If it did the
| re-holeing that'd be great to.

### untested code, but you'll get the idea...

#!/usr/bin/perl

{
	$where = tell(STDIN);
	last unless read(STDIN,$_,512);
	if (/[^\000]/) {
		seek(STDOUT,0,$where);
		print;
	}
	redo;
}

| 2 -- Find duplicate files and make them one hard-linked file.  Tar
| doesn't keep track of which inodes it's seen already so if two files
| are hard linked together the resulting output is to see both files
| twice.

Your tar is broken.  Get GNU tar.  But, more to the point, here's my
"linksame" (which *is* tested and frequently used by me).

################################################## snip snip
#!/usr/bin/perl

$| = 1;

require 'find.pl';

sub wanted {
	return unless -f $_;
	$len{-s _} .= "$name\n";
	# print "$name\n";
}

@ARGV = ('.') unless @ARGV;
&find(@ARGV);

sub numdown { $b <=> $a; }

for $len (sort numdown keys len) {
	@samelen = split(/\n/,$len{$len});
	while ($target = shift(samelen)) {
		next unless @samelen > 0;
		@t = lstat($target);
		print "$target (dev $t[0] inode $t[1] nlink $t[3] size $t[7])\n";
		for $cand (@samelen) {
			@c = lstat($cand);
			print "  $cand (dev $c[0] inode $c[1] nlink $c[3] size $c[7])\n";
			next if $t[0] != $c[0]; # different disk
			next if $t[1] == $c[1]; # same file
			print "  comparing...\n";
			# next if system "cmp -s $target $cand";
			next if &different($target,$cand);
			print "  saving $c[7] bytes..." if $c[3] < 2;
			print "  rm $cand; ln $target $cand\n";
			unlink($cand) || die "cannot unlink $cand ($!)";
			link($target,$cand) || die "cannot link $target $cand ($!)";
		}
	}
}

sub different {
	($different'LEFT,$different'RIGHT) = @_;
	package different;
	open(LEFT) || return 1; # different if cannot open
	open(RIGHT) || return 1; # ditto
	return 1 if -s LEFT != -s RIGHT; # quick check if different sizes
	while (read(LEFT,$l,32768)) {
		read(RIGHT,$r,32768);
		return 1 if $l ne $r;
	}
	0;
}
################################################## snip snip

print pack("V*",unpack("N*","tsuJona rehtreP ah lrekc   ,"))
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| [email-masked] ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Intel: putting the 'backward' in 'backward compatible'..."====/