#!/usr/bin/perl -w
-
+use strict;
my $bresto_enable = 1;
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
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) = @_ ;
}
}
+# 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();
return $result->[0];
}
+# we are working with these jobids
sub set_curjobids
{
my ($self, @jobids) = @_;
# $self->update_brestore_table(@jobids);
}
+# get the PathId from a Path
sub get_pathid
{
my ($self, $dir) = @_;
"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
$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("
print STDERR "Creating missing recursion paths for $job\n";
- $query = "SELECT brestore_pathvisibility.PathId, Path FROM brestore_pathvisibility
- JOIN Path ON( brestore_pathvisibility.PathId = Path.PathId)
- LEFT JOIN brestore_pathhierarchy ON (brestore_pathvisibility.PathId = brestore_pathhierarchy.PathId)
- WHERE brestore_pathvisibility.JobId = $job
- AND brestore_pathhierarchy.PathId IS NULL
- ORDER BY Path";
+ $query = "
+SELECT brestore_pathvisibility.PathId, Path FROM brestore_pathvisibility
+ JOIN Path ON( brestore_pathvisibility.PathId = Path.PathId)
+ LEFT JOIN brestore_pathhierarchy ON (brestore_pathvisibility.PathId = brestore_pathhierarchy.PathId)
+ WHERE brestore_pathvisibility.JobId = $job
+ AND brestore_pathhierarchy.PathId IS NULL
+ ORDER BY Path";
my $sth = $self->dbh_prepare($query);
$sth->execute();
# This query gives all parent pathids for a given jobid that aren't stored.
# It has to be called until no record is updated ...
$query = "
- INSERT INTO brestore_pathvisibility (PathId, JobId) (
- SELECT a.PathId,$job
- FROM
- (SELECT DISTINCT h.PPathId AS PathId
- FROM brestore_pathhierarchy AS h
- JOIN brestore_pathvisibility AS p ON (h.PathId=p.PathId)
- WHERE p.JobId=$job) AS a
- LEFT JOIN
- (SELECT PathId
- FROM brestore_pathvisibility
- WHERE JobId=$job) AS b
- ON (a.PathId = b.PathId)
- WHERE b.PathId IS NULL)";
+INSERT INTO brestore_pathvisibility (PathId, JobId) (
+ SELECT a.PathId,$job
+ FROM (
+ SELECT DISTINCT h.PPathId AS PathId
+ FROM brestore_pathhierarchy AS h
+ JOIN brestore_pathvisibility AS p ON (h.PathId=p.PathId)
+ WHERE p.JobId=$job) AS a LEFT JOIN
+ (SELECT PathId
+ FROM brestore_pathvisibility
+ WHERE JobId=$job) AS b ON (a.PathId = b.PathId)
+ WHERE b.PathId IS NULL)";
my $rows_affected;
while (($rows_affected = $self->dbh_do($query)) and ($rows_affected !~ /^0/))
}
}
+# compute the parent directory
sub parent_dir
{
my ($path) = @_;
}
}
+# list all files in a directory, accross curjobids
sub ls_files
{
my ($self) = @_;
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
- FROM
- (SELECT Filename.Name, max(File.FileId) as id
+ FROM File, (
+ SELECT Filename.Name, max(File.FileId) as id
FROM File, Filename
- WHERE File.FilenameId = Filename.FilenameId
- AND Filename.Name != ''
- AND File.PathId IN ($inlistpath)
- AND File.JobId IN ($inclause)
- GROUP BY Filename.Name
- ORDER BY Filename.Name) AS listfiles,
-File
+ WHERE File.FilenameId = Filename.FilenameId
+ AND Filename.Name != ''
+ AND File.PathId = $inpath
+ AND File.JobId IN ($inclause)
+ $filter
+ GROUP BY Filename.Name
+ 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);
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})
# incrementals and differentials until we have found a full so it goes
# like this : store all incrementals until we have found a differential
# or a full, then find the full
- my $query = "SELECT JobId, FileSet, Level, JobStatus
- FROM Job JOIN FileSet USING (FileSetId)
- JOIN Client USING (ClientId) $filter
- WHERE EndTime <= $date
- AND Client.Name = '$client'
- AND Type IN ('B')
- AND JobStatus IN ('T')
- ORDER BY FileSet, JobTDate DESC";
+ my $query = "
+SELECT JobId, FileSet, Level, JobStatus
+ FROM Job
+ JOIN FileSet USING (FileSetId)
+ JOIN Client USING (ClientId) $filter
+ WHERE EndTime <= $date
+ AND Client.Name = '$client'
+ AND Type IN ('B')
+ AND JobStatus IN ('T')
+ ORDER BY FileSet, JobTDate DESC";
my @CurrentJobIds;
my $result = $self->dbh_selectall_arrayref($query);
# 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
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);
}
# 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]
# 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]});
}
}
+# get jobids that the current user can view (ACL)
sub get_jobids
{
my ($self, @jobid) = @_;
package main;
use strict;
+use POSIX qw/strftime/;
use Bweb;
my $conf = new Bweb::Config(config_file => $Bweb::config_file);
my $action = CGI::param('action') || '';
my $args = $bvfs->get_form('pathid', 'filenameid', 'fileid', 'qdate',
- 'limit', 'offset', 'client');
+ 'limit', 'offset', 'client', 'qpattern');
-print CGI::header('application/x-javascript');
+if ($action eq 'batch') {
+ $bvfs->update_cache();
+ exit 0;
+}
-if ($action eq 'list_client') {
+# 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') {
+ # 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'
print "[";
print join(',', map {
- "[$_->[4], '$_->[0]', '$_->[0] $_->[1] $_->[2] ($_->[3])']"
+ "[$_->[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";
my $lst = $bvfs->dbh_selectall_arrayref($q);
exit 0;
}
-my @jobid = $bvfs->get_jobids(grep { /^\d+$/ } CGI::param('jobid'));
+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+)$/) {
} else {
$pathid = $bvfs->get_root();
}
-
$bvfs->ch_dir($pathid);
-if ($action eq 'list_files') {
- print "[";
+#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
+ my $arg = $bvfs->get_form(qw/client storage regexwhere where/);
+
+ if (!$arg->{client}) {
+ print "ERROR: missing client\n";
+ exit 1;
+ }
+
+ my $table = fill_table_for_restore(@jobid);
+ if (!$table) {
+ exit 1;
+ }
+
+ my $bconsole = $bvfs->get_bconsole();
+ # TODO: pouvoir choisir le replace et le jobname
+ my $jobid = $bconsole->run(client => $arg->{client},
+ storage => $arg->{storage},
+ where => $arg->{where},
+ regexwhere=> $arg->{regexwhere},
+ restore => 1,
+ file => "?$table");
+
+ $bvfs->dbh_do("DROP TABLE $table");
+
+ if (!$jobid) {
+ print CGI::header('text/html');
+ $bvfs->display_begin();
+ $bvfs->error("Can't start your job:<br/>" . $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_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, \"$_->[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 { "{ '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') {
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 = 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 MAX(FirstIndex) AS FirstIndex, MIN(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";
-
-} elsif ($action eq 'restore') {
- 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 FROM File WHERE FileId IN ($fileid))";
+ 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";
}
- # 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))";
+ if ($table) {
+ $bvfs->dbh_do("DROP TABLE $table");
}
- return unless scalar(@union);
-
- my $u = join(" UNION ", @union);
-
- $bvfs->dbh_do("CREATE TEMP 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
-)");
-
- print "restore file=?b2$$ done\n";
}
__END__