@@ -188,6 +188,7 @@ fn get_deletions(
188188fn get_modifications (
189189 pristine : & Directory < CustomMetadata > ,
190190 current : & Directory < CustomMetadata > ,
191+ new : & Directory < CustomMetadata > ,
191192 mut current_path : PathBuf ,
192193 diff : & mut Diff ,
193194) -> anyhow:: Result < ( ) > {
@@ -205,7 +206,21 @@ fn get_modifications(
205206 diff. modified . push ( current_path. clone ( ) ) ;
206207 }
207208
208- get_modifications ( old_dir, & curr_dir, current_path. clone ( ) , diff) ?
209+ let total_added = diff. added . len ( ) ;
210+ let total_modified = diff. modified . len ( ) ;
211+
212+ get_modifications ( old_dir, & curr_dir, new, current_path. clone ( ) , diff) ?;
213+
214+ // This directory or its contents were modified/added
215+ // Check if the new directory was deleted from new_etc
216+ // If it was, we want to add the directory back
217+ if new. get_directory_opt ( & current_path. as_os_str ( ) ) ?. is_none ( ) {
218+ if diff. added . len ( ) != total_added {
219+ diff. added . insert ( total_added, current_path. clone ( ) ) ;
220+ } else if diff. modified . len ( ) != total_modified {
221+ diff. modified . insert ( total_modified, current_path. clone ( ) ) ;
222+ }
223+ }
209224 }
210225
211226 Err ( ImageError :: NotFound ( ..) ) => {
@@ -343,6 +358,7 @@ pub fn traverse_etc(
343358pub fn compute_diff (
344359 pristine_etc_files : & Directory < CustomMetadata > ,
345360 current_etc_files : & Directory < CustomMetadata > ,
361+ new_etc_files : & Directory < CustomMetadata > ,
346362) -> anyhow:: Result < Diff > {
347363 let mut diff = Diff {
348364 added : vec ! [ ] ,
@@ -353,6 +369,7 @@ pub fn compute_diff(
353369 get_modifications (
354370 & pristine_etc_files,
355371 & current_etc_files,
372+ & new_etc_files,
356373 PathBuf :: new ( ) ,
357374 & mut diff,
358375 ) ?;
@@ -641,7 +658,7 @@ fn merge_leaf(
641658 } else {
642659 current_etc_fd
643660 . copy ( & file, new_etc_fd, & file)
644- . context ( format ! ( "Copying file {file:?}" ) ) ?;
661+ . with_context ( || format ! ( "Copying file {file:?}" ) ) ?;
645662 } ;
646663
647664 rustix:: fs:: chownat (
@@ -719,7 +736,7 @@ pub fn merge(
719736 current_etc_dirtree : & Directory < CustomMetadata > ,
720737 new_etc_fd : & CapStdDir ,
721738 new_etc_dirtree : & Directory < CustomMetadata > ,
722- diff : Diff ,
739+ diff : & Diff ,
723740) -> anyhow:: Result < ( ) > {
724741 merge_modified_files (
725742 & diff. added ,
@@ -739,7 +756,7 @@ pub fn merge(
739756 )
740757 . context ( "Merging modified files" ) ?;
741758
742- for removed in diff. removed {
759+ for removed in & diff. removed {
743760 let stat = new_etc_fd. metadata_optional ( & removed) ?;
744761
745762 let Some ( stat) = stat else {
@@ -779,7 +796,7 @@ mod tests {
779796 ] ;
780797
781798 #[ test]
782- fn test_etc_diff ( ) -> anyhow:: Result < ( ) > {
799+ fn test_etc_diff_plus_merge ( ) -> anyhow:: Result < ( ) > {
783800 let tempdir = cap_std_ext:: cap_tempfile:: tempdir ( cap_std:: ambient_authority ( ) ) ?;
784801
785802 tempdir. create_dir ( "pristine_etc" ) ?;
@@ -822,17 +839,28 @@ mod tests {
822839 c. remove_file ( deleted_files[ 0 ] ) ?;
823840 c. remove_file ( deleted_files[ 1 ] ) ?;
824841
825- let ( pristine_etc_files, current_etc_files, _ ) = traverse_etc ( & p , & c , Some ( & n ) ) ? ;
826- let res = compute_diff ( & pristine_etc_files , & current_etc_files ) ?;
842+ let ( pristine_etc_files, current_etc_files, new_etc_files ) =
843+ traverse_etc ( & p , & c , Some ( & n ) ) ?;
827844
828- // Test added files
829- assert_eq ! ( res. added. len( ) , new_files. len( ) ) ;
830- assert ! ( res. added. iter( ) . all( |file| {
831- new_files
832- . iter( )
833- . find( |x| PathBuf :: from( * x) == * file)
834- . is_some( )
835- } ) ) ;
845+ let res = compute_diff (
846+ & pristine_etc_files,
847+ & current_etc_files,
848+ new_etc_files. as_ref ( ) . unwrap ( ) ,
849+ ) ?;
850+
851+ merge (
852+ & c,
853+ & current_etc_files,
854+ & n,
855+ new_etc_files. as_ref ( ) . unwrap ( ) ,
856+ & res,
857+ )
858+ . expect ( "Merge failed" ) ;
859+
860+ let added_dirs = [ "a" , "a/b" , "a/b/c" ] ;
861+
862+ // 3 for the files, and 3 for the directories
863+ assert_eq ! ( res. added. len( ) , new_files. len( ) + added_dirs. len( ) ) ;
836864
837865 // Test modified files
838866 let all_modified_files = overwritten_files
@@ -1008,8 +1036,12 @@ mod tests {
10081036
10091037 let ( pristine_etc_files, current_etc_files, new_etc_files) =
10101038 traverse_etc ( & p, & c, Some ( & n) ) ?;
1011- let diff = compute_diff ( & pristine_etc_files, & current_etc_files) ?;
1012- merge ( & c, & current_etc_files, & n, & new_etc_files. unwrap ( ) , diff) ?;
1039+ let diff = compute_diff (
1040+ & pristine_etc_files,
1041+ & current_etc_files,
1042+ & new_etc_files. as_ref ( ) . unwrap ( ) ,
1043+ ) ?;
1044+ merge ( & c, & current_etc_files, & n, & new_etc_files. unwrap ( ) , & diff) ?;
10131045
10141046 assert ! ( files_eq( & c, & n, "new_file.txt" ) ?) ;
10151047 assert ! ( files_eq( & c, & n, "a/new_file.txt" ) ?) ;
@@ -1081,9 +1113,13 @@ mod tests {
10811113
10821114 let ( pristine_etc_files, current_etc_files, new_etc_files) =
10831115 traverse_etc ( & p, & c, Some ( & n) ) ?;
1084- let diff = compute_diff ( & pristine_etc_files, & current_etc_files) ?;
1116+ let diff = compute_diff (
1117+ & pristine_etc_files,
1118+ & current_etc_files,
1119+ & new_etc_files. as_ref ( ) . unwrap ( ) ,
1120+ ) ?;
10851121
1086- let merge_res = merge ( & c, & current_etc_files, & n, & new_etc_files. unwrap ( ) , diff) ;
1122+ let merge_res = merge ( & c, & current_etc_files, & n, & new_etc_files. unwrap ( ) , & diff) ;
10871123
10881124 assert ! ( merge_res. is_err( ) ) ;
10891125 assert_eq ! (
0 commit comments