PVE/API2/Storage/Content.pm | 37 ++++++++++++++++++++++++++++---------
PVE/Storage.pm | 9 +++++++++
PVE/Storage/DirPlugin.pm | 26 ++++++++++++++++++++++++--
PVE/Storage/Plugin.pm | 7 +++++++
test/prune_backups_test.pm | 13 +++++++++++++
5 files changed, 81 insertions(+), 11 deletions(-)
diff --git a/PVE/API2/Storage/Content.pm b/PVE/API2/Storage/Content.pm
index b3dc593..45b8de8 100644
--- a/PVE/API2/Storage/Content.pm
+++ b/PVE/API2/Storage/Content.pm
@@ -113,6 +113,11 @@ __PACKAGE__->register_method ({
},
optional => 1,
},
+ protected => {
+ description => "Protection status. Currently only
supported for backups.",
+ type => 'boolean',
+ optional => 1,
+ },
},
},
links => [ { rel => 'child', href => "{volid}" } ],
@@ -295,7 +300,12 @@ __PACKAGE__->register_method ({
description => "Optional notes.",
optional => 1,
type => 'string',
- }
+ },
+ protected => {
+ description => "Protection status. Currently only supported
for backups.",
+ type => 'boolean',
+ optional => 1,
+ },
},
},
code => sub {
@@ -321,12 +331,14 @@ __PACKAGE__->register_method ({
format => $format,
};
- # keep going if fetching an optional attribute fails
- eval {
- my $notes = PVE::Storage::get_volume_attribute($cfg, $volid,
'notes');
- $entry->{notes} = $notes if defined($notes);
- };
- warn $@ if $@;
+ for my $attribute (qw(notes protected)) {
+ # keep going if fetching an optional attribute fails
+ eval {
+ my $value = PVE::Storage::get_volume_attribute($cfg, $volid,
$attribute);
+ $entry->{$attribute} = $value if defined($value);
+ };
+ warn $@ if $@;
+ }
return $entry;
}});
@@ -356,6 +368,11 @@ __PACKAGE__->register_method ({
type => 'string',
optional => 1,
},
+ protected => {
+ description => "Protection status. Currently only supported
for backups.",
+ type => 'boolean',
+ optional => 1,
+ },
},
},
returns => { type => 'null' },
@@ -371,8 +388,10 @@ __PACKAGE__->register_method ({
PVE::Storage::check_volume_access($rpcenv, $authuser, $cfg,
undef, $volid);
- if (exists $param->{notes}) {
- PVE::Storage::update_volume_attribute($cfg, $volid, 'notes',
$param->{notes});
+ for my $attr (qw(notes protected)) {
+ if (exists $param->{$attr}) {
+ PVE::Storage::update_volume_attribute($cfg, $volid, $attr,
$param->{$attr});
+ }
}
return undef;
diff --git a/PVE/Storage.pm b/PVE/Storage.pm
index e7d8e62..3beb645 100755
--- a/PVE/Storage.pm
+++ b/PVE/Storage.pm
@@ -1463,6 +1463,12 @@ sub decompressor_info {
return $info;
}
+sub protection_file_path {
+ my ($path) = @_;
+
+ return "${path}.protected";
+}
+
sub archive_info {
my ($archive) = shift;
my $info;
@@ -1494,6 +1500,9 @@ sub archive_info {
sub archive_remove {
my ($archive_path) = @_;
+ die "cannot remove protected archive '$archive_path'\n"
+ if -e protection_file_path($archive_path);
+
my $dirname = dirname($archive_path);
my $archive_info = eval { archive_info($archive_path) } // {};
my $logfn = $archive_info->{logfilename};
diff --git a/PVE/Storage/DirPlugin.pm b/PVE/Storage/DirPlugin.pm
index 6ab9ef2..99a6eaf 100644
--- a/PVE/Storage/DirPlugin.pm
+++ b/PVE/Storage/DirPlugin.pm
@@ -2,8 +2,11 @@ package PVE::Storage::DirPlugin;
use strict;
use warnings;
+
use Cwd;
use File::Path;
+use IO::File;
+
use PVE::Storage::Plugin;
use PVE::JSONSchema qw(get_standard_option);
@@ -93,13 +96,16 @@ sub get_volume_attribute {
my ($vtype) = $class->parse_volname($volname);
return if $vtype ne 'backup';
+ my $path = $class->filesystem_path($scfg, $volname);
+
if ($attribute eq 'notes') {
- my $path = $class->filesystem_path($scfg, $volname);
$path .= $class->SUPER::NOTES_EXT;
return PVE::Tools::file_get_contents($path) if -f $path;
return '';
+ } elsif ($attribute eq 'protected') {
+ return -e PVE::Storage::protection_file_path($path) ? 1 : 0;
}
return;
@@ -111,8 +117,9 @@ sub update_volume_attribute {
my ($vtype) = $class->parse_volname($volname);
die "only backups support attribute '$attribute'\n" if $vtype ne
'backup';
+ my $path = $class->filesystem_path($scfg, $volname);
+
if ($attribute eq 'notes') {
- my $path = $class->filesystem_path($scfg, $volname);
$path .= $class->SUPER::NOTES_EXT;
if (defined($value) && $value ne '') {
@@ -120,6 +127,21 @@ sub update_volume_attribute {
} elsif (-e $path) {
unlink $path or die "could not delete notes - $!\n";
}
+ return;
+ } elsif ($attribute eq 'protected') {
+ my $protection_path = PVE::Storage::protection_file_path($path);
+
+ return if !((-e $protection_path) xor $value); # protection
status already correct