]> git.sur5r.net Git - bacula/bacula/blob - gui/bweb/cgi/bfileview.pl
bweb: Update some GPL2 notice to AGPL
[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    Affero 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 Kern Sibbald.
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 "<br/>
175  <form action='$url_action' method='get'>
176   <div align='left'>
177    <input title='jobids' type='hidden' name='jobid' value='$jobid'>
178    <input title='directory' 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     $limit = int($limit);
374
375     my $ret = $bweb->dbh_selectall_arrayref("
376    SELECT FilenameId AS filenameid, Name AS name, size
377    FROM (
378          SELECT FilenameId, base64_decode_lstat(8,LStat) AS size
379            FROM File
380           WHERE PathId  = $rep
381             AND JobId = $jobid
382         ) AS S INNER JOIN Filename USING (FilenameId)
383    WHERE S.size > $min
384    ORDER BY S.size DESC
385    LIMIT $limit
386 ");
387
388     return $ret;
389 }
390
391 sub fv_update_size
392 {
393     my ($jobid, $rep, $size) = @_;
394
395     my $nb = $bweb->dbh_do("
396  UPDATE brestore_pathvisibility SET Size = $size 
397   WHERE JobId = $jobid 
398     AND PathId = $rep 
399 ");
400
401     return $nb;
402 }
403
404 sub fv_get_root_pathid
405 {
406     my ($path) = @_;
407     $path = $bweb->dbh_quote($path);
408     my $ret = $bweb->dbh_selectrow_hashref("SELECT PathId FROM Path WHERE Path = $path");
409     return $ret->{pathid};
410 }
411
412 sub fv_get_root_path
413 {
414     my ($pathid) = @_;
415     my $ret = $bweb->dbh_selectrow_hashref("SELECT Path FROM Path WHERE PathId = $pathid");
416     return $ret->{path};
417 }
418
419
420 __END__
421
422 CREATE OR REPLACE FUNCTION base64_decode_lstat(int4, varchar) RETURNS int8 AS $$
423 DECLARE
424 val int8;
425 b64 varchar(64);
426 size varchar(64);
427 i int;
428 BEGIN
429 size := split_part($2, ' ', $1);
430 b64 := 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
431 val := 0;
432 FOR i IN 1..length(size) LOOP
433 val := val + (strpos(b64, substr(size, i, 1))-1) * (64^(length(size)-i));
434 END LOOP;
435 RETURN val;
436 END;
437 $$ language 'plpgsql';
438
439 ALTER TABLE brestore_pathvisibility ADD Size  int8;
440
441
442
443 ALTER TABLE brestore_pathvisibility ADD Files int4;