@@ -9,6 +9,9 @@ use walkdir::WalkDir;
99use crate :: config:: * ;
1010use crate :: errors:: Failure ;
1111use crate :: errors:: Failure :: * ;
12+ use std:: fs;
13+ use std:: os:: unix:: fs:: PermissionsExt ;
14+ use std:: fs:: Metadata ;
1215
1316pub fn apply_permissions ( path : & str ) -> Result < ( ) , Failure > {
1417 check_path ( path) . and_then ( check_links) . and_then ( visit_all)
@@ -47,7 +50,13 @@ fn check_links(path: &Path) -> Result<&Path, Failure> {
4750 } )
4851}
4952
53+ fn add_parent_permissions ( parent : & Path ) -> Result < ( ) , Failure > {
54+ let mask = fetch_permissions ( parent) | CHMOD_MASK_WX_GROUP ;
55+ set_permissions ( parent, mask)
56+ }
57+
5058fn visit_all ( path : & Path ) -> Result < ( ) , Failure > {
59+ let parent_result = path. parent ( ) . map_or ( Ok ( ( ) ) , |p| add_parent_permissions ( p) . and_then ( |_| set_group ( p) ) ) ;
5160 let result: Result < Vec < ( ) > , Failure > = WalkDir :: new ( path)
5261 . into_iter ( )
5362 . map ( |e| {
@@ -60,13 +69,21 @@ fn visit_all(path: &Path) -> Result<(), Failure> {
6069 }
6170 } )
6271 . collect ( ) ;
63- result. map ( |_| ( ) )
72+ parent_result. and_then ( |_| result. map ( |_| ( ) ) )
73+
6474}
6575
6676fn set_owner ( path : & Path ) -> Result < ( ) , Failure > {
77+ set_custom_owner ( path, get_uid ( ) ?, get_gid ( ) ?)
78+ }
79+
80+ fn set_group ( path : & Path ) -> Result < ( ) , Failure > {
81+ let metadata = fetch_metadata ( path) ;
82+ set_custom_owner ( path, metadata. uid ( ) , get_gid ( ) ?)
83+ }
84+
85+ fn set_custom_owner ( path : & Path , uid : u32 , gid : u32 ) -> Result < ( ) , Failure > {
6786 let p = CString :: new ( path. as_os_str ( ) . as_bytes ( ) ) . map_err ( |_| PathCannotHaveNull ) ?;
68- let uid = get_uid ( ) ?;
69- let gid = get_gid ( ) ?;
7087 let chown = unsafe { chown ( p. as_ptr ( ) as * const i8 , uid, gid) } ;
7188 if chown == 0 {
7289 Ok ( ( ) )
@@ -85,11 +102,18 @@ fn set_permissions(path: &Path, mask: u32) -> Result<(), Failure> {
85102 }
86103}
87104
105+ fn fetch_permissions ( path : & Path ) -> u32 {
106+ fetch_metadata ( path) . permissions ( ) . mode ( )
107+ }
108+
109+ fn fetch_metadata ( path : & Path ) -> Metadata {
110+ fs:: metadata ( path) . expect ( "failed to read file metadata" )
111+ }
112+
88113#[ cfg( test) ]
89114mod tests {
90- use std:: fs;
91115 use std:: io;
92- use std:: os:: unix:: fs:: { symlink, MetadataExt , PermissionsExt } ;
116+ use std:: os:: unix:: fs:: { symlink, MetadataExt } ;
93117
94118 use rand:: { thread_rng, Rng } ;
95119
@@ -123,6 +147,19 @@ mod tests {
123147 assert ! ( fs:: remove_file( p) . is_ok( ) ) ;
124148 }
125149
150+ #[ test]
151+ fn test_set_group ( ) {
152+ setup ( ) ;
153+ let p = Path :: new ( "/tmp/nexus-fixer/batman" ) ;
154+ assert ! ( touch( p) . is_ok( ) ) ;
155+ assert ! ( set_owner( p) . is_ok( ) ) ;
156+ check_group (
157+ p,
158+ get_gid ( ) . expect ( "failed to read GID" ) ,
159+ ) ;
160+ assert ! ( fs:: remove_file( p) . is_ok( ) ) ;
161+ }
162+
126163 #[ test]
127164 fn test_set_permissions ( ) {
128165 setup ( ) ;
@@ -171,6 +208,7 @@ mod tests {
171208 assert ! ( touch( file_a) . is_ok( ) ) ;
172209 assert ! ( touch( file_b) . is_ok( ) ) ;
173210 assert ! ( touch( file_c) . is_ok( ) ) ;
211+ check_permissions ( Path :: new ( "/tmp/nexus-fixer/" ) , 0o755 ) ;
174212 assert ! ( visit_all( Path :: new( "/tmp/nexus-fixer/a" ) ) . is_ok( ) ) ;
175213
176214 let uid = get_uid ( ) . expect ( "failed to read UID" ) ;
@@ -183,6 +221,8 @@ mod tests {
183221 check_owner ( Path :: new ( "/tmp/nexus-fixer/a/b" ) , uid, gid) ;
184222 check_permissions ( Path :: new ( "/tmp/nexus-fixer/a/b/c" ) , DIR_MASK ) ;
185223 check_owner ( Path :: new ( "/tmp/nexus-fixer/a/b/c" ) , uid, gid) ;
224+ check_permissions ( Path :: new ( "/tmp/nexus-fixer/" ) , 0o775 ) ;
225+
186226 // files
187227 check_permissions ( file_a, FILE_MASK ) ;
188228 check_owner ( file_a, uid, gid) ;
@@ -194,14 +234,18 @@ mod tests {
194234 }
195235
196236 fn check_owner ( path : & Path , uid : u32 , gid : u32 ) {
197- let metadata = fs :: metadata ( path) . expect ( "failed to read file metadata" ) ;
237+ let metadata = fetch_metadata ( path) ;
198238 assert_eq ! ( metadata. uid( ) , uid) ;
199239 assert_eq ! ( metadata. gid( ) , gid) ;
200240 }
201241
242+ fn check_group ( path : & Path , gid : u32 ) {
243+ let metadata = fetch_metadata ( path) ;
244+ assert_eq ! ( metadata. gid( ) , gid) ;
245+ }
246+
202247 fn check_permissions ( path : & Path , mask : u32 ) {
203- let metadata = fs:: metadata ( path) . expect ( "failed to read file metadata" ) ;
204- assert_eq ! ( metadata. permissions( ) . mode( ) & 0o777 , mask) ;
248+ assert_eq ! ( fetch_permissions( path) & 0o777 , mask) ;
205249 }
206250
207251 fn random_mask ( ) -> u32 {
0 commit comments