@@ -47,41 +47,51 @@ impl<'a> RunChroot<'a> {
4747 fn bind_mount_directory ( & self , entry : & fs:: DirEntry ) {
4848 let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
4949
50- // if there is already a dir here, recurse into it,
51- // and mount any subdirs which don't already exist
52- if mountpoint. is_dir ( ) {
53- let dir = fs:: read_dir ( entry. path ( ) ) . unwrap_or_else ( |err| {
54- panic ! ( "failed to list dir {}: {}" , entry. path( ) . display( ) , err)
55- } ) ;
56-
57- let child = RunChroot :: new ( & mountpoint) ;
58- for entry in dir {
59- child. bind_mount_direntry ( entry) ;
60- }
61- } else {
50+ // if the destination doesn't exist we can proceed as normal
51+ if !mountpoint. exists ( ) {
6252 if let Err ( e) = fs:: create_dir ( & mountpoint) {
6353 if e. kind ( ) != io:: ErrorKind :: AlreadyExists {
6454 panic ! ( "failed to create {}: {}" , & mountpoint. display( ) , e) ;
6555 }
6656 }
6757
6858 bind_mount ( & entry. path ( ) , & mountpoint)
59+ } else {
60+ // otherwise, if the dest is also a dir, we can recurse into it
61+ // and mount subdirectory siblings of existing paths
62+ if mountpoint. is_dir ( ) {
63+ let dir = fs:: read_dir ( entry. path ( ) ) . unwrap_or_else ( |err| {
64+ panic ! ( "failed to list dir {}: {}" , entry. path( ) . display( ) , err)
65+ } ) ;
66+
67+ let child = RunChroot :: new ( & mountpoint) ;
68+ for entry in dir {
69+ let entry = entry. expect ( "error while listing subdir" ) ;
70+ child. bind_mount_direntry ( & entry) ;
71+ }
72+ }
6973 }
7074 }
7175
7276 fn bind_mount_file ( & self , entry : & fs:: DirEntry ) {
7377 let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
78+ if mountpoint. exists ( ) {
79+ return ;
80+ }
7481 fs:: File :: create ( & mountpoint)
7582 . unwrap_or_else ( |err| panic ! ( "failed to create {}: {}" , & mountpoint. display( ) , err) ) ;
7683
7784 bind_mount ( & entry. path ( ) , & mountpoint)
7885 }
7986
8087 fn mirror_symlink ( & self , entry : & fs:: DirEntry ) {
88+ let link_path = self . rootdir . join ( entry. file_name ( ) ) ;
89+ if link_path. exists ( ) {
90+ return ;
91+ }
8192 let path = entry. path ( ) ;
8293 let target = fs:: read_link ( & path)
8394 . unwrap_or_else ( |err| panic ! ( "failed to resolve symlink {}: {}" , & path. display( ) , err) ) ;
84- let link_path = self . rootdir . join ( entry. file_name ( ) ) ;
8595 symlink ( & target, & link_path) . unwrap_or_else ( |_| {
8696 panic ! (
8797 "failed to create symlink {} -> {}" ,
@@ -91,16 +101,12 @@ impl<'a> RunChroot<'a> {
91101 } ) ;
92102 }
93103
94- fn bind_mount_direntry ( & self , entry : io:: Result < fs:: DirEntry > ) {
95- let entry = entry. expect ( "error while listing from /nix directory" ) ;
96- // do not bind mount an existing nix installation
97- if entry. file_name ( ) == PathBuf :: from ( "nix" ) {
98- return ;
99- }
104+ fn bind_mount_direntry ( & self , entry : & fs:: DirEntry ) {
100105 let path = entry. path ( ) ;
101106 let stat = entry
102107 . metadata ( )
103108 . unwrap_or_else ( |err| panic ! ( "cannot get stat of {}: {}" , path. display( ) , err) ) ;
109+
104110 if stat. is_dir ( ) {
105111 self . bind_mount_directory ( & entry) ;
106112 } else if stat. is_file ( ) {
@@ -132,7 +138,12 @@ impl<'a> RunChroot<'a> {
132138 let nix_root = PathBuf :: from ( "/" ) ;
133139 let dir = fs:: read_dir ( & nix_root) . expect ( "failed to list /nix directory" ) ;
134140 for entry in dir {
135- self . bind_mount_direntry ( entry) ;
141+ let entry = entry. expect ( "error while listing from /nix directory" ) ;
142+ // do not bind mount an existing nix installation
143+ if entry. file_name ( ) == PathBuf :: from ( "nix" ) {
144+ continue ;
145+ }
146+ self . bind_mount_direntry ( & entry) ;
136147 }
137148
138149 // mount the store
0 commit comments