Imported Upstream version 3.3.3
[debian/amanda] / perl / Amanda / Recovery / Clerk.pm
index 7f193bc84d853bf8b2b0bec67f3784f139fb3f9e..c40d40f7de7d5e0b9e6d40f9fb38eaa75f5ea792 100644 (file)
@@ -1,8 +1,9 @@
-# Copyright (c) 2010 Zmanda, Inc.  All Rights Reserved.
+# Copyright (c) 2010-2012 Zmanda, Inc.  All Rights Reserved.
 #
-# This library is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License version 2.1 as
-# published by the Free Software Foundation.
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+#* License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
 #
 # This library is distributed in the hope that it will be useful, but
 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
@@ -69,7 +70,7 @@ Amanda::Recovery::Clerk - handle assembling dumpfiles from multiple parts
 
 =head1 OVERVIEW
 
-This package is the counterpart to L<Amanda::Recovery::Scribe>, and handles
+This package is the counterpart to L<Amanda::Taper::Scribe>, and handles
 re-assembling dumpfiles from multiple parts, possibly distributed over several
 volumes.
 
@@ -179,10 +180,10 @@ user-defined feedback object should inherit from
 C<Amanda::Recovery::Clerk::Feedback>, which implements no-op versions of all of
 the methods.
 
-The C<notif_part> method is called just before each part is restored, and is
+The C<clerk_notif_part> method is called just before each part is restored, and is
 given the label, filenum, and header.  Its return value, if any, is ignored.
-Similarly, C<notif_holding> is called for a holding-disk recovery and is given
-the holding filename and its header.  Note that C<notif_holding> is called
+Similarly, C<clerk_notif_holding> is called for a holding-disk recovery and is given
+the holding filename and its header.  Note that C<clerk_notif_holding> is called
 before the C<xfer_src_cb>, since data will begin flowing from a holding disk
 immediately when the transfer is started.
 
@@ -190,7 +191,7 @@ A typical Clerk feedback class might look like:
 
     use base 'Amanda::Recovery::Clerk::Feedback';
 
-    sub part_notif {
+    sub clerk_notif_part {
        my $self = shift;
        my ($label, $filenum, $hdr) = @_;
        print "restoring part ", $hdr->{'partnum'},
@@ -228,12 +229,12 @@ sub get_xfer_src {
     my $self = shift;
     my %params = @_;
 
-    for my $rq_param qw(dump xfer_src_cb) {
+    for my $rq_param (qw(dump xfer_src_cb)) {
        croak "required parameter '$rq_param' missing"
            unless exists $params{$rq_param};
     }
 
-    die "Clerk is already busy" if $self->{'xfer_state'};
+    confess "Clerk is already busy" if $self->{'xfer_state'};
 
     # set up a new xfer_state
     my $xfer_state = $self->{'xfer_state'} = {
@@ -262,13 +263,13 @@ sub start_recovery {
     my %params = @_;
 
     $self->dbg("starting recovery");
-    for my $rq_param qw(xfer recovery_cb) {
+    for my $rq_param (qw(xfer recovery_cb)) {
        croak "required parameter '$rq_param' missing"
            unless exists $params{$rq_param};
     }
 
-    die "no xfer is in progress" unless $self->{'xfer_state'};
-    die "get_xfer_src has not finished"
+    confess "no xfer is in progress" unless $self->{'xfer_state'};
+    confess "get_xfer_src has not finished"
        if defined $self->{'xfer_state'}->{'xfer_src_cb'};
 
     my $xfer_state = $self->{'xfer_state'};
@@ -300,18 +301,25 @@ sub handle_xmsg {
 sub quit {
     my $self = shift;
     my %params = @_;
+    my $finished_cb = $params{'finished_cb'};
 
-    die "Cannot quit a Clerk while a transfer is in progress"
-       if $self->{'xfer_state'};
+    confess "Cannot quit a Clerk while a transfer is in progress"
+       if $self->{'xfer_state'} and $self->{'xfer_state'}->{'xfer'};
 
-    # if we have a reservation, we need to release it; otherwise, we can
-    # just call finished_cb
-    if ($self->{'current_res'}) {
-       $self->{'current_dev'}->finish();
-       $self->{'current_res'}->release(finished_cb => $params{'finished_cb'});
-    } else {
-       $params{'finished_cb'}->();
-    }
+    my $steps = define_steps 
+       cb_ref => \$finished_cb,
+       finalize => sub { $self->{'scan'}->quit() if defined $self->{'scan'} };
+
+    step release => sub {
+       # if we have a reservation, we need to release it; otherwise, we can
+       # just call finished_cb
+       if ($self->{'current_res'}) {
+           $self->{'current_dev'}->finish();
+           $self->{'current_res'}->release(finished_cb => $finished_cb);
+       } else {
+           $finished_cb->();
+       }
+    };
 }
 
 sub _xmsg_ready {
@@ -333,7 +341,7 @@ sub _xmsg_part_done {
     my $next_label = $xfer_state->{'next_part'}->{'label'};
     my $next_filenum = $xfer_state->{'next_part'}->{'filenum'};
 
-    die "read incorrect filenum"
+    confess "read incorrect filenum"
        unless $next_filenum == $msg->{'fileno'};
     $self->dbg("done reading file $next_filenum on '$next_label'");
 
@@ -367,6 +375,7 @@ sub _xmsg_done {
     return $xfer_state->{'recovery_cb'}->(
        result => $result,
        errors => $xfer_state->{'errors'},
+       bytes_read => $xfer_state->{'xfer_src'}->get_bytes_read()
     );
 }
 
@@ -409,7 +418,7 @@ sub _maybe_start_part {
        # first, see if anything remains to be done
        if (!exists $xfer_state->{'dump'}{'parts'}[$xfer_state->{'next_part_idx'}]) {
            # this should not happen until the xfer is started..
-           die "xfer should be running already"
+           confess "xfer should be running already"
                unless $xfer_state->{'xfer'};
 
            # tell the source to generate EOF
@@ -551,7 +560,7 @@ sub _maybe_start_part {
 
        } else {
            # notify caller of the part
-           $self->{'feedback'}->notif_part($next_label, $next_filenum, $on_vol_hdr);
+           $self->{'feedback'}->clerk_notif_part($next_label, $next_filenum, $on_vol_hdr);
 
            # start the part
            $self->dbg("reading file $next_filenum on '$next_label'");
@@ -574,6 +583,9 @@ sub _maybe_start_part {
            return $steps->{'handle_error'}->();
        }
 
+       # remove CONT_FILENAME from the header, since it's not needed anymore
+       $on_disk_hdr->{'cont_filename'} = '';
+
        if (!$self->_header_expected($on_disk_hdr)) {
            # _header_expected already pushed an error message or two
            return $steps->{'handle_error'}->();
@@ -591,7 +603,7 @@ sub _maybe_start_part {
            $xfer_state->{'xfer_src_ready'} = 1;
 
            # notify caller of the part, *before* xfer_src_cb is called!
-           $self->{'feedback'}->notif_holding($next_filename, $on_disk_hdr);
+           $self->{'feedback'}->clerk_notif_holding($next_filename, $on_disk_hdr);
 
            $self->dbg("successfully located holding file for recovery");
            $cb->(undef, $on_disk_hdr, $xfer_state->{'xfer_src'}, 0);
@@ -622,6 +634,14 @@ sub _maybe_start_part {
     };
 }
 
+sub _zeropad {
+    my ($timestamp) = @_;
+    if (length($timestamp) == 8) {
+       return $timestamp."000000";
+    }
+    return $timestamp;
+}
+
 sub _header_expected {
     my $self = shift;
     my ($on_vol_hdr) = @_;
@@ -637,7 +657,10 @@ sub _header_expected {
        push @errs, "got disk '$on_vol_hdr->{disk}'; " .
                    "expected '$next_part->{dump}->{diskname}'";
     }
-    if ($on_vol_hdr->{'datestamp'} ne $next_part->{'dump'}->{'dump_timestamp'}) {
+    # zeropad the datestamps before comparing them, to avoid any compliations
+    # from usetimestamps=0
+    if (_zeropad($on_vol_hdr->{'datestamp'})
+       ne _zeropad($next_part->{'dump'}->{'dump_timestamp'})) {
        push @errs, "got datestamp '$on_vol_hdr->{datestamp}'; " .
                    "expected '$next_part->{dump}->{dump_timestamp}'";
     }
@@ -681,8 +704,8 @@ sub new {
     return bless {}, shift;
 }
 
-sub notif_part { }
+sub clerk_notif_part { }
 
-sub notif_holding { }
+sub clerk_notif_holding { }
 
 1;