From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 4D8651FF0B0 for ; Tue, 27 Oct 2026 11:12:46 +0100 (CET) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 44F9B2164A; Tue, 27 Oct 2026 11:12:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=genua.de; s=202307; t=1793095927; bh=2tFc9wSafOtLq5SDJGW3gfFaX8sNpiA67JjMyLeYYS8=; h=Date:From:To:Subject:References:In-Reply-To:From; b=HAUgSDAWCbth+k//+SUdqk3YAbQOZMXYEZ8b5bAVOsK5fhQL4OH4lfAYPG5IwyQhl E6DZk2PTiEmRLNXHFYDgqDMk7UrcG0vDLXut47Yi+TcaubdXO9VPTf+5bYa681G7W3 jiZnnFzOmsQbwfzYzqctYtWJSmPD8c0N52N6l34o2kUkM8SU370VDPm+vn/ByRfFes cvyhb/uj14QxEnHy8zBX8TIaJUNe3uOdwaLN7zDTC1vXfcEmmnn4tiqfr/6RU7HvF7 pZyXAU39UTPJm1mXbof4DVGLnkxuC87+0Vo5as1txA1mYw6pAs64JND4KRJncMuq4m Ec7JyfDMc/pIw== Date: Tue, 27 Oct 2026 11:12:06 +0100 From: Christian Ludwig To: Subject: [PATCH pve-storage v3 01/19] plugin: add efi-firmware content type Message-ID: <01c34eb1dde147435381239f92e2a0fcccfcffbe.1793029144.git@genua.de> References: MIME-Version: 1.0 In-Reply-To: X-Originating-IP: [192.168.217.185] X-ClientProxiedBy: kch1-mta07.win.genua.de (10.208.16.107) To kch1-mta07.win.genua.de (10.208.16.107) Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline X-SPAM-LEVEL: Spam detection results: 0 AWL 0.072 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record UNPARSEABLE_RELAY 0.001 Informational: message has unparseable relay lines Message-ID-Hash: D3VKEPF2G6GMNTQPW6U3EI27UV74RAOP X-Message-ID-Hash: D3VKEPF2G6GMNTQPW6U3EI27UV74RAOP X-MailFrom: christian_ludwig@genua.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Holds custom OVMF code images in the efi-firmware/ subdirectory of a storage. File names are restricted to the safe character class and must end with '.fd'. Requiring the extension avoids confusion with other image formats and leaves room for supporting other firmware formats later on. Access is granted like for ISO images. Signed-off-by: Christian Ludwig --- src/PVE/Storage.pm | 23 +++++++++++++++++++---- src/PVE/Storage/Plugin.pm | 15 ++++++++++++++- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm index cfbbabd..03ec6a1 100755 --- a/src/PVE/Storage.pm +++ b/src/PVE/Storage.pm @@ -123,6 +123,8 @@ our $IMPORT_EXT_RE_1 = qr/\.(ova|ovf|qcow2|raw|vmdk)/; our $UPLOAD_IMPORT_EXT_RE_1 = qr/\.(ova|qcow2|raw|vmdk)/; +our $EFI_FIRMWARE_EXT_RE_1 = qr/\.(fd)/; + our $SAFE_CHAR_CLASS_RE = qr/[a-zA-Z0-9\-\.\+\=\_]/; our $SAFE_CHAR_WITH_WHITESPACE_CLASS_RE = qr/[ a-zA-Z0-9\-\.\+\=\_]/; @@ -629,7 +631,12 @@ sub check_volume_access { return if $rpcenv->check($user, "/storage/$sid", ['Datastore.Allocate'], 1); - if ($vtype eq 'iso' || $vtype eq 'vztmpl' || $vtype eq 'import') { + if ( + $vtype eq 'iso' + || $vtype eq 'vztmpl' + || $vtype eq 'import' + || $vtype eq 'efi-firmware' + ) { # require at least read access to storage, (custom) templates/ISOs could be sensitive $rpcenv->check_any( $user, @@ -719,6 +726,7 @@ sub path_to_volume_id { my $backupdir = $plugin->get_subdir($scfg, 'backup'); my $snippetsdir = $plugin->get_subdir($scfg, 'snippets'); my $importdir = $plugin->get_subdir($scfg, 'import'); + my $firmwaredir = $plugin->get_subdir($scfg, 'efi-firmware'); if ($path =~ m!^\Q$imagedir\E/(\d+)/([^/\s]+)$!) { my $vmid = $1; @@ -747,6 +755,9 @@ sub path_to_volume_id { } elsif ($path =~ m!^\Q$importdir\E/(${SAFE_CHAR_CLASS_RE}+${IMPORT_EXT_RE_1})$!) { my $name = $1; return ('import', "$sid:import/$name"); + } elsif ($path =~ m!^\Q$firmwaredir\E/(${SAFE_CHAR_CLASS_RE}+${EFI_FIRMWARE_EXT_RE_1})$!) { + my $name = $1; + return ('efi-firmware', "$sid:efi-firmware/$name"); } } @@ -1269,7 +1280,11 @@ sub template_list { my ($cfg, $storeid, $tt) = @_; die "unknown template type '$tt'\n" - if !($tt eq 'iso' || $tt eq 'vztmpl' || $tt eq 'backup' || $tt eq 'snippets'); + if !($tt eq 'iso' + || $tt eq 'vztmpl' + || $tt eq 'backup' + || $tt eq 'snippets' + || $tt eq 'efi-firmware'); my $ids = $cfg->{ids}; @@ -1297,7 +1312,7 @@ sub template_list { sub volume_list { my ($cfg, $storeid, $vmid, $content) = @_; - my @ctypes = qw(rootdir images vztmpl iso backup snippets import); + my @ctypes = qw(rootdir images vztmpl iso backup snippets import efi-firmware); my $cts = $content ? [$content] : [@ctypes]; @@ -2264,7 +2279,7 @@ sub complete_storage_enabled { sub complete_content_type { my ($cmdname, $pname, $cvalue) = @_; - return [qw(rootdir images vztmpl iso backup snippets import)]; + return [qw(rootdir images vztmpl iso backup snippets import efi-firmware)]; } sub complete_volume { diff --git a/src/PVE/Storage/Plugin.pm b/src/PVE/Storage/Plugin.pm index 8318a68..43af559 100644 --- a/src/PVE/Storage/Plugin.pm +++ b/src/PVE/Storage/Plugin.pm @@ -384,7 +384,7 @@ PVE::JSONSchema::register_format('pve-storage-content', \&verify_content); sub verify_content { my ($ct, $noerr) = @_; - return $ct if $ct eq 'import'; + return $ct if $ct eq 'import' || $ct eq 'efi-firmware'; my $valid_content = valid_content_types('dir'); # dir includes all other types @@ -843,6 +843,10 @@ sub parse_volname { m!^import/(${PVE::Storage::SAFE_CHAR_WITH_WHITESPACE_CLASS_RE}+$PVE::Storage::IMPORT_EXT_RE_1)$! ) { return ('import', $1, undef, undef, undef, undef, $2); + } elsif ($volname =~ + m!^efi-firmware/(${PVE::Storage::SAFE_CHAR_CLASS_RE}+$PVE::Storage::EFI_FIRMWARE_EXT_RE_1)$! + ) { + return ('efi-firmware', $1, undef, undef, undef, undef, 'raw'); } die "unable to parse directory volume name '$volname'\n"; @@ -948,6 +952,7 @@ my $vtype_subdirs = { backup => 'dump', snippets => 'snippets', import => 'import', + 'efi-firmware' => 'efi-firmware', }; sub get_vtype_subdirs { @@ -1855,6 +1860,12 @@ my $get_subdir_files = sub { m!/(${PVE::Storage::SAFE_CHAR_CLASS_RE}+$PVE::Storage::IMPORT_EXT_RE_1)$!i; $info = { volid => "$sid:import/$1", format => "$2" }; + } elsif ($tt eq 'efi-firmware') { + next + if $fn !~ + m!/(${PVE::Storage::SAFE_CHAR_CLASS_RE}+$PVE::Storage::EFI_FIRMWARE_EXT_RE_1)$!; + + $info = { volid => "$sid:efi-firmware/$1", format => 'raw' }; } $info->{size} = $st->size; @@ -1891,6 +1902,8 @@ sub list_volumes { $data = $get_subdir_files->($storeid, $path, 'snippets'); } elsif ($type eq 'import') { $data = $get_subdir_files->($storeid, $path, 'import'); + } elsif ($type eq 'efi-firmware' && !defined($vmid)) { + $data = $get_subdir_files->($storeid, $path, 'efi-firmware'); } } -- 2.34.1