# 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
$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 ) {
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
}
}
$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;
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 {
$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) ) {
# 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:
#
# 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.
#
# This setting only matters if $Conf{XferMethod} = 'smb'.
#
-$Conf{SmbClientPath} = '/usr/bin/smbclient';
+$Conf{SmbClientPath} = '';
#
# Command to run smbclient for a full dump.
#
# 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
#
# 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
# 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
# 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
#
# $Conf{PingPath} = '/bin/echo';
#
-$Conf{PingPath} = '/bin/ping';
+$Conf{PingPath} = '';
#
# Ping command. The following variables are substituted at run-time:
# 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.
EOF
exit(1) if ( $opts{batch} );
+ } else {
+ last;
}
}
# 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");
- 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
#
#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"});
}
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;
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 ) {
} 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 ) {
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;
}
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) ) {
}
} 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)}">
$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" ) {
<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;
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 ) {
$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
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
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);
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);
$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
#
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}) ) {
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);
<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);
# 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;
if ( defined($overrideVar) ) {
$onChange .= "checkboxSet('$overrideVar');";
} else {
- $onChange .= "varChange('$overrideVar');";
+ $onChange .= "varChange('$varName');";
}
if ( $onchangeSubmit ) {
$onChange .= "document.editForm.submit();";
}
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 );
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";
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);
} 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
} 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;
}
$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 {
$$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 );
} 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 "" ) {
}
}
} 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 "" );
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) ) {
#
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;
}
#
#
sub digestAdd
{
- my($class, $file, $blockSize, $checksumSeed, $verify) = @_;
+ my($class, $file, $blockSize, $checksumSeed, $verify,
+ $protocol_version) = @_;
my $retValue = 0;
#
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)) );
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;
#
# 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;
}
}
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;
}
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;
$blockSize
|| BackupPC::Xfer::RsyncDigest->blockSize(
$fileSize, $defBlkSize),
- $checksumSeed);
+ $checksumSeed, $dg->{protocol_version});
if ( $ret < 0 ) {
&$Log("digestAdd($fileName) failed ($ret)");
}
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)
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}));
}
}
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
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);"
(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;
}
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};
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 );
}