#!/usr/bin/perl # # NAME # supplant - replace files with authoritative version. # # SYNOPSIS # supplant file... [dir]... # # DESCRIPTION # This program scans the named directories ("." by default) looking for # files named the same as the "file" in $ARGV[1]; if any are found, they # are replaced by the named file. The replacing is done via Lc, so: (1) ln # will be used if possible, and cp if ln fails; and (2) The old file will # be renamed to a backup copy. # # You must give at least one file. If you list more than one file, we will # do each of them in turn, searching all the listed directories for each # file, and doing a supplant for each. # # This program shows its actions via the messages: # ++++> file successful supplant. # ----> file didn't supplant (already linked). # Note that only "plain files" are noticed; directories are not supplanted. # # BUGS: # For different file systems, supplanting will always be done. We might # insert a check for this situation; doing it right will then require a # full compare of the files. # # STATUS: # 0 if at least one file supplanted; 1 if not. # # AUTHOR: # John Chambers # # PERMISSIONS: # You may use this program freely as long as you don't claim that you wrote # it, and you agree to pass it along to anyone else who asks for it. If you # come up with any useful additions, you might email me a copy. ($me = $0) =~ s".*/""; $V = $ENV{"V_$me"} || $ENV{"D_$me"} || 1; $| = 1; for $x (@ARGV) { # Run thru the args, building @file and @dir lists. if ( -d $x) { push @dir, $x unless -l $x; } elsif ( -f $x) { push @file, $x unless -l $x; } else { print STDERR "$0: \"$x\" does not exist.\n"; } } @dir = ('.') if !@dir; die "Usage: $0 file... [dir]...\n" if !@file; for $F (@file) { # Run thru the file names. ($f = $F) =~ s".*/""; # Remove directories from filename. if (($fdev,$fino,$fm,$fnl,$fu,$fg,$frd,$fsize) = stat($F)) { print "Supplanting $f in @dir ...\n"; for $d (@dir) { # Run thru the directory list recursively. &supplant($f,$d); } } else { print STDERR "$0: Can't stat \"$F\"\n"; } } exit ($files == 0); # Success if at least one file supplanted. sub supplant { local($f,$d) = @_; # printf STDERR "Dir : \"$d\"\n"; if (opendir(D,$d)) { local(@list) = grep(!/\.\.?$/, readdir(D)); # printf STDERR "Close \"$d\"\n"; closedir(D); $p = "$d/$f"; $p =~ s/^\.\///; if (-f $p) { # Only look at "files", not directories. # printf STDERR "File: \"$p\"\n"; if (($pdev,$pino,$pm,$pnl,$pu,$pg,$prd,$psize) = stat($p)) { if ($pdev == $fdev && $pino == $fino) { printf STDERR "----> \"$p\"\n"; } else { printf STDERR "++++> \"$p\"\n"; system "Lc '$F' '$d/$f'"; ++$files; } } else { printf STDERR "$0: Can't stat \"$f\"\n"; } } elsif (-l $p) { printf STDERR "(lnk) \"$p\"\n"; } elsif (-d $p) { printf STDERR "(dir) \"$p\"\n"; } for $x (@list) { # printf STDERR "Try : \"$d/$x\"\n"; next if ($x eq "." || $x eq ".."); if (-d "$d/$x") { # printf STDERR "Sub : \"$d/$x\"\n"; &supplant($f,"$d/$x") unless -l "$d/$x"; } } } else { printf STDERR "$0: Can't access \"$d\"\n"; } }