* Removed default paths from conf/config.pl so configure.pl will
authorcbarratt <cbarratt>
Sun, 3 Dec 2006 02:43:42 +0000 (02:43 +0000)
committercbarratt <cbarratt>
Sun, 3 Dec 2006 02:43:42 +0000 (02:43 +0000)
  determine the correct ones at install time.  Avoids problem of
  the config editor complaining about bad executable paths the
  first time you use it.

* Changed first byte of compressed files with rsync checksums appended
  to 0xd7 to allow correct protocol_version >= 27 md4 checksums to be
  written.  Old cached checksum files have a first byte 0xd6 and are
  now considered to be uncached.  They will be automatically updated
  as needed.

* BackupPC_tarPCCopy now handles all file types correctly.  Reported
  by George Avrunin.

* Fixes for rsync restore where hardlink is to file outside of the
  top-level restore directory.  Reported by George Avrunin, who helped
  with debugging.

* Fixes for checksum mismatch on restore for certain file sizes.
  Reported by George Avrunin and others.

ChangeLog
bin/BackupPC_tarCreate
bin/BackupPC_tarPCCopy
conf/config.pl
configure.pl
lib/BackupPC/CGI/EditConfig.pm
lib/BackupPC/FileZIO.pm
lib/BackupPC/Xfer/RsyncDigest.pm
lib/BackupPC/Xfer/RsyncFileIO.pm

index 7dccc15..366ba11 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 # Version __VERSION__, __RELEASEDATE__
 #------------------------------------------------------------------------
 
+* Removed default paths from conf/config.pl so configure.pl will
+  determine the correct ones at install time.  Avoids problem of
+  the config editor complaining about bad executable paths the
+  first time you use it.
+
+* Changed first byte of compressed files with rsync checksums appended
+  to 0xd7 to allow correct protocol_version >= 27 md4 checksums to be
+  written.  Old cached checksum files have a first byte 0xd6 and are
+  now considered to be uncached.  They will be automatically updated
+  as needed.
+
+* BackupPC_tarPCCopy now handles all file types correctly.  Reported
+  by George Avrunin.
+
+* Fixes for rsync restore where hardlink is to file outside of the
+  top-level restore directory.  Reported by George Avrunin, who helped
+  with debugging.
+
+* Fixes for checksum mismatch on restore for certain file sizes.
+  Reported by George Avrunin and others.
+
 * Fix for config.pl writing code to handle multi-line expressions.
   Reported by David Relson and others.
 
 * Fix for CGI editor when deleting hash entries whose keys are
-  non alphanumeric.  Report by David Relson.
+  non alphanumeric.  Report by David Relson and Aaron Ciarlotta.
+
+* Two fixes to configure.pl from Andreas Vögele.
 
 #------------------------------------------------------------------------
 # Version 3.0.0beta2, 18 Nov 2006
index e0fd0fb..45eb1cb 100755 (executable)
@@ -502,7 +502,7 @@ sub TarWriteFile
                $arg = "/" if ( $arg eq "." );
                $arg =~ s{^\./+}{/};
                $arg =~ s{/+$}{};
-               $done = 1 if ( $name eq $arg || $name =~ /^\Q$arg\// );
+               $done = 1 if ( $name eq $arg || $name =~ /^\Q$arg\// || $arg eq "" );
            }
        }
        if ( $done ) {
index c703528..53f3981 100755 (executable)
@@ -175,8 +175,7 @@ sub archiveFile
     my @s = stat($_);
 
     #
-    # We just handle directories and files; no symlinks or
-    # char/block special files.
+    # Default type - we'll update later if it is a symlink, hardlink etc
     #
     $hdr->{type}     = -d _ ? BPC_FTYPE_DIR
                      : -f _ ? BPC_FTYPE_FILE
@@ -230,8 +229,7 @@ sub archiveFile
                 }
             }
             $hdr->{compress} = $ClientBkupCompress;
-            if ( $hdr->{type} == BPC_FTYPE_FILE && $hdr->{nlink} > 1
-                    && $hdr->{name} =~ /^f/ ) {
+            if ( $hdr->{type} == BPC_FTYPE_FILE && $hdr->{name} =~ /^f/ ) {
                 (my $dir = $hdr->{fullPath}) =~ s{(.*)/.*}{$1};
                 if ( $ClientDir ne $dir ) {
                     $ClientDir = $dir;
@@ -247,8 +245,12 @@ sub archiveFile
                 my $name = $hdr->{name};
                 $name = $bpc->fileNameUnmangle($name) if ( $ClientBkupMangle );
                 my $attr = $ClientDirAttr->get($name);
-                $hdr->{realSize} = $attr->{size} if ( defined($attr) );
-                #print STDERR "$hdr->{fullPath} has real size $hdr->{realSize}\n";
+                if ( defined($attr) ) {
+                    $hdr->{type}     = $attr->{type};
+                    $hdr->{realSize} = $attr->{size}
+                                if ( $attr->{type} == BPC_FTYPE_FILE );
+                }
+                #print STDERR "$hdr->{fullPath} has type $hdr->{type} and real size $hdr->{realSize}\n";
             }
         }
     } else {
@@ -425,91 +427,97 @@ sub TarWriteFile
         $hdr->{name} .= "/" if ( $hdr->{name} !~ m{/$} );
         TarWriteFileInfo($fh, $hdr);
        $DirCnt++;
-    } elsif ( $hdr->{type} == BPC_FTYPE_FILE ) {
+    } elsif ( $hdr->{type} == BPC_FTYPE_FILE
+            || $hdr->{type} == BPC_FTYPE_HARDLINK
+            || $hdr->{type} == BPC_FTYPE_SYMLINK
+            || $hdr->{type} == BPC_FTYPE_CHARDEV
+            || $hdr->{type} == BPC_FTYPE_BLOCKDEV
+            || $hdr->{type} == BPC_FTYPE_FIFO
+            || $hdr->{type} == BPC_FTYPE_SOCKET ) {
         #
-        # Regular file: write the header and file
+        # Underlying file is a regular file: write the header and file
         #
         my($data, $dataMD5, $size, $linkName);
 
-        if ( $hdr->{type} == BPC_FTYPE_FILE && $hdr->{nlink} > 1 ) {
-            if ( defined($Inode2Path{$hdr->{inode}}) ) {
-                $linkName = $Inode2Path{$hdr->{inode}};
-                #print STDERR "Got cache hit for $linkName\n";
-            } else {
-                my $f = BackupPC::FileZIO->open($hdr->{fullPath}, 0,
-                                                $hdr->{compress});
-                if ( !defined($f) ) {
-                    print(STDERR "Unable to open file $hdr->{fullPath}\n");
-                    $ErrorCnt++;
-                    return;
-                }
+        if ( defined($Inode2Path{$hdr->{inode}}) ) {
+            $linkName = $Inode2Path{$hdr->{inode}};
+            #print STDERR "Got cache hit for $linkName\n";
+        } else {
+            my $f = BackupPC::FileZIO->open($hdr->{fullPath}, 0,
+                                            $hdr->{compress});
+            if ( !defined($f) ) {
+                print(STDERR "Unable to open file $hdr->{fullPath}\n");
+                $ErrorCnt++;
+                return;
+            }
+            #
+            # Try to find the hardlink it points to by computing
+            # the pool file digest.
+            #
+            $f->read(\$dataMD5, $BufSize);
+            if ( !defined($hdr->{realSize}) ) {
                 #
-                # Try to find the hardlink it points to by computing
-                # the pool file digest.
+                # Need to get the real size
                 #
-                $f->read(\$dataMD5, $BufSize);
-                if ( !defined($hdr->{realSize}) ) {
-                    #
-                    # Need to get the real size
-                    #
-                    $size = length($dataMD5);
-                    while ( $f->read(\$data, $BufSize) > 0 ) {
-                        $size += length($data);
-                    }
-                    $hdr->{realSize} = $size;
+                $size = length($dataMD5);
+                while ( $f->read(\$data, $BufSize) > 0 ) {
+                    $size += length($data);
                 }
-                $f->close();
-                my $md5 = Digest::MD5->new;
-                my $len = length($dataMD5);
-                $hdr->{realSize} = $len if ( $hdr->{type} != BPC_FTYPE_FILE );
-                if ( $hdr->{realSize} < 1048576
-                            && length($dataMD5) != $hdr->{realSize} ) {
-                    print(STDERR "File $hdr->{fullPath} has bad size"
-                                . " (expect $hdr->{realSize}, got $len)\n");
-                } else {
-                    my $digest = $bpc->Buffer2MD5($md5, $hdr->{realSize},
-                                                  \$dataMD5);
-                    my $path = $bpc->MD52Path($digest, $hdr->{compress});
-                    my $i = -1;
-
-                    # print(STDERR "Looking up $hdr->{fullPath} at $path\n");
-                    while ( 1 ) {
-                        my $testPath = $path;
-                        $testPath .= "_$i" if ( $i >= 0 );
-                        last if ( !-f $testPath );
-                        my $inode = (stat(_))[1];
-                        if ( $inode == $hdr->{inode} ) {
-                            #
-                            # Found it!  Just emit a tar hardlink
-                            #
-                            $testPath =~ s{\Q$TopDir\E}{..};
-                            $linkName = $testPath;
-                            last;
-                        }
-                        $i++;
+                $hdr->{realSize} = $size;
+            }
+            $f->close();
+            my $md5 = Digest::MD5->new;
+            my $len = length($dataMD5);
+            if ( $hdr->{realSize} < 1048576
+                        && length($dataMD5) != $hdr->{realSize} ) {
+                print(STDERR "File $hdr->{fullPath} has bad size"
+                            . " (expect $hdr->{realSize}, got $len)\n");
+            } else {
+                my $digest = $bpc->Buffer2MD5($md5, $hdr->{realSize},
+                                              \$dataMD5);
+                my $path = $bpc->MD52Path($digest, $hdr->{compress});
+                my $i = -1;
+
+                # print(STDERR "Looking up $hdr->{fullPath} at $path\n");
+                while ( 1 ) {
+                    my $testPath = $path;
+                    $testPath .= "_$i" if ( $i >= 0 );
+                    last if ( !-f $testPath );
+                    my $inode = (stat(_))[1];
+                    if ( $inode == $hdr->{inode} ) {
+                        #
+                        # Found it!  Just emit a tar hardlink
+                        #
+                        $testPath =~ s{\Q$TopDir\E}{..};
+                        $linkName = $testPath;
+                        last;
                     }
+                    $i++;
                 }
             }
-            if ( defined($linkName) ) {
-                $hdr->{type}     = BPC_FTYPE_HARDLINK;
-                $hdr->{linkname} = $linkName;
-                TarWriteFileInfo($fh, $hdr);
-                $HLinkCnt++;
-                #print STDERR "$hdr->{relPath} matches $testPath\n";
-                if ( !$opts{c} && $hdr->{nlink} > 2 ) {
-                    #
-                    # add it to the cache if there are more
-                    # than 2 links (pool + current file),
-                    # since there are more to go
-                    #
-                    $Inode2Path{$hdr->{inode}} = $linkName;
-                }
-                return;
+        }
+        if ( defined($linkName) ) {
+            $hdr->{type}     = BPC_FTYPE_HARDLINK;
+            $hdr->{linkname} = $linkName;
+            TarWriteFileInfo($fh, $hdr);
+            $HLinkCnt++;
+            #print STDERR "$hdr->{relPath} matches $testPath\n";
+            if ( !$opts{c} && $hdr->{nlink} > 2 ) {
+                #
+                # add it to the cache if there are more
+                # than 2 links (pool + current file),
+                # since there are more to go
+                #
+                $Inode2Path{$hdr->{inode}} = $linkName;
             }
-            $size = 0;
+            return;
+        }
+        $size = 0;
+        if ( $hdr->{nlink} > 1 ) {
             print STDERR "Can't find $hdr->{relPath} in pool, will copy file\n";
             $ErrorCnt++;
         }
+        $hdr->{type} = BPC_FTYPE_FILE;
 
         my $f = BackupPC::FileZIO->open($hdr->{fullPath}, 0, 0);
         if ( !defined($f) ) {
index 6caece2..9d0c276 100644 (file)
@@ -201,7 +201,7 @@ $Conf{MaxOldLogFiles} = 14;
 # Full path to the df command.  Security caution: normal users
 # should not allowed to write to this file or directory.
 #
-$Conf{DfPath} = '/bin/df';
+$Conf{DfPath} = '';
 
 #
 # Command to run df.  The following variables are substituted at run-time:
@@ -214,12 +214,11 @@ $Conf{DfCmd} = '$dfPath $topDir';
 #
 # Full path to various commands for archiving
 #
-
-$Conf{SplitPath} = '/usr/bin/split';
-$Conf{ParPath}   = '/usr/bin/par2';
-$Conf{CatPath}   = '/bin/cat';
-$Conf{GzipPath}  = '/bin/gzip';
-$Conf{Bzip2Path} = '/usr/bin/bzip2';
+$Conf{SplitPath} = '';
+$Conf{ParPath}   = '';
+$Conf{CatPath}   = '';
+$Conf{GzipPath}  = '';
+$Conf{Bzip2Path} = '';
 
 #
 # Maximum threshold for disk utilization on the __TOPDIR__ filesystem.
@@ -912,7 +911,7 @@ $Conf{SmbSharePasswd} = '';
 #
 # This setting only matters if $Conf{XferMethod} = 'smb'.
 #
-$Conf{SmbClientPath} = '/usr/bin/smbclient';
+$Conf{SmbClientPath} = '';
 
 #
 # Command to run smbclient for a full dump.
@@ -1091,12 +1090,12 @@ $Conf{TarClientRestoreCmd} = '$sshPath -q -x -l root $host'
 #
 # This setting only matters if $Conf{XferMethod} = 'tar'.
 #
-$Conf{TarClientPath} = '/bin/tar';
+$Conf{TarClientPath} = '';
 
 #
 # Path to rsync executable on the client
 #
-$Conf{RsyncClientPath} = '/bin/rsync';
+$Conf{RsyncClientPath} = '';
 
 #
 # Full command to run rsync on the client machine.  The following variables
@@ -1297,7 +1296,7 @@ $Conf{BackupPCdShareName} = '/';
 #
 # Path to backuppcd executable on the server
 #
-$Conf{BackupPCdPath} = '/usr/bin/backuppcd';
+$Conf{BackupPCdPath} = '';
 
 #
 # Full command to run backuppcd on the server to backup a given
@@ -1413,7 +1412,7 @@ $Conf{ArchiveClientCmd} = '$Installdir/bin/BackupPC_archiveHost'
 # Full path for ssh. Security caution: normal users should not
 # allowed to write to this file or directory.
 #
-$Conf{SshPath} = '/usr/bin/ssh';
+$Conf{SshPath} = '';
 
 #
 # Full path for nmblookup. Security caution: normal users should not
@@ -1422,7 +1421,7 @@ $Conf{SshPath} = '/usr/bin/ssh';
 # nmblookup is from the Samba distribution. nmblookup is used to get the
 # netbios name, necessary for DHCP hosts.
 #
-$Conf{NmbLookupPath} = '/usr/bin/nmblookup';
+$Conf{NmbLookupPath} = '';
 
 #
 # NmbLookup command.  Given an IP address, does an nmblookup on that
@@ -1482,7 +1481,7 @@ $Conf{FixedIPNetBiosNameCheck} = 0;
 #
 #     $Conf{PingPath} = '/bin/echo';
 #
-$Conf{PingPath} = '/bin/ping';
+$Conf{PingPath} = '';
 
 #
 # Ping command.  The following variables are substituted at run-time:
@@ -1699,7 +1698,7 @@ $Conf{ClientNameAlias} = undef;
 # Full path to the sendmail command.  Security caution: normal users
 # should not allowed to write to this file or directory.
 #
-$Conf{SendmailPath} = '/usr/sbin/sendmail';
+$Conf{SendmailPath} = '';
 
 #
 # Minimum period between consecutive emails to a single user.
index 5a03034..03317be 100755 (executable)
@@ -333,6 +333,8 @@ check the name and verify that this user is in the passwd file.
 
 EOF
         exit(1) if ( $opts{batch} );
+    } else {
+        last;
     }
 }
 
@@ -539,7 +541,7 @@ foreach my $dir ( qw(bin doc
 # Create CGI image directory
 #
 foreach my $dir ( ($Conf{CgiImageDir}) ) {
-    next if ( $dir eq "" || -d $dir );
+    next if ( $dir eq "" || -d "$DestDir$dir" );
     mkpath("$DestDir$dir", 0, 0755);
     if ( !-d "$DestDir$dir" || !my_chown($Uid, $Gid, "$DestDir$dir") ) {
         die("Failed to create or chown $DestDir$dir");
@@ -846,6 +848,8 @@ will need to do:
 
   - Verify that the CGI script BackupPC_Admin runs correctly.  You might
     need to change the permissions or group ownership of BackupPC_Admin.
+    If this is an upgrade and you are using mod_perl, you will need
+    to restart Apache.  Otherwise it will have stale code.
 
   - BackupPC should be ready to start.  Don't forget to run it
     as user $Conf{BackupPCUser}!  The installation also contains an
index f8f0add..351f429 100644 (file)
@@ -373,8 +373,8 @@ sub action
             #
             #print STDERR Dumper(\%In);
             foreach my $v ( keys(%In) ) {
-                next if ( $v !~ /^v_z_(\Q$var\E(_z_.*|$))/ );
-                delete($In{$v}) if ( !defined($In{"orig_z_$1"}) );
+                next if ( $v !~ /^v_zZ_(\Q$var\E(_zZ_.*|$))/ );
+                delete($In{$v}) if ( !defined($In{"orig_zZ_$1"}) );
             }
             delete($In{"vflds.$var"});
         }
@@ -572,8 +572,8 @@ EOF
            return false;
        }
        var allVars = {};
-       var varRE  = new RegExp("^v_z_(" + varName + ".*)");
-       var origRE = new RegExp("^orig_z_(" + varName + ".*)");
+       var varRE  = new RegExp("^v_zZ_(" + varName + ".*)");
+       var origRE = new RegExp("^orig_zZ_(" + varName + ".*)");
         for ( var i = 0 ; i < document.editForm.elements.length ; i++ ) {
            var e = document.editForm.elements[i];
            var re;
@@ -582,7 +582,7 @@ EOF
                    allVars[re[1]] = 0;
                }
                allVars[re[1]]++;
-               //debugMsg("found v_z_ match with " + re[1]);
+               //debugMsg("found v_zZ_ match with " + re[1]);
                //debugMsg("allVars[" + re[1] + "] = " + allVars[re[1]]);
            } else if ( (re = origRE.exec(e.name)) != null ) {
                if ( allVars[re[1]] == null ) {
@@ -600,7 +600,7 @@ EOF
            } else {
                 // copy the original variable values
                //debugMsg("setting " + v);
-               eval("document.editForm.v_z_" + v + ".value = document.editForm.orig_z_" + v + ".value");
+               eval("document.editForm.v_zZ_" + v + ".value = document.editForm.orig_zZ_" + v + ".value");
             }
        }
        if ( sameShape ) {
@@ -661,7 +661,7 @@ EOF
     if ( $In{deleteVar} ne "" && %$errors > 0 ) {
         my $matchAll = 1;
         foreach my $v ( keys(%$errors) ) {
-            if ( $v ne $In{deleteVar} && $v !~ /^\Q$In{deleteVar}_z_/ ) {
+            if ( $v ne $In{deleteVar} && $v !~ /^\Q$In{deleteVar}_zZ_/ ) {
                 $matchAll = 0;
                 last;
             }
@@ -848,7 +848,7 @@ EOF
     if ( defined($In{menu}) || $In{saveAction} eq "Save" ) {
         if ( $In{saveAction} eq "Save" && !$userHost ) {
             #
-            # Emit the new settings as orig_z_ parameters
+            # Emit the new settings as orig_zZ_ parameters
             #
             $doneParam = {};
             foreach my $param ( keys(%ConfigMeta) ) {
@@ -867,10 +867,10 @@ EOF
             }
         } else {
             #
-            # Just switching menus: copy all the orig_z_ input parameters
+            # Just switching menus: copy all the orig_zZ_ input parameters
             #
             foreach my $var ( keys(%In) ) {
-                next if ( $var !~ /^orig_z_/ );
+                next if ( $var !~ /^orig_zZ_/ );
                 my $val = decode_utf8($In{$var});
                 $contentHidden .= <<EOF;
 <input type="hidden" name="$var" value="${EscHTML($val)}">
@@ -920,7 +920,7 @@ sub fieldHiddenBuild
         $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
 
         for ( my $i = 0 ; $i < @$varValue ; $i++ ) {
-            $content .= fieldHiddenBuild($type->{child}, "${varName}_z_$i",
+            $content .= fieldHiddenBuild($type->{child}, "${varName}_zZ_$i",
                                          $varValue->[$i], $prefix);
         }
     } elsif ( $type->{type} eq "hash" || $type->{type} eq "horizHash" ) {
@@ -948,18 +948,18 @@ sub fieldHiddenBuild
 <input type="hidden" name="vflds.$varName" value="${EscHTML($fld)}">
 EOF
             }
-            $content .= fieldHiddenBuild($childType, "${varName}_z_$fld",
+            $content .= fieldHiddenBuild($childType, "${varName}_zZ_$fld",
                                          $varValue->{$fld}, $prefix);
         }
     } elsif ( $type->{type} eq "shortlist" ) {
        $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
        $varValue = join(", ", @$varValue);
         $content .= <<EOF;
-<input type="hidden" name="${prefix}_z_$varName" value="${EscHTML($varValue)}">
+<input type="hidden" name="${prefix}_zZ_$varName" value="${EscHTML($varValue)}">
 EOF
     } else {
         $content .= <<EOF;
-<input type="hidden" name="${prefix}_z_$varName" value="${EscHTML($varValue)}">
+<input type="hidden" name="${prefix}_zZ_$varName" value="${EscHTML($varValue)}">
 EOF
     }
     return $content;
@@ -990,9 +990,9 @@ sub fieldEditBuild
 EOF
        if ( defined($overrideVar) ) {
            my $override_checked = "";
-           if ( !$isError && $In{deleteVar}      =~ /^\Q${varName}_z_/
-                  || !$isError && $In{insertVar} =~ /^\Q${varName}\E(_z_|$)/
-                  || !$isError && $In{addVar}    =~ /^\Q${varName}\E(_z_|$)/ ) {
+           if ( !$isError && $In{deleteVar}      =~ /^\Q${varName}_zZ_/
+                  || !$isError && $In{insertVar} =~ /^\Q${varName}\E(_zZ_|$)/
+                  || !$isError && $In{addVar}    =~ /^\Q${varName}\E(_zZ_|$)/ ) {
                $overrideSet = 1;
            }
            if ( $overrideSet ) {
@@ -1009,7 +1009,7 @@ EOF
         $content .= "<td class=\"border\">\n";
         $varValue = [] if ( !defined($varValue) );
         $varValue = [$varValue] if ( ref($varValue) ne "ARRAY" );
-        if ( !$isError && $In{deleteVar} =~ /^\Q${varName}_z_\E(\d+)$/
+        if ( !$isError && $In{deleteVar} =~ /^\Q${varName}_zZ_\E(\d+)$/
                 && $1 < @$varValue ) {
             #
             # User deleted entry in this array
@@ -1017,7 +1017,7 @@ EOF
             splice(@$varValue, $1, 1) if ( @$varValue > 1 || $type->{emptyOk} );
             $In{deleteVar} = "";
         }
-        if ( !$isError && $In{insertVar} =~ /^\Q${varName}_z_\E(\d+)$/
+        if ( !$isError && $In{insertVar} =~ /^\Q${varName}_zZ_\E(\d+)$/
                 && $1 < @$varValue ) {
             #
             # User inserted entry in this array
@@ -1054,12 +1054,12 @@ EOF
                 if ( @$varValue > 1 || $type->{emptyOk} ) {
                     $content .= <<EOF;
 <td class="border">
-<input type="button" name="del_${varName}_z_$i" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
-    onClick="deleteSubmit('${varName}_z_$i')">
+<input type="button" name="del_${varName}_zZ_$i" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
+    onClick="deleteSubmit('${varName}_zZ_$i')">
 </td>
 EOF
                 }
-                $content .= fieldEditBuild($type->{child}, "${varName}_z_$i",
+                $content .= fieldEditBuild($type->{child}, "${varName}_zZ_$i",
                                   $varValue->[$i], $errors, $level + 1, undef,
                                   $isError, $onchangeSubmit,
                                   $overrideVar, $overrideSet);
@@ -1069,17 +1069,17 @@ EOF
             for ( my $i = 0 ; $i < @$varValue ; $i++ ) {
                 $content .= <<EOF;
 <tr><td class="border">
-<input type="button" name="ins_${varName}_z_$i" value="${EscHTML($Lang->{CfgEdit_Button_Insert})}"
-    onClick="insertSubmit('${varName}_z_$i')">
+<input type="button" name="ins_${varName}_zZ_$i" value="${EscHTML($Lang->{CfgEdit_Button_Insert})}"
+    onClick="insertSubmit('${varName}_zZ_$i')">
 EOF
                 if ( @$varValue > 1 || $type->{emptyOk} ) {
                     $content .= <<EOF;
-<input type="button" name="del_${varName}_z_$i" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
-    onClick="deleteSubmit('${varName}_z_$i')">
+<input type="button" name="del_${varName}_zZ_$i" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
+    onClick="deleteSubmit('${varName}_zZ_$i')">
 EOF
                 }
                 $content .= "</td>\n";
-                $content .= fieldEditBuild($type->{child}, "${varName}_z_$i",
+                $content .= fieldEditBuild($type->{child}, "${varName}_zZ_$i",
                                     $varValue->[$i], $errors, $level + 1, undef,
                                     $isError, $onchangeSubmit,
                                     $overrideVar, $overrideSet);
@@ -1099,8 +1099,8 @@ EOF
         $varValue = {} if ( ref($varValue) ne "HASH" );
 
         if ( !$isError && !$type->{noKeyEdit}
-                        && $In{deleteVar} !~ /^\Q${varName}_z_\E.*_z_/
-                        && $In{deleteVar} =~ /^\Q${varName}_z_\E(.*)$/ ) {
+                        && $In{deleteVar} !~ /^\Q${varName}_zZ_\E.*_zZ_/
+                        && $In{deleteVar} =~ /^\Q${varName}_zZ_\E(.*)$/ ) {
             #
             # User deleted entry in this hash
             #
@@ -1134,8 +1134,8 @@ EOF
             if ( !$type->{noKeyEdit}
                    && (keys(%$varValue) > 1 || $type->{emptyOk}) ) {
                 $content .= <<EOF;
-<input type="submit" name="del_${varName}_z_$fld" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
-        onClick="deleteSubmit('${varName}_z_$fld')">
+<input type="submit" name="del_${varName}_zZ_$fld" value="${EscHTML($Lang->{CfgEdit_Button_Delete})}"
+        onClick="deleteSubmit('${varName}_zZ_$fld')">
 EOF
             }
             if ( defined($type->{child}) ) {
@@ -1151,7 +1151,7 @@ EOF
 EOF
             }
             $content .= "</td>\n";
-            $content .= fieldEditBuild($childType, "${varName}_z_$fld",
+            $content .= fieldEditBuild($childType, "${varName}_zZ_$fld",
                             $varValue->{$fld}, $errors, $level + 1, undef,
                            $isError, $onchangeSubmit,
                            $overrideVar, $overrideSet);
@@ -1193,7 +1193,7 @@ EOF
 <input type="hidden" name="vflds.$varName" value="${EscHTML($fld)}">
 EOF
             }
-            $content .= fieldEditBuild($childType, "${varName}_z_$fld",
+            $content .= fieldEditBuild($childType, "${varName}_zZ_$fld",
                             $varValue->{$fld}, $errors, $level + 1, undef,
                            $isError, $onchangeSubmit,
                            $overrideVar, $overrideSet);
@@ -1206,7 +1206,7 @@ EOF
             # in %In, rather than the parsed values in $varValue.
             # This is so that the user's erroneous input is preserved.
             #
-            $varValue = $In{"v_z_$varName"} if ( defined($In{"v_z_$varName"}) );
+            $varValue = $In{"v_zZ_$varName"} if ( defined($In{"v_zZ_$varName"}) );
         }
         if ( defined($errors->{$varName}) ) {
             $content .= <<EOF;
@@ -1217,7 +1217,7 @@ EOF
        if ( defined($overrideVar) ) {
             $onChange .= "checkboxSet('$overrideVar');";
        } else {
-            $onChange .= "varChange('$overrideVar');";
+            $onChange .= "varChange('$varName');";
        }
         if ( $onchangeSubmit ) {
             $onChange .= "document.editForm.submit();";
@@ -1238,17 +1238,17 @@ EOF
            }
             my $textType = ($varName =~ /Passwd/) ? "password" : "text";
             $content .= <<EOF;
-<input type="$textType" class="editTextInput" name="v_z_$varName" size="$size" maxlength="256" value="${EscHTML($varValue)}"$onChange>
+<input type="$textType" class="editTextInput" name="v_zZ_$varName" size="$size" maxlength="256" value="${EscHTML($varValue)}"$onChange>
 EOF
         } elsif ( $type->{type} eq "boolean" ) {
             # checkbox
             my $checked = "checked" if ( $varValue );
             $content .= <<EOF;
-<input type="checkbox" name="v_z_$varName" $checked value="1"$onChange>
+<input type="checkbox" name="v_zZ_$varName" $checked value="1"$onChange>
 EOF
         } elsif ( $type->{type} eq "select" ) {
             $content .= <<EOF;
-<select name="v_z_$varName"$onChange>
+<select name="v_zZ_$varName"$onChange>
 EOF
             foreach my $option ( @{$type->{values}} ) {
                 my $sel = " selected" if ( $varValue eq $option );
@@ -1260,7 +1260,7 @@ EOF
            my $rowCnt = $varValue =~ tr/\n//;
            $rowCnt = 1 if ( $rowCnt < 1 );
             $content .= <<EOF;
-<textarea name="v_z_$varName" class="editTextArea" cols="$size" rows="$rowCnt"$onChange>${EscHTML($varValue)}</textarea>
+<textarea name="v_zZ_$varName" class="editTextArea" cols="$size" rows="$rowCnt"$onChange>${EscHTML($varValue)}</textarea>
 EOF
         }
         $content .= "</td>\n";
@@ -1286,7 +1286,7 @@ sub fieldErrorCheck
 
     if ( $type->{type} eq "list" ) {
         for ( my $i = 0 ; ; $i++ ) {
-            last if ( fieldErrorCheck($type->{child}, "${varName}_z_$i", $errors) );
+            last if ( fieldErrorCheck($type->{child}, "${varName}_zZ_$i", $errors) );
         }
     } elsif ( $type->{type} eq "hash" || $type->{type} eq "horizHash" ) {
         my(@order, $childType);
@@ -1305,31 +1305,31 @@ sub fieldErrorCheck
             } else {
                 $childType = $type->{childType};
             }
-            $ret ||= fieldErrorCheck($childType, "${varName}_z_$fld", $errors);
+            $ret ||= fieldErrorCheck($childType, "${varName}_zZ_$fld", $errors);
         }
         return $ret;
     } else {
-        $In{"v_z_$varName"} = "0" if ( $type->{type} eq "boolean"
-                                        && $In{"v_z_$varName"} eq "" );
+        $In{"v_zZ_$varName"} = "0" if ( $type->{type} eq "boolean"
+                                        && $In{"v_zZ_$varName"} eq "" );
 
-        return 1 if ( !exists($In{"v_z_$varName"}) );
+        return 1 if ( !exists($In{"v_zZ_$varName"}) );
 
-        (my $var = $varName) =~ s/_z_/./g;
+        (my $var = $varName) =~ s/_zZ_/./g;
 
         if ( $type->{type} eq "integer"
                 || $type->{type} eq "boolean" ) {
-            if ( $In{"v_z_$varName"} !~ /^-?\d+\s*$/s
-                           && $In{"v_z_$varName"} ne "" ) {
+            if ( $In{"v_zZ_$varName"} !~ /^-?\d+\s*$/s
+                           && $In{"v_zZ_$varName"} ne "" ) {
                 $errors->{$varName} = eval("qq{$Lang->{CfgEdit_Error__must_be_an_integer}}");
             }
         } elsif ( $type->{type} eq "float" ) {
-            if ( $In{"v_z_$varName"} !~ /^-?\d*(\.\d*)?\s*$/s
-                           && $In{"v_z_$varName"} ne "" ) {
+            if ( $In{"v_zZ_$varName"} !~ /^-?\d*(\.\d*)?\s*$/s
+                           && $In{"v_zZ_$varName"} ne "" ) {
                 $errors->{$varName}
                         = eval("qq{$Lang->{CfgEdit_Error__must_be_real_valued_number}}");
             }
         } elsif ( $type->{type} eq "shortlist" ) {
-           my @vals = split(/[,\s]+/, $In{"v_z_$varName"});
+           my @vals = split(/[,\s]+/, $In{"v_zZ_$varName"});
            for ( my $i = 0 ; $i < @vals ; $i++ ) {
                if ( $type->{child} eq "integer"
                        && $vals[$i] !~ /^-?\d+\s*$/s
@@ -1346,7 +1346,7 @@ sub fieldErrorCheck
         } elsif ( $type->{type} eq "select" ) {
             my $match = 0;
             foreach my $option ( @{$type->{values}} ) {
-                if ( $In{"v_z_$varName"} eq $option ) {
+                if ( $In{"v_zZ_$varName"} eq $option ) {
                     $match = 1;
                     last;
                 }
@@ -1354,7 +1354,7 @@ sub fieldErrorCheck
             $errors->{$varName} = eval("qq{$Lang->{CfgEdit_Error__must_be_valid_option}}")
                             if ( !$match );
         } elsif ( $type->{type} eq "execPath" ) {
-            if ( $In{"v_z_$varName"} ne "" && !-x $In{"v_z_$varName"} ) {
+            if ( $In{"v_zZ_$varName"} ne "" && !-x $In{"v_zZ_$varName"} ) {
                 $errors->{$varName} = eval("qq{$Lang->{CfgEdit_Error__must_be_executable_program}}");
             }
         } else {
@@ -1395,7 +1395,7 @@ sub fieldInputParse
         $$value = [];
         for ( my $i = 0 ; ; $i++ ) {
             my $val;
-            last if ( fieldInputParse($type->{child}, "${varName}_z_$i", \$val) );
+            last if ( fieldInputParse($type->{child}, "${varName}_zZ_$i", \$val) );
             push(@$$value, $val);
         }
         $$value = undef if ( $type->{undefIfEmpty} && @$$value == 0 );
@@ -1419,19 +1419,19 @@ sub fieldInputParse
             } else {
                 $childType = $type->{childType};
             }
-            $ret ||= fieldInputParse($childType, "${varName}_z_$fld", \$val);
+            $ret ||= fieldInputParse($childType, "${varName}_zZ_$fld", \$val);
             last if ( $ret );
             $$value->{$fld} = $val;
         }
         return $ret;
     } else {
         if ( $type->{type} eq "boolean" ) {
-            $$value = 0 + $In{"v_z_$varName"};
-        } elsif ( !exists($In{"v_z_$varName"}) ) {
+            $$value = 0 + $In{"v_zZ_$varName"};
+        } elsif ( !exists($In{"v_zZ_$varName"}) ) {
             return 1;
         }
 
-        my $v = $In{"v_z_$varName"};
+        my $v = $In{"v_zZ_$varName"};
 
         if ( $type->{type} eq "integer" ) {
             if ( $v =~ /^-?\d+\s*$/s || $v eq "" ) {
@@ -1464,7 +1464,7 @@ sub fieldInputParse
                 }
             }
         } else {
-            $$value = decode_utf8($In{"v_z_$varName"});
+            $$value = decode_utf8($In{"v_zZ_$varName"});
             $$value =~ s/\r\n/\n/g;
         }
         $$value = undef if ( $type->{undefIfEmpty} && $$value eq "" );
index c520725..ab30bae 100644 (file)
@@ -173,13 +173,13 @@ sub read
             my $chr = substr($self->{dataIn}, 0, 1);
 
             $self->{inflateStart} = 0;
-            if ( $chr eq chr(0xd6) ) {
+            if ( $chr eq chr(0xd6) || $chr eq chr(0xd7) ) {
                 #
-                # Flag 0xd6 means this is a compressed file with
+                # Flag 0xd6 or 0xd7 means this is a compressed file with
                 # appended md4 block checksums for rsync.  Change
                 # the first byte back to 0x78 and proceed.
                 #
-                ##print("Got 0xd6 block: normal\n");
+                ##print("Got 0xd6/0xd7 block: normal\n");
                 substr($self->{dataIn}, 0, 1) = chr(0x78);
             } elsif ( $chr eq chr(0xb3) ) {
                 #
index b2d5f50..2790346 100644 (file)
@@ -105,7 +105,7 @@ sub fileDigestIsCached
     binmode($fh);
     return -2 if ( sysread($fh, $data, 1) != 1 );
     close($fh);
-    return $data eq chr(0xd6) ? 1 : 0;
+    return $data eq chr(0xd7) ? 1 : 0;
 }
 
 #
@@ -121,7 +121,8 @@ sub fileDigestIsCached
 #
 sub digestAdd
 {
-    my($class, $file, $blockSize, $checksumSeed, $verify) = @_;
+    my($class, $file, $blockSize, $checksumSeed, $verify,
+                $protocol_version) = @_;
     my $retValue = 0;
 
     #
@@ -140,6 +141,8 @@ sub digestAdd
     return -101 if ( !$RsyncLibOK );
 
     my $digest = File::RsyncP::Digest->new;
+    $digest->protocol($protocol_version)
+                        if ( defined($protocol_version) );
     $digest->add(pack("V", $checksumSeed)) if ( $checksumSeed );
 
     return -102 if ( !defined(my $fh = BackupPC::FileZIO->open($file, 0, 1)) );
@@ -171,7 +174,7 @@ sub digestAdd
     sysopen(my $fh2, $file, O_RDWR) || return -103;
     binmode($fh2);
     return -104 if ( sysread($fh2, $data, 1) != 1 );
-    if ( $data ne chr(0x78) && $data ne chr(0xd6) ) {
+    if ( $data ne chr(0x78) && $data ne chr(0xd6) && $data ne chr(0xd7) ) {
         &$Log(sprintf("digestAdd: $file has unexpected first char 0x%x",
                              ord($data)));
         return -105;
@@ -183,7 +186,7 @@ sub digestAdd
         #
         # Verify the cached checksums
         #
-        return -107 if ( $data ne chr(0xd6) );
+        return -107 if ( $data ne chr(0xd7) );
         return -108 if ( sysread($fh2, $data3, length($data2) + 1) < 0 );
         if ( $data2 eq $data3 ) {
             return 1;
@@ -220,7 +223,7 @@ sub digestAdd
         }
     }
     return -113 if ( !defined(sysseek($fh2, 0, 0)) );
-    return -114 if ( syswrite($fh2, chr(0xd6)) != 1 );
+    return -114 if ( syswrite($fh2, chr(0xd7)) != 1 );
     close($fh2);
     return $retValue;
 }
@@ -254,9 +257,11 @@ sub digestStart
         name     => $fileName,
         needMD4  => $needMD4,
         digest   => File::RsyncP::Digest->new,
+        protocol_version => $protocol_version,
     }, $class;
 
-    $dg->{digest}->protocol($protocol_version);
+    $dg->{digest}->protocol($dg->{protocol_version})
+                        if ( defined($dg->{protocol_version}) );
 
     if ( $fileSize > 0 && $compress && $doCache >= 0 ) {
         open(my $fh, "<", $fileName) || return -2;
@@ -282,7 +287,7 @@ sub digestStart
                             $blockSize
                                 || BackupPC::Xfer::RsyncDigest->blockSize(
                                                     $fileSize, $defBlkSize),
-                                $checksumSeed);
+                                $checksumSeed, $dg->{protocol_version});
             if ( $ret < 0 ) {
                 &$Log("digestAdd($fileName) failed ($ret)");
             }
@@ -293,7 +298,7 @@ sub digestStart
             binmode($fh);
             return -5 if ( read($fh, $data, 1) != 1 );
         }
-        if ( $ret >= 0 && $data eq chr(0xd6) ) {
+        if ( $ret >= 0 && $data eq chr(0xd7) ) {
             #
             # Looks like this file has cached checksums
             # Read the last 48 bytes: that's 2 file MD4s (32 bytes)
@@ -343,6 +348,8 @@ sub digestStart
         return -9 if ( !defined($dg->{fh}) );
         if ( $needMD4) {
             $dg->{csumDigest} = File::RsyncP::Digest->new;
+            $dg->{csumDigest}->protocol($dg->{protocol_version})
+                                if ( defined($dg->{protocol_version}) );
             $dg->{csumDigest}->add(pack("V", $dg->{checksumSeed}));
         }
     }
@@ -387,7 +394,13 @@ sub digestEnd
 
     if ( $dg->{cached} ) {
         close($dg->{fh});
-        return $dg->{md4DigestOld} if ( $dg->{needMD4} );
+        if ( $dg->{needMD4} ) {
+            if ( $dg->{protocol_version} <= 26 ) {
+                return $dg->{md4DigestOld};
+            } else {
+                return $dg->{md4Digest};
+            }
+        }
     } else {
         #
         # make sure we read the entire file for the file MD4 digest
index 2d2f0b2..6a1460c 100644 (file)
@@ -170,7 +170,8 @@ sub csumStart
         if ( $isCached || $isInvalid ) {
             my $ret = BackupPC::Xfer::RsyncDigest->digestAdd(
                             $attr->{fullPath}, $blkSize,
-                            $fio->{checksumSeed}, 1        # verify
+                            $fio->{checksumSeed}, 1,        # verify
+                            $fio->{protocol_version}
                         );
             if ( $ret != 1 ) {
                 $fio->log("Bad cached digest for $attr->{fullPath} ($ret);"
@@ -186,19 +187,18 @@ sub csumStart
     (my $err, $fio->{csum}, my $blkSize)
          = BackupPC::Xfer::RsyncDigest->digestStart($attr->{fullPath},
                         $attr->{size}, 0, $defBlkSize, $fio->{checksumSeed},
-                        $needMD4, $attr->{compress}, 1,
-                         $fio->{protocol_version});
-    if ( $fio->{logLevel} >= 5 ) {
-        my($isCached, $invalid) = $fio->{csum}->isCached;
-        $fio->log("$attr->{fullPath} cache = $isCached,"
-                . " invalid = $invalid, phase = $phase");
-    }
+                        $needMD4, $attr->{compress}, 1, $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;
     }
+    if ( $fio->{logLevel} >= 5 ) {
+        my($isCached, $invalid) = $fio->{csum}->isCached;
+        $fio->log("$attr->{fullPath} cache = $isCached,"
+                . " invalid = $invalid, phase = $phase");
+    }
     return $blkSize;
 }
 
@@ -323,12 +323,14 @@ sub viewCacheDir
 
 sub attribGetWhere
 {
-    my($fio, $f, $noCache) = @_;
-    my($dir, $fname, $share, $shareM, $partial, $attr);
+    my($fio, $f, $noCache, $fname) = @_;
+    my($dir, $share, $shareM, $partial, $attr);
 
-    $fname = $f->{name};
-    $fname = "$fio->{xfer}{pathHdrSrc}/$fname"
+    if ( !defined($fname) ) {
+        $fname = $f->{name};
+        $fname = "$fio->{xfer}{pathHdrSrc}/$fname"
                       if ( defined($fio->{xfer}{pathHdrSrc}) );
+    }
     $fname =~ s{//+}{/}g;
     if ( $fname =~ m{(.*)/(.*)}s ) {
        $shareM = $fio->{shareM};
@@ -388,15 +390,10 @@ sub attribGet
             return $attr;
         }
         $target = "/$target" if ( $target !~ /^\// );
-        $fio->log("$attr->{fullPath}: redirecting to $target (will trim "
-                . "$fio->{xfer}{pathHdrSrc})") if ( $fio->{logLevel} >= 4 );
-        $target =~ s/^\Q$fio->{xfer}{pathHdrSrc}//;
+        $fio->log("$attr->{fullPath}: redirecting to $target")
+                                    if ( $fio->{logLevel} >= 4 );
         $target =~ s{^/+}{};
-        #
-        # Note: overwrites name to point to real file
-        #
-        $f->{name} = $target;
-        ($attr) = $fio->attribGetWhere($f, 1);
+        ($attr) = $fio->attribGetWhere($f, 1, $target);
         $fio->log(" ... now got $attr->{fullPath}")
                             if ( $fio->{logLevel} >= 4 );
     }