MacOSX-File
view release on metacpan or search on metacpan
}
}
$opt_v and do_log("fixing directory attributes ...");
# sort must be this order for depth-first traversal
for my $k (sort {$b cmp $a} keys %Action){
$Action{$k} > 0 or next;
my ($size, $mtime) = unpack("N2", $Signature{$k});
my ($mode, $uid, $gid, $atime) = unpack("N4", $Attribs{$k});
S_ISDIR($mode) or next; # -d
my $spath = $Root{$k} . $k; $spath =~ s,^/+,/,o;
my $dpath = $Dst . $k;
unless ($opt_n){
copyattrib($spath, $dpath, $mode, $uid, $gid, $atime, $mtime);
$opt_v and do_log(sprintf "0%04o,%s,%s $dpath", ($mode & 07777),
(getpwuid($uid))[0],(getgrgid($gid))[0] );
}
}
if ($opt_r >= 2){
# these are to make DB operation fast enough
my $hashinfo = DB_File::HASHINFO->new;
$hashinfo->{nelem} = scalar keys %Action;
$hashinfo->{bsize} = 1024; # MAXPATHLEN
$hashinfo->{cachesize} = 4 * 1024 * 1024;
tie (my %db, 'DB_File', $Psync_DB, O_CREAT|O_RDWR, 0640, $hashinfo)
or die "$Psync_DB : $!";
$opt_v and do_log("Using $Dst/$Psync_DB to store extra attributes.");
my $count;
while ( my ($k, $v) = each %Action){
if ($v >= 0){
$db{$k} = $Attribs{$k};
$count++ % 10000 == 0 and do_log("$count items stored.");
}
}
untie %db;
move $Psync_DB, "$Dst/$Psync_DB" or die "Can't move $Psync_DB";
}
sub copyattrib{
my ($spath, $dpath, $mode, $uid, $gid, $atime, $mtime) = @_;
my $finfo = getfinfo($spath);
unless ($opt_r > 1){
chmod $mode & 07777, $dpath;
chown $uid, $gid, $dpath;
}
$finfo and $finfo->set($dpath);
utime $atime, $mtime, $dpath;
}
exit;
sub do_log{
print shift, "\n";
}
sub sig2txt{
return sprintf("0x%08x,0x%08x",unpack("N2",shift));
}
sub addsig{
my ($path, $mode,$uid,$gid,$size,$atime,$mtime, $action) = @_;
my $sig = pack("N2", (S_ISREG($mode) ? $size : 0), $mtime);
tied %Attribs or $Attribs{$path} = pack("N4", $mode, $uid, $gid, $atime);
if ($opt_v > 3 and $action > 0){
do_log qq(was: ) . sig2txt($Signature{$path});
do_log qq(now: ) . sig2txt($sig);
}
if ($Signature{$path} eq $sig){
$opt_f or $action = 0; # same file
}else{
$Signature{$path} = $sig; # different
}
$Action{$path} = $action;
$opt_v > 2 and
do_log(join("," => $Action{$path},
sprintf("0x%08x,0x%08x,0x%08x",
unpack("N2",$Signature{$path})),
$path));
}
# File::Find is too general purpose thus slow.
# we implement our own traversal routine
sub scantree {
my ($root, $path, $action) = @_;
if ($opt_v){
$ScanCount % 8192 == 0 and printf "\n%10d:", $ScanCount;
$ScanCount % 128 == 0 and print ".";
$ScanCount++;
}
if ($path =~ $IgnorePat){
addsig($path, 0, 0, 0, 0, 0, 0, $Del_Ignored);
return;
}
$action > 0 and $Root{$path} = $root;
my $fpath = $root . $path;
my ($dev, $mode, $nlink, $uid, $gid, $size, $atime, $mtime) =
(lstat($fpath))[0,2,3,4,5,7,8,9] or warn "can't stat $fpath";
addsig($path, $mode, $uid, $gid, $size, $atime, $mtime, $action);
if (-d _){
$dev != $Topdev and return;
opendir my $d, $fpath or warn "$fpath:$!";
# see ._* is avoided
my @f = grep !/^\.(?:\.?$|_)/o, readdir $d;
closedir $d;
for my $f (@f){
my $spath = "$path/$f";
if ($IgnoreFiles{$f}){
addsig($spath, $mode, $uid, $gid, $size, $mtime, $atime,
$Del_IgFiles) unless $f eq $Psync_DB;
}else{
scantree($root, $spath, $action);
}
}
}
}
sub help{
print <<"EOT";
psync [-c][-d][-n][-q|-v] source_items ... target_directory
psync -r[-c][-d][-n][-q|-v] source_directory target_directory
EOT
exit;
}
1;
__END__
=head1 NAME
psync -- update copy
=head1 SYNOPSIS
psync [-c][-d][-n][-q|-v] source_items ... target_directory
psync -r[-c][-d][-n][-q|-v] source_directory target_directory
=head1 TIGER
As of Mac OS X v10.4 (Tiger) L<rsync(1)> does support resorce fork
with -E option. You should also consider using it.
=head1 DESCRIPTION
psync does an update copy. It compares source directory and target
directory at first, then erases items that are nonexistent on source
directory if specified and finally copies everything on source directory.
Items with the same modification date and (data fork) size remain
untouched, saving time on operation.
Currently psync supports options below
=over 4
=item -r
Remote backup/restore mode. Ownership and permissions are
stored/retrieved via C<.psync.db>
If the source directory contains a file C<.psync.db>, psync
turns into remote restore mode. It uses .psync.db on source
directory to restore ownership and permissions.
If not, psync turns into remote backup mode. After the backup
it stores ownership and permissions to C<.psync.db>
As the name suggests, this option is imperative when the backup
directory is on remote volume such as AFP, NFS, and Samba.
=item -dI<n>
( run in 0.506 second using v1.01-cache-2.11-cpan-71847e10f99 )