]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bfileview.pl
ebl use $CONF_DIR instead of /etc/bacula
[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');
53 my $where = $arg->{where};
54 my $jobid = $arg->{jobid};
55 my $jobid_url = "jobid=$jobid";
56 my $opt_level = 2 ;
57 my $max_file = 20;
58 my $batch = CGI::param("mode") || '';
59
60 my $md5_rep = md5_hex("$where:$jobid") ;
61 my $base_url = '/bweb/fv' ;
62 my $base_fich = $conf->{fv_write_path};
63
64 if ($where and $jobid and $batch eq 'batch') {
65     my $root = fv_get_root_pathid($where);
66     if ($root) {
67         fv_compute_size($jobid, $root);
68         exit 0;
69     }
70     exit 1;
71 }
72
73 print CGI::header('text/html');
74 $bweb->display_begin();
75 $bweb->display_job_zoom($jobid);
76
77 unless ($where and $jobid) {
78     $bweb->error("Can't get where or jobid");
79     exit 0;
80 }
81
82 unless ($base_fich and -w $base_fich) {
83     $bweb->error("fv_write_path ($base_fich) is not writable." . 
84                  " See Bweb configuration.");
85     exit 0;
86 }
87
88 if (-f "$base_fich/$md5_rep.png" and -f "$base_fich/$md5_rep.tpl")
89 {
90     $bweb->display({}, "$base_fich/$md5_rep.tpl");
91     $bweb->display_end();
92     exit 0;
93 }
94  
95 my $attribs = fv_get_file_attribute($jobid, $where);
96 if ($attribs->{found}) {
97     $bweb->display($attribs, 'fv_file_attribs.tpl');
98     $bweb->display_end();
99     exit 0;
100 }
101
102 if ($where !~ m!/$!) {
103     $where = $where . "/" ;
104 }
105
106 my $root = fv_get_root_pathid($where);
107 if (!$root) {
108     $bweb->error("Can't find $where in catalog");
109     $bweb->display_end();
110     exit 0;
111 }
112
113 my $total = fv_compute_size($jobid, $root);
114
115 my $url_action = "bfileview.pl?opt_level=$opt_level" ;
116 my $top = new CCircle(
117                       display_other => 1,
118                       base_url => "$url_action;$jobid_url;where=$where",
119                       ) ;
120
121 fv_display_rep($top, $total, $root, $opt_level) ;
122
123 $top->draw_labels() ;
124 $top->set_title(Bweb::human_size($total)) ;
125
126 open(OUT, ">$base_fich/$md5_rep.png") or die "$base_fich/$md5_rep.png $!";
127 # make sure we are writing to a binary stream
128 binmode OUT;
129 # Convert the image to PNG and print it on standard output
130 print OUT $CCircle::gd->png;
131 close(OUT) ;
132
133 open(OUT, ">$base_fich/$md5_rep.tpl") or die "$base_fich/$md5_rep.tpl $!";
134 print OUT "
135  <form action='$url_action' method='get'>
136   <div align='right'>
137    <input title='jobids' type='hidden' name='jobid' value='$jobid'>
138    <input title='repertoire' type='text' name='where' value='$where'/>
139    <input type='submit' size='256' name='go' value='go'/>
140   </div>
141  </form>
142  <br/>
143 " ;
144
145 print OUT $top->get_imagemap($where, "$base_url/$md5_rep.png") ;
146 close(OUT) ;
147
148 $bweb->display({}, "$base_fich/$md5_rep.tpl");
149 $bweb->display_end();
150
151 sub fv_display_rep
152 {
153     my ($ccircle, $max, $rep, $level) = @_ ;
154     return if ($max < 1);
155
156     my $sum = 0;
157     my $dirs = fv_list_dirs($jobid, $rep);      # 0: pathid, 1: pathname
158
159     foreach my $dir (@{$dirs})
160     {
161         my $size = fv_compute_size($jobid, $dir->[0]);
162         $sum += $size;
163
164         my $per = $size * 100 / $max;
165         my $chld = $ccircle->add_part($per, 
166                                       basename($dir->[1]) . '/',
167                                       basename($dir->[1]) 
168                                        . sprintf(' %.0f%% ', $per)
169                                        . Bweb::human_size($size)
170                                       ) ;
171         
172         if ($chld and $level > 0) {
173             fv_display_rep($chld, $size, $dir->[0], $level - 1) ;
174         }
175     }
176
177     # 0: name, 1: size
178     my $files = fv_get_big_files($jobid, $rep, 3*100/$max, $max_file/($level+1));
179     foreach my $f (@{$files}) {
180         $ccircle->add_part($f->[1] * 100 / $max, 
181                            $f->[0],
182                            $f->[0] . "\n" . Bweb::human_size($f->[1]));
183         $sum += $f->[1];
184     }
185
186     if ($sum < $max) {
187         $ccircle->add_part(($max - $sum) * 100 / $max, 
188                            "other files < 3%",
189                            "other\n" . Bweb::human_size($max - $sum));
190     }
191
192     $ccircle->finalize() ;
193 }
194
195 sub fv_compute_size
196 {
197     my ($jobid, $rep) = @_;
198
199     my $size = fv_get_size($jobid, $rep);
200     if ($size) {
201         return $size;
202     }
203
204     $size = fv_get_files_size($jobid, $rep);
205
206     my $dirs = fv_list_dirs($jobid, $rep);
207     foreach my $dir (@{$dirs}) {
208         $size += fv_compute_size($jobid, $dir->[0]);
209     }
210     
211     fv_update_size($jobid, $rep, $size);
212     return $size;
213 }
214
215 sub fv_list_dirs
216 {
217     my ($jobid, $rep) = @_;
218
219     my $ret = $bweb->dbh_selectall_arrayref("
220       SELECT P.PathId,
221              (
222               SELECT Path FROM Path WHERE PathId = P.PathId
223               UNION 
224               SELECT Path FROM brestore_missing_path WHERE PathId = P.PathId
225              ) AS Path
226         FROM (
227           SELECT PathId
228             FROM brestore_pathvisibility 
229       INNER JOIN brestore_pathhierarchy USING (PathId)
230            WHERE PPathId  = $rep
231              AND JobId = $jobid
232              ) AS P
233 ");
234
235     return $ret;
236 }
237
238 sub fv_get_file_attribute
239 {
240     my ($jobid, $full_name) = @_;
241     
242     my $filename = $bweb->dbh_quote(basename($full_name));
243     my $path     = $bweb->dbh_quote(dirname($full_name) . "/");
244
245     my $attr = $bweb->dbh_selectrow_hashref("
246  SELECT 1    AS found,
247         MD5  AS md5,
248         base64_decode_lstat(8,  LStat) AS size,
249         base64_decode_lstat(11, LStat) AS atime,
250         base64_decode_lstat(12, LStat) AS mtime,
251         base64_decode_lstat(13, LStat) AS ctime
252
253    FROM File INNER JOIN Filename USING (FilenameId)
254              INNER JOIN Path     USING (PathId)
255   WHERE Name  = $filename
256    AND  Path  = $path
257    AND  JobId = $jobid
258 ");
259
260     $attr->{filename} = $full_name;
261     $attr->{size} = Bweb::human_size($attr->{size});
262     foreach my $d (qw/atime ctime mtime/) {
263         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
264     }
265     return $attr;
266 }
267
268 sub fv_get_size
269 {
270     my ($jobid, $rep) = @_;
271
272     my $ret = $bweb->dbh_selectrow_hashref("
273  SELECT Size AS size
274    FROM brestore_pathvisibility
275   WHERE PathId = $rep
276     AND JobId = $jobid
277 ");
278
279     return $ret->{size};
280 }
281
282 sub fv_get_files_size
283 {
284     my ($jobid, $rep) = @_;
285
286     my $ret = $bweb->dbh_selectrow_hashref("
287  SELECT sum(base64_decode_lstat(8,LStat)) AS size
288    FROM File
289   WHERE PathId  = $rep
290     AND JobId = $jobid
291 ");
292
293     return $ret->{size};
294 }
295
296 sub fv_get_big_files
297 {
298     my ($jobid, $rep, $min, $limit) = @_;
299
300     my $ret = $bweb->dbh_selectall_arrayref("
301    SELECT Name, size
302    FROM (
303          SELECT FilenameId,base64_decode_lstat(8,LStat) AS size
304            FROM File
305           WHERE PathId  = $rep
306             AND JobId = $jobid
307         ) AS S INNER JOIN Filename USING (FilenameId)
308    WHERE S.size > $min
309    ORDER BY S.size DESC
310    LIMIT $limit
311 ");
312
313     return $ret;
314 }
315
316 sub fv_update_size
317 {
318     my ($jobid, $rep, $size) = @_;
319
320     my $nb = $bweb->dbh_do("
321  UPDATE brestore_pathvisibility SET Size = $size 
322   WHERE JobId = $jobid 
323     AND PathId = $rep 
324 ");
325
326     return $nb;
327 }
328
329 sub fv_get_root_pathid
330 {
331     my ($path) = @_;
332     $path = $bweb->dbh_quote($path);
333     my $ret = $bweb->dbh_selectrow_hashref("
334 SELECT PathId FROM Path WHERE Path = $path
335    UNION 
336 SELECT PathId FROM brestore_missing_path WHERE PATH = $path
337 ");
338     return $ret->{pathid};
339 }
340
341 __END__
342
343 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
344 DECLARE
345 val int8;
346 b64 varchar(64);
347 size varchar(64);
348 i int;
349 BEGIN
350 size := split_part($2, ' ', $1);
351 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
352 val := 0;
353 FOR i IN 1..length(size) LOOP
354 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
355 END LOOP;
356 RETURN val;
357 END;
358 $$ language 'plpgsql';
359
360 ALTER TABLE brestore_pathvisibility ADD Size  int8;
361
362
363
364 ALTER TABLE brestore_pathvisibility ADD Files int4;