[PATCH pve-storage v1 26/54] tree-wide: replace usages of inline regexes for snippets with parsers

Max R. Carrara
2026-04-22T11:16:01Z

Add support for the 'snippets' volume type in
`PVE::Storage::Common::Parse`.

Also add corresponding test cases.

Use the module's parsing functions to replace parsing the a snippet
file's name via regexes or the `basename()` function.

Signed-off-by: Max R. Carrara <m.carrara@proxmox.com>
---
src/PVE/Storage.pm | 4 +---
src/PVE/Storage/Common/Parse.pm | 8 +++++++
src/PVE/Storage/Common/test/parser_tests.pl | 25 +++++++++++++++++++++
src/PVE/Storage/Plugin.pm | 11 +++++----
4 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
index ce6d2154..20b7bafa 100755
--- a/src/PVE/Storage.pm
+++ b/src/PVE/Storage.pm
@@ -769,9 +769,7 @@ sub path_to_volume_id {
}

if ($vtype eq 'snippets') {
- return if $filename !~ m!/([^/]+)$!;
- my $name = $1;
- return "$sid:snippets/$name";
+ return parse_path_as_volid($sid, $scfg, $path, $vtype);
}

if ($vtype eq 'import') {
diff --git a/src/PVE/Storage/Common/Parse.pm b/src/PVE/Storage/Common/Parse.pm
index 950f6b18..33220758 100644
--- a/src/PVE/Storage/Common/Parse.pm
+++ b/src/PVE/Storage/Common/Parse.pm
@@ -106,16 +106,24 @@ my $RE_BACKUP_FILE_PATH = qr!
)
!xn;

+my $RE_SNIPPETS_FILE_PATH = qr!
+ (?<path>
+ (?<file> [^/]+ )
+ )
+!xn;
+
my $RE_FILE_PATH_FOR_VTYPE = {
iso => qr/^$RE_ISO_FILE_PATH$/,
vztmpl => qr/^$RE_VZTMPL_FILE_PATH$/,
backup => qr/^$RE_BACKUP_FILE_PATH$/,
+ snippets => qr/^$RE_SNIPPETS_FILE_PATH$/,
};

my $RE_VOLNAME_FOR_VTYPE = {
iso => qr/^$RE_ISO_FILE_PATH$/,
vztmpl => qr/^$RE_VZTMPL_FILE_PATH$/,
backup => qr/^$RE_BACKUP_FILE_PATH$/,
+ snippets => qr/^$RE_SNIPPETS_FILE_PATH$/,
};

my sub contains_parent_dir($path) {
diff --git a/src/PVE/Storage/Common/test/parser_tests.pl b/src/PVE/Storage/Common/test/parser_tests.pl
index 96159608..e0029fc6 100755
--- a/src/PVE/Storage/Common/test/parser_tests.pl
+++ b/src/PVE/Storage/Common/test/parser_tests.pl
@@ -372,10 +372,35 @@ my $volname_cases_backup_invalid = [
},
];

+my $volname_cases_snippets_valid = [
+ # plain files
+ {
+ path => 'hookscript.pl',
+ expected => {
+ file => 'hookscript.pl',
+ 'disk-path' => 'hookscript.pl',
+ path => 'hookscript.pl',
+ vtype => 'snippets',
+ volname => 'snippets/hookscript.pl',
+ },
+ },
+ {
+ path => 'userconfig.yaml',
+ expected => {
+ file => 'userconfig.yaml',
+ 'disk-path' => 'userconfig.yaml',
+ path => 'userconfig.yaml',
+ vtype => 'snippets',
+ volname => 'snippets/userconfig.yaml',
+ },
+ },
+];
+
my $cases_valid_all = [
$volname_cases_iso_valid,
$volname_cases_vztmpl_valid,
$volname_cases_backup_valid,
+ $volname_cases_snippets_valid,
];

my $cases_invalid_all = [
diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm
index 4d63e0a5..b08e038b 100644
--- a/src/PVE/Storage/Plugin.pm
+++ b/src/PVE/Storage/Plugin.pm
@@ -835,10 +835,10 @@ sub parse_volname {
if ($vtype eq 'backup') {
return ($vtype, $volume_path, $parts->{vmid}, undef, undef, undef, 'raw');
}
- }

- if ($volname =~ m!^snippets/([^/]+)$!) {
- return ('snippets', $1, undef, undef, undef, undef, 'raw');
+ if ($vtype eq 'snippets') {
+ return ($vtype, $volume_path, undef, undef, undef, undef, 'raw');
+ }
}

if ($volname =~
@@ -1758,8 +1758,11 @@ my sub get_subdir_files {
}

if ($vtype eq 'snippets') {
+ my $parts = parse_path_as_volid_parts($storeid, $scfg, $path, $vtype);
+ return if !defined($parts);
+
return {
- volid => "$storeid:snippets/" . basename($filename),
+ volid => $parts->{volid},
format => 'snippet',
};
}
--
2.47.3