#!/usr/bin/perl
#
#   cpdir [options] d1 d2
#   lndir [options] d1 d2
#
# This does a recursive copy or link from d1 to d2, preserving links and times.
#
# Options:
#   +b  Backup (Using Cp and Rm)
#   -b  No backup (Use cp and rm) [default]
#   +d  Debug messages
#   +m  Merge (Don't empty out target directories) [default]
#   -m  Don't merge (Empty out target directories before copying)
#   +n  Newer files replace older versions [default]
#   -n  Newness of files ignored; src files always copied
#   +v  Verbose messages (same as -d)
#
# By  default,  existing  files  under  d2  will   disappear   whenever   the
# corresponding  file  under d1 is copied; existing files under d2 that don't
# have a counterpart under d1 will be preserved.  This is  called  "merging",
# and  can  be defeated by the -m option, which will cause all existing files
# under d2 to disappear.
#

$st = 0;
$| = 1;
($op = $0) =~ s".*/"";
$op =~ s/dir$//i;
$op =~ s/-r$//i;
$cp = 'cp';
$rm = 'rm';
$rd = 'rm -rf';
$merge = 1;		# Merge directories by default.
$newer = 0;		# If true, newer file is always produced

for $a (@ARGV) {
	if (($opf,$opt) = ($a =~ /^([-+])(.*)/)) {
		if ($opt =~ /b/i) {
			$backup = ($opf eq '+');
			$cp = 'Cp';
			$rm = 'Rm';
		} 
		if ($opt =~ /[dv]/i) {
			if ($opt =~ /[dv](\d+)/i) {
				$dbg = $1;
			} else {
				$dbg = 1;
			}
		} 
		if ($opt =~ /m/i) {
			$merge = ($opf eq '+');
		} 
		if ($opt =~ /n/i) {
			$newer = ($opf eq '+');
		}
	} else {
		if (!$d1) {
			$d1 = $a;
		} elsif (!$d2) {
			$d2 = $a;
		} else {
			printf STDERR "$0: Arg \"$a\" ignored.\n";
		}
	}
}
die "Usage: $0 dir1 dir2\n" if (!d2);

&cpdir($d1,$d2);
exit $st;

sub cpdir {
	local($d1,$d2) = @_;
	local(@files,$f,$p1,$p2,$x);
	local($dev1,$ino1,$md1,$nl1,$uid1,$gid1,$rd1,$sz1,$at1,$mt1);
	local($dev2,$ino2,$md2,$nl2,$uid2,$gid2,$rd2,$sz2,$at2,$mt2);
	if (!opendir(D,$d1)) {
		print STDERR "$0: Can't read \"$d1\" [$!]\n";
		return 0;
	}
	system "$rm '$d2'" if (-f $d2 && $rm);
	system "$rd '$d2'" if (-d $d2 && $rd && !$merge);
	print  "mkdir -p '$d2'\n" if ($dbg && (!-d $d2));
	system "mkdir -p '$d2'" if (! -d $d2);
	@files = readdir(D);
	for $f (@files) {
		next if $f eq '.';
		next if $f eq '..';
		$p1 = "$d1/$f";
		$p2 = "$d2/$f";
		if ($backup && -e $p2) {
			system "$rm '$f2'";
		}
		if (-d $p1) {
			&cpdir($p1,$p2);
			next;
		}
		($dev1,$ino1,$md1,$nl1,$uid1,$gid1,$rd1,$sz1,$at1,$mt1) = stat($p1);
		($dev2,$ino2,$md2,$nl2,$uid2,$gid2,$rd2,$sz2,$at2,$mt2) = stat($p2);
		if ($newer && (-f $p2) && ($mt1 <= $mt2)) {
			print "Older $p1	-> $p2\n" if $dbg;
			next;
		}
		system "$rm '$p2'" if (-e $p2);
		if ($nl1 > 1) {
			if ($x = $ino{$dev1,$ino1}) {
				print  "link  $x	-> $p2\n" if $dbg;
				if (!link($x,$p2)) {
					printf STDERR "$0: Can't link(\"$x\",\"$p2\") [$!]\n";
				}
			} else {
				$ino{$dev1,$ino1} = $p2;
				print  "$op '$p1'	'$p2'\n" if $dbg;
				system "$op '$p1'	'$p2'";
			}
		} else {
			print  "$op '$p1'	'$p2'\n" if $dbg;
			system "$op '$p1'	'$p2'";
		}
	}
}
