summaryrefslogtreecommitdiffstats
path: root/lib/App
diff options
context:
space:
mode:
Diffstat (limited to 'lib/App')
-rw-r--r--lib/App/BorgRestore/DB.pm185
-rw-r--r--lib/App/BorgRestore/Helper.pm22
-rw-r--r--lib/App/BorgRestore/Settings.pm33
3 files changed, 240 insertions, 0 deletions
diff --git a/lib/App/BorgRestore/DB.pm b/lib/App/BorgRestore/DB.pm
new file mode 100644
index 0000000..d4e61df
--- /dev/null
+++ b/lib/App/BorgRestore/DB.pm
@@ -0,0 +1,185 @@
+package App::BorgRestore::DB;
+use v5.10;
+use strict;
+use warnings;
+
+use App::BorgRestore::Helper;
+
+use Data::Dumper;
+use DBI;
+
+sub new {
+ my $class = shift;
+ my $db_path = shift;
+
+ my $self = {};
+ bless $self, $class;
+
+ $self->_open_db($db_path);
+
+ return $self;
+}
+
+sub _open_db {
+ my $self = shift;
+ my $dbfile = shift;
+
+ $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$dbfile","","", {RaiseError => 1, Taint => 1});
+ $self->{dbh}->do("PRAGMA cache_size=-1024000");
+ $self->{dbh}->do("PRAGMA strict=ON");
+}
+
+sub initialize_db {
+ my $self = shift;
+
+ $self->{dbh}->do('create table `files` (`path` text, primary key (`path`)) without rowid;');
+ $self->{dbh}->do('create table `archives` (`archive_name` text unique);');
+}
+
+sub get_archive_names {
+ my $self = shift;
+
+ my @ret;
+
+ my $st = $self->{dbh}->prepare("select `archive_name` from `archives`;");
+ $st->execute();
+ while (my $result = $st->fetchrow_hashref) {
+ push @ret, $result->{archive_name};
+ }
+ return \@ret;
+}
+
+sub get_archive_row_count {
+ my $self = shift;
+
+ my $st = $self->{dbh}->prepare("select count(*) count from `files`;");
+ $st->execute();
+ my $result = $st->fetchrow_hashref;
+ return $result->{count};
+}
+
+sub add_archive_name {
+ my $self = shift;
+ my $archive = shift;
+
+ $archive = App::BorgRestore::Helper::untaint_archive_name($archive);
+
+ my $st = $self->{dbh}->prepare('insert into `archives` (`archive_name`) values (?);');
+ $st->execute($archive);
+
+ $self->_add_column_to_table("files", $archive);
+}
+
+sub _add_column_to_table {
+ my $self = shift;
+ my $table = shift;
+ my $column = shift;
+
+ my $st = $self->{dbh}->prepare('alter table `'.$table.'` add column `'._prefix_archive_id($column).'` integer;');
+ $st->execute();
+}
+
+sub remove_archive {
+ my $self = shift;
+ my $archive = shift;
+
+ $archive = App::BorgRestore::Helper::untaint_archive_name($archive);
+
+ my $archive_id = $self->get_archive_id($archive);
+
+ my @keep_archives = grep {$_ ne $archive;} @{$self->get_archive_names()};
+
+ $self->{dbh}->do('create table `files_new` (`path` text, primary key (`path`)) without rowid;');
+ for my $archive (@keep_archives) {
+ $self->_add_column_to_table("files_new", $archive);
+ }
+
+ my @columns_to_copy = map {'`'._prefix_archive_id($_).'`'} @keep_archives;
+ @columns_to_copy = ('`path`', @columns_to_copy);
+ $self->{dbh}->do('insert into `files_new` select '.join(',', @columns_to_copy).' from files');
+
+ $self->{dbh}->do('drop table `files`');
+
+ $self->{dbh}->do('alter table `files_new` rename to `files`');
+
+ my $st = $self->{dbh}->prepare('delete from `archives` where `archive_name` = ?;');
+ $st->execute($archive);
+}
+
+sub _prefix_archive_id {
+ my $archive = shift;
+
+ $archive = App::BorgRestore::Helper::untaint_archive_name($archive);
+
+ return 'timestamp-'.$archive;
+}
+
+sub get_archive_id {
+ my $self = shift;
+ my $archive = shift;
+
+ return _prefix_archive_id($archive);
+}
+
+sub get_archives_for_path {
+ my $self = shift;
+ my $path = shift;
+
+ my $st = $self->{dbh}->prepare('select * from `files` where `path` = ?;');
+ $st->execute(App::BorgRestore::Helper::untaint($path, qr(.*)));
+
+ my @ret;
+
+ my $result = $st->fetchrow_hashref;
+ my $archives = $self->get_archive_names();
+
+ for my $archive (@$archives) {
+ my $archive_id = $self->get_archive_id($archive);
+ my $timestamp = $result->{$archive_id};
+
+ push @ret, {
+ modification_time => $timestamp,
+ archive => $archive,
+ };
+ }
+
+ return \@ret;
+}
+
+
+sub add_path {
+ my $self = shift;
+ my $archive_id = shift;
+ my $path = shift;
+ my $time = shift;
+
+ my $st = $self->{dbh}->prepare_cached('insert or ignore into `files` (`path`, `'.$archive_id.'`)
+ values(?, ?)');
+ $st->execute($path, $time);
+
+ $st = $self->{dbh}->prepare_cached('update files set `'.$archive_id.'` = ? where `path` = ?');
+ $st->execute($time, $path);
+}
+
+sub begin_work {
+ my $self = shift;
+
+ $self->{dbh}->begin_work();
+}
+
+sub commit {
+ my $self = shift;
+
+ $self->{dbh}->commit();
+}
+
+sub vacuum {
+ my $self = shift;
+
+ $self->{dbh}->do("vacuum");
+}
+
+
+1;
+
+__END__
diff --git a/lib/App/BorgRestore/Helper.pm b/lib/App/BorgRestore/Helper.pm
new file mode 100644
index 0000000..b4d52e5
--- /dev/null
+++ b/lib/App/BorgRestore/Helper.pm
@@ -0,0 +1,22 @@
+package App::BorgRestore::Helper;
+use v5.10;
+use strict;
+use warnings;
+
+
+sub untaint {
+ my $data = shift;
+ my $regex = shift;
+
+ $data =~ m/^($regex)$/ or die "Failed to untaint: $data";
+ return $1;
+}
+
+sub untaint_archive_name {
+ my $archive = shift;
+ return untaint($archive, qr([a-zA-Z0-9-:+]+));
+}
+
+1;
+
+__END__
diff --git a/lib/App/BorgRestore/Settings.pm b/lib/App/BorgRestore/Settings.pm
new file mode 100644
index 0000000..7416c54
--- /dev/null
+++ b/lib/App/BorgRestore/Settings.pm
@@ -0,0 +1,33 @@
+package App::BorgRestore::Settings;
+use v5.10;
+use strict;
+use warnings;
+
+use App::BorgRestore::Helper;
+
+our $borg_repo = "";
+our $cache_path_base = sprintf("%s/borg-restore.pl", $ENV{XDG_CACHE_HOME} // $ENV{HOME}."/.cache");
+our @backup_prefixes = (
+ {regex => "^/", replacement => ""},
+);
+
+my @configfiles = (
+ sprintf("%s/borg-restore.cfg", $ENV{XDG_CONFIG_HOME} // $ENV{HOME}."/.config"),
+ "/etc/borg-restore.cfg",
+);
+
+for my $configfile (@configfiles) {
+ $configfile = App::BorgRestore::Helper::untaint($configfile, qr/.*/);
+ if (-e $configfile) {
+ unless (my $return = do $configfile) {
+ die "couldn't parse $configfile: $@" if $@;
+ die "couldn't do $configfile: $!" unless defined $return;
+ die "couldn't run $configfile" unless $return;
+ }
+ }
+}
+$cache_path_base = App::BorgRestore::Helper::untaint($cache_path_base, qr/.*/);
+
+1;
+
+__END__