]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bfileview.pl
ebl Fix display of / on bfileview
[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     $bweb->display_end();
82     exit 0;
83 }
84
85 unless ($base_fich and -w $base_fich) {
86     $bweb->error("fv_write_path ($base_fich) is not writable." . 
87                  " See Bweb configuration.");
88     $bweb->display_end();
89     exit 0;
90 }
91
92 if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
93 {
94     $bweb->display({}, "$base_fich/$md5_rep.tpl");
95     $bweb->display_end();
96     exit 0;
97 }
98
99 my $r = $bweb->dbh_selectrow_hashref("SELECT PurgedFiles AS ok FROM Job WHERE JobId = $jobid");
100 if (!$r || $r->{ok}) {
101     $bweb->error("File information for job $jobid has been pruned from catalog");
102     $bweb->display_end();
103     exit 0;    
104
105
106 $r = $bweb->dbh_selectrow_hashref("SELECT JobId AS ok FROM brestore_knownjobid WHERE JobId = $jobid");
107 if (!$r || !$r->{ok}) {         # TODO: compute information
108     $bweb->error("Path information for job $jobid has not been updated in the catalog");
109     $bweb->display_end();
110     exit 0;    
111
112
113 # if it's a file, display it
114 if ($fnid and $pathid)
115 {
116     my $attribs = fv_get_file_attribute_from_id($jobid, $pathid, $fnid);
117     if ($attribs->{found}) {
118         $bweb->display($attribs, 'fv_file_attribs.tpl');
119         $bweb->display_end();
120         exit 0;
121     }
122
123 } elsif ($where ne '/') {
124
125     my $attribs = fv_get_file_attribute($jobid, $where);
126     if ($attribs->{found}) {
127         $bweb->display($attribs, 'fv_file_attribs.tpl');
128         $bweb->display_end();
129         exit 0;
130     }
131 }
132
133 my $root;
134
135 if ($pathid) {
136     $root = $pathid;
137     $where = fv_get_root_path($pathid);
138
139 } else {
140     if ($where !~ m!/$!) {
141         $where = $where . "/" ;
142     }
143     
144     $root = fv_get_root_pathid($where);
145 }
146
147 if (!$root) {
148     $bweb->error("Can't find $where in catalog");
149     $bweb->display_end();
150     exit 0;
151 }
152
153 my $total = fv_compute_size($jobid, $root);
154
155 my $url_action = "bfileview.pl?opt_level=$opt_level" ;
156 my $top = new CCircle(
157                       display_other => 1,
158                       base_url => "$url_action;pathid=$root;$jobid_url;here=$where",
159                       ) ;
160
161 fv_display_rep($top, $total, $root, $opt_level) ;
162
163 $top->draw_labels() ;
164 $top->set_title(Bweb::human_size($total)) ;
165
166 open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
167 # make sure we are writing to a binary stream
168 binmode OUT;
169 # Convert the image to PNG and print it on standard output
170 print OUT $CCircle::gd->png;
171 close(OUT) ;
172
173 open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
174 print OUT "
175  <form action='$url_action' method='get'>
176   <div align='right'>
177    <input title='jobids' type='hidden' name='jobid' value='$jobid'>
178    <input title='repertoire' type='text' name='where' value='$where'/>
179    <input type='submit' size='256' name='go' value='go'/>
180   </div>
181  </form>
182  <br/>
183 " ;
184
185 print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
186 close(OUT) ;
187
188 $bweb->display({}, "$base_fich/$md5_rep.tpl");
189 $bweb->display_end();
190
191 sub fv_display_rep
192 {
193     my ($ccircle, $max, $rep, $level) = @_ ;
194     return if ($max < 1);
195
196     my $sum = 0;
197     my $dirs = fv_list_dirs($jobid, $rep);      # 0: pathid, 1: pathname
198
199     foreach my $dir (@{$dirs})
200     {
201         my $size = fv_compute_size($jobid, $dir->[0]);
202         $sum += $size;
203
204         my $per = $size * 100 / $max;
205         # can't use pathname when using utf or accent
206         # a bit ugly
207         $ccircle->{base_url} =~ s/pathid=\d+;/pathid=$dir->[0];/;
208
209         my $chld = $ccircle->add_part($per, 
210                                       basename($dir->[1]) . '/',
211                                       basename($dir->[1]) 
212                                        . sprintf(' %.0f%% ', $per)
213                                        . Bweb::human_size($size)
214                                       ) ;
215
216         if ($chld && $level > 0) {
217             fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
218         }
219     }
220
221     # 0: filenameid, 1: filename, 2: size
222     my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
223     foreach my $f (@{$files}) {
224         $ccircle->{base_url} =~ s/pathid=\d+;(filenameid=\d+)?/pathid=$rep;filenameid=$f->[0];/;
225
226         $ccircle->add_part($f->[2] * 100 / $max, 
227                            $f->[1],
228                            $f->[1] . "\n" . Bweb::human_size($f->[2]));
229         $sum += $f->[2];
230     }
231
232     if ($sum < $max) {
233         $ccircle->add_part(($max - $sum) * 100 / $max, 
234                            "other files < 3%",
235                            "other\n" . Bweb::human_size($max - $sum));
236     }
237
238     $ccircle->finalize() ;
239 }
240
241 sub fv_compute_size
242 {
243     my ($jobid, $rep) = @_;
244
245     my $size = fv_get_size($jobid, $rep);
246     if ($size) {
247         return $size;
248     }
249
250     $size = fv_get_files_size($jobid, $rep);
251
252     my $dirs = fv_list_dirs($jobid, $rep);
253     foreach my $dir (@{$dirs}) {
254         $size += fv_compute_size($jobid, $dir->[0]);
255     }
256     
257     fv_update_size($jobid, $rep, $size);
258     return $size;
259 }
260
261 sub fv_list_dirs
262 {
263     my ($jobid, $rep) = @_;
264
265     my $ret = $bweb->dbh_selectall_arrayref("
266       SELECT P.PathId,
267              ( SELECT Path FROM Path WHERE PathId = P.PathId) AS Path
268         FROM (
269           SELECT PathId
270             FROM brestore_pathvisibility 
271       INNER JOIN brestore_pathhierarchy USING (PathId)
272            WHERE PPathId  = $rep
273              AND JobId = $jobid
274              ) AS P
275 ");
276
277     return $ret;
278 }
279
280 sub fv_get_file_attribute
281 {
282     my ($jobid, $full_name) = @_;
283
284     if ($full_name eq '/') {
285         return {found => 0};
286     }
287     
288     my $filename = $bweb->dbh_quote(basename($full_name));
289     my $path     = $bweb->dbh_quote(dirname($full_name) . "/");
290
291     my $attr = $bweb->dbh_selectrow_hashref("
292  SELECT 1    AS found,
293         MD5  AS md5,
294         base64_decode_lstat(8,  LStat) AS size,
295         base64_decode_lstat(11, LStat) AS atime,
296         base64_decode_lstat(12, LStat) AS mtime,
297         base64_decode_lstat(13, LStat) AS ctime
298
299    FROM File JOIN Filename USING (FilenameId)
300              JOIN Path     USING (PathId)
301   WHERE Name  = $filename
302    AND  Path  = $path
303    AND  JobId = $jobid
304 ");
305
306     $attr->{filename} = $full_name;
307     $attr->{size} = Bweb::human_size($attr->{size});
308     foreach my $d (qw/atime ctime mtime/) {
309         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
310     }
311     return $attr;
312 }
313
314
315 sub fv_get_file_attribute_from_id
316 {
317     my ($jobid, $pathid, $filenameid) = @_;
318     
319     my $attr = $bweb->dbh_selectrow_hashref("
320  SELECT 1    AS found,
321         MD5  AS md5,
322         base64_decode_lstat(8,  LStat) AS size,
323         base64_decode_lstat(11, LStat) AS atime,
324         base64_decode_lstat(12, LStat) AS mtime,
325         base64_decode_lstat(13, LStat) AS ctime,
326         Path.Path ||  Filename.Name AS filename
327
328    FROM File INNER JOIN Filename USING (FilenameId)
329              INNER JOIN Path     USING (PathId)
330   WHERE FilenameId  = $filenameid
331    AND  PathId  = $pathid
332    AND  JobId = $jobid
333 ");
334
335     $attr->{size} = Bweb::human_size($attr->{size});
336     foreach my $d (qw/atime ctime mtime/) {
337         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
338     }
339     return $attr;
340 }
341
342 sub fv_get_size
343 {
344     my ($jobid, $rep) = @_;
345
346     my $ret = $bweb->dbh_selectrow_hashref("
347  SELECT Size AS size
348    FROM brestore_pathvisibility
349   WHERE PathId = $rep
350     AND JobId = $jobid
351 ");
352
353     return $ret->{size};
354 }
355
356 sub fv_get_files_size
357 {
358     my ($jobid, $rep) = @_;
359
360     my $ret = $bweb->dbh_selectrow_hashref("
361  SELECT sum(base64_decode_lstat(8,LStat)) AS size
362    FROM File
363   WHERE PathId  = $rep
364     AND JobId = $jobid
365 ");
366
367     return $ret->{size};
368 }
369
370 sub fv_get_big_files
371 {
372     my ($jobid, $rep, $min, $limit) = @_;
373
374     my $ret = $bweb->dbh_selectall_arrayref("
375    SELECT FilenameId AS filenameid, Name AS name, size
376    FROM (
377          SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
378            FROM File
379           WHERE PathId  = $rep
380             AND JobId = $jobid
381         ) AS S INNER JOIN Filename USING (FilenameId)
382    WHERE S.size > $min
383    ORDER BY S.size DESC
384    LIMIT $limit
385 ");
386
387     return $ret;
388 }
389
390 sub fv_update_size
391 {
392     my ($jobid, $rep, $size) = @_;
393
394     my $nb = $bweb->dbh_do("
395  UPDATE brestore_pathvisibility SET Size = $size 
396   WHERE JobId = $jobid 
397     AND PathId = $rep 
398 ");
399
400     return $nb;
401 }
402
403 sub fv_get_root_pathid
404 {
405     my ($path) = @_;
406     $path = $bweb->dbh_quote($path);
407     my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
408     return $ret->{pathid};
409 }
410
411 sub fv_get_root_path
412 {
413     my ($pathid) = @_;
414     my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
415     return $ret->{path};
416 }
417
418
419 __END__
420
421 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
422 DECLARE
423 val int8;
424 b64 varchar(64);
425 size varchar(64);
426 i int;
427 BEGIN
428 size := split_part($2, ' ', $1);
429 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
430 val := 0;
431 FOR i IN 1..length(size) LOOP
432 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
433 END LOOP;
434 RETURN val;
435 END;
436 $$ language 'plpgsql';
437
438 ALTER TABLE brestore_pathvisibility ADD Size  int8;
439
440
441
442 ALTER TABLE brestore_pathvisibility ADD Files int4;