+ ($size) = ($size =~ /^(\d+)$/) or die "size '$size' not an integer\n"; # untaint
+ ($used) = ($used =~ /^(\d+)$/) or die "used '$used' not an integer\n"; # untaint
+ ($format) = ($format =~ /^(\S+)$/) or die "format '$format' includes whitespace\n"; # untaint
+ if (defined($parent)) {
+ ($parent) = ($parent =~ /^(\S+)$/) or die "parent '$parent' includes whitespace\n"; # untaint
+ }
+ return wantarray ? ($size, $format, $used, $parent, $st->ctime) : $size;
+}
+
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use get_volume_attribute instead.
+sub get_volume_notes {
+ my ($class, $scfg, $storeid, $volname, $timeout) = @_;
+
+ die "volume notes are not supported for $class";
+}
+
+# FIXME remove on the next APIAGE reset.
+# Deprecated, use update_volume_attribute instead.
+sub update_volume_notes {
+ my ($class, $scfg, $storeid, $volname, $notes, $timeout) = @_;
+
+ die "volume notes are not supported for $class";
+}
+
+# Returns undef if the attribute is not supported for the volume.
+# Should die if there is an error fetching the attribute.
+# Possible attributes:
+# notes - user-provided comments/notes.
+# protected - not to be removed by free_image, and for backups, ignored when pruning.
+sub get_volume_attribute {
+ my ($class, $scfg, $storeid, $volname, $attribute) = @_;
+
+ if ($attribute eq 'notes') {
+ my $notes = eval { $class->get_volume_notes($scfg, $storeid, $volname); };
+ if (my $err = $@) {
+ return if $err =~ m/^volume notes are not supported/;
+ die $err;
+ }
+ return $notes;
+ }
+
+ return;
+}
+
+# Dies if the attribute is not supported for the volume.
+sub update_volume_attribute {
+ my ($class, $scfg, $storeid, $volname, $attribute, $value) = @_;
+
+ if ($attribute eq 'notes') {
+ $class->update_volume_notes($scfg, $storeid, $volname, $value);
+ }
+
+ die "attribute '$attribute' is not supported for storage type '$scfg->{type}'\n";