33#![ allow( dead_code) ]
44
55use fn_error_context:: context;
6- use std:: cell:: RefCell ;
76use std:: collections:: BTreeMap ;
87use std:: ffi:: OsStr ;
98use std:: io:: BufReader ;
109use std:: io:: Write ;
1110use std:: os:: fd:: { AsFd , AsRawFd } ;
1211use std:: os:: unix:: ffi:: OsStrExt ;
1312use std:: path:: { Path , PathBuf } ;
14- use std:: rc:: Rc ;
1513
1614use anyhow:: Context ;
1715use cap_std_ext:: cap_std;
1816use cap_std_ext:: cap_std:: fs:: { Dir as CapStdDir , MetadataExt , Permissions , PermissionsExt } ;
1917use cap_std_ext:: dirext:: CapStdExtDirExt ;
2018use cfsctl:: composefs;
2119use composefs:: fsverity:: { FsVerityHashValue , Sha256HashValue , Sha512HashValue } ;
22- use composefs:: generic_tree:: { Directory , Inode , Leaf , LeafContent , Stat } ;
20+ use composefs:: generic_tree:: { Directory , FileSystem , Inode , Leaf , LeafContent , LeafId , Stat } ;
2321use composefs:: tree:: ImageError ;
2422use rustix:: fs:: {
2523 AtFlags , Gid , Uid , XattrFlags , lgetxattr, llistxattr, lsetxattr, readlinkat, symlinkat,
@@ -43,7 +41,7 @@ impl CustomMetadata {
4341 }
4442}
4543
46- type Xattrs = RefCell < BTreeMap < Box < OsStr > , Box < [ u8 ] > > > ;
44+ type Xattrs = BTreeMap < Box < OsStr > , Box < [ u8 ] > > ;
4745
4846struct MyStat ( Stat ) ;
4947
@@ -147,7 +145,7 @@ fn get_deletions(
147145 }
148146 }
149147
150- Inode :: Leaf ( ..) => match current. ref_leaf ( file_name) {
148+ Inode :: Leaf ( ..) => match current. leaf_id ( file_name) {
151149 Ok ( ..) => {
152150 // Empty as all additions/modifications are tracked earlier in `get_modifications`
153151 }
@@ -189,6 +187,8 @@ fn get_deletions(
189187fn get_modifications (
190188 pristine : & Directory < CustomMetadata > ,
191189 current : & Directory < CustomMetadata > ,
190+ pristine_leaves : & [ Leaf < CustomMetadata > ] ,
191+ current_leaves : & [ Leaf < CustomMetadata > ] ,
192192 new : & Directory < CustomMetadata > ,
193193 mut current_path : PathBuf ,
194194 diff : & mut Diff ,
@@ -210,7 +210,15 @@ fn get_modifications(
210210 let total_added = diff. added . len ( ) ;
211211 let total_modified = diff. modified . len ( ) ;
212212
213- get_modifications ( old_dir, & curr_dir, new, current_path. clone ( ) , diff) ?;
213+ get_modifications (
214+ old_dir,
215+ & curr_dir,
216+ pristine_leaves,
217+ current_leaves,
218+ new,
219+ current_path. clone ( ) ,
220+ diff,
221+ ) ?;
214222
215223 // This directory or its contents were modified/added
216224 // Check if the new directory was deleted from new_etc
@@ -242,8 +250,10 @@ fn get_modifications(
242250 }
243251 }
244252
245- Inode :: Leaf ( leaf) => match pristine. ref_leaf ( path) {
246- Ok ( old_leaf) => {
253+ Inode :: Leaf ( leaf_id, _) => match pristine. leaf_id ( path) {
254+ Ok ( old_leaf_id) => {
255+ let leaf = & current_leaves[ leaf_id. 0 ] ;
256+ let old_leaf = & pristine_leaves[ old_leaf_id. 0 ] ;
247257 if !stat_eq_ignore_mtime ( & old_leaf. stat , & leaf. stat ) {
248258 diff. modified . push ( current_path. clone ( ) ) ;
249259 current_path. pop ( ) ;
@@ -328,22 +338,31 @@ pub fn traverse_etc(
328338 current_etc : & CapStdDir ,
329339 new_etc : Option < & CapStdDir > ,
330340) -> anyhow:: Result < (
331- Directory < CustomMetadata > ,
332- Directory < CustomMetadata > ,
333- Option < Directory < CustomMetadata > > ,
341+ FileSystem < CustomMetadata > ,
342+ FileSystem < CustomMetadata > ,
343+ Option < FileSystem < CustomMetadata > > ,
334344) > {
335- let mut pristine_etc_files = Directory :: new ( Stat :: uninitialized ( ) ) ;
336- recurse_dir ( pristine_etc, & mut pristine_etc_files)
337- . context ( format ! ( "Recursing {pristine_etc:?}" ) ) ?;
345+ let mut pristine_etc_files = FileSystem :: new ( Stat :: uninitialized ( ) ) ;
346+ recurse_dir (
347+ pristine_etc,
348+ & mut pristine_etc_files. root ,
349+ & mut pristine_etc_files. leaves ,
350+ )
351+ . context ( format ! ( "Recursing {pristine_etc:?}" ) ) ?;
338352
339- let mut current_etc_files = Directory :: new ( Stat :: uninitialized ( ) ) ;
340- recurse_dir ( current_etc, & mut current_etc_files)
341- . context ( format ! ( "Recursing {current_etc:?}" ) ) ?;
353+ let mut current_etc_files = FileSystem :: new ( Stat :: uninitialized ( ) ) ;
354+ recurse_dir (
355+ current_etc,
356+ & mut current_etc_files. root ,
357+ & mut current_etc_files. leaves ,
358+ )
359+ . context ( format ! ( "Recursing {current_etc:?}" ) ) ?;
342360
343361 let new_etc_files = match new_etc {
344362 Some ( new_etc) => {
345- let mut new_etc_files = Directory :: new ( Stat :: uninitialized ( ) ) ;
346- recurse_dir ( new_etc, & mut new_etc_files) . context ( format ! ( "Recursing {new_etc:?}" ) ) ?;
363+ let mut new_etc_files = FileSystem :: new ( Stat :: uninitialized ( ) ) ;
364+ recurse_dir ( new_etc, & mut new_etc_files. root , & mut new_etc_files. leaves )
365+ . context ( format ! ( "Recursing {new_etc:?}" ) ) ?;
347366
348367 Some ( new_etc_files)
349368 }
@@ -357,9 +376,9 @@ pub fn traverse_etc(
357376/// Computes the differences between two directory snapshots.
358377#[ context( "Computing diff" ) ]
359378pub fn compute_diff (
360- pristine_etc_files : & Directory < CustomMetadata > ,
361- current_etc_files : & Directory < CustomMetadata > ,
362- new_etc_files : & Directory < CustomMetadata > ,
379+ pristine_etc_files : & FileSystem < CustomMetadata > ,
380+ current_etc_files : & FileSystem < CustomMetadata > ,
381+ new_etc_files : & FileSystem < CustomMetadata > ,
363382) -> anyhow:: Result < Diff > {
364383 let mut diff = Diff {
365384 added : vec ! [ ] ,
@@ -368,16 +387,18 @@ pub fn compute_diff(
368387 } ;
369388
370389 get_modifications (
371- & pristine_etc_files,
372- & current_etc_files,
373- & new_etc_files,
390+ & pristine_etc_files. root ,
391+ & current_etc_files. root ,
392+ & pristine_etc_files. leaves ,
393+ & current_etc_files. leaves ,
394+ & new_etc_files. root ,
374395 PathBuf :: new ( ) ,
375396 & mut diff,
376397 ) ?;
377398
378399 get_deletions (
379- & pristine_etc_files,
380- & current_etc_files,
400+ & pristine_etc_files. root ,
401+ & current_etc_files. root ,
381402 PathBuf :: new ( ) ,
382403 & mut diff,
383404 ) ?;
@@ -418,7 +439,7 @@ fn collect_xattrs(etc_fd: &CapStdDir, rel_path: impl AsRef<Path>) -> anyhow::Res
418439 size = llistxattr ( & path, & mut xattrs_name_buf) . context ( "llistxattr" ) ?;
419440 }
420441
421- let xattrs: Xattrs = RefCell :: new ( BTreeMap :: new ( ) ) ;
442+ let mut xattrs: Xattrs = BTreeMap :: new ( ) ;
422443
423444 for name_buf in xattrs_name_buf[ ..size]
424445 . split ( |& b| b == 0 )
@@ -434,7 +455,7 @@ fn collect_xattrs(etc_fd: &CapStdDir, rel_path: impl AsRef<Path>) -> anyhow::Res
434455 size = lgetxattr ( & path, name_buf, & mut xattrs_value_buf) . context ( "lgetxattr" ) ?;
435456 }
436457
437- xattrs. borrow_mut ( ) . insert (
458+ xattrs. insert (
438459 Box :: < OsStr > :: from ( name) ,
439460 Box :: < [ u8 ] > :: from ( & xattrs_value_buf[ ..size] ) ,
440461 ) ;
@@ -445,7 +466,7 @@ fn collect_xattrs(etc_fd: &CapStdDir, rel_path: impl AsRef<Path>) -> anyhow::Res
445466
446467#[ context( "Copying xattrs" ) ]
447468fn copy_xattrs ( xattrs : & Xattrs , new_etc_fd : & CapStdDir , path : & Path ) -> anyhow:: Result < ( ) > {
448- for ( attr, value) in xattrs. borrow ( ) . iter ( ) {
469+ for ( attr, value) in xattrs. iter ( ) {
449470 let fdpath = & Path :: new ( & format ! ( "/proc/self/fd/{}" , new_etc_fd. as_raw_fd( ) ) ) . join ( path) ;
450471 lsetxattr ( fdpath, attr. as_ref ( ) , value, XattrFlags :: empty ( ) )
451472 . with_context ( || format ! ( "setxattr {attr:?} for {fdpath:?}" ) ) ?;
@@ -454,7 +475,11 @@ fn copy_xattrs(xattrs: &Xattrs, new_etc_fd: &CapStdDir, path: &Path) -> anyhow::
454475 Ok ( ( ) )
455476}
456477
457- fn recurse_dir ( dir : & CapStdDir , root : & mut Directory < CustomMetadata > ) -> anyhow:: Result < ( ) > {
478+ fn recurse_dir (
479+ dir : & CapStdDir ,
480+ root : & mut Directory < CustomMetadata > ,
481+ leaves : & mut Vec < Leaf < CustomMetadata > > ,
482+ ) -> anyhow:: Result < ( ) > {
458483 for entry in dir. entries ( ) ? {
459484 let entry = entry. context ( format ! ( "Getting entry" ) ) ?;
460485 let entry_name = entry. file_name ( ) ;
@@ -474,13 +499,12 @@ fn recurse_dir(dir: &CapStdDir, root: &mut Directory<CustomMetadata>) -> anyhow:
474499
475500 let os_str = OsStr :: from_bytes ( readlinkat_result. as_bytes ( ) ) ;
476501
477- root. insert (
478- & entry_name,
479- Inode :: Leaf ( Rc :: new ( Leaf {
480- stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
481- content : LeafContent :: Symlink ( Box :: from ( os_str) ) ,
482- } ) ) ,
483- ) ;
502+ let id = LeafId ( leaves. len ( ) ) ;
503+ leaves. push ( Leaf {
504+ stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
505+ content : LeafContent :: Symlink ( Box :: from ( os_str) ) ,
506+ } ) ;
507+ root. insert ( & entry_name, Inode :: leaf ( id) ) ;
484508
485509 continue ;
486510 }
@@ -492,7 +516,7 @@ fn recurse_dir(dir: &CapStdDir, root: &mut Directory<CustomMetadata>) -> anyhow:
492516
493517 let mut directory = Directory :: new ( MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ) ;
494518
495- recurse_dir ( & dir, & mut directory) ?;
519+ recurse_dir ( & dir, & mut directory, leaves ) ?;
496520
497521 root. insert ( & entry_name, Inode :: Directory ( Box :: new ( directory) ) ) ;
498522
@@ -524,16 +548,15 @@ fn recurse_dir(dir: &CapStdDir, root: &mut Directory<CustomMetadata>) -> anyhow:
524548 } ;
525549
526550 if let Some ( measured_verity) = measured_verity {
527- root. insert (
528- & entry_name,
529- Inode :: Leaf ( Rc :: new ( Leaf {
530- stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
531- content : LeafContent :: Regular ( CustomMetadata :: new (
532- "" . into ( ) ,
533- Some ( measured_verity) ,
534- ) ) ,
535- } ) ) ,
536- ) ;
551+ let id = LeafId ( leaves. len ( ) ) ;
552+ leaves. push ( Leaf {
553+ stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
554+ content : LeafContent :: Regular ( CustomMetadata :: new (
555+ "" . into ( ) ,
556+ Some ( measured_verity) ,
557+ ) ) ,
558+ } ) ;
559+ root. insert ( & entry_name, Inode :: leaf ( id) ) ;
537560
538561 continue ;
539562 }
@@ -549,13 +572,12 @@ fn recurse_dir(dir: &CapStdDir, root: &mut Directory<CustomMetadata>) -> anyhow:
549572
550573 let content_digest = hex:: encode ( hasher. finish ( ) ?) ;
551574
552- root. insert (
553- & entry_name,
554- Inode :: Leaf ( Rc :: new ( Leaf {
555- stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
556- content : LeafContent :: Regular ( CustomMetadata :: new ( content_digest, None ) ) ,
557- } ) ) ,
558- ) ;
575+ let id = LeafId ( leaves. len ( ) ) ;
576+ leaves. push ( Leaf {
577+ stat : MyStat :: from ( ( & entry_meta, xattrs) ) . 0 ,
578+ content : LeafContent :: Regular ( CustomMetadata :: new ( content_digest, None ) ) ,
579+ } ) ;
580+ root. insert ( & entry_name, Inode :: leaf ( id) ) ;
559581 }
560582
561583 Ok ( ( ) )
@@ -630,7 +652,7 @@ fn create_dir_with_perms(
630652fn merge_leaf (
631653 current_etc_fd : & CapStdDir ,
632654 new_etc_fd : & CapStdDir ,
633- leaf : & Rc < Leaf < CustomMetadata > > ,
655+ leaf : & Leaf < CustomMetadata > ,
634656 new_inode : Option < & Inode < CustomMetadata > > ,
635657 file : & PathBuf ,
636658) -> anyhow:: Result < ( ) > {
@@ -680,6 +702,7 @@ fn merge_modified_files(
680702 files : & Vec < PathBuf > ,
681703 current_etc_fd : & CapStdDir ,
682704 current_etc_dirtree : & Directory < CustomMetadata > ,
705+ current_leaves : & [ Leaf < CustomMetadata > ] ,
683706 new_etc_fd : & CapStdDir ,
684707 new_etc_dirtree : & Directory < CustomMetadata > ,
685708) -> anyhow:: Result < ( ) > {
@@ -701,22 +724,32 @@ fn merge_modified_files(
701724
702725 match current_inode {
703726 Inode :: Directory ( ..) => {
704- create_dir_with_perms ( new_etc_fd, file, current_inode. stat ( ) , new_inode) ?;
727+ create_dir_with_perms (
728+ new_etc_fd,
729+ file,
730+ current_inode. stat ( current_leaves) ,
731+ new_inode,
732+ ) ?;
705733 }
706734
707- Inode :: Leaf ( leaf) => {
735+ Inode :: Leaf ( leaf_id, _) => {
736+ let leaf = & current_leaves[ leaf_id. 0 ] ;
708737 merge_leaf ( current_etc_fd, new_etc_fd, leaf, new_inode, file) ?
709738 }
710739 } ;
711740 }
712741
713742 // Directory/File does not exist in the new /etc
714743 Err ( ImageError :: NotFound ( ..) ) => match current_inode {
715- Inode :: Directory ( ..) => {
716- create_dir_with_perms ( new_etc_fd, file, current_inode. stat ( ) , None ) ?
717- }
718-
719- Inode :: Leaf ( leaf) => {
744+ Inode :: Directory ( ..) => create_dir_with_perms (
745+ new_etc_fd,
746+ file,
747+ current_inode. stat ( current_leaves) ,
748+ None ,
749+ ) ?,
750+
751+ Inode :: Leaf ( leaf_id, _) => {
752+ let leaf = & current_leaves[ leaf_id. 0 ] ;
720753 merge_leaf ( current_etc_fd, new_etc_fd, leaf, None , file) ?;
721754 }
722755 } ,
@@ -734,26 +767,28 @@ fn merge_modified_files(
734767#[ context( "Merging" ) ]
735768pub fn merge (
736769 current_etc_fd : & CapStdDir ,
737- current_etc_dirtree : & Directory < CustomMetadata > ,
770+ current_etc_dirtree : & FileSystem < CustomMetadata > ,
738771 new_etc_fd : & CapStdDir ,
739- new_etc_dirtree : & Directory < CustomMetadata > ,
772+ new_etc_dirtree : & FileSystem < CustomMetadata > ,
740773 diff : & Diff ,
741774) -> anyhow:: Result < ( ) > {
742775 merge_modified_files (
743776 & diff. added ,
744777 current_etc_fd,
745- current_etc_dirtree,
778+ & current_etc_dirtree. root ,
779+ & current_etc_dirtree. leaves ,
746780 new_etc_fd,
747- new_etc_dirtree,
781+ & new_etc_dirtree. root ,
748782 )
749783 . context ( "Merging added files" ) ?;
750784
751785 merge_modified_files (
752786 & diff. modified ,
753787 current_etc_fd,
754- current_etc_dirtree,
788+ & current_etc_dirtree. root ,
789+ & current_etc_dirtree. leaves ,
755790 new_etc_fd,
756- new_etc_dirtree,
791+ & new_etc_dirtree. root ,
757792 )
758793 . context ( "Merging modified files" ) ?;
759794
0 commit comments