#!/usr/bin/perl -w
#
# Copyright (c) 2005 - 2007 Miek Gieben; Mark J Hewitt
# See LICENSE for the license

use strict;

use Getopt::Long qw(:config no_ignore_case bundling);
use File::Basename;
use File::Path;
use File::Copy;
use File::Copy::Recursive qw(dircopy rcopy fcopy);
use Fcntl qw(:mode);

# common functions
my $prefix="/usr";
require "/usr/share/rdup/shared.pl" or die "** Require \`shared.pl' failed";

my $progName = basename $0;
my ($help, $version, $verbose, $attr, $remote, $from, $toDir, $strip);

$strip = 0;
GetOptions("h" => \$help,
        "V" => \$version,
        "a" => \$attr, # extended attr support
	"p=i" => \$strip, # strip i slashes
        "c" => \$remote,
        "v" => \$verbose);

usage() if $help;
version($progName) if $version;
die "** Need a directory to copy to" if $#ARGV < 0;
$toDir = $ARGV[0];
my $hostname = `hostname`; chomp $hostname;
my $attr_there = check_attr() if $attr;

my ($t, $bits, $uid, $gid, $psize, $fsize, $path);

if (exist($toDir) == 0) {
        mkpath($toDir) or die "** Cannot create `$toDir': $!";
} else {
        die "** `$toDir' is not a directory" unless -d _;
}

if ($remote) {
        while (($_ = <STDIN>)) {
                chomp;
                ($t, $bits, $uid, $gid, $psize, $fsize) = split(" ", $_, 6);
                _cp($toDir);
        }
} else {
        while (($_ = <STDIN>)) {
                chomp;
                ($t, $bits, $uid, $gid, $psize, $fsize, $path) = split(" ", $_, 7);
                _cp($toDir);
        }
}

sub _cp {
        my $dir = $_[0];
        my $dump = substr($t, 0, 1);
        my $type = substr($t, 1, 1);
	my $tpath;

        sanity_check($dump, $bits, $psize, $fsize, $uid, $gid);
        if ($remote) {
                $path = "";
                read STDIN, $path, $psize;
        }
	$tpath = strip_path($strip, $path);
	if ($tpath eq "") {
		warn "** Empty destination path, from $path";
		return;
	}
        print STDERR "$path\n" if $verbose;

        if ($dump eq '+') {        # add
                my $target = "$dir/$tpath";
                if ($type eq '-') {        # REG
                        if (exist($target) == 1) {      # We only have a suffix if the file exists
                                unlink $target or warn "** Cannot unlink: $target: $!";
                        }
                        if ($remote) {
                                open FILE, ">$target" or warn "** Cannot create: $target: $!";
                                if ($fsize != 0) {
                                        copyout($fsize, *FILE);
                                }
                                rchown($uid, $gid, $target);
                                chown_attr($attr_there, $uid, $gid, $target);
                                rchmod($bits, $target);
                                close FILE or warn "** Failed to close: $!";
                        } else {
                                copy($path, $target) or warn "** Copy failed: $! $path $target";
                                rchown($uid, $gid, $target);
                                chown_attr($attr_there, $uid, $gid, $target);
                                rchmod($bits, $target);
                        }
                } elsif ($type eq 'd') {        # DIR
                        exist($target);  # side effects Go!
                        if (-f _ || -l _) {      # Type of entiry has changed
                                unlink $target or warn "** Cannot unlink: $target: $!";
                        }
                        mkpath($target) unless -d _;
                        rchown($uid, $gid, $target);
                        chown_attr($attr_there, $uid, $gid, $target);
                        if ($> != 0 && $bits == 0) {
                                print STDERR "** Chmod $target to 700\n";
                                $bits = "0700";
                        }
                        rchmod($bits, $target);
                } elsif ($type eq 'l') {        # LNK; target id the content
                        if (exist($target)== 1) {
                                unlink $target or warn "** Cannot unlink: $target: $!";
                        }
                        if ($remote) {
                                my $linkTarget = "";
                                read STDIN, $linkTarget, $fsize;
                                symlink $linkTarget, $target or warn "** Cannot create link: $target -> $linkTarget: $!";
                        } else {
                                symlink(readlink($path), $target) or warn "** Cannot create link: $target -> $path: $!";
                        }
                        rchown($uid, $gid, $target);
                        chown_attr($attr_there, $uid, $gid, $target);
                }
        } else {        # Remove
                my $target = "$dir/$path";
                warn "** Not removing: $target";
        }
}

sub strip_path {
	my $s = $_[0];
        my $p = $_[1];

	if ($s < 0) {
		$s = 0;
	}

        my @path = split /\/+/, $p;
        my $r = join '/', @path[$s..$#path];
        return $r;
}

sub usage {
        print "$progName [OPTIONS] DEST\n\n";
        print "Copy files read from standard in to DEST\n";
        print "DEST is a directory\n\n";
        print "OPTIONS\n";
        print " -a      write extended attributes r_uid/r_gid with uid/gid\n";
        print " -c      process the file content also (rdup -c)\n";
        print " -P NUM  strip NUM slashes from the filenames\n";
        print " -v      print the files processed to standard error\n";
        print " -h      this help\n";
        print " -V      print version\n";
        exit 0;
}
