]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bfileview.pl
7196ea7ac781d9bf3e1eae595c57b96566a5e92f
[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 } else {
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     # default to /
285     my $path = "'/'";
286     my $filename = "''";
287     
288     if ($full_name ne '/') {
289         $filename = $bweb->dbh_quote(basename($full_name));
290         $path     = $bweb->dbh_quote(dirname($full_name) . "/");
291     }
292
293     my $attr = $bweb->dbh_selectrow_hashref("
294  SELECT 1    AS found,
295         MD5  AS md5,
296         base64_decode_lstat(8,  LStat) AS size,
297         base64_decode_lstat(11, LStat) AS atime,
298         base64_decode_lstat(12, LStat) AS mtime,
299         base64_decode_lstat(13, LStat) AS ctime
300
301    FROM File JOIN Filename USING (FilenameId)
302              JOIN Path     USING (PathId)
303   WHERE Name  = $filename
304    AND  Path  = $path
305    AND  JobId = $jobid
306 ");
307
308     $attr->{filename} = $full_name;
309     $attr->{size} = Bweb::human_size($attr->{size});
310     foreach my $d (qw/atime ctime mtime/) {
311         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
312     }
313     return $attr;
314 }
315
316
317 sub fv_get_file_attribute_from_id
318 {
319     my ($jobid, $pathid, $filenameid) = @_;
320     
321     my $attr = $bweb->dbh_selectrow_hashref("
322  SELECT 1    AS found,
323         MD5  AS md5,
324         base64_decode_lstat(8,  LStat) AS size,
325         base64_decode_lstat(11, LStat) AS atime,
326         base64_decode_lstat(12, LStat) AS mtime,
327         base64_decode_lstat(13, LStat) AS ctime,
328         Path.Path ||  Filename.Name AS filename
329
330    FROM File INNER JOIN Filename USING (FilenameId)
331              INNER JOIN Path     USING (PathId)
332   WHERE FilenameId  = $filenameid
333    AND  PathId  = $pathid
334    AND  JobId = $jobid
335 ");
336
337     $attr->{size} = Bweb::human_size($attr->{size});
338     foreach my $d (qw/atime ctime mtime/) {
339         $attr->{$d} = strftime('%F %H:%M', localtime($attr->{$d}));
340     }
341     return $attr;
342 }
343
344 sub fv_get_size
345 {
346     my ($jobid, $rep) = @_;
347
348     my $ret = $bweb->dbh_selectrow_hashref("
349  SELECT Size AS size
350    FROM brestore_pathvisibility
351   WHERE PathId = $rep
352     AND JobId = $jobid
353 ");
354
355     return $ret->{size};
356 }
357
358 sub fv_get_files_size
359 {
360     my ($jobid, $rep) = @_;
361
362     my $ret = $bweb->dbh_selectrow_hashref("
363  SELECT sum(base64_decode_lstat(8,LStat)) AS size
364    FROM File
365   WHERE PathId  = $rep
366     AND JobId = $jobid
367 ");
368
369     return $ret->{size};
370 }
371
372 sub fv_get_big_files
373 {
374     my ($jobid, $rep, $min, $limit) = @_;
375
376     my $ret = $bweb->dbh_selectall_arrayref("
377    SELECT FilenameId AS filenameid, Name AS name, size
378    FROM (
379          SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
380            FROM File
381           WHERE PathId  = $rep
382             AND JobId = $jobid
383         ) AS S INNER JOIN Filename USING (FilenameId)
384    WHERE S.size > $min
385    ORDER BY S.size DESC
386    LIMIT $limit
387 ");
388
389     return $ret;
390 }
391
392 sub fv_update_size
393 {
394     my ($jobid, $rep, $size) = @_;
395
396     my $nb = $bweb->dbh_do("
397  UPDATE brestore_pathvisibility SET Size = $size 
398   WHERE JobId = $jobid 
399     AND PathId = $rep 
400 ");
401
402     return $nb;
403 }
404
405 sub fv_get_root_pathid
406 {
407     my ($path) = @_;
408     $path = $bweb->dbh_quote($path);
409     my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
410     return $ret->{pathid};
411 }
412
413 sub fv_get_root_path
414 {
415     my ($pathid) = @_;
416     my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
417     return $ret->{path};
418 }
419
420
421 __END__
422
423 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
424 DECLARE
425 val int8;
426 b64 varchar(64);
427 size varchar(64);
428 i int;
429 BEGIN
430 size := split_part($2, ' ', $1);
431 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
432 val := 0;
433 FOR i IN 1..length(size) LOOP
434 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
435 END LOOP;
436 RETURN val;
437 END;
438 $$ language 'plpgsql';
439
440 ALTER TABLE brestore_pathvisibility ADD Size  int8;
441
442
443
444 ALTER TABLE brestore_pathvisibility ADD Files int4;