@@ -162,6 +162,39 @@ impl Efi {
162162 clear_efi_target ( & product_name) ?;
163163 create_efi_boot_entry ( device, espdir, vendordir, & product_name)
164164 }
165+
166+ /// Copy firmware files from /boot/efi to target directory
167+ fn copy_firmware_blobs ( & self , src_root : & openat:: Dir , dest_root : & str ) -> Result < ( ) > {
168+ let src_efi = "boot/efi" ;
169+
170+ // Always create destination directory structure
171+ let dest_path = Path :: new ( dest_root) . join ( "boot/efi" ) ;
172+ std:: fs:: create_dir_all ( & dest_path) ?;
173+
174+ // Skip if source doesn't exist
175+ if !src_root. exists ( src_efi) ? {
176+ log:: debug!( "No EFI directory found at {}" , src_efi) ;
177+ return Ok ( ( ) ) ;
178+ }
179+
180+ // Open destination directory
181+ let dest_dir = openat:: Dir :: open ( Path :: new ( dest_root) ) ?;
182+
183+ // Copy all files from source
184+ for entry in src_root. list_dir ( src_efi) ? {
185+ let entry = entry?;
186+ if let Some ( openat:: SimpleType :: File ) = entry. simple_type ( ) {
187+ let src_path = Path :: new ( src_efi) . join ( entry. file_name ( ) ) ;
188+ let dest_path = Path :: new ( "boot/efi" ) . join ( entry. file_name ( ) ) ;
189+ src_root
190+ . copy_file_at ( & src_path, & dest_dir, & dest_path)
191+ . with_context ( || format ! ( "Failed to copy {:?} to {:?}" , src_path, dest_path) ) ?;
192+ log:: debug!( "Copied firmware file: {:?} to {:?}" , src_path, dest_path) ;
193+ }
194+ }
195+
196+ Ok ( ( ) )
197+ }
165198}
166199
167200#[ context( "Get product name" ) ]
@@ -304,13 +337,16 @@ impl Component for Efi {
304337 let srcdir_name = component_updatedirname ( self ) ;
305338 let ft = crate :: filetree:: FileTree :: new_from_dir ( & src_root. sub_dir ( & srcdir_name) ?) ?;
306339 let destdir = & self . ensure_mounted_esp ( Path :: new ( dest_root) ) ?;
307-
308340 let destd = & openat:: Dir :: open ( destdir)
309341 . with_context ( || format ! ( "opening dest dir {}" , destdir. display( ) ) ) ?;
310342 validate_esp ( destd) ?;
311343
312344 // TODO - add some sort of API that allows directly setting the working
313345 // directory to a file descriptor.
346+
347+ // Copy firmware files
348+ self . copy_firmware_blobs ( src_root, dest_root) ?;
349+
314350 std:: process:: Command :: new ( "cp" )
315351 . args ( [ "-rp" , "--reflink=auto" ] )
316352 . arg ( & srcdir_name)
@@ -579,9 +615,8 @@ fn find_file_recursive<P: AsRef<Path>>(dir: P, target_file: &str) -> Result<Vec<
579615
580616#[ cfg( test) ]
581617mod tests {
582- use cap_std_ext:: dirext:: CapStdExtDirExt ;
583-
584618 use super :: * ;
619+ use cap_std_ext:: dirext:: CapStdExtDirExt ;
585620
586621 #[ test]
587622 fn test_parse_boot_entries ( ) -> Result < ( ) > {
@@ -697,4 +732,64 @@ Boot0003* test";
697732 }
698733 Ok ( ( ) )
699734 }
735+ #[ test]
736+ fn test_copy_firmware_blobs ( ) -> Result < ( ) > {
737+ // Setup temp directory structure
738+ let tmpd = tempfile:: tempdir ( ) ?;
739+ let tmp_path = tmpd. path ( ) ;
740+
741+ // Create source structure
742+ std:: fs:: create_dir_all ( tmp_path. join ( "boot/efi" ) ) ?;
743+ std:: fs:: write ( tmp_path. join ( "boot/efi/fwfile1.bin" ) , "test1" ) ?;
744+ std:: fs:: write ( tmp_path. join ( "boot/efi/fwfile2.bin" ) , "test2" ) ?;
745+
746+ // Destination directory
747+ let dest_tmpd = tempfile:: tempdir ( ) ?;
748+ let dest_path = dest_tmpd. path ( ) ;
749+
750+ // Test the copy
751+ let efi = Efi :: default ( ) ;
752+ let src_dir = openat:: Dir :: open ( tmp_path) ?;
753+ efi. copy_firmware_blobs ( & src_dir, dest_path. to_str ( ) . unwrap ( ) ) ?;
754+
755+ // Verify files were copied
756+ assert ! ( dest_path. join( "boot/efi/fwfile1.bin" ) . exists( ) ) ;
757+ assert ! ( dest_path. join( "boot/efi/fwfile2.bin" ) . exists( ) ) ;
758+
759+ // Verify contents
760+ assert_eq ! (
761+ std:: fs:: read_to_string( dest_path. join( "boot/efi/fwfile1.bin" ) ) ?,
762+ "test1"
763+ ) ;
764+ assert_eq ! (
765+ std:: fs:: read_to_string( dest_path. join( "boot/efi/fwfile2.bin" ) ) ?,
766+ "test2"
767+ ) ;
768+
769+ Ok ( ( ) )
770+ }
771+
772+ #[ test]
773+ fn test_copy_firmware_blobs_empty ( ) -> Result < ( ) > {
774+ // Source directory (empty)
775+ let tmpd = tempfile:: tempdir ( ) ?;
776+ let tmp_path = tmpd. path ( ) ;
777+
778+ // Destination directory
779+ let dest_tmpd = tempfile:: tempdir ( ) ?;
780+ let dest_path = dest_tmpd. path ( ) ;
781+
782+ // Test the copy
783+ let efi = Efi :: default ( ) ;
784+ let src_dir = openat:: Dir :: open ( tmp_path) ?;
785+ efi. copy_firmware_blobs ( & src_dir, dest_path. to_str ( ) . unwrap ( ) ) ?;
786+
787+ // Verify directory was created
788+ assert ! ( dest_path. join( "boot/efi" ) . exists( ) ) ;
789+
790+ // Verify directory is empty
791+ assert ! ( dest_path. join( "boot/efi" ) . read_dir( ) ?. next( ) . is_none( ) ) ;
792+
793+ Ok ( ( ) )
794+ }
700795}
0 commit comments