Merge branch 'master' into squeeze
[debian/amanda] / ndmp-src / idx_dump.pl
diff --git a/ndmp-src/idx_dump.pl b/ndmp-src/idx_dump.pl
new file mode 100644 (file)
index 0000000..32b20ee
--- /dev/null
@@ -0,0 +1,293 @@
+#!/usr/bin/perl
+#
+#
+
+use strict;
+use Socket;
+use integer;
+
+my $prog = $0;
+$prog =~ s/^.*\/(\S+)$/$1/;
+
+my $debug = 0;
+my $do_dirs = 0;
+my $do_empty_dirs = 0;
+my $do_inode = 0;
+my $do_fhinfo = 0;
+
+
+#
+# parse switches
+#
+while ($ARGV[0] =~ /^-\S+/) {
+    if ($ARGV[0] eq "-d" || $ARGV[0] eq "-debug") {
+       $debug = 1;
+    } elsif ($ARGV[0] eq "-dirs") {
+       $do_dirs = 1;
+    } elsif ($ARGV[0] eq "-empty_dirs") {
+       $do_empty_dirs = 1;
+    } elsif ($ARGV[0] eq "-i") {
+       $do_inode = 1;
+    } elsif ($ARGV[0] eq "-fhinfo") {
+       $do_fhinfo = 1;
+    } else {
+       print STDERR "Unknown switch $ARGV[0]\n";
+       exit -1;
+    }
+    shift @ARGV;
+}
+if (@ARGV != 1) {
+    print STDERR "Usage: $prog [-d|-debug] [-dirs] [-i] [-fhinfo] <index file>\n";
+    exit 1;
+}
+
+#
+# parse index file
+#
+my $idxfile = $ARGV[0];
+open(IDXFILE, $idxfile) ||
+    die "$prog: can not open '$idxfile': $!";
+
+my $root_node = "";
+my %dir_inode;
+my %dir_entry_count;
+my %inode;
+my %first_ino_ref;
+
+sub find_path {
+    my ($i) = @_;
+
+    print "find_path called on $i\n" if $debug;
+
+    # check root
+    if ($i == $root_node) {
+       return "";
+    }
+
+    # find the inode of the directory that refers to this inode
+    if (!exists $first_ino_ref{$i}) {
+       print "find_path failed first_ino_ref on $i\n";
+       return "";
+    }
+    my $dir_i = $first_ino_ref{$i};
+
+    # find the directory entry that refers to this inode
+    my $ilist;
+    if (exists $dir_inode{$dir_i}) {
+       $ilist = $dir_inode{$dir_i};
+    } else {
+       print "find_path failed dir_inode for $dir_i on $i\n";
+       return "";
+    }
+
+    # search through the directory for the name entry
+    my $inode_entry_name = "";
+    foreach my $nam (keys %$ilist) {
+       if (($nam eq ".") || ($nam eq "..")) {
+           next;
+       }
+       if ($ilist->{$nam} == $i) {
+           # found entry
+           $inode_entry_name = $nam;
+           last;
+       }
+    }
+    print "find_path found name '$inode_entry_name' for $i\n" if $debug;
+
+    # get the path for the directory
+    if ($dir_i != $i) {
+       my $path = &find_path ($dir_i);
+       if ($path ne "") {
+           return "$path/$inode_entry_name";
+       }
+    }
+    return $inode_entry_name;
+}
+
+# Pass #1: get directory information
+while (<IDXFILE>) {
+    chomp;
+    # emacs sucks with perl
+    if (/^#/) {
+       next;
+    }
+    if (/^CM\s+/) {
+       next;
+    }
+    if (/^DE\s+(.+)\s*$/) {
+       print "Environment: $1\n" if $debug;
+       next;
+    }
+    if (/^DHr\s+(.+)\s*$/) {
+       if ($1 ne "") {
+           $root_node = $1;
+       }
+       next;
+    }
+    if (/^DHd\s+([0-9]+)\s+(\S+)\s+UNIX+\s+([0-9]+)\s*$/) {
+       # directory entry inode $1 has name $2 pointing to inode $3
+       print "$1 => $2 $3\n" if $debug;
+
+       my $ilist;
+       if (exists $dir_inode{$1}) {
+           $ilist = $dir_inode{$1};
+       } else {
+           $ilist = {};
+       }
+       $ilist->{$2} = $3;
+       $dir_inode{$1} = $ilist;
+
+       # if not "." or ".." then record the first reference to the inode
+       if (($2 eq ".") || ($2 eq "..")) {
+           next;
+       }
+
+       # count the directory entry
+       if (exists $dir_entry_count{$1}) {
+           $dir_entry_count{$1}++;
+       } else {
+           $dir_entry_count{$1} = 1;
+       }
+
+       if (!exists $first_ino_ref{$3}) {
+           $first_ino_ref{$3} = $1;
+       }
+
+
+       next;
+    }
+
+    if (/^DHn\s+([0-9]+)\s+UNIX\s+f([dc])\s+m(\S+)\s+u(\S+)\s+g(\S+)\s+tm(\S+)\s*$/) {
+       $inode{$1} = {
+           TYPE => $2,
+           MODE => $3,
+           UID => $4,
+           GID => $5,
+           MTIME => $6,
+           FHINFO => "0",
+       };
+       next;
+    }
+    if (/^DHn\s+([0-9]+)\s+UNIX\s+f([dc])\s+m(\S+)\s+u(\S+)\s+g(\S+)\s+tm(\S+)\s+@([-0-9]+)\s*$/) {
+       $inode{$1} = {
+           TYPE => $2,
+           MODE => $3,
+           UID => $4,
+           GID => $5,
+           MTIME => $6,
+           FHINFO => $7
+       };
+       next;
+    }
+    if (/^DHn\s+([0-9]+)\s+UNIX\s+f(\S+)\s+m(\S+)\s+u(\S+)\s+g(\S+)\s+s(\S+)\s+tm(\S+)\s*$/) {
+       $inode{$1} = {
+           TYPE => $2,
+           MODE => $3,
+           UID => $4,
+           GID => $5,
+           SIZE => $6,
+           MTIME => $7,
+           FHINFO => "0"
+       };
+       next;
+    }
+    if (/^DHn\s+([0-9]+)\s+UNIX\s+f(\S+)\s+m(\S+)\s+u(\S+)\s+g(\S+)\s+s(\S+)\s+tm(\S+)\s+@([-0-9]+)\s*$/) {
+       $inode{$1} = {
+           TYPE => $2,
+           MODE => $3,
+           UID => $4,
+           GID => $5,
+           SIZE => $6,
+           MTIME => $7,
+           FHINFO => $8
+       };
+       next;
+    }
+    print "Unknown keyword line: $_\n";
+}
+
+print "Root node: '$root_node'\n" if $debug;
+
+# rewind input
+seek (IDXFILE, 0, 0);
+
+# Pass 2: get file information including multiple names (hard links) for the
+#         same file
+
+
+my $last_path = "";
+my $last_inode = 0;
+while (<IDXFILE>) {
+    chomp;
+    # emacs sucks with perl
+    if (/^#/) {
+       next;
+    }
+    if (/^DHd\s+([0-9]+)\s+(\S+)\s+UNIX+\s+([0-9]+)\s*$/) {
+       # directory entry inode $1 has name $2 pointing to inode $3
+       print "$1 => $2 $3\n" if $debug;
+
+       if (($2 eq ".") || ($2 eq "..")) {
+           next;
+       }
+
+       # find the pathname for this directory
+       my $path;
+       if ($last_inode == $1) {
+           $path = $last_path;
+       } else {
+          $last_path = $path = &find_path ($1);
+          $last_inode = $1;
+       }
+
+
+       # see if it is a directory
+       if ($inode{$3}{TYPE} eq "d") {
+           if ($do_empty_dirs && !$do_dirs) {
+               if (exists $dir_entry_count{$3}) {
+                   next;
+               }
+           } elsif (!$do_dirs) {
+               # ignore directories
+               next;
+           }
+       }
+
+
+       # print out path name for this entry
+       my $full_path;
+       if ($path eq "") {
+           $full_path = "$2";
+       } else {
+           $full_path = "$path/$2";
+       }
+
+       # translate "=" into %3d".
+       $full_path =~ s/=/%3d/g;
+
+       if ($do_inode != 0 || $debug) {
+           if ($do_fhinfo) {
+               print "$inode{$3}{FHINFO} " . "$3" . ": $full_path\n";
+           } else {
+               print "$3" . ": $full_path\n";
+           }
+       } else {
+           if ($do_fhinfo) {
+               print "$inode{$3}{FHINFO} " . "$full_path\n";
+           } else {
+               print "$full_path\n";
+           }
+       }
+
+       next;
+    }
+}
+
+close(IDXFILE);
+
+
+#
+# all done
+#
+exit 0;
+