* checkin with 3.2.0beta0 release header
[BackupPC.git] / lib / BackupPC / CGI / RestoreFile.pm
1 #============================================================= -*-perl-*-
2 #
3 # BackupPC::CGI::RestoreFile package
4 #
5 # DESCRIPTION
6 #
7 #   This module implements the RestoreFile action for the CGI interface.
8 #
9 # AUTHOR
10 #   Craig Barratt  <cbarratt@users.sourceforge.net>
11 #
12 # COPYRIGHT
13 #   Copyright (C) 2003-2007  Craig Barratt
14 #
15 #   This program is free software; you can redistribute it and/or modify
16 #   it under the terms of the GNU General Public License as published by
17 #   the Free Software Foundation; either version 2 of the License, or
18 #   (at your option) any later version.
19 #
20 #   This program is distributed in the hope that it will be useful,
21 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
22 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 #   GNU General Public License for more details.
24 #
25 #   You should have received a copy of the GNU General Public License
26 #   along with this program; if not, write to the Free Software
27 #   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 #
29 #========================================================================
30 #
31 # Version 3.2.0beta0, released 5 April 2009.
32 #
33 # See http://backuppc.sourceforge.net.
34 #
35 #========================================================================
36
37 package BackupPC::CGI::RestoreFile;
38
39 use strict;
40 use BackupPC::CGI::Lib qw(:all);
41 use BackupPC::FileZIO;
42 use BackupPC::Attrib qw(:all);
43 use BackupPC::View;
44 use Encode qw/from_to decode_utf8/;
45
46 sub action
47 {
48     restoreFile($In{host}, $In{num}, $In{share}, $In{dir});
49 }
50
51 sub restoreFile
52 {
53     my($host, $num, $share, $dir, $skipHardLink, $origName) = @_;
54     my($Privileged) = CheckPermission($host);
55
56     #
57     # Some common content (media) types from www.iana.org (via MIME::Types).
58     #
59     my $Ext2ContentType = {
60         'asc'  => 'text/plain',
61         'avi'  => 'video/x-msvideo',
62         'bmp'  => 'image/bmp',
63         'book' => 'application/x-maker',
64         'cc'   => 'text/plain',
65         'cpp'  => 'text/plain',
66         'csh'  => 'application/x-csh',
67         'csv'  => 'text/comma-separated-values',
68         'c'    => 'text/plain',
69         'deb'  => 'application/x-debian-package',
70         'doc'  => 'application/msword',
71         'dot'  => 'application/msword',
72         'dtd'  => 'text/xml',
73         'dvi'  => 'application/x-dvi',
74         'eps'  => 'application/postscript',
75         'fb'   => 'application/x-maker',
76         'fbdoc'=> 'application/x-maker',
77         'fm'   => 'application/x-maker',
78         'frame'=> 'application/x-maker',
79         'frm'  => 'application/x-maker',
80         'gif'  => 'image/gif',
81         'gtar' => 'application/x-gtar',
82         'gz'   => 'application/x-gzip',
83         'hh'   => 'text/plain',
84         'hpp'  => 'text/plain',
85         'h'    => 'text/plain',
86         'html' => 'text/html',
87         'htmlx'=> 'text/html',
88         'htm'  => 'text/html',
89         'iges' => 'model/iges',
90         'igs'  => 'model/iges',
91         'jpeg' => 'image/jpeg',
92         'jpe'  => 'image/jpeg',
93         'jpg'  => 'image/jpeg',
94         'js'   => 'application/x-javascript',
95         'latex'=> 'application/x-latex',
96         'maker'=> 'application/x-maker',
97         'mid'  => 'audio/midi',
98         'midi' => 'audio/midi',
99         'movie'=> 'video/x-sgi-movie',
100         'mov'  => 'video/quicktime',
101         'mp2'  => 'audio/mpeg',
102         'mp3'  => 'audio/mpeg',
103         'mpeg' => 'video/mpeg',
104         'mpg'  => 'video/mpeg',
105         'mpp'  => 'application/vnd.ms-project',
106         'pdf'  => 'application/pdf',
107         'pgp'  => 'application/pgp-signature',
108         'php'  => 'application/x-httpd-php',
109         'pht'  => 'application/x-httpd-php',
110         'phtml'=> 'application/x-httpd-php',
111         'png'  => 'image/png',
112         'ppm'  => 'image/x-portable-pixmap',
113         'ppt'  => 'application/powerpoint',
114         'ppt'  => 'application/vnd.ms-powerpoint',
115         'ps'   => 'application/postscript',
116         'qt'   => 'video/quicktime',
117         'rgb'  => 'image/x-rgb',
118         'rtf'  => 'application/rtf',
119         'rtf'  => 'text/rtf',
120         'shar' => 'application/x-shar',
121         'shtml'=> 'text/html',
122         'swf'  => 'application/x-shockwave-flash',
123         'tex'  => 'application/x-tex',
124         'texi' => 'application/x-texinfo',
125         'texinfo'=> 'application/x-texinfo',
126         'tgz'  => 'application/x-gtar',
127         'tiff' => 'image/tiff',
128         'tif'  => 'image/tiff',
129         'txt'  => 'text/plain',
130         'vcf'  => 'text/x-vCard',
131         'vrml' => 'model/vrml',
132         'wav'  => 'audio/x-wav',
133         'wmls' => 'text/vnd.wap.wmlscript',
134         'wml'  => 'text/vnd.wap.wml',
135         'wrl'  => 'model/vrml',
136         'xls'  => 'application/vnd.ms-excel',
137         'xml'  => 'text/xml',
138         'xwd'  => 'image/x-xwindowdump',
139         'z'    => 'application/x-compress',
140         'zip'  => 'application/zip',
141         %{$Conf{CgiExt2ContentType}},       # add site-specific values
142     };
143     if ( !$Privileged ) {
144         ErrorExit(eval("qq{$Lang->{Only_privileged_users_can_restore_backup_files2}}"));
145     }
146     $bpc->ConfigRead($host);
147     %Conf = $bpc->Conf();
148     ServerConnect();
149     ErrorExit($Lang->{Empty_host_name}) if ( $host eq "" );
150
151     $dir = "/" if ( $dir eq "" );
152     my @Backups = $bpc->BackupInfoRead($host);
153     my $view = BackupPC::View->new($bpc, $host, \@Backups);
154     my $a = $view->fileAttrib($num, $share, $dir);
155     if ( $dir =~ m{(^|/)\.\.(/|$)} || !defined($a) ) {
156         $dir = decode_utf8($dir);
157         ErrorExit("Can't restore bad file ${EscHTML($dir)} ($num, $share)");
158     }
159     my $f = BackupPC::FileZIO->open($a->{fullPath}, 0, $a->{compress});
160     if ( !defined($f) ) {
161         my $fullPath = decode_utf8($a->{fullPath});
162         ErrorExit("Unable to open file ${EscHTML($fullPath)} ($num, $share)");
163     }
164     my $data;
165     if ( !$skipHardLink && $a->{type} == BPC_FTYPE_HARDLINK ) {
166         #
167         # hardlinks should look like the file they point to
168         #
169         my $linkName;
170         while ( $f->read(\$data, 65536) > 0 ) {
171             $linkName .= $data;
172         }
173         $f->close;
174         $linkName =~ s/^\.\///;
175         restoreFile($host, $num, $share, $linkName, 1, $dir);
176         return;
177     }
178     $bpc->ServerMesg("log User $User recovered file $host/$num:$share/$dir ($a->{fullPath})");
179     $dir = $origName if ( defined($origName) );
180     my $ext = $1 if ( $dir =~ /\.([^\/\.]+)$/ );
181     my $contentType = $Ext2ContentType->{lc($ext)}
182                                     || "application/octet-stream";
183     my $fileName = $1 if ( $dir =~ /.*\/(.*)/ );
184     $fileName =~ s/"/\\"/g;
185
186     print "Content-Type: $contentType\r\n";
187     print "Content-Transfer-Encoding: binary\r\n";
188
189     if ( $ENV{HTTP_USER_AGENT} =~ /\bmsie\b/i
190                 && $ENV{HTTP_USER_AGENT} !~ /\bopera\b/i ) {
191         #
192         # Convert to cp1252 for MS IE.  TODO: find a way to get IE
193         # to accept UTF8 encoding.  Firefox accepts inline encoding
194         # using the "=?UTF-8?B?base64?=" format, but IE doesn't.
195         #
196         from_to($fileName, "utf8", "cp1252")
197                         if ( $Conf{ClientCharset} ne "" );
198     }
199     print "Content-Disposition: attachment; filename=\"$fileName\"\r\n\r\n";
200     while ( $f->read(\$data, 1024 * 1024) > 0 ) {
201         print STDOUT $data;
202     }
203     $f->close;
204 }
205
206 1;