- push @CurrentJobIds,($jobid);
- }
- elsif ($level eq 'F')
- {
- push @CurrentJobIds,($jobid);
- }
-
- my $status = $refrow->[3] ;
- if ($status eq 'T') { # good end of job
- $progress{$fileset} = $level;
- }
- }
- print Data::Dumper::Dumper(\@CurrentJobIds) if $debug;
-
- return @CurrentJobIds;
-}
-
-# Lists all directories contained inside a directory.
-# Uses the current dir, the client name, and CurrentJobIds for visibility.
-# Returns an array of dirs
-sub list_dirs
-{
- my ($self,$dir,$client)=@_;
-
- print "list_dirs(<$dir>, <$client>)\n" if $debug;
-
- if ($dir ne '' and substr $dir,-1 ne '/')
- {
- $dir .= '/'; # In the db, there is a / at the end of the dirs ...
- }
-
- my $dbh = $self->{dbh};
- my $query = "SELECT PathId FROM Path WHERE Path = ?
- UNION SELECT PathId FROM brestore_missing_path WHERE PATH = ?";
- my $sth = $dbh->prepare($query);
- $sth->execute($dir,$dir);
- my $result = $sth->fetchrow_arrayref();
- $sth->finish();
- my $pathid = $result->[0];
- my @jobids = @{$self->{CurrentJobIds}};
- my $jobclause = join (',', @jobids);
- # 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
- $query = "SELECT FilenameId FROM Filename WHERE Name = ''";
- $sth = $dbh->prepare($query);
- $sth->execute();
- $result = $sth->fetchrow_arrayref();
- $sth->finish();
- my $dir_filenameid = $result->[0];
-
- # Then we get all the dir entries from File ...
- # It's ugly because there are records in brestore_missing_path ...
- $query = "
-SELECT Path, JobId, Lstat FROM(
- (
- SELECT Path.Path, lower(Path.Path),
- listfile.JobId, listfile.Lstat
- FROM (
- SELECT DISTINCT brestore_pathhierarchy.PathId
- FROM brestore_pathhierarchy
- JOIN Path
- ON (brestore_pathhierarchy.PathId = Path.PathId)
- JOIN brestore_pathvisibility
- ON (brestore_pathhierarchy.PathId = brestore_pathvisibility.PathId)
- WHERE brestore_pathhierarchy.PPathId = $pathid
- AND brestore_pathvisibility.jobid IN ($jobclause)) AS listpath
- JOIN Path ON (listpath.PathId = Path.PathId)
- LEFT JOIN (
- SELECT File.PathId, File.JobId, File.Lstat FROM File
- WHERE File.FilenameId = $dir_filenameid
- AND File.JobId IN ($jobclause)) AS listfile
- ON (listpath.PathId = listfile.PathId)
- UNION
- SELECT brestore_missing_path.Path, lower(brestore_missing_path.Path),
- listfile.JobId, listfile.Lstat
- FROM (
- SELECT DISTINCT brestore_pathhierarchy.PathId
- FROM brestore_pathhierarchy
- JOIN brestore_missing_path
- ON (brestore_pathhierarchy.PathId = brestore_missing_path.PathId)
- JOIN brestore_pathvisibility
- ON (brestore_pathhierarchy.PathId = brestore_pathvisibility.PathId)
- WHERE brestore_pathhierarchy.PPathId = $pathid
- AND brestore_pathvisibility.jobid IN ($jobclause)) AS listpath
- JOIN brestore_missing_path ON (listpath.PathId = brestore_missing_path.PathId)
- LEFT JOIN (
- SELECT File.PathId, File.JobId, File.Lstat FROM File
- WHERE File.FilenameId = $dir_filenameid
- AND File.JobId IN ($jobclause)) AS listfile
- ON (listpath.PathId = listfile.PathId))
-ORDER BY 2,3 DESC ) As a";
- print STDERR "$query\n" if $debug;
- $sth=$dbh->prepare($query);
- $sth->execute();
- $result = $sth->fetchall_arrayref();
- my @return_list;
- my $prev_dir='';
- foreach my $refrow (@{$result})
- {
- my $dir = $refrow->[0];
- my $jobid = $refrow->[1];
- my $lstat = $refrow->[2];
- next if ($dir eq $prev_dir);
- # We have to clean up this dirname ... we only want it's 'basename'
- my $return_value;
- if ($dir ne '/')
- {
- my @temp = split ('/',$dir);
- $return_value = pop @temp;
- }
- else
- {
- $return_value = '/';
- }
- my @return_array = ($return_value,$lstat);
- push @return_list,(\@return_array);
- $prev_dir = $dir;
- }
- return @return_list;
-}
-
-
-# List all files in a directory. dir as parameter, CurrentJobIds for visibility
-# Returns an array of dirs
-sub list_files
-{
- my ($self, $dir)=@_;
- my $dbh = $self->{dbh};
-
- my $empty = [];
-
- print "list_files($dir)\n" if $debug;
-
- if ($dir ne '' and substr $dir,-1 ne '/')
- {
- $dir .= '/'; # In the db, there is a / at the end of the dirs ...
- }
-
- my $query = "SELECT Path.PathId
- FROM Path
- WHERE Path.Path = '$dir'
- UNION
- SELECT brestore_missing_path.PathId
- FROM brestore_missing_path
- WHERE brestore_missing_path.Path = '$dir'";
- print $query,"\n" if $debug;
- my @list_pathid=();
- my $result = $dbh->selectall_arrayref($query);
- foreach my $refrow (@$result)
- {
- push @list_pathid,($refrow->[0]);
- }
-
- if (@list_pathid == 0)
- {
- print "No pathid found for $dir\n" if $debug;
- return $empty;
- }
-
- my $inlistpath = join (',', @list_pathid);
- my $inclause = join (',', @{$self->{CurrentJobIds}});
- if ($inclause eq '')
- {
- return $empty;
- }
-
- $query =
-"SELECT listfiles.id, listfiles.Name, File.LStat, File.JobId
- FROM
- (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.FileId = listfiles.id";
-
- print STDERR $query,"\n" if $debug;
- $result = $dbh->selectall_arrayref($query);
-
- return $result;
-}
-
-sub refresh_screen
-{
- Gtk2->main_iteration while (Gtk2->events_pending);
-}
-
-sub create_brestore_tables
-{
- my ($self) = @_;
-
- my $verif = "SELECT 1 FROM brestore_knownjobid LIMIT 1";
-
- unless ($self->dbh_do($verif)) {
- new DlgWarn("brestore can't find brestore_xxx tables on your database. I will create them.");
-
- $self->{error} = "Creating internal brestore tables";
- my $req = "
- CREATE TABLE brestore_knownjobid
- (
- JobId int4 NOT NULL,
- CONSTRAINT brestore_knownjobid_pkey PRIMARY KEY (JobId)
- )";
- $self->dbh_do($req);
- }
-
- $verif = "SELECT 1 FROM brestore_pathhierarchy LIMIT 1";
- unless ($self->dbh_do($verif)) {
- my $req = "
- CREATE TABLE brestore_pathhierarchy
- (
- PathId int4 NOT NULL,
- PPathId int4 NOT NULL,
- CONSTRAINT brestore_pathhierarchy_pkey PRIMARY KEY (PathId)
- )";
- $self->dbh_do($req);
-
-
- $req = "CREATE INDEX brestore_pathhierarchy_ppathid
- ON brestore_pathhierarchy (PPathId)";
- $self->dbh_do($req);
- }
-
- $verif = "SELECT 1 FROM brestore_pathvisibility LIMIT 1";
- unless ($self->dbh_do($verif)) {
- my $req = "
- CREATE TABLE brestore_pathvisibility
- (
- PathId int4 NOT NULL,
- JobId int4 NOT NULL,
- CONSTRAINT brestore_pathvisibility_pkey PRIMARY KEY (JobId, PathId)
- )";
- $self->dbh_do($req);
-
- $req = "CREATE INDEX brestore_pathvisibility_jobid
- ON brestore_pathvisibility (JobId)";
- $self->dbh_do($req);
- }
-
- $verif = "SELECT 1 FROM brestore_missing_path LIMIT 1";
- unless ($self->dbh_do($verif)) {
- my $req = "
- CREATE TABLE brestore_missing_path
- (
- PathId int4 NOT NULL,
- Path text NOT NULL,
- CONSTRAINT brestore_missing_path_pkey PRIMARY KEY (PathId)
- )";
- $self->dbh_do($req);
-
- $req = "CREATE INDEX brestore_missing_path_path
- ON brestore_missing_path (Path)";
- $self->dbh_do($req);
- }
-}
-
-# Recursive function to calculate the visibility of each directory in the cache
-# tree Working with references to save time and memory
-# For each directory, we want to propagate it's visible jobids onto it's
-# parents directory.
-# A tree is visible if
-# - it's been in a backup pointed by the CurrentJobIds
-# - one of it's subdirs is in a backup pointed by the CurrentJobIds
-# In the second case, the directory is visible but has no metadata.
-# We symbolize this with lstat = 1 for this jobid in the cache.
-
-# Input : reference directory
-# Output : visibility of this dir. Has to know visibility of all subdirs
-# to know it's visibility, hence the recursing.
-sub list_visible
-{
- my ($refdir)=@_;
-
- my %visibility;
- # Get the subdirs array references list
- my @list_ref_subdirs;
- while( my (undef,$ref_subdir) = each (%{$refdir->[0]}))
- {
- push @list_ref_subdirs,($ref_subdir);
- }
-
- # Now lets recurse over these subdirs and retrieve the reference of a hash
- # containing the jobs where they are visible
- foreach my $ref_subdir (@list_ref_subdirs)
- {
- my $ref_list_jobs = list_visible($ref_subdir);
- foreach my $jobid (keys %$ref_list_jobs)
- {
- $visibility{$jobid}=1;
- }
- }
-
- # Ok. Now, we've got the list of those jobs. We are going to update our
- # hash (element 1 of the dir array) containing our jobs Do NOT overwrite
- # the lstat for the known jobids. Put 1 in the new elements... But first,
- # let's store the current jobids
- my @known_jobids;
- foreach my $jobid (keys %{$refdir->[1]})
- {
- push @known_jobids,($jobid);
- }
-
- # Add the new jobs
- foreach my $jobid (keys %visibility)
- {
- next if ($refdir->[1]->{$jobid});
- $refdir->[1]->{$jobid} = 1;
- }
- # Add the known_jobids to %visibility
- foreach my $jobid (@known_jobids)
- {
- $visibility{$jobid}=1;
- }
- return \%visibility;
-}
-
-# Returns the list of media required for a list of jobids.
-# Input : dbh, jobid1, jobid2...
-# Output : reference to array of (joibd, inchanger)
-sub get_required_media_from_jobid
-{
- my ($dbh, @jobids)=@_;
- my $inclause = join(',',@jobids);
- my $query = "
-SELECT DISTINCT JobMedia.MediaId, Media.InChanger
-FROM JobMedia, Media
-WHERE JobMedia.MediaId=Media.MediaId
-AND JobId In ($inclause)
-ORDER BY MediaId";
- my $result = $dbh->selectall_arrayref($query);
- return $result;
-}
-
-# Returns the fileindex from dirname and jobid.
-# Input : dbh, dirname, jobid
-# Output : fileindex
-sub get_fileindex_from_dir_jobid
-{
- my ($dbh, $dirname, $jobid)=@_;
- my $query;
- $query = "SELECT File.FileIndex
- FROM File, Filename, Path
- WHERE File.FilenameId = Filename.FilenameId
- AND File.PathId = Path.PathId
- AND Filename.Name = ''
- AND Path.Path = '$dirname'
- AND File.JobId = '$jobid'
- ";
-
- print STDERR $query,"\n" if $debug;
- my $result = $dbh->selectall_arrayref($query);
- return $result->[0]->[0];
-}
-
-# Returns the fileindex from filename and jobid.
-# Input : dbh, filename, jobid
-# Output : fileindex
-sub get_fileindex_from_file_jobid
-{
- my ($dbh, $filename, $jobid)=@_;
-
- my @dirs = split(/\//, $filename);
- $filename=pop(@dirs);
- my $dirname = join('/', @dirs) . '/';
-
-
- my $query;
- $query =
-"SELECT File.FileIndex
- FROM File, Filename, Path
- WHERE File.FilenameId = Filename.FilenameId
- AND File.PathId = Path.PathId
- AND Filename.Name = '$filename'
- AND Path.Path = '$dirname'
- AND File.JobId = '$jobid'";
-
- print STDERR $query,"\n" if $debug;
- my $result = $dbh->selectall_arrayref($query);
- return $result->[0]->[0];
-}
-
-
-# Returns list of versions of a file that could be restored
-# returns an array of
-# ('FILE:',filename,jobid,fileindex,mtime,size,inchanger,md5,volname)
-# It's the same as entries of restore_list (hidden) + mtime and size and inchanger
-# and volname and md5
-# and of course, there will be only one jobid in the array of jobids...
-sub get_all_file_versions
-{
- my ($dbh,$path,$file,$client,$see_all)=@_;
-
- defined $see_all or $see_all=0;
-
- my @versions;
- my $query;
- $query =
-"SELECT File.JobId, File.FileIndex, File.Lstat,
- File.Md5, Media.VolumeName, Media.InChanger
- FROM File, Filename, Path, Job, Client, JobMedia, Media
- WHERE File.FilenameId = Filename.FilenameId
- AND File.PathId=Path.PathId
- AND File.JobId = Job.JobId
- AND Job.ClientId = Client.ClientId
- AND Job.JobId = JobMedia.JobId
- AND File.FileIndex >= JobMedia.FirstIndex
- AND File.FileIndex <= JobMedia.LastIndex
- AND JobMedia.MediaId = Media.MediaId
- AND Path.Path = '$path'
- AND Filename.Name = '$file'
- AND Client.Name = '$client'";
-
- print STDERR $query if $debug;
-
- my $result = $dbh->selectall_arrayref($query);
-
- foreach my $refrow (@$result)
- {
- my ($jobid, $fileindex, $lstat, $md5, $volname, $inchanger) = @$refrow;
- my @attribs = parse_lstat($lstat);
- my $mtime = array_attrib('st_mtime',\@attribs);
- my $size = array_attrib('st_size',\@attribs);
-
- my @list = ('FILE:', $path.$file, $jobid, $fileindex, $mtime, $size,
- $inchanger, $md5, $volname);
- push @versions, (\@list);
- }
-
- # We have the list of all versions of this file.
- # We'll sort it by mtime desc, size, md5, inchanger desc
- # the rest of the algorithm will be simpler
- # ('FILE:',filename,jobid,fileindex,mtime,size,inchanger,md5,volname)
- @versions = sort { $b->[4] <=> $a->[4]
- || $a->[5] <=> $b->[5]
- || $a->[7] cmp $a->[7]
- || $b->[6] <=> $a->[6]} @versions;
-
- my @good_versions;
- my %allready_seen_by_mtime;
- my %allready_seen_by_md5;
- # Now we should create a new array with only the interesting records
- foreach my $ref (@versions)
- {
- if ($ref->[7])
- {
- # The file has a md5. We compare his md5 to other known md5...
- # We take size into account. It may happen that 2 files
- # have the same md5sum and are different. size is a supplementary
- # criterion
-
- # If we allready have a (better) version
- next if ( (not $see_all)
- and $allready_seen_by_md5{$ref->[7] .'-'. $ref->[5]});