123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- #!/usr/bin/perl -w
- #
- # ./compare-dir-trees.pl /first/path /second/path
- #
- # returns 0 if both paths have the same elements.
- # an element is not the same as another element if it is a different kind of
- # object (link, directory, file).
- # a directory is not the same as another directory if it has different children.
- # a link is not the same as another link if the link data is different.
- # a normal file is not the same as another file if their contents differ.
- #
- # returns a non zero value if any of the above do not hold.
- my ($left, $right) = @ARGV;
- my $verbose = 0;
- sub debug {
- return unless $verbose;
- my ($debug) = @_;
- print STDERR $debug . "\n";
- }
- sub ensure_d {
- my ($dir) = @_;
- return 0 if -d $dir;
- debug "$dir does not exist!";
- exit -2;
- }
- sub compare_items {
- my ($l, $lf, $r, $rf) = @_;
- if ($lf eq $rf) {
- return ("$l/$lf", "$r/$rf");
- }
- debug "directory contents mismatch for $l - $r: $lf - $rf";
- exit 1;
- }
- sub compare_dirs {
- my ($l, $r) = @_;
- my ($l_fail, $r_fail) = (0, 0);
- $l_fail = 1 unless opendir(LEFT, $l);
- $r_fail = 1 unless opendir(RIGHT, $r);
- unless ($l_fail == $r_fail) {
- debug "$l-$l_fail did not match $r-$r_fail!";
- exit 1;
- }
- return if $l_fail;
- my (@llinks, @rlinks, @ldirs, @rdirs, @lfiles, @rfiles);
- {
- my @names = sort readdir(LEFT);
- foreach my $i (@names) {
- next if $i eq '.';
- next if $i eq '..';
- if (-l "$l/$i") {
- push @llinks, $i;
- } elsif (-d "$l/$i") {
- push @ldirs, $i;
- } else {
- push @lfiles, $i
- }
- }
- closedir LEFT;
- }
- {
- my @names = sort readdir(RIGHT);
- foreach my $i (@names) {
- next if $i eq '.';
- next if $i eq '..';
- if (-l "$r/$i") {
- push @rlinks, $i;
- } elsif (-d "$r/$i") {
- push @rdirs, $i;
- } else {
- push @rfiles, $i
- }
- }
- closedir RIGHT;
- }
- my ($lc, $rc) = (scalar @llinks, scalar @rlinks);
- unless ($lc == $rc) {
- debug "link count mismatch $l / $r";
- exit 1;
- }
- {
- for (my $i = 0; $i < $lc; ++$i) {
- my ($lfile, $rfile) = compare_items($l, $llinks[$i], $r, $rlinks[$i]);
- $llink = readlink $lfile;
- $rlink = readlink $rfile;
- if ($llink ne $rlink) {
- debug "$lfile($llink) does not match $rfile($rlink)";
- exit 1;
- }
- }
- }
- ($lc, $rc) = (scalar @lfiles, scalar @rfiles);
- unless ($lc == $rc) {
- debug "file count mismatch $l / $r";
- exit 1;
- }
- {
- for (my $i = 0; $i < $lc; ++$i) {
- my ($lfile, $rfile) = compare_items($l, $lfiles[$i], $r, $rfiles[$i]);
- system('cmp', '-s', $lfile, $rfile);
- if ($? == -1) {
- debug "failed to execute: $!";
- exit 1;
- }
- if ($? & 127) {
- debug "cmp died!";
- exit 1;
- }
- if ($? >> 8) {
- debug "$lfile does not match $rfile";
- exit 1;
- }
- }
- }
- ($lc, $rc) = (scalar @ldirs, scalar @rdirs);
- unless ($lc == $rc) {
- debug "dir count mismatch $l / $r";
- exit 1;
- }
- {
- for (my $i = 0; $i < $lc; ++$i) {
- my ($lfile, $rfile) = compare_items($l, $ldirs[$i], $r, $rdirs[$i]);
- compare_dirs($lfile, $rfile);
- }
- }
- }
- sub main {
- debug qq!Comparing: "$left" "$right"
- !;
- if ($left eq $right) {
- debug "paths are actually the same!";
- exit 0;
- }
- ensure_d($left);
- ensure_d($right);
- compare_dirs($left, $right);
- exit 0;
- }
- main();
|