#!/usr/bin/perl use strict; use File::Find; use File::Spec; use vars qw( $VERSION ); $VERSION = 0.10; die "Usage: $0 source dest\n" unless $#ARGV == 1; # We have to store the times for the directories, and update them # after we've finished copying the directory contents. my @dir_times; my $source_path = shift @ARGV; my $destination_path = shift @ARGV; my $starting_directory = `pwd`; chomp $starting_directory; if (-d $source_path) { die "$destination_path must be a directory" if -e $destination_path && !-d $destination_path; find(\&wanted, $source_path); } else { if (-d $destination_path) { my $dest; my $dest_file = (File::Spec->splitpath( $source_path, 0 ))[2]; $destination_path = File::Spec->catfile($destination_path, $dest_file); copy_file_ex($source_path,$destination_path); } else { copy_file_ex($source_path,$destination_path); } } foreach my $time_info (@dir_times) { utime $time_info->{atime}, $time_info->{mtime}, $time_info->{dir}; } exit; # ------------------------------------------------------------------------ sub wanted { return if $_ eq File::Spec->updir() or $_ eq File::Spec->curdir(); my $filename = $_; my @source_dirs = File::Spec->splitdir($source_path); my @file_dirs = File::Spec->splitdir($File::Find::dir); while (defined $file_dirs[0] && $file_dirs[0] eq $source_dirs[0]) { shift @file_dirs, shift @source_dirs } my $relative_path; $relative_path = File::Spec->catdir(@file_dirs); my $dest; $dest = File::Spec->catdir($destination_path, $relative_path); $dest = File::Spec->catfile($dest, $filename); my $current_directory = `pwd`; chomp $current_directory; chdir $starting_directory; copy_file_ex($File::Find::name, $dest); chdir $current_directory; } # ------------------------------------------------------------------------ sub copy_file_ex { my ($src, $dest) = @_; #print qq{Copying "$src" to "$dest"\n}; my $srctime = (stat($src))[9]; my $srcmode = (stat($src))[2]; my $destmode; if (-e $dest) { $destmode = (stat($dest))[2]; chmod(0666, $dest); } else { # use dest file mode if avail, else use source file's mode $destmode = $srcmode; } my $src_directory = (File::Spec->splitpath( $src, 0 ))[1]; my $dest_directory = (File::Spec->splitpath( $dest, 0 ))[1]; my $directory_atime = (stat($src_directory))[8]; my $directory_mtime = (stat($src_directory))[9]; # Permissions are the low bits of the mode my $directory_perms = (stat($src_directory))[2] & 0777; if (!-e $dest_directory) { mkdir ( $dest_directory, $directory_perms ) or die("Couldn't create directory: $dest_directory: $!"); push @dir_times, {dir => $dest_directory, atime => $directory_atime, mtime => $directory_mtime}; } unless (-d $src) { my $old_mask = umask; umask(0000); if (-e $dest) { # Not foolproof, since the file may already exist. my $tempfile = "$dest.$$.tmp"; rename $dest,$tempfile; system qq{cp "$src" "$dest"}; unlink $tempfile; } else { system qq{cp "$src" "$dest"}; } utime $srctime, $srctime, $dest; chmod $destmode, $dest; umask($old_mask); } }