]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bfileview.pl
ebl Add Enabled option to update_media, extern/intern
[bacula/bacula] / gui / bweb / cgi / bfileview.pl
1 #!/usr/bin/perl -w
2
3 =head1 LICENSE
4
5    Bweb - A Bacula web interface
6    Bacula® - The Network Backup Solution
7
8    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
9
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
14    This program is Free Software; you can redistribute it and/or
15    modify it under the terms of version two of the GNU General Public
16    License as published by the Free Software Foundation plus additions
17    that are listed in the file LICENSE.
18
19    This program is distributed in the hope that it will be useful, but
20    WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22    General Public License for more details.
23
24    You should have received a copy of the GNU General Public License
25    along with this program; if not, write to the Free Software
26    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27    02110-1301, USA.
28
29    Bacula® is a registered trademark of John Walker.
30    The licensor of Bacula is the Free Software Foundation Europe
31    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich,
32    Switzerland, email:ftf@fsfeurope.org.
33
34 =head1 VERSION
35
36     $Id$
37
38 =cut
39
40 use strict;
41 use POSIX qw/strftime/;
42 use Bweb;
43 use CCircle ;
44 use Digest::MD5 qw(md5_hex);
45 use File::Basename qw/basename dirname/;
46
47 my $conf = new Bweb::Config(config_file => $Bweb::config_file);
48 $conf->load();
49 my $bweb = new Bweb(info => $conf);
50 $bweb->connect_db();
51
52 my $arg = $bweb->get_form('where', 'jobid', 'pathid', 'filenameid');
53 my $where = $arg->{where} || '/';
54 my $jobid = $arg->{jobid};
55 my $pathid = $arg->{pathid};
56 my $fnid = $arg->{filenameid};
57 my $jobid_url = "jobid=$jobid";
58 my $opt_level = 2 ;
59 my $max_file = 20;
60 my $batch = CGI::param("mode") || '';
61
62 my $md5_rep = md5_hex("$where:$jobid:$pathid:$fnid") ;
63 my $base_url = '/bweb/fv' ;
64 my $base_fich = $conf->{fv_write_path};
65
66 if ($jobid and $batch eq 'batch') {
67     my $root = fv_get_root_pathid($where);
68     if ($root) {
69         fv_compute_size($jobid, $root);
70         exit 0;
71     }
72     exit 1;
73 }
74
75 print CGI::header('text/html');
76 $bweb->display_begin();
77 $bweb->display_job_zoom($jobid);
78
79 unless ($jobid) {
80     $bweb->error("Can't get where or jobid");
81     exit 0;
82 }
83
84 unless ($base_fich and -w $base_fich) {
85     $bweb->error("fv_write_path ($base_fich) is not writable." . 
86                  " See Bweb configuration.");
87     exit 0;
88 }
89
90 if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
91 {
92     $bweb->display({}, "$base_fich/$md5_rep.tpl");
93     $bweb->display_end();
94     exit 0;
95 }
96
97
98 # if it's a file, display it
99 if ($fnid and $pathid)
100 {
101     my $attribs = fv_get_file_attribute_from_id($jobid, $pathid, $fnid);
102     if ($attribs->{found}) {
103         $bweb->display($attribs, 'fv_file_attribs.tpl');
104         $bweb->display_end();
105         exit 0;
106     }
107
108 } else {
109
110     my $attribs = fv_get_file_attribute($jobid, $where);
111     if ($attribs->{found}) {
112         $bweb->display($attribs, 'fv_file_attribs.tpl');
113         $bweb->display_end();
114         exit 0;
115     }
116 }
117
118 my $root;
119
120 if ($pathid) {
121     $root = $pathid;
122     $where = fv_get_root_path($pathid);
123
124 } else {
125     if ($where !~ m!/$!) {
126         $where = $where . "/" ;
127     }
128     
129     $root = fv_get_root_pathid($where);
130 }
131
132 if (!$root) {
133     $bweb->error("Can't find $where in catalog");
134     $bweb->display_end();
135     exit 0;
136 }
137
138 my $total = fv_compute_size($jobid, $root);
139
140 my $url_action = "bfileview.pl?opt_level=$opt_level" ;
141 my $top = new CCircle(
142                       display_other => 1,
143                       base_url => "$url_action;pathid=$root;$jobid_url;here=$where",
144                       ) ;
145
146 fv_display_rep($top, $total, $root, $opt_level) ;
147
148 $top->draw_labels() ;
149 $top->set_title(Bweb::human_size($total)) ;
150
151 open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
152 # make sure we are writing to a binary stream
153 binmode OUT;
154 # Convert the image to PNG and print it on standard output
155 print OUT $CCircle::gd->png;
156 close(OUT) ;
157
158 open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
159 print OUT "
160  <form action='$url_action' method='get'>
161   <div align='right'>
162    <input title='jobids' type='hidden' name='jobid' value='$jobid'>
163    <input title='repertoire' type='text' name='where' value='$where'/>
164    <input type='submit' size='256' name='go' value='go'/>
165   </div>
166  </form>
167  <br/>
168 " ;
169
170 print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
171 close(OUT) ;
172
173 $bweb->display({}, "$base_fich/$md5_rep.tpl");
174 $bweb->display_end();
175
176 sub fv_display_rep
177 {
178     my ($ccircle, $max, $rep, $level) = @_ ;
179     return if ($max < 1);
180
181     my $sum = 0;
182     my $dirs = fv_list_dirs($jobid, $rep);      # 0: pathid, 1: pathname
183
184     foreach my $dir (@{$dirs})
185     {
186         my $size = fv_compute_size($jobid, $dir->[0]);
187         $sum += $size;
188
189         my $per = $size * 100 / $max;
190         # can't use pathname when using utf or accent
191         # a bit ugly
192         $ccircle->{base_url} =~ s/pathid=\d+;/pathid=$dir->[0];/;
193
194         my $chld = $ccircle->add_part($per, 
195                                       basename($dir->[1]) . '/',
196                                       basename($dir->[1]) 
197                                        . sprintf(' %.0f%% ', $per)
198                                        . Bweb::human_size($size)
199                                       ) ;
200
201         if ($chld && $level > 0) {
202             fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
203         }
204     }
205
206     # 0: filenameid, 1: filename, 2: size
207     my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
208     foreach my $f (@{$files}) {
209         $ccircle->{base_url} =~ s/pathid=\d+;(filenameid=\d+)?/pathid=$rep;filenameid=$f->[0];/;
210
211         $ccircle->add_part($f->[2] * 100 / $max, 
212                            $f->[1],
213                            $f->[1] . "\n" . Bweb::human_size($f->[2]));
214         $sum += $f->[2];
215     }
216
217     if ($sum < $max) {
218         $ccircle->add_part(($max - $sum) * 100 / $max, 
219                            "other files < 3%",
220                            "other\n" . Bweb::human_size($max - $sum));
221     }
222
223     $ccircle->finalize() ;
224 }
225
226 sub fv_compute_size
227 {
228     my ($jobid, $rep) = @_;
229
230     my $size = fv_get_size($jobid, $rep);
231     if ($size) {
232         return $size;
233     }
234
235     $size = fv_get_files_size($jobid, $rep);
236
237     my $dirs = fv_list_dirs($jobid, $rep);
238     foreach my $dir (@{$dirs}) {
239         $size += fv_compute_size($jobid, $dir->[0]);
240     }
241     
242     fv_update_size($jobid, $rep, $size);
243     return $size;
244 }
245
246 sub fv_list_dirs
247 {
248     my ($jobid, $rep) = @_;
249
250     my $ret = $bweb->dbh_selectall_arrayref("
251       SELECT P.PathId,
252              ( SELECT Path FROM Path WHERE PathId = P.PathId) AS Path
253         FROM (
254           SELECT PathId
255             FROM brestore_pathvisibility 
256       INNER JOIN brestore_pathhierarchy USING (PathId)
257            WHERE PPathId  = $rep
258              AND JobId = $jobid
259              ) AS P
260 ");
261
262     return $ret;
263 }
264
265 sub fv_get_file_attribute
266 {
267     my ($jobid, $full_name) = @_;
268     
269     my $filename = $bweb->dbh_quote(basename($full_name));
270     my $path     = $bweb->dbh_quote(dirname($full_name) . "/");
271
272     my $attr = $bweb->dbh_selectrow_hashref("
273  SELECT 1    AS found,
274         MD5  AS md5,
275         base64_decode_lstat(8,  LStat) AS size,
276         base64_decode_lstat(11, LStat) AS atime,
277         base64_decode_lstat(12, LStat) AS mtime,
278         base64_decode_lstat(13, LStat) AS ctime
279
280    FROM File INNER JOIN Filename USING (FilenameId)
281              INNER JOIN Path     USING (PathId)
282   WHERE Name  = $filename
283    AND  Path  = $path
284    AND  JobId = $jobid
285 ");
286
287     $attr->{filename} = $full_name;
288     $attr->{size} = Bweb::human_size($attr->{size});
289     foreach my $d (qw/atime ctime mtime/) {
290         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
291     }
292     return $attr;
293 }
294
295
296 sub fv_get_file_attribute_from_id
297 {
298     my ($jobid, $pathid, $filenameid) = @_;
299     
300     my $attr = $bweb->dbh_selectrow_hashref("
301  SELECT 1    AS found,
302         MD5  AS md5,
303         base64_decode_lstat(8,  LStat) AS size,
304         base64_decode_lstat(11, LStat) AS atime,
305         base64_decode_lstat(12, LStat) AS mtime,
306         base64_decode_lstat(13, LStat) AS ctime,
307         Path.Path ||  Filename.Name AS filename
308
309    FROM File INNER JOIN Filename USING (FilenameId)
310              INNER JOIN Path     USING (PathId)
311   WHERE FilenameId  = $filenameid
312    AND  PathId  = $pathid
313    AND  JobId = $jobid
314 ");
315
316     $attr->{size} = Bweb::human_size($attr->{size});
317     foreach my $d (qw/atime ctime mtime/) {
318         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
319     }
320     return $attr;
321 }
322
323 sub fv_get_size
324 {
325     my ($jobid, $rep) = @_;
326
327     my $ret = $bweb->dbh_selectrow_hashref("
328  SELECT Size AS size
329    FROM brestore_pathvisibility
330   WHERE PathId = $rep
331     AND JobId = $jobid
332 ");
333
334     return $ret->{size};
335 }
336
337 sub fv_get_files_size
338 {
339     my ($jobid, $rep) = @_;
340
341     my $ret = $bweb->dbh_selectrow_hashref("
342  SELECT sum(base64_decode_lstat(8,LStat)) AS size
343    FROM File
344   WHERE PathId  = $rep
345     AND JobId = $jobid
346 ");
347
348     return $ret->{size};
349 }
350
351 sub fv_get_big_files
352 {
353     my ($jobid, $rep, $min, $limit) = @_;
354
355     my $ret = $bweb->dbh_selectall_arrayref("
356    SELECT FilenameId AS filenameid, Name AS name, size
357    FROM (
358          SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
359            FROM File
360           WHERE PathId  = $rep
361             AND JobId = $jobid
362         ) AS S INNER JOIN Filename USING (FilenameId)
363    WHERE S.size > $min
364    ORDER BY S.size DESC
365    LIMIT $limit
366 ");
367
368     return $ret;
369 }
370
371 sub fv_update_size
372 {
373     my ($jobid, $rep, $size) = @_;
374
375     my $nb = $bweb->dbh_do("
376  UPDATE brestore_pathvisibility SET Size = $size 
377   WHERE JobId = $jobid 
378     AND PathId = $rep 
379 ");
380
381     return $nb;
382 }
383
384 sub fv_get_root_pathid
385 {
386     my ($path) = @_;
387     $path = $bweb->dbh_quote($path);
388     my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
389     return $ret->{pathid};
390 }
391
392 sub fv_get_root_path
393 {
394     my ($pathid) = @_;
395     my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
396     return $ret->{path};
397 }
398
399
400 __END__
401
402 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
403 DECLARE
404 val int8;
405 b64 varchar(64);
406 size varchar(64);
407 i int;
408 BEGIN
409 size := split_part($2, ' ', $1);
410 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
411 val := 0;
412 FOR i IN 1..length(size) LOOP
413 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
414 END LOOP;
415 RETURN val;
416 END;
417 $$ language 'plpgsql';
418
419 ALTER TABLE brestore_pathvisibility ADD Size  int8;
420
421
422
423 ALTER TABLE brestore_pathvisibility ADD Files int4;