File-System Sync

=File System Synchronization=

Overview
Rather than a conventional backup I want to recursively replicate complete file-system branches onto my NAS. Then, upon further execution, only new or modified files need to be updated. The initial idea is for a quick and dirty Perl script. Thus it will run for any machine that has Perl installed (e.g. Windows or Linux, etc). Even if the script does not do exactly what you want in its current form, it is easily modifiable.

Requirements
You'll need a Perl 5 installation to run this script. Other than that there are no requirements (not even a LinkStation).

Usage
To run the script, enter the following: From Windows: perl sync.pl [-v][-e exclude_file][-s absolute_source]-d absolute_destination From Linux: sync.pl [-v][-e exclude_file][-s absolute_source]-d absolute_destination

Where: -v Specifies give verbose output (all excluded file-system items are listed).

-e Specifies the name of a file containing details of files to be excluded from the synchronization. If not specified all files will be synchronized. -s Specifies the name of the source path from which files will be copied. NOTE: must be an absolute path. If not specified the current directory is used. -d Specifies the name of the path to which files will be copied. NOTE: must be an absolute path.Files will only be copied if the do not exist or if they have a more recent modification time. Directories will be created as required.

Exclude File
This is a text file where each line specifies a regular expression pattern that, if matched, will exclude the file or directory from being synchronized. Comments may be included by placing a '#' character at the very start of a line.

A sample exclude file is shown below: \.log$ Picasa.ini$ desktop.ini$ pspbrwse.jbf$ ZbThumbnail.info$ Thumbs.db$ (^|[\/])te?mp([\/]|$)
 * 1) Exclude file for My Photos directory hierarchy for use with sync.pl
 * 2) Exclude files ending with '.log'.
 * 1) Exclude some windows files.
 * 1) Exclude 'temp' or 'tmp' directories and their contents.

Perl Script
The Perl script is detailed below: use warnings; use strict;
 * 1) !/usr/bin/perl

use Cwd     qw(abs_path); use File::Find qw(find); use File::Copy qw(copy); use Getopt::Long;

our $verbose; our @excludes;  # List of exclude patterns.

use Cmd 'abs_path'; our $SRC = abs_path'.'; our $DST; our $EXCL; GetOptions("v" => \$verbose,		 "e=s" => \$EXCL,		 "s=s" => \$SRC,		 "d=s" => \$DST);

print "Source <". $SRC. ">\n"; die "Usage: $0 [-v][-e exclude_file][-s source]-d destination" unless defined $DST;
 * 1) A destination is mandatory.

if (defined $EXCL) { print "Using exclude list: '$EXCL'.\n"; open(EXCL_FILE, "<$EXCL") or die "Could not open exclude list '$EXCL': $!"; while () { chomp; push(@excludes, $_) unless (m/^#/);  # Each line as an exclude. } close EXCL_FILE; }
 * 1) If an exclude file is define and exists read it.

chdir $SRC or die "Can't chdir to $SRC: $!";
 * 1) Start from the specified source.

unless (-d $DST) { mkdir($DST) or die "Can't mkdir $DST: $!"; }
 * 1) Ensure that the destination directory exists.

find { wanted => \&duplicate } => ".";
 * 1) Recurse through the file system below the source point.

sub duplicate { (my $name = $File::Find::name) =~ s!^\./!!;  # Correct name. return if $name eq "."; foreach (@excludes) { if ($name =~ m/$_/i) { print "Excluded: $name with $_\n" if $verbose; return; } } my (undef, undef, undef, undef, undef, undef, undef,	undef, $src_atime, $src_mtime) = stat("$SRC/$name"); if (-d) {    # Process a directory unless (-d "$DST/$name") { mkdir("$DST/$name") or die "Can't mkdir $DST/$name: $!"; utime $src_atime, $src_mtime, "$DST/$name"; print "Created: $DST/$name\n"; } } elsif (-f) { # Process a "normal" file. unless (-e "$DST/$name") { copy ("$SRC/$name", "$DST/$name") or die "Failed to copy file $SRC/$name to $DST/$name: $!"; utime $src_atime, $src_mtime, "$DST/$name"; print "Copied: $SRC/$name\n"; } else { my (undef, undef, undef, undef, undef, undef, undef,		undef, $dst_atime, $dst_mtime) = stat("$DST/$name"); if ($src_mtime > (${dst_mtime} + 1)) { copy ("$SRC/$name", "$DST/$name") or die "Failed to copy file $SRC/$name to $DST/$name: $!"; utime $src_atime, $src_mtime, "$DST/$name"; print "Updated: $SRC/$name\n"; } } } }
 * 1) Get source creation and modification times.

.