5 Bweb - A Bacula web interface
6 Bacula® - The Network Backup Solution
8 Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
10 The main author of Bweb is Eric Bollengier.
11 The main author of Bacula is Kern Sibbald, with contributions from
12 many others, a complete list can be found in the file AUTHORS.
13 This program is Free Software; you can redistribute it and/or
14 modify it under the terms of version three of the GNU Affero General Public
15 License as published by the Free Software Foundation and included
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 Affero General Public License for more details.
23 You should have received a copy of the GNU Affero General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 Bacula® is a registered trademark of Kern Sibbald.
29 The licensor of Bacula is the Free Software Foundation Europe
30 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
31 Switzerland, email:ftf@fsfeurope.org.
36 use POSIX qw/strftime/;
39 use Digest::MD5 qw(md5_hex);
40 use File::Basename qw/basename dirname/;
42 my $conf = new Bweb::Config(config_file => $Bweb::config_file);
44 my $bweb = new Bweb(info => $conf);
47 my $arg = $bweb->get_form('where', 'jobid', 'pathid', 'filenameid');
48 my $where = $arg->{where} || '/';
49 my $jobid = $arg->{jobid};
50 my $pathid = $arg->{pathid};
51 my $fnid = $arg->{filenameid};
52 my $jobid_url = "jobid=$jobid";
55 my $batch = CGI::param("mode") || '';
57 my $md5_rep = md5_hex("$where:$jobid:$pathid:$fnid") ;
58 my $base_url = '/bweb/fv' ;
59 my $base_fich = $conf->{fv_write_path};
61 if ($jobid and $batch eq 'batch') {
62 my $root = fv_get_root_pathid($where);
64 fv_compute_size($jobid, $root);
70 print CGI::header('text/html');
71 $bweb->display_begin();
72 $bweb->display_job_zoom($jobid);
75 $bweb->error("Can't get where or jobid");
80 unless ($base_fich and -w $base_fich) {
81 $bweb->error("fv_write_path ($base_fich) is not writable." .
82 " See Bweb configuration.");
87 if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
89 $bweb->display({}, "$base_fich/$md5_rep.tpl");
94 my $r = $bweb->dbh_selectrow_hashref("SELECT PurgedFiles AS ok FROM Job WHERE JobId = $jobid");
95 if (!$r || $r->{ok}) {
96 $bweb->error("File information for job $jobid has been pruned from catalog");
101 $r = $bweb->dbh_selectrow_hashref("SELECT JobId AS ok FROM brestore_knownjobid WHERE JobId = $jobid");
102 if (!$r || !$r->{ok}) { # TODO: compute information
103 $bweb->error("Path information for job $jobid has not been updated in the catalog");
104 $bweb->display_end();
108 # if it's a file, display it
109 if ($fnid and $pathid)
111 my $attribs = fv_get_file_attribute_from_id($jobid, $pathid, $fnid);
112 if ($attribs->{found}) {
113 $bweb->display($attribs, 'fv_file_attribs.tpl');
114 $bweb->display_end();
118 } elsif ($where ne '/') {
120 my $attribs = fv_get_file_attribute($jobid, $where);
121 if ($attribs->{found}) {
122 $bweb->display($attribs, 'fv_file_attribs.tpl');
123 $bweb->display_end();
132 $where = fv_get_root_path($pathid);
135 if ($where !~ m!/$!) {
136 $where = $where . "/" ;
139 $root = fv_get_root_pathid($where);
143 $bweb->error("Can't find $where in catalog");
144 $bweb->display_end();
148 my $total = fv_compute_size($jobid, $root);
150 my $url_action = "bfileview.pl?opt_level=$opt_level" ;
151 my $top = new CCircle(
153 base_url => "$url_action;pathid=$root;$jobid_url;here=$where",
156 fv_display_rep($top, $total, $root, $opt_level) ;
158 $top->draw_labels() ;
159 $top->set_title(Bweb::human_size($total)) ;
161 open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
162 # make sure we are writing to a binary stream
164 # Convert the image to PNG and print it on standard output
165 print OUT $CCircle::gd->png;
168 open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
170 <form action='$url_action' method='get'>
172 <input title='jobids' type='hidden' name='jobid' value='$jobid'>
173 <input title='directory' type='text' name='where' value='$where'/>
174 <input type='submit' size='256' name='go' value='go'/>
180 print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
183 $bweb->display({}, "$base_fich/$md5_rep.tpl");
184 $bweb->display_end();
188 my ($ccircle, $max, $rep, $level) = @_ ;
189 return if ($max < 1);
192 my $dirs = fv_list_dirs($jobid, $rep); # 0: pathid, 1: pathname
194 foreach my $dir (@{$dirs})
196 my $size = fv_compute_size($jobid, $dir->[0]);
199 my $per = $size * 100 / $max;
200 # can't use pathname when using utf or accent
202 $ccircle->{base_url} =~ s/pathid=\d+;/pathid=$dir->[0];/;
204 my $chld = $ccircle->add_part($per,
205 basename($dir->[1]) . '/',
207 . sprintf(' %.0f%% ', $per)
208 . Bweb::human_size($size)
211 if ($chld && $level > 0) {
212 fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
216 # 0: filenameid, 1: filename, 2: size
217 my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
218 foreach my $f (@{$files}) {
219 $ccircle->{base_url} =~ s/pathid=\d+;(filenameid=\d+)?/pathid=$rep;filenameid=$f->[0];/;
221 $ccircle->add_part($f->[2] * 100 / $max,
223 $f->[1] . "\n" . Bweb::human_size($f->[2]));
228 $ccircle->add_part(($max - $sum) * 100 / $max,
230 "other\n" . Bweb::human_size($max - $sum));
233 $ccircle->finalize() ;
238 my ($jobid, $rep) = @_;
240 my $size = fv_get_size($jobid, $rep);
245 $size = fv_get_files_size($jobid, $rep);
247 my $dirs = fv_list_dirs($jobid, $rep);
248 foreach my $dir (@{$dirs}) {
249 $size += fv_compute_size($jobid, $dir->[0]);
252 fv_update_size($jobid, $rep, $size);
258 my ($jobid, $rep) = @_;
260 my $ret = $bweb->dbh_selectall_arrayref("
262 ( SELECT Path FROM Path WHERE PathId = P.PathId) AS Path
265 FROM brestore_pathvisibility
266 INNER JOIN brestore_pathhierarchy USING (PathId)
275 sub fv_get_file_attribute
277 my ($jobid, $full_name) = @_;
279 if ($full_name eq '/') {
283 my $filename = $bweb->dbh_quote(basename($full_name));
284 my $path = $bweb->dbh_quote(dirname($full_name) . "/");
286 my $attr = $bweb->dbh_selectrow_hashref("
289 base64_decode_lstat(8, LStat) AS size,
290 base64_decode_lstat(11, LStat) AS atime,
291 base64_decode_lstat(12, LStat) AS mtime,
292 base64_decode_lstat(13, LStat) AS ctime
294 FROM File JOIN Filename USING (FilenameId)
295 JOIN Path USING (PathId)
296 WHERE Name = $filename
301 $attr->{filename} = $full_name;
302 $attr->{size} = Bweb::human_size($attr->{size});
303 foreach my $d (qw/atime ctime mtime/) {
304 $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
310 sub fv_get_file_attribute_from_id
312 my ($jobid, $pathid, $filenameid) = @_;
314 my $attr = $bweb->dbh_selectrow_hashref("
317 base64_decode_lstat(8, LStat) AS size,
318 base64_decode_lstat(11, LStat) AS atime,
319 base64_decode_lstat(12, LStat) AS mtime,
320 base64_decode_lstat(13, LStat) AS ctime,
321 Path.Path || Filename.Name AS filename
323 FROM File INNER JOIN Filename USING (FilenameId)
324 INNER JOIN Path USING (PathId)
325 WHERE FilenameId = $filenameid
330 $attr->{size} = Bweb::human_size($attr->{size});
331 foreach my $d (qw/atime ctime mtime/) {
332 $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
339 my ($jobid, $rep) = @_;
341 my $ret = $bweb->dbh_selectrow_hashref("
343 FROM brestore_pathvisibility
351 sub fv_get_files_size
353 my ($jobid, $rep) = @_;
355 my $ret = $bweb->dbh_selectrow_hashref("
356 SELECT sum(base64_decode_lstat(8,LStat)) AS size
368 my ($jobid, $rep, $min, $limit) = @_;
369 $limit = int($limit);
371 my $ret = $bweb->dbh_selectall_arrayref("
372 SELECT FilenameId AS filenameid, Name AS name, size
374 SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
379 ) AS S INNER JOIN Filename USING (FilenameId)
390 my ($jobid, $rep, $size) = @_;
392 my $nb = $bweb->dbh_do("
393 UPDATE brestore_pathvisibility SET Size = $size
401 sub fv_get_root_pathid
404 $path = $bweb->dbh_quote($path);
405 my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
406 return $ret->{pathid};
412 my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
419 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
426 size := split_part($2, ' ', $1);
427 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
429 FOR i IN 1..length(size) LOOP
430 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
434 $$ language 'plpgsql';
436 ALTER TABLE brestore_pathvisibility ADD Size int8;
440 ALTER TABLE brestore_pathvisibility ADD Files int4;