X-Git-Url: http://git.vrable.net/?a=blobdiff_plain;f=restore.pl;h=ad1f5949840fc1ef9caa20e7a4816d6b6fff1e36;hb=315e528bb31f6a1abfda0bd1e3c81d982d6ead44;hp=9ba3a067de89a853936f23fc1f8123e3fef3236d;hpb=7a8869315b6b7cfa35eaf38b4af6a6f41713024c;p=cumulus.git diff --git a/restore.pl b/restore.pl index 9ba3a06..ad1f594 100755 --- a/restore.pl +++ b/restore.pl @@ -25,8 +25,10 @@ my $OBJECT_DIR; # Where are the unpacked objects available? my $DEST_DIR = "."; # Where should restored files should be placed? my $RECURSION_LIMIT = 3; # Bound on recursive object references +my $VERBOSE = 0; # Set to 1 to enable debugging messages + ############################ CHECKSUM VERIFICATION ############################ -# A very simple later for verifying checksums. Checksums may be used on object +# A very simple layer for verifying checksums. Checksums may be used on object # references directly, and can also be used to verify entire reconstructed # files. # @@ -69,7 +71,7 @@ sub verifier_check { my $digester = $verifier->{DIGESTER}; my $newhash = $digester->hexdigest(); - if ($verifier->{HASH} ne $newhash) { + if ($VERBOSE && $verifier->{HASH} ne $newhash) { print STDERR "Verification failure: ", $newhash, " != ", $verifier->{HASH}, "\n"; } @@ -138,6 +140,15 @@ sub load_ref { # iterate_objects is a helper function used to iterate over the set of object # references that contain the file data for a regular file. +sub parse_int { + my $str = shift; + if ($str =~ /^0/) { + return oct($str); + } else { + return $str + 0; + } +} + sub uri_decode { my $str = shift; $str =~ s/%([0-9a-f]{2})/chr(hex($1))/ge; @@ -164,7 +175,7 @@ sub iterate_objects { next if $obj eq ""; if ($obj =~ /^@(\S+)$/) { my $indirect = load_ref($1); - iterate_objects($callback, $arg, $1, $recursion_level + 1); + iterate_objects($callback, $arg, $indirect, $recursion_level + 1); } else { &$callback($arg, $obj); } @@ -195,6 +206,8 @@ sub unpack_file { die "File $name is missing checksum or size"; } + $info{size} = parse_int($info{size}); + # Open the file to be recreated. The data will be written out by the call # to iterate_objects. open FILE, ">", "$DEST_DIR/$name" @@ -225,7 +238,7 @@ sub process_file { my $type = $info{type}; my $filename = uri_decode($info{name}); - print "process_file: $filename\n"; + print "$filename\n" if $VERBOSE; # Restore the specified file. How to do so depends upon the file type, so # dispatch based on that. @@ -264,18 +277,25 @@ sub process_file { # Restore mode, ownership, and any other metadata for the file. This is # split out from the code above since the code is the same regardless of # file type. - my $atime = $info{atime} || time(); my $mtime = $info{mtime} || time(); - utime $atime, $mtime, $dest - or warn "Unable to update atime/mtime for $dest"; - - my $uid = $info{user} || -1; - my $gid = $info{group} || -1; + utime time(), $mtime, $dest + or warn "Unable to update mtime for $dest"; + + my $uid = -1; + my $gid = -1; + if (defined $info{user}) { + my @items = split /\s/, $info{user}; + $uid = parse_int($items[0]) if exists $items[0]; + } + if (defined $info{group}) { + my @items = split /\s/, $info{group}; + $gid = parse_int($items[0]) if exists $items[0]; + } chown $uid, $gid, $dest or warn "Unable to change ownership for $dest"; if (defined $info{mode}) { - my $mode = $info{mode}; + my $mode = parse_int($info{mode}); chmod $mode, $dest or warn "Unable to change permissions for $dest"; } @@ -319,7 +339,7 @@ sub process_metadata { # Recursively handle indirect metadata blocks. if ($line =~ m/^@(\S+)$/) { - print "Indirect: $1\n"; + print "Indirect: $1\n" if $VERBOSE; my $indirect = load_ref($1); process_metadata($indirect, $recursion_level + 1); next; @@ -328,7 +348,7 @@ sub process_metadata { # Try to parse the data as "key: value" pairs of file metadata. Also # handle continuation lines, which start with whitespace and continue # the previous "key: value" pair. - if ($line =~ m/^(\w+):\s+(.*)\s*$/) { + if ($line =~ m/^(\w+):\s*(.*)$/) { $info{$1} = $2; $last_key = $1; } elsif ($line =~/^\s/ && defined $last_key) { @@ -363,16 +383,38 @@ if (defined($ARGV[1])) { } $OBJECT_DIR = dirname($descriptor); -print "Source directory: $OBJECT_DIR\n"; +print "Source directory: $OBJECT_DIR\n" if $VERBOSE; -# Read the snapshot descriptor to find the root object. +# Read the snapshot descriptor to find the root object. Parse it to get a set +# of key/value pairs. open DESCRIPTOR, "<", $descriptor or die "Cannot open backup descriptor file $descriptor: $!"; -my $line = ; -if ($line !~ m/^root: (\S+)$/) { - die "Expected 'root:' specification in backup descriptor file"; +my %descriptor = (); +my ($line, $last_key); +while (defined($line = )) { + # Any lines of the form "key: value" should be inserted into the + # %descriptor dictionary. Any continuation line (a line starting with + # whitespace) will append text to the previous key's value. Ignore other + # lines. + chomp $line; + + if ($line =~ m/^(\w+):\s*(.*)$/) { + $descriptor{$1} = $2; + $last_key = $1; + } elsif ($line =~/^\s/ && defined $last_key) { + $descriptor{$last_key} .= $line; + } else { + undef $last_key; + print STDERR "Ignoring line in backup descriptor: $line\n"; + } +} + +# A valid backup descriptor should at the very least specify the root metadata +# object. +if (!exists $descriptor{Root}) { + die "Expected 'Root:' specification in backup descriptor file"; } -my $root = $1; +my $root = $descriptor{Root}; close DESCRIPTOR; # Set the umask to something restrictive. As we unpack files, we'll originally @@ -382,6 +424,6 @@ close DESCRIPTOR; umask 077; # Start processing metadata stored in the root to recreate the files. -print "Root object: $root\n"; +print "Root object: $root\n" if $VERBOSE; my $contents = load_ref($root); process_metadata($contents);