@@ -4,7 +4,7 @@ use anyhow::{Context, Result};
4
4
use filetime:: FileTime ;
5
5
use std:: env;
6
6
use std:: ffi:: { OsStr , OsString } ;
7
- use std:: fs:: { self , File , Metadata , OpenOptions } ;
7
+ use std:: fs:: { self , File , Metadata , OpenOptions , Permissions } ;
8
8
use std:: io;
9
9
use std:: io:: prelude:: * ;
10
10
use std:: iter;
@@ -185,10 +185,34 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()>
185
185
/// write_atomic uses tempfile::persist to accomplish atomic writes.
186
186
pub fn write_atomic < P : AsRef < Path > , C : AsRef < [ u8 ] > > ( path : P , contents : C ) -> Result < ( ) > {
187
187
let path = path. as_ref ( ) ;
188
+
189
+ // On unix platforms, get the permissions of the original file. Copy only the user/group/other
190
+ // read/write/execute permission bits. The tempfile lib defaults to an initial mode of 0o600,
191
+ // and we'll set the proper permissions after creating the file.
192
+ #[ cfg( unix) ]
193
+ let perms = path. metadata ( ) . ok ( ) . map ( |meta| {
194
+ use std:: os:: unix:: fs:: PermissionsExt ;
195
+
196
+ // these constants are u16 on macOS
197
+ let mask = u32:: from ( libc:: S_IRWXU | libc:: S_IRWXG | libc:: S_IRWXO ) ;
198
+ let mode = meta. permissions ( ) . mode ( ) & mask;
199
+
200
+ Permissions :: from_mode ( mode)
201
+ } ) ;
202
+
188
203
let mut tmp = TempFileBuilder :: new ( )
189
204
. prefix ( path. file_name ( ) . unwrap ( ) )
190
205
. tempfile_in ( path. parent ( ) . unwrap ( ) ) ?;
191
206
tmp. write_all ( contents. as_ref ( ) ) ?;
207
+
208
+ // On unix platforms, set the permissions on the newly created file. We can use fchmod (called
209
+ // by the std lib; subject to change) which ignores the umask so that the new file has the same
210
+ // permissions as the old file.
211
+ #[ cfg( unix) ]
212
+ if let Some ( perms) = perms {
213
+ tmp. as_file ( ) . set_permissions ( perms) ?;
214
+ }
215
+
192
216
tmp. persist ( path) ?;
193
217
Ok ( ( ) )
194
218
}
@@ -846,7 +870,7 @@ mod tests {
846
870
let new_perms = std:: fs:: metadata ( tmp. path ( ) ) . unwrap ( ) . permissions ( ) ;
847
871
848
872
let mask = u32:: from ( libc:: S_IRWXU | libc:: S_IRWXG | libc:: S_IRWXO ) ;
849
- assert_eq ! ( 0o600 , new_perms. mode( ) & mask) ;
873
+ assert_eq ! ( original_perms . mode ( ) , new_perms. mode( ) & mask) ;
850
874
}
851
875
852
876
#[ test]
0 commit comments