Release for 3.2.0. Changes since 3.2.0beta1:
[BackupPC.git] / lib / BackupPC / Xfer / RsyncFileIO.pm
index 044ee55..6cbefe1 100644 (file)
@@ -8,11 +8,25 @@
 #   Craig Barratt  <cbarratt@users.sourceforge.net>
 #
 # COPYRIGHT
-#   Copyright (C) 2002-2003  Craig Barratt
+#   Copyright (C) 2002-2009  Craig Barratt
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 #========================================================================
 #
-# Version 3.0.0, released 28 Jan 2007.
+# Version 3.2.0, released 31 Jul 2010.
 #
 # See http://backuppc.sourceforge.net.
 #
@@ -162,6 +176,12 @@ sub csumStart
                                      $defBlkSize, $fio->{checksumSeed},
                                      0, $attr->{compress}, 0,
                                      $fio->{protocol_version});
+        if ( $err ) {
+            $fio->log("Can't get rsync digests from $attr->{fullPath}"
+                    . " (err=$err, name=$f->{name})");
+            $fio->{stats}{errorCnt}++;
+            return -1;
+        }
         my($isCached, $isInvalid) = $d->isCached;
         if ( $fio->{logLevel} >= 5 ) {
             $fio->log("$attr->{fullPath} verify; cached = $isCached,"
@@ -436,6 +456,8 @@ sub attribSet
     my($fio, $f, $placeHolder) = @_;
     my($dir, $file);
 
+    return if ( $placeHolder && $fio->{phase} > 0 );
+
     if ( $f->{name} =~ m{(.*)/(.*)}s ) {
        $file = $2;
        $dir  = "$fio->{shareM}/" . $1;
@@ -447,10 +469,13 @@ sub attribSet
        $file = $f->{name};
     }
 
-    if ( !defined($fio->{attribLastDir}) || $fio->{attribLastDir} ne $dir ) {
+    if ( $dir ne ""
+            && (!defined($fio->{attribLastDir}) || $fio->{attribLastDir} ne $dir) ) {
         #
         # Flush any directories that don't match the first part
-        # of the new directory
+        # of the new directory.  Don't flush the top-level directory
+        # (ie: $dir eq "") since the "." might get sorted in the middle
+        # of other top-level directories or files.
         #
         foreach my $d ( keys(%{$fio->{attrib}}) ) {
             next if ( $d eq "" || "$dir/" =~ m{^\Q$d/} );
@@ -459,17 +484,29 @@ sub attribSet
        $fio->{attribLastDir} = $dir;
     }
     if ( !exists($fio->{attrib}{$dir}) ) {
+        $fio->log("attribSet: dir=$dir not found") if ( $fio->{logLevel} >= 4 );
         $fio->{attrib}{$dir} = BackupPC::Attrib->new({
                                     compress => $fio->{xfer}{compress},
                                });
-       my $path = $fio->{outDir} . $dir;
-        if ( -f $fio->{attrib}{$dir}->fileName($path)
-                    && !$fio->{attrib}{$dir}->read($path) ) {
-            $fio->log(sprintf("Unable to read attribute file %s",
+        my $dirM = $dir;
+       $dirM = $1 . "/" . $fio->{bpc}->fileNameMangle($2)
+                       if ( $dirM =~ m{(.*?)/(.*)}s );
+       my $path = $fio->{outDir} . $dirM;
+        if ( -f $fio->{attrib}{$dir}->fileName($path) ) {
+            if ( !$fio->{attrib}{$dir}->read($path) ) {
+                $fio->log(sprintf("Unable to read attribute file %s",
                            $fio->{attrib}{$dir}->fileName($path)));
+            } else {
+                $fio->log(sprintf("attribRead file %s",
+                           $fio->{attrib}{$dir}->fileName($path)))
+                                     if ( $fio->{logLevel} >= 4 );
+            }
         }
+    } else {
+        $fio->log("attribSet: dir=$dir exists") if ( $fio->{logLevel} >= 4 );
     }
-    $fio->log("attribSet(dir=$dir, file=$file)") if ( $fio->{logLevel} >= 4 );
+    $fio->log("attribSet(dir=$dir, file=$file, size=$f->{size}, placeholder=$placeHolder)")
+                        if ( $fio->{logLevel} >= 4 );
 
     my $mode = $f->{mode};
 
@@ -490,11 +527,6 @@ sub attribWrite
     my($fio, $d) = @_;
     my($poolWrite);
 
-    #
-    # Don't write attributes on 2nd phase - they're already
-    # taken care of during the first phase.
-    #
-    return if ( $fio->{phase} > 0 );
     if ( !defined($d) ) {
         #
         # flush all entries (in reverse order)
@@ -505,6 +537,7 @@ sub attribWrite
         return;
     }
     return if ( !defined($fio->{attrib}{$d}) );
+
     #
     # Set deleted files in the attributes.  Any file in the view
     # that doesn't have attributes is flagged as deleted for
@@ -541,7 +574,7 @@ sub attribWrite
                                }) if ( $fio->{logLevel} >= 2
                                       && $a->{type} == BPC_FTYPE_FILE );
                    }
-               } elsif ( !$fio->{full} ) {
+               } elsif ( $fio->{phase} == 0 && !$fio->{full} ) {
                    ##print("Delete file $f\n");
                    $fio->logFileAction("delete", {
                                %{$fio->{viewCache}{$d}{$f}},
@@ -559,7 +592,7 @@ sub attribWrite
            }
        }
     }
-    if ( $fio->{attrib}{$d}->fileCount ) {
+    if ( $fio->{attrib}{$d}->fileCount || $fio->{phase} > 0 ) {
         my $data = $fio->{attrib}{$d}->writeData;
        my $dirM = $d;
 
@@ -583,7 +616,10 @@ sub processClose
     my($exists, $digest, $outSize, $errs) = $poolWrite->close;
 
     $fileName =~ s{^/+}{};
-    $fio->log(@$errs) if ( defined($errs) && @$errs );
+    if ( defined($errs) && @$errs ) {
+        $fio->log(@$errs);
+        $fio->{stats}{errorCnt} += @$errs;
+    }
     if ( $doStats ) {
        $fio->{stats}{TotalFileCnt}++;
        $fio->{stats}{TotalFileSize} += $origSize;
@@ -625,7 +661,7 @@ sub makePath
     $fio->logFileAction("create", $f) if ( $fio->{logLevel} >= 1 );
     $fio->log("makePath($path, 0777)") if ( $fio->{logLevel} >= 5 );
     $path = $1 if ( $path =~ /(.*)/s );
-    File::Path::mkpath($path, 0, 0777) if ( !-d $path );
+    eval { File::Path::mkpath($path, 0, 0777) } if ( !-d $path );
     return $fio->attribSet($f) if ( -d $path );
     $fio->log("Can't create directory $path");
     $fio->{stats}{errorCnt}++;
@@ -1142,11 +1178,11 @@ sub fileDeltaRxDone
             if ( $phase > 0 ) {
                 $fio->log("$name: fatal error: md4 doesn't match on retry;"
                         . " file removed");
+                $fio->{stats}{errorCnt}++;
             } else {
                 $fio->log("$name: md4 doesn't match: will retry in phase 1;"
                         . " file removed");
             }
-            $fio->{stats}{errorCnt}++;
             if ( defined($fio->{rxOutFd}) ) {
                 $fio->{rxOutFd}->close;
                 unlink($fio->{rxOutFile});