@@ -47,41 +47,51 @@ impl<'a> RunChroot<'a> {
47
47
fn bind_mount_directory ( & self , entry : & fs:: DirEntry ) {
48
48
let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
49
49
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 ( ) {
62
52
if let Err ( e) = fs:: create_dir ( & mountpoint) {
63
53
if e. kind ( ) != io:: ErrorKind :: AlreadyExists {
64
54
panic ! ( "failed to create {}: {}" , & mountpoint. display( ) , e) ;
65
55
}
66
56
}
67
57
68
58
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
+ }
69
73
}
70
74
}
71
75
72
76
fn bind_mount_file ( & self , entry : & fs:: DirEntry ) {
73
77
let mountpoint = self . rootdir . join ( entry. file_name ( ) ) ;
78
+ if mountpoint. exists ( ) {
79
+ return ;
80
+ }
74
81
fs:: File :: create ( & mountpoint)
75
82
. unwrap_or_else ( |err| panic ! ( "failed to create {}: {}" , & mountpoint. display( ) , err) ) ;
76
83
77
84
bind_mount ( & entry. path ( ) , & mountpoint)
78
85
}
79
86
80
87
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
+ }
81
92
let path = entry. path ( ) ;
82
93
let target = fs:: read_link ( & path)
83
94
. unwrap_or_else ( |err| panic ! ( "failed to resolve symlink {}: {}" , & path. display( ) , err) ) ;
84
- let link_path = self . rootdir . join ( entry. file_name ( ) ) ;
85
95
symlink ( & target, & link_path) . unwrap_or_else ( |_| {
86
96
panic ! (
87
97
"failed to create symlink {} -> {}" ,
@@ -91,16 +101,12 @@ impl<'a> RunChroot<'a> {
91
101
} ) ;
92
102
}
93
103
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 ) {
100
105
let path = entry. path ( ) ;
101
106
let stat = entry
102
107
. metadata ( )
103
108
. unwrap_or_else ( |err| panic ! ( "cannot get stat of {}: {}" , path. display( ) , err) ) ;
109
+
104
110
if stat. is_dir ( ) {
105
111
self . bind_mount_directory ( & entry) ;
106
112
} else if stat. is_file ( ) {
@@ -132,7 +138,12 @@ impl<'a> RunChroot<'a> {
132
138
let nix_root = PathBuf :: from ( "/" ) ;
133
139
let dir = fs:: read_dir ( & nix_root) . expect ( "failed to list /nix directory" ) ;
134
140
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) ;
136
147
}
137
148
138
149
// mount the store
0 commit comments