RestoreFile.pm (BackupPC-4.3.2) | : | RestoreFile.pm (BackupPC-4.4.0) | ||
---|---|---|---|---|
skipping to change at line 30 | skipping to change at line 30 | |||
# This program is distributed in the hope that it will be useful, | # This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | # GNU General Public License for more details. | |||
# | # | |||
# You should have received a copy of the GNU General Public License | # You should have received a copy of the GNU General Public License | |||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
# | # | |||
#======================================================================== | #======================================================================== | |||
# | # | |||
# Version 4.3.2, released 17 Feb 2020. | # Version 4.4.0, released 20 Jun 2020. | |||
# | # | |||
# See http://backuppc.sourceforge.net. | # See http://backuppc.sourceforge.net. | |||
# | # | |||
#======================================================================== | #======================================================================== | |||
package BackupPC::CGI::RestoreFile; | package BackupPC::CGI::RestoreFile; | |||
use strict; | use strict; | |||
use BackupPC::CGI::Lib qw(:all); | use BackupPC::CGI::Lib qw(:all); | |||
use BackupPC::XS qw(:all); | use BackupPC::XS qw(:all); | |||
use BackupPC::View; | use BackupPC::View; | |||
use Encode qw/from_to decode_utf8/; | use Encode qw/from_to decode_utf8/; | |||
sub action | sub action | |||
{ | { | |||
my $num = $In{num}; | my $num = $In{num}; | |||
my $share = $In{share}; | my $share = $In{share}; | |||
my $dir = $In{dir}; | my $dir = $In{dir}; | |||
ErrorExit(eval("qq{$Lang->{Invalid_number__num}}")) | ErrorExit(eval("qq{$Lang->{Invalid_number__num}}")) | |||
if ( $num ne "" && $num !~ /^\d+$/ ); | if ( $num ne "" && $num !~ /^\d+$/ ); | |||
ErrorExit($Lang->{Nice_try__but_you_can_t_put}) | ErrorExit($Lang->{Nice_try__but_you_can_t_put}) | |||
if ( $dir =~ m{(^|/)\.\.(/|$)} ); | if ( $dir =~ m{(^|/)\.\.(/|$)} ); | |||
restoreFile($In{host}, $num, $share, $dir); | restoreFile($In{host}, $num, $share, $dir); | |||
} | } | |||
sub restoreFile | sub restoreFile | |||
{ | { | |||
my($host, $num, $share, $dir, $skipHardLink, $origName) = @_; | my($host, $num, $share, $dir, $skipHardLink, $origName) = @_; | |||
my($Privileged) = CheckPermission($host); | my($Privileged) = CheckPermission($host); | |||
# | # | |||
# Some common content (media) types from www.iana.org (via MIME::Types). | # Some common content (media) types from www.iana.org (via MIME::Types). | |||
# | # | |||
my $Ext2ContentType = { | my $Ext2ContentType = { | |||
'asc' => 'text/plain', | 'asc' => 'text/plain', | |||
'avi' => 'video/x-msvideo', | 'avi' => 'video/x-msvideo', | |||
'bmp' => 'image/bmp', | 'bmp' => 'image/bmp', | |||
'book' => 'application/x-maker', | 'book' => 'application/x-maker', | |||
'cc' => 'text/plain', | 'cc' => 'text/plain', | |||
'cpp' => 'text/plain', | 'cpp' => 'text/plain', | |||
'csh' => 'application/x-csh', | 'csh' => 'application/x-csh', | |||
'csv' => 'text/comma-separated-values', | 'csv' => 'text/comma-separated-values', | |||
'c' => 'text/plain', | 'c' => 'text/plain', | |||
'deb' => 'application/x-debian-package', | 'deb' => 'application/x-debian-package', | |||
'doc' => 'application/msword', | 'doc' => 'application/msword', | |||
'dot' => 'application/msword', | 'dot' => 'application/msword', | |||
'dtd' => 'text/xml', | 'dtd' => 'text/xml', | |||
'dvi' => 'application/x-dvi', | 'dvi' => 'application/x-dvi', | |||
'eps' => 'application/postscript', | 'eps' => 'application/postscript', | |||
'fb' => 'application/x-maker', | 'fb' => 'application/x-maker', | |||
'fbdoc'=> 'application/x-maker', | 'fbdoc' => 'application/x-maker', | |||
'fm' => 'application/x-maker', | 'fm' => 'application/x-maker', | |||
'frame'=> 'application/x-maker', | 'frame' => 'application/x-maker', | |||
'frm' => 'application/x-maker', | 'frm' => 'application/x-maker', | |||
'gif' => 'image/gif', | 'gif' => 'image/gif', | |||
'gtar' => 'application/x-gtar', | 'gtar' => 'application/x-gtar', | |||
'gz' => 'application/x-gzip', | 'gz' => 'application/x-gzip', | |||
'hh' => 'text/plain', | 'hh' => 'text/plain', | |||
'hpp' => 'text/plain', | 'hpp' => 'text/plain', | |||
'h' => 'text/plain', | 'h' => 'text/plain', | |||
'html' => 'text/html', | 'html' => 'text/html', | |||
'htmlx'=> 'text/html', | 'htmlx' => 'text/html', | |||
'htm' => 'text/html', | 'htm' => 'text/html', | |||
'iges' => 'model/iges', | 'iges' => 'model/iges', | |||
'igs' => 'model/iges', | 'igs' => 'model/iges', | |||
'jpeg' => 'image/jpeg', | 'jpeg' => 'image/jpeg', | |||
'jpe' => 'image/jpeg', | 'jpe' => 'image/jpeg', | |||
'jpg' => 'image/jpeg', | 'jpg' => 'image/jpeg', | |||
'js' => 'application/x-javascript', | 'js' => 'application/x-javascript', | |||
'latex'=> 'application/x-latex', | 'latex' => 'application/x-latex', | |||
'maker'=> 'application/x-maker', | 'maker' => 'application/x-maker', | |||
'mid' => 'audio/midi', | 'mid' => 'audio/midi', | |||
'midi' => 'audio/midi', | 'midi' => 'audio/midi', | |||
'movie'=> 'video/x-sgi-movie', | 'movie' => 'video/x-sgi-movie', | |||
'mov' => 'video/quicktime', | 'mov' => 'video/quicktime', | |||
'mp2' => 'audio/mpeg', | 'mp2' => 'audio/mpeg', | |||
'mp3' => 'audio/mpeg', | 'mp3' => 'audio/mpeg', | |||
'mpeg' => 'video/mpeg', | 'mpeg' => 'video/mpeg', | |||
'mpg' => 'video/mpeg', | 'mpg' => 'video/mpeg', | |||
'mpp' => 'application/vnd.ms-project', | 'mpp' => 'application/vnd.ms-project', | |||
'pdf' => 'application/pdf', | 'pdf' => 'application/pdf', | |||
'pgp' => 'application/pgp-signature', | 'pgp' => 'application/pgp-signature', | |||
'php' => 'application/x-httpd-php', | 'php' => 'application/x-httpd-php', | |||
'pht' => 'application/x-httpd-php', | 'pht' => 'application/x-httpd-php', | |||
'phtml'=> 'application/x-httpd-php', | 'phtml' => 'application/x-httpd-php', | |||
'png' => 'image/png', | 'png' => 'image/png', | |||
'ppm' => 'image/x-portable-pixmap', | 'ppm' => 'image/x-portable-pixmap', | |||
'ppt' => 'application/powerpoint', | 'ppt' => 'application/powerpoint', | |||
'ppt' => 'application/vnd.ms-powerpoint', | 'ppt' => 'application/vnd.ms-powerpoint', | |||
'ps' => 'application/postscript', | 'ps' => 'application/postscript', | |||
'qt' => 'video/quicktime', | 'qt' => 'video/quicktime', | |||
'rgb' => 'image/x-rgb', | 'rgb' => 'image/x-rgb', | |||
'rtf' => 'application/rtf', | 'rtf' => 'application/rtf', | |||
'rtf' => 'text/rtf', | 'rtf' => 'text/rtf', | |||
'shar' => 'application/x-shar', | 'shar' => 'application/x-shar', | |||
'shtml'=> 'text/html', | 'shtml' => 'text/html', | |||
'swf' => 'application/x-shockwave-flash', | 'swf' => 'application/x-shockwave-flash', | |||
'tex' => 'application/x-tex', | 'tex' => 'application/x-tex', | |||
'texi' => 'application/x-texinfo', | 'texi' => 'application/x-texinfo', | |||
'texinfo'=> 'application/x-texinfo', | 'texinfo' => 'application/x-texinfo', | |||
'tgz' => 'application/x-gtar', | 'tgz' => 'application/x-gtar', | |||
'tiff' => 'image/tiff', | 'tiff' => 'image/tiff', | |||
'tif' => 'image/tiff', | 'tif' => 'image/tiff', | |||
'txt' => 'text/plain', | 'txt' => 'text/plain', | |||
'vcf' => 'text/x-vCard', | 'vcf' => 'text/x-vCard', | |||
'vrml' => 'model/vrml', | 'vrml' => 'model/vrml', | |||
'wav' => 'audio/x-wav', | 'wav' => 'audio/x-wav', | |||
'wmls' => 'text/vnd.wap.wmlscript', | 'wmls' => 'text/vnd.wap.wmlscript', | |||
'wml' => 'text/vnd.wap.wml', | 'wml' => 'text/vnd.wap.wml', | |||
'wrl' => 'model/vrml', | 'wrl' => 'model/vrml', | |||
'xls' => 'application/vnd.ms-excel', | 'xls' => 'application/vnd.ms-excel', | |||
'xml' => 'text/xml', | 'xml' => 'text/xml', | |||
'xwd' => 'image/x-xwindowdump', | 'xwd' => 'image/x-xwindowdump', | |||
'z' => 'application/x-compress', | 'z' => 'application/x-compress', | |||
'zip' => 'application/zip', | 'zip' => 'application/zip', | |||
%{$Conf{CgiExt2ContentType}}, # add site-specific values | %{$Conf{CgiExt2ContentType}}, # add site-specific values | |||
}; | }; | |||
if ( !$Privileged ) { | if ( !$Privileged ) { | |||
ErrorExit(eval("qq{$Lang->{Only_privileged_users_can_restore_backup_file s2}}")); | ErrorExit(eval("qq{$Lang->{Only_privileged_users_can_restore_backup_file s2}}")); | |||
} | } | |||
$bpc->ConfigRead($host); | $bpc->ConfigRead($host); | |||
%Conf = $bpc->Conf(); | %Conf = $bpc->Conf(); | |||
ServerConnect(); | ServerConnect(); | |||
ErrorExit($Lang->{Empty_host_name}) if ( $host eq "" ); | ErrorExit($Lang->{Empty_host_name}) if ( $host eq "" ); | |||
$dir = "/" if ( $dir eq "" ); | $dir = "/" if ( $dir eq "" ); | |||
my @Backups = $bpc->BackupInfoRead($host); | my @Backups = $bpc->BackupInfoRead($host); | |||
my $view = BackupPC::View->new($bpc, $host, \@Backups); | my $view = BackupPC::View->new($bpc, $host, \@Backups); | |||
my $a = $view->fileAttrib($num, $share, $dir); | my $a = $view->fileAttrib($num, $share, $dir); | |||
if ( $dir =~ m{(^|/)\.\.(/|$)} || !defined($a) ) { | if ( $dir =~ m{(^|/)\.\.(/|$)} || !defined($a) ) { | |||
$dir = decode_utf8($dir); | $dir = decode_utf8($dir); | |||
ErrorExit("Can't restore bad file ${EscHTML($dir)} (${EscHTML($num)}, ${ EscHTML($share)})"); | ErrorExit("Can't restore bad file ${EscHTML($dir)} (${EscHTML($num)}, ${ EscHTML($share)})"); | |||
} | } | |||
my $f = BackupPC::XS::FileZIO::open($a->{fullPath}, 0, $a->{compress}); | my $f = BackupPC::XS::FileZIO::open($a->{fullPath}, 0, $a->{compress}); | |||
if ( !defined($f) ) { | if ( !defined($f) ) { | |||
my $fullPath = decode_utf8($a->{fullPath}); | my $fullPath = decode_utf8($a->{fullPath}); | |||
ErrorExit("Unable to open file ${EscHTML($fullPath)} (${EscHTML($num)}, ${EscHTML($share)})"); | ErrorExit("Unable to open file ${EscHTML($fullPath)} (${EscHTML($num)}, ${EscHTML($share)})"); | |||
} | } | |||
my $data; | my $data; | |||
if ( !$skipHardLink && $a->{type} == BPC_FTYPE_HARDLINK ) { | if ( !$skipHardLink && $a->{type} == BPC_FTYPE_HARDLINK ) { | |||
# | # | |||
# hardlinks should look like the file they point to | # hardlinks should look like the file they point to | |||
# | # | |||
my $linkName; | my $linkName; | |||
while ( $f->read(\$data, 65536) > 0 ) { | while ( $f->read(\$data, 65536) > 0 ) { | |||
$linkName .= $data; | $linkName .= $data; | |||
} | } | |||
$f->close; | $f->close; | |||
$linkName =~ s/^\.\///; | $linkName =~ s/^\.\///; | |||
restoreFile($host, $num, $share, $linkName, 1, $dir); | restoreFile($host, $num, $share, $linkName, 1, $dir); | |||
return; | return; | |||
} | } | |||
$bpc->ServerMesg("log User $User recovered file $host/$num:$share/$dir ($a-> {fullPath})"); | $bpc->ServerMesg("log User $User recovered file $host/$num:$share/$dir ($a-> {fullPath})"); | |||
$dir = $origName if ( defined($origName) ); | $dir = $origName if ( defined($origName) ); | |||
my $ext = $1 if ( $dir =~ /\.([^\/\.]+)$/ ); | my $ext = $1 if ( $dir =~ /\.([^\/\.]+)$/ ); | |||
my $contentType = $Ext2ContentType->{lc($ext)} | my $contentType = $Ext2ContentType->{lc($ext)} | |||
|| "application/octet-stream"; | || "application/octet-stream"; | |||
my $fileName = $1 if ( $dir =~ /.*\/(.*)/ ); | my $fileName = $1 if ( $dir =~ /.*\/(.*)/ ); | |||
$fileName =~ s/"/\\"/g; | $fileName =~ s/"/\\"/g; | |||
print "Content-Type: $contentType\r\n"; | print "Content-Type: $contentType\r\n"; | |||
print "Content-Transfer-Encoding: binary\r\n"; | print "Content-Transfer-Encoding: binary\r\n"; | |||
if ( $ENV{HTTP_USER_AGENT} =~ /\bmsie\b/i | if ( $ENV{HTTP_USER_AGENT} =~ /\bmsie\b/i && $ENV{HTTP_USER_AGENT} !~ /\bope | |||
&& $ENV{HTTP_USER_AGENT} !~ /\bopera\b/i ) { | ra\b/i ) { | |||
# | # | |||
# Convert to cp1252 for MS IE. TODO: find a way to get IE | # Convert to cp1252 for MS IE. TODO: find a way to get IE | |||
# to accept UTF8 encoding. Firefox accepts inline encoding | # to accept UTF8 encoding. Firefox accepts inline encoding | |||
# using the "=?UTF-8?B?base64?=" format, but IE doesn't. | # using the "=?UTF-8?B?base64?=" format, but IE doesn't. | |||
# | # | |||
from_to($fileName, "utf8", "cp1252") | from_to($fileName, "utf8", "cp1252") | |||
if ( $Conf{ClientCharset} ne "" ); | if ( $Conf{ClientCharset} ne "" ); | |||
} | } | |||
print "Content-Disposition: attachment; filename=\"$fileName\"\r\n\r\n"; | print "Content-Disposition: attachment; filename=\"$fileName\"\r\n\r\n"; | |||
while ( $f->read(\$data, 1024 * 1024) > 0 ) { | while ( $f->read(\$data, 1024 * 1024) > 0 ) { | |||
print $data; | print $data; | |||
} | } | |||
$f->close; | $f->close; | |||
} | } | |||
1; | 1; | |||
End of changes. 11 change blocks. | ||||
102 lines changed or deleted | 102 lines changed or added |