When cleaning the cache of objects, don't be so verbose.
[cumulus.git] / restore.pl
index be94078..ad1f594 100755 (executable)
@@ -28,7 +28,7 @@ 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.
 #
@@ -140,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;
@@ -166,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);
         }
@@ -197,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"
@@ -272,13 +283,19 @@ sub process_file {
 
     my $uid = -1;
     my $gid = -1;
-    $uid = $info{user} + 0 if defined $info{user};
-    $gid = $info{group} + 0 if defined $info{group};
+    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";
     }
@@ -331,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) {
@@ -368,14 +385,36 @@ if (defined($ARGV[1])) {
 $OBJECT_DIR = dirname($descriptor);
 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 = <DESCRIPTOR>;
-if ($line !~ m/^Root: (\S+)$/) {
+my %descriptor = ();
+my ($line, $last_key);
+while (defined($line = <DESCRIPTOR>)) {
+    # 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