X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=gui%2Fbweb%2Fcgi%2Fbresto.pl;h=df92a485990138cbdde7a556c8d5d8ea709c660f;hb=7e1317de9a79040f9d5fe721aa18da51c3ad5bda;hp=6a77af6c630ef39574ce10e67f01e938e838a1e1;hpb=c70d6b583c464a5e23c5ad9b348c8a22fe7d62e9;p=bacula%2Fbacula diff --git a/gui/bweb/cgi/bresto.pl b/gui/bweb/cgi/bresto.pl index 6a77af6c63..df92a48599 100755 --- a/gui/bweb/cgi/bresto.pl +++ b/gui/bweb/cgi/bresto.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -w - +use strict; my $bresto_enable = 1; die "bresto is not enabled" if (not $bresto_enable); @@ -13,25 +13,24 @@ die "bresto is not enabled" if (not $bresto_enable); The main author of Bweb is Eric Bollengier. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. - This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public - License as published by the Free Software Foundation plus additions - that are listed in the file LICENSE. + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Affero General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe - (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zurich, + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. =head1 VERSION @@ -51,12 +50,14 @@ sub get_root return $self->get_pathid(''); } +# change the current directory sub ch_dir { my ($self, $pathid) = @_; $self->{cwdid} = $pathid; } +# do a cd .. sub up_dir { my ($self) = @_ ; @@ -74,19 +75,19 @@ sub up_dir } } +# return the current PWD sub pwd { my ($self) = @_; return $self->get_path($self->{cwdid}); } +# get the Path from a PathId sub get_path { my ($self, $pathid) = @_; $self->debug("Call with pathid = $pathid"); - my $query = - "SELECT Path FROM Path WHERE PathId IN (?)"; - + my $query = "SELECT Path FROM Path WHERE PathId = ?"; my $sth = $self->dbh_prepare($query); $sth->execute($pathid); my $result = $sth->fetchrow_arrayref(); @@ -94,6 +95,7 @@ sub get_path return $result->[0]; } +# we are working with these jobids sub set_curjobids { my ($self, @jobids) = @_; @@ -101,6 +103,7 @@ sub set_curjobids # $self->update_brestore_table(@jobids); } +# get the PathId from a Path sub get_pathid { my ($self, $dir) = @_; @@ -108,10 +111,10 @@ sub get_pathid "SELECT PathId FROM Path WHERE Path = ?"; my $sth = $self->dbh_prepare($query); $sth->execute($dir); - my $result = $sth->fetchall_arrayref(); + my $result = $sth->fetchrow_arrayref(); $sth->finish(); - return join(',', map { $_->[0] } @$result); + return $result->[0]; } sub set_limits @@ -121,19 +124,32 @@ sub set_limits $self->{offset} = $offset || 0; } +sub set_pattern +{ + my ($self, $pattern) = @_; + $self->{pattern} = $pattern; +} + +# fill brestore_xxx tables for speedup sub update_cache { my ($self) = @_; $self->{dbh}->begin_work(); + # getting all Jobs to "cache" my $query = " SELECT JobId from Job - WHERE JobId NOT IN (SELECT JobId FROM brestore_knownjobid) AND JobStatus IN ('T', 'f', 'A') ORDER BY JobId"; + WHERE JobId NOT IN (SELECT JobId FROM brestore_knownjobid) + AND Type IN ('B') AND JobStatus IN ('T', 'f', 'A') + ORDER BY JobId"; my $jobs = $self->dbh_selectall_arrayref($query); $self->update_brestore_table(map { $_->[0] } @$jobs); + $self->{dbh}->commit(); + $self->{dbh}->begin_work(); # we can break here + print STDERR "Cleaning path visibility\n"; my $nb = $self->dbh_do(" @@ -224,6 +240,7 @@ INSERT INTO brestore_pathvisibility (PathId, JobId) ( } } +# compute the parent directory sub parent_dir { my ($path) = @_; @@ -326,6 +343,7 @@ sub return_pathid_from_path } } +# list all files in a directory, accross curjobids sub ls_files { my ($self) = @_; @@ -333,7 +351,11 @@ sub ls_files return undef unless ($self->{curjobids}); my $inclause = $self->{curjobids}; - my $inlistpath = $self->{cwdid}; + my $inpath = $self->{cwdid}; + my $filter = ''; + if ($self->{pattern}) { + $filter = " AND Filename.Name $self->{sql}->{MATCH} $self->{pattern} "; + } my $query = "SELECT File.FilenameId, listfiles.id, listfiles.Name, File.LStat, File.JobId @@ -342,12 +364,15 @@ sub ls_files FROM File, Filename WHERE File.FilenameId = Filename.FilenameId AND Filename.Name != '' - AND File.PathId IN ($inlistpath) + AND File.PathId = $inpath AND File.JobId IN ($inclause) + $filter GROUP BY Filename.Name - ORDER BY Filename.Name) AS listfiles + ORDER BY Filename.Name LIMIT $self->{limit} OFFSET $self->{offset} + ) AS listfiles WHERE File.FileId = listfiles.id"; +# print STDERR $query; $self->debug($query); my $result = $self->dbh_selectall_arrayref($query); $self->debug($result); @@ -355,53 +380,119 @@ WHERE File.FileId = listfiles.id"; return $result; } - -# return ($dirid,$dir_basename,$lstat,$jobid) -sub ls_dirs +sub ls_special_dirs { my ($self) = @_; - return undef unless ($self->{curjobids}); my $pathid = $self->{cwdid}; my $jobclause = $self->{curjobids}; + my $dir_filenameid = $self->get_dir_filenameid(); + + my $sq1 = +"((SELECT PPathId AS PathId, '..' AS Path + FROM brestore_pathhierarchy + WHERE PathId = $pathid) +UNION + (SELECT $pathid AS PathId, '.' AS Path))"; + + my $sq2 = " +SELECT tmp.PathId, tmp.Path, LStat, JobId + FROM $sq1 AS tmp LEFT JOIN ( -- get attributes if any + SELECT File1.PathId, File1.JobId, File1.LStat FROM File AS File1 + WHERE File1.FilenameId = $dir_filenameid + AND File1.JobId IN ($jobclause)) AS listfile1 + ON (tmp.PathId = listfile1.PathId) + ORDER BY tmp.Path, JobId DESC +"; - # Let's retrieve the list of the visible dirs in this dir ... - # First, I need the empty filenameid to locate efficiently the dirs in the file table + my $result = $self->dbh_selectall_arrayref($sq2); + + my @return_list; + my $prev_dir=''; + foreach my $refrow (@{$result}) + { + my $dirid = $refrow->[0]; + my $dir = $refrow->[1]; + my $lstat = $refrow->[3]; + my $jobid = $refrow->[2] || 0; + next if ($dirid eq $prev_dir); + my @return_array = ($dirid,$dir,$lstat,$jobid); + push @return_list,(\@return_array); + $prev_dir = $dirid; + } + + return \@return_list; +} + +# Let's retrieve the list of the visible dirs in this dir ... +# First, I need the empty filenameid to locate efficiently +# the dirs in the file table +sub get_dir_filenameid +{ + my ($self) = @_; + if ($self->{dir_filenameid}) { + return $self->{dir_filenameid}; + } my $query = "SELECT FilenameId FROM Filename WHERE Name = ''"; my $sth = $self->dbh_prepare($query); $sth->execute(); my $result = $sth->fetchrow_arrayref(); $sth->finish(); - my $dir_filenameid = $result->[0]; + return $self->{dir_filenameid} = $result->[0]; +} + +# list all directories in a directory, accross curjobids +# return ($dirid,$dir_basename,$lstat,$jobid) +sub ls_dirs +{ + my ($self) = @_; + + return undef unless ($self->{curjobids}); + + my $pathid = $self->{cwdid}; + my $jobclause = $self->{curjobids}; + my $filter =''; + + if ($self->{pattern}) { + $filter = " AND Path2.Path $self->{sql}->{MATCH} $self->{pattern} "; + } + + # Let's retrieve the list of the visible dirs in this dir ... + # First, I need the empty filenameid to locate efficiently + # the dirs in the file table + my $dir_filenameid = $self->get_dir_filenameid(); # Then we get all the dir entries from File ... - $query = " -SELECT PathId, Path, JobId, Lstat FROM ( + my $query = " +SELECT PathId, Path, JobId, LStat FROM ( SELECT Path1.PathId, Path1.Path, lower(Path1.Path), - listfile1.JobId, listfile1.Lstat + listfile1.JobId, listfile1.LStat FROM ( - SELECT DISTINCT brestore_pathhierarchy1.PathId - FROM brestore_pathhierarchy AS brestore_pathhierarchy1 - JOIN Path AS Path2 - ON (brestore_pathhierarchy1.PathId = Path2.PathId) - JOIN brestore_pathvisibility AS brestore_pathvisibility1 - ON (brestore_pathhierarchy1.PathId = brestore_pathvisibility1.PathId) - WHERE brestore_pathhierarchy1.PPathId = $pathid - AND brestore_pathvisibility1.jobid IN ($jobclause)) AS listpath1 - JOIN Path AS Path1 ON (listpath1.PathId = Path1.PathId) - LEFT JOIN ( - SELECT File1.PathId, File1.JobId, File1.Lstat FROM File AS File1 - WHERE File1.FilenameId = $dir_filenameid - AND File1.JobId IN ($jobclause)) AS listfile1 - ON (listpath1.PathId = listfile1.PathId) - ) AS A ORDER BY 2,3 DESC + SELECT DISTINCT brestore_pathhierarchy1.PathId + FROM brestore_pathhierarchy AS brestore_pathhierarchy1 + JOIN Path AS Path2 + ON (brestore_pathhierarchy1.PathId = Path2.PathId) + JOIN brestore_pathvisibility AS brestore_pathvisibility1 + ON (brestore_pathhierarchy1.PathId = brestore_pathvisibility1.PathId) + WHERE brestore_pathhierarchy1.PPathId = $pathid + AND brestore_pathvisibility1.jobid IN ($jobclause) + $filter + ) AS listpath1 + JOIN Path AS Path1 ON (listpath1.PathId = Path1.PathId) + + LEFT JOIN ( -- get attributes if any + SELECT File1.PathId, File1.JobId, File1.LStat FROM File AS File1 + WHERE File1.FilenameId = $dir_filenameid + AND File1.JobId IN ($jobclause)) AS listfile1 + ON (listpath1.PathId = listfile1.PathId) + ) AS A ORDER BY 2,3 DESC LIMIT $self->{limit} OFFSET $self->{offset} "; - $self->debug($query); - $sth=$self->dbh_prepare($query); +# print STDERR $query; + my $sth=$self->dbh_prepare($query); $sth->execute(); - $result = $sth->fetchall_arrayref(); + my $result = $sth->fetchall_arrayref(); my @return_list; my $prev_dir=''; foreach my $refrow (@{$result}) @@ -512,14 +603,18 @@ sub dbh_selectrow_arrayref # there will be only one jobid in the array of jobids... sub get_all_file_versions { - my ($self,$pathid,$fileid,$client,$see_all)=@_; + my ($self,$pathid,$fileid,$client,$see_all,$see_copies)=@_; defined $see_all or $see_all=0; + my $backup_type=" AND Job.Type = 'B' "; + if ($see_copies) { + $backup_type=" AND Job.Type IN ('C', 'B') "; + } my @versions; my $query; $query = -"SELECT File.JobId, File.FileId, File.Lstat, +"SELECT File.JobId, File.FileId, File.LStat, File.Md5, Media.VolumeName, Media.InChanger FROM File, Job, Client, JobMedia, Media WHERE File.FilenameId = $fileid @@ -530,7 +625,9 @@ sub get_all_file_versions AND File.FileIndex >= JobMedia.FirstIndex AND File.FileIndex <= JobMedia.LastIndex AND JobMedia.MediaId = Media.MediaId - AND Client.Name = '$client'"; + AND Client.Name = '$client' + $backup_type +"; $self->debug($query); my $result = $self->dbh_selectall_arrayref($query); @@ -549,7 +646,7 @@ sub get_all_file_versions } # We have the list of all versions of this file. - # We'll sort it by mtime desc, size, md5, inchanger desc + # We'll sort it by mtime desc, size, md5, inchanger desc, FileId # the rest of the algorithm will be simpler # ('FILE:',filename,jobid,fileindex,mtime,size,inchanger,md5,volname) @versions = sort { $b->[4] <=> $a->[4] @@ -577,7 +674,7 @@ sub get_all_file_versions # we never met this one before... $allready_seen_by_md5{$ref->[7] .'-'. $ref->[5]}=1; } - # Even if it has a md5, we should also work with mtimes + # Even if it has a md5, we should also work with mtimes # We allready have a (better) version next if ( (not $see_all) and $allready_seen_by_mtime{$ref->[4] .'-'. $ref->[5]}); @@ -704,6 +801,7 @@ sub get_all_file_versions } } +# get jobids that the current user can view (ACL) sub get_jobids { my ($self, @jobid) = @_; @@ -725,6 +823,7 @@ SELECT JobId package main; use strict; +use POSIX qw/strftime/; use Bweb; my $conf = new Bweb::Config(config_file => $Bweb::config_file); @@ -736,31 +835,36 @@ $bvfs->connect_db(); my $action = CGI::param('action') || ''; my $args = $bvfs->get_form('pathid', 'filenameid', 'fileid', 'qdate', - 'limit', 'offset', 'client'); + 'limit', 'offset', 'client', 'qpattern'); -if (CGI::param('batch')) { +if ($action eq 'batch') { $bvfs->update_cache(); exit 0; } -if ($action eq 'list_client') { - print CGI::header('application/x-javascript'); +# All these functions are returning JSON compatible data +# for javascript parsing - my $filter = $bvfs->get_client_filter(); - my $q = "SELECT Name FROM Client $filter"; - my $ret = $bvfs->dbh_selectall_arrayref($q); +if ($action eq 'list_client') { # list all client [ ['c1'],['c2']..] + print CGI::header('application/x-javascript'); - print "["; - print join(',', map { "['$_->[0]']" } @$ret); - print "]\n"; - exit 0; + my $filter = $bvfs->get_client_filter(); + my $q = "SELECT Name FROM Client $filter"; + my $ret = $bvfs->dbh_selectall_arrayref($q); + print "["; + print join(',', map { "['$_->[0]']" } @$ret); + print "]\n"; + exit 0; + } elsif ($action eq 'list_job') { - print CGI::header('application/x-javascript'); + # list jobs for a client [[jobid,endtime,'desc'],..] + print CGI::header('application/x-javascript'); + my $filter = $bvfs->get_client_filter(); my $query = " - SELECT Job.EndTime, FileSet.FileSet, Job.Level, Job.JobStatus, Job.JobId + SELECT Job.JobId,Job.EndTime, FileSet.FileSet, Job.Level, Job.JobStatus FROM Job JOIN FileSet USING (FileSetId) JOIN Client USING (ClientId) $filter WHERE Client.Name = '$args->{client}' AND Job.Type = 'B' @@ -771,12 +875,12 @@ if ($action eq 'list_client') { print "["; print join(',', map { - "[$_->[4], '$_->[0]', '$_->[0] $_->[1] $_->[2] ($_->[3]) $_->[4]']" + "[$_->[0], '$_->[1]', '$_->[1] $_->[2] $_->[3] ($_->[4]) $_->[0]']" } @$result); print "]\n"; exit 0; -} elsif ($action eq 'list_storage') { # TODO: use .storage hier +} elsif ($action eq 'list_storage') { # TODO: use .storage here print CGI::header('application/x-javascript'); my $q="SELECT Name FROM Storage"; @@ -787,22 +891,129 @@ if ($action eq 'list_client') { exit 0; } +sub fill_table_for_restore +{ + my (@jobid) = @_; + + # in "force" mode, we need the FileId to compute media list + my $FileId = CGI::param('force')?",FileId":""; + + my $fileid = join(',', grep { /^\d+$/ } CGI::param('fileid')); + # can get dirid=("10,11", 10, 11) + my @dirid = grep { /^\d+$/ } map { split(/,/) } CGI::param('dirid') ; + my $inclause = join(',', @jobid); + + my @union; + + if ($fileid) { + push @union, + "(SELECT JobId, FileIndex, FilenameId, PathId $FileId + FROM File WHERE FileId IN ($fileid))"; + } + + foreach my $dirid (@dirid) { + my $p = $bvfs->get_path($dirid); + $p =~ s/([%_\\])/\\$1/g; # Escape % and _ for LIKE search + $p = $bvfs->dbh_quote($p); + push @union, " + (SELECT File.JobId, File.FileIndex, File.FilenameId, File.PathId $FileId + FROM Path JOIN File USING (PathId) + WHERE Path.Path LIKE " . $bvfs->dbh_strcat($p, "'%'") . " + AND File.JobId IN ($inclause))"; + } + + return unless scalar(@union); + + my $u = join(" UNION ", @union); + + $bvfs->dbh_do("CREATE TEMPORARY TABLE btemp AS $u"); + # TODO: remove FilenameId et PathId + + # now we have to choose the file with the max(jobid) + # for each file of btemp + if ($bvfs->dbh_is_mysql()) { + $bvfs->dbh_do("CREATE TABLE b2$$ AS ( +SELECT max(JobId) as JobId, FileIndex $FileId + FROM btemp + GROUP BY PathId, FilenameId + HAVING FileIndex > 0 +)"); + } else { # postgresql have distinct with more than one criteria + $bvfs->dbh_do("CREATE TABLE b2$$ AS ( +SELECT JobId, FileIndex $FileId +FROM ( + SELECT DISTINCT ON (PathId, FilenameId) JobId, FileIndex $FileId + FROM btemp + ORDER BY PathId, FilenameId, JobId DESC + ) AS T + WHERE FileIndex > 0 +)"); + } + + return "b2$$"; +} + +sub get_media_list_with_dir +{ + my ($table) = @_; + my $q=" + SELECT DISTINCT VolumeName, Enabled, InChanger + FROM $table, + ( -- Get all media from this job + SELECT MIN(FirstIndex) AS FirstIndex, MAX(LastIndex) AS LastIndex, + VolumeName, Enabled, Inchanger + FROM JobMedia JOIN Media USING (MediaId) + WHERE JobId IN (SELECT DISTINCT JobId FROM $table) + GROUP BY VolumeName,Enabled,InChanger + ) AS allmedia + WHERE $table.FileIndex >= allmedia.FirstIndex + AND $table.FileIndex <= allmedia.LastIndex +"; + my $lst = $bvfs->dbh_selectall_arrayref($q); + return $lst; +} + +sub get_media_list +{ + my ($jobid, $fileid) = @_; + my $q=" + SELECT DISTINCT VolumeName, Enabled, InChanger + FROM File, + ( -- Get all media from this job + SELECT MIN(FirstIndex) AS FirstIndex, MAX(LastIndex) AS LastIndex, + VolumeName, Enabled, Inchanger + FROM JobMedia JOIN Media USING (MediaId) + WHERE JobId IN ($jobid) + GROUP BY VolumeName,Enabled,InChanger + ) AS allmedia + WHERE File.FileId IN ($fileid) + AND File.FileIndex >= allmedia.FirstIndex + AND File.FileIndex <= allmedia.LastIndex +"; + my $lst = $bvfs->dbh_selectall_arrayref($q); + return $lst; +} + +# get jobid param and apply user filter my @jobid = $bvfs->get_jobids(grep { /^\d+(,\d+)*$/ } CGI::param('jobid')); + +# get jobid from date arg if (!scalar(@jobid) and $args->{qdate} and $args->{client}) { @jobid = $bvfs->set_job_ids_for_date($args->{client}, $args->{qdate}); } + $bvfs->set_curjobids(@jobid); -$bvfs->set_limits($args->{limit}, $args->{offset}); +$bvfs->set_limits($args->{offset}, $args->{limit}); if (!scalar(@jobid)) { exit 0; } -if (CGI::param('init')) { +if (CGI::param('init')) { # used when choosing a job $bvfs->update_brestore_table(@jobid); } -my $pathid = CGI::param('node') || ''; +my $pathid = CGI::param('node') || CGI::param('pathid') || ''; my $path = CGI::param('path'); if ($pathid =~ /^(\d+)$/) { @@ -812,9 +1023,15 @@ if ($pathid =~ /^(\d+)$/) { } else { $pathid = $bvfs->get_root(); } - $bvfs->ch_dir($pathid); +#print STDERR "pathid=$pathid\n"; + +# permit to use a regex filter +if ($args->{qpattern}) { + $bvfs->set_pattern($args->{qpattern}); +} + if ($action eq 'restore') { # TODO: pouvoir choisir le replace et le jobname @@ -825,48 +1042,11 @@ if ($action eq 'restore') { exit 1; } - my $fileid = join(',', grep { /^\d+$/ } CGI::param('fileid')); - my @dirid = grep { /^\d+$/ } CGI::param('dirid'); - my $inclause = join(',', @jobid); - - my @union; - - if ($fileid) { - push @union, - "(SELECT JobId, FileIndex, FilenameId, PathId FROM File WHERE FileId IN ($fileid))"; + my $table = fill_table_for_restore(@jobid); + if (!$table) { + exit 1; } - # using this is not good because the sql engine doesn't know - # what LIKE will use. It will be better to get Path% in perl - # but it doesn't work with accents... :( - foreach my $dirid (@dirid) { - push @union, " - (SELECT File.JobId, File.FileIndex, File.FilenameId, File.PathId - FROM Path JOIN File USING (PathId) - WHERE Path.Path LIKE - (SELECT ". $bvfs->dbh_strcat('Path',"'\%'") ." FROM Path - WHERE PathId = $dirid - ) - AND File.JobId IN ($inclause))"; - } - - return unless scalar(@union); - - my $u = join(" UNION ", @union); - - $bvfs->dbh_do("CREATE TEMPORARY TABLE btemp AS ($u)"); - # TODO: remove FilenameId et PathId - $bvfs->dbh_do("CREATE TABLE b2$$ AS ( -SELECT btemp.JobId, btemp.FileIndex, btemp.FilenameId, btemp.PathId - FROM btemp, - (SELECT max(JobId) as JobId, PathId, FilenameId - FROM btemp - GROUP BY PathId, FilenameId - ORDER BY JobId DESC) AS a - WHERE a.JobId = btemp.JobId - AND a.PathId= btemp.PathId - AND a.FilenameId = btemp.FilenameId -)"); my $bconsole = $bvfs->get_bconsole(); # TODO: pouvoir choisir le replace et le jobname my $jobid = $bconsole->run(client => $arg->{client}, @@ -874,37 +1054,131 @@ SELECT btemp.JobId, btemp.FileIndex, btemp.FilenameId, btemp.PathId where => $arg->{where}, regexwhere=> $arg->{regexwhere}, restore => 1, - file => "?b2$$"); + file => "?$table"); - $bvfs->dbh_do("DROP TABLE b2$$"); + $bvfs->dbh_do("DROP TABLE $table"); + + if (!$jobid) { + print CGI::header('text/html'); + $bvfs->display_begin(); + $bvfs->error("Can't start your job:
" . $bconsole->before()); + $bvfs->display_end(); + exit 0; + } sleep(2); print CGI::redirect("bweb.pl?action=dsp_cur_job;jobid=$jobid") ; exit 0; } +sub escape_quote +{ + my ($str) = @_; + my %esc = ( + "\n" => '\n', + "\r" => '\r', + "\t" => '\t', + "\f" => '\f', + "\b" => '\b', + "\"" => '\"', + "\\" => '\\\\', + "\'" => '\\\'', + ); + + if (!$str) { + return ''; + } + + $str =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/g; + $str =~ s/\//\\\//g; + $str =~ s/([\x00-\x08\x0b\x0e-\x1f])/'\\u00' . unpack('H2', $1)/eg; + return $str; +} print CGI::header('application/x-javascript'); -if ($action eq 'list_files') { - print "["; + +if ($action eq 'list_files_dirs') { +# fileid, filenameid, pathid, jobid, name, size, mtime + my $jids = join(",", @jobid); + + my $files = $bvfs->ls_special_dirs(); + # return ($dirid,$dir_basename,$lstat,$jobid) + print "[\n"; + print join(',', + map { my @p=Bvfs::parse_lstat($_->[3]); + '[' . join(',', + 0, # fileid + 0, # filenameid + $_->[0], # pathid + "'$jids'", # jobid + '"' . escape_quote($_->[1]) . '"', # name + "'" . $p[7] . "'", # size + "'" . strftime('%Y-%m-%d %H:%m:%S', localtime($p[11]||0)) . "'") . + ']'; + } @$files); + print "," if (@$files); + + $files = $bvfs->ls_dirs(); + # return ($dirid,$dir_basename,$lstat,$jobid) + print join(',', + map { my @p=Bvfs::parse_lstat($_->[3]); + '[' . join(',', + 0, # fileid + 0, # filenameid + $_->[0], # pathid + "'$jids'", # jobid + '"' . escape_quote($_->[1]) . '"', # name + "'" . $p[7] . "'", # size + "'" . strftime('%Y-%m-%d %H:%m:%S', localtime($p[11]||0)) . "'") . + ']'; + } @$files); + + print "," if (@$files); + + $files = $bvfs->ls_files(); + print join(',', + map { my @p=Bvfs::parse_lstat($_->[3]); + '[' . join(',', + $_->[1], + $_->[0], + $pathid, + $_->[4], + '"' . escape_quote($_->[2]) . '"', # name + "'" . $p[7] . "'", + "'" . strftime('%Y-%m-%d %H:%m:%S', localtime($p[11])) . "'") . + ']'; + } @$files); + print "]\n"; + +} elsif ($action eq 'list_files') { + print "[[0,0,0,0,'.',4096,'1970-01-01 00:00:00'],"; my $files = $bvfs->ls_files(); # [ 1, 2, 3, "Bill", 10, '2007-01-01 00:00:00'], # File.FilenameId, listfiles.id, listfiles.Name, File.LStat, File.JobId print join(',', - map { "[$_->[1], $_->[0], $pathid, $_->[4], \"$_->[2]\", 10, \"2007-01-01 00:00:00\"]" } - @$files); + map { my @p=Bvfs::parse_lstat($_->[3]); + '[' . join(',', + $_->[1], + $_->[0], + $pathid, + $_->[4], + '"' . escape_quote($_->[2]) . '"', # name + "'" . $p[7] . "'", + "'" . strftime('%Y-%m-%d %H:%m:%S', localtime($p[11])) . "'") . + ']'; + } @$files); print "]\n"; } elsif ($action eq 'list_dirs') { print "["; my $dirs = $bvfs->ls_dirs(); - # return ($dirid,$dir_basename,$lstat,$jobid) + # return ($dirid,$dir_basename,$lstat,$jobid) print join(',', - map { "{ 'jobid': '$bvfs->{curjobids}', 'id': '$_->[0]', 'text': '$_->[1]', 'cls':'folder'}" } + map { "{ 'jobid': '$bvfs->{curjobids}', 'id': '$_->[0]'," . + "'text': '" . escape_quote($_->[1]) . "', 'cls':'folder'}" } @$dirs); - print "]\n"; } elsif ($action eq 'list_versions') { @@ -912,39 +1186,51 @@ if ($action eq 'list_files') { my $vafv = CGI::param('vafv') || 'false'; # view all file versions $vafv = ($vafv eq 'false')?0:1; + my $vcopies = CGI::param('vcopies') || 'false'; # view copies file versions + $vcopies = ($vcopies eq 'false')?0:1; + print "["; #  0 1 2 3 4 5 6 7 8 #($pathid,$fileid,$jobid, $fid, $mtime, $size, $inchanger, $md5, $volname); - my $files = $bvfs->get_all_file_versions($args->{pathid}, $args->{filenameid}, $args->{client}, $vafv); + my $files = $bvfs->get_all_file_versions($args->{pathid}, $args->{filenameid}, $args->{client}, $vafv, $vcopies); print join(',', - map { "[ $_->[3], $_->[1], $_->[0], $_->[2], '$_->[8]', $_->[6], '$_->[7]', $_->[5], $_->[4] ]" } + map { "[ $_->[3], $_->[1], $_->[0], $_->[2], '$_->[8]', $_->[6], '$_->[7]', $_->[5],'" . strftime('%Y-%m-%d %H:%m:%S', localtime($_->[4])) . "']" } @$files); print "]\n"; +# this action is used when the restore box appear, we can display +# the media list that will be needed for restore } elsif ($action eq 'get_media') { + my ($jobid, $fileid, $table); + my $lst; + + # in this mode, we compute the result to get all needed media +# print STDERR "force=", CGI::param('force'), "\n"; + if (CGI::param('force')) { + $table = fill_table_for_restore(@jobid); + if (!$table) { + exit 1; + } + # mysql is very slow without this index... + if ($bvfs->dbh_is_mysql()) { + $bvfs->dbh_do("CREATE INDEX idx_$table ON $table (JobId)"); + } + $lst = get_media_list_with_dir($table); + } else { + $jobid = join(',', @jobid); + $fileid = join(',', grep { /^\d+(,\d+)*$/ } CGI::param('fileid')); + $lst = get_media_list($jobid, $fileid); + } + + if ($lst) { + print "["; + print join(',', map { "['$_->[0]',$_->[1],$_->[2]]" } @$lst); + print "]\n"; + } - my $jobid = join(',', @jobid); - my $fileid = join(',', grep { /^\d+$/ } CGI::param('fileid')); - - # TODO: use client filter - my $q=" - SELECT DISTINCT VolumeName, InChanger - FROM File, - ( -- Get all media from this job - SELECT MIN(FirstIndex) AS FirstIndex, MAX(LastIndex) AS LastIndex, - VolumeName, Inchanger - FROM JobMedia JOIN Media USING (MediaId) - WHERE JobId IN ($jobid) - GROUP BY VolumeName, InChanger - ) AS allmedia - WHERE File.FileId IN ($fileid) - AND File.FileIndex >= allmedia.FirstIndex - AND File.FileIndex <= allmedia.LastIndex -"; - my $lst = $bvfs->dbh_selectall_arrayref($q); - print "["; - print join(',', map { "[ '$_->[0]', $_->[1]]" } @$lst); - print "]\n"; + if ($table) { + $bvfs->dbh_do("DROP TABLE $table"); + } }