#!/usr/bin/perl # Allow us to copy files correctly. use File::Copy; # User-configurable. Don't include a / at the end of the path. # Source = Base directory to start the backup from # Dest = Base directory to backup to $Source = "/www"; $Dest = "/wwwbackups/current"; $Reverse = 0; if ($Reverse) { $Temp = $Source; $Source = $Dest; $Dest = $Temp; } # Global variable. Turn on Verbose Mode by using "mirror.pl -v" $Verbose = 0; # Define what you do not want copied over. It is case sensitive. # If you want a specific directory not copied, such as the "/logs/" # directory, use "^/logs/" to specify that directory. It uses a regexp # to see if the directory which is about to be copied should be excluded. # If you do not specify the ^ in front, such as the "/_themes/" directory, # it will exclude all _themes directories it comes across. # You can specify a file by using "^/dir/dir/file.txt" or all files with # a particular name by "/file.txt$" and making sure that $ is there so # it matches to end of line. #@Excludes = ("^/backup/", # "^/ftp/", # "^/Images/", # "^/logs/", # "^/publish/", # "^/recycled/", "^/RECYCLED/", # "^/recycler/", "^/RECYCLER/", # "/_borders/", "/_BORDERS", # "/_derived/", "/_DERIVED/", # "/_fpclass/", "/_FPCLASS/", # "/_overlay/", "/_OVERLAY/", # "/_private/", "/_PRIVATE/", # "/_themes/", "/_THEMES/", # "/_vti_bin/", "/_VTI_BIN/", # "/_vti_cnf/", "/_VTI_CNF/", # "/_vti_log/", "/_VTI_LOG/", # "/_vti_pvt/", "/_VTI_PVT/", # "/_vti_txt/", "/_VTI_TXT/"); #################################### # End of user-configurable section # #################################### if ($ARGV[0] eq "-v") { print "Verbose mode ON!\n"; $Verbose = 1; } PerformBackup("/"); # End of the main driver, proceed directly to functions. # Gets a listing of files. Returns the array. sub GetFiles { local ($Dir) = @_; local (@Files); opendir(DIR, $Dir); @Files = readdir(DIR); closedir(DIR); return @Files; } # Checks to see if the file/directory name passed in should be # excluded in the backup sub IsExcluded { local ($File) = @_; foreach (@Excludes) { if ($File =~ /$_/) { print "Excluding $File\n" if ($Verbose); return 1; } } return 0; } # Compares/copies files sub BackupFile { local ($File) = @_; # Only copy if newer or different sized from what I have if (-e "$Dest$File") { if (-M "$Source$File" >= -M "$Dest$File") { if (-s "$Source$File" == -s "$Dest$File") { return; } } } # Exclude files which can be excluded if (IsExcluded($File)) { return; } print " $File\n" if ($Verbose); copy("$Source$File", "$Dest$File"); } # Performs the backup on the specified directory, recursively calling # itself for each subdirectory which does not get excluded. sub PerformBackup { local ($Dir) = @_; local (@SFiles, @DFiles, @Dirs, $File); print "$Dir\n" if ($Verbose); # Get the file lists @SFiles = GetFiles("$Source$Dir"); @DFiles = GetFiles("$Dest$Dir"); # For each file, possibly copy. # For each directory, save list of directories for later. foreach (sort(@SFiles)) { # Ignore ".", "..", and hidden files next if (/^\./); $File = $_; # If it is a directory, save it for later. # Else, possibly copy now. if (-d "$Source$Dir$File") { push(@Dirs, $File); } else { BackupFile("$Dir$File"); } } # Process the directories foreach (sort(@Dirs)) { $File = "$Dir$_/"; next if (IsExcluded($File)); if (! -d "$Dest$File") { mkdir("$Dest$File", 0755); } PerformBackup("$File"); } }