@@ -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,51 @@ 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
+
203
+ // On non-unix platforms, get the "readonly" permission of the original file.
204
+ #[ cfg( not( unix) ) ]
205
+ let readonly = path
206
+ . metadata ( )
207
+ . ok ( )
208
+ . map ( |meta| meta. permissions ( ) . readonly ( ) ) ;
209
+
188
210
let mut tmp = TempFileBuilder :: new ( )
189
211
. prefix ( path. file_name ( ) . unwrap ( ) )
190
212
. tempfile_in ( path. parent ( ) . unwrap ( ) ) ?;
191
213
tmp. write_all ( contents. as_ref ( ) ) ?;
214
+
215
+ // On unix platforms, set the permissions on the newly created file. We can use fchmod (called
216
+ // by the std lib; subject to change) which ignores the umask so that the new file has the same
217
+ // permissions as the old file.
218
+ #[ cfg( unix) ]
219
+ if let Some ( perms) = perms {
220
+ tmp. as_file ( ) . set_permissions ( perms) ?;
221
+ }
222
+
223
+ // On non-unix platforms, update the readonly permissions on the newly created file.
224
+ #[ cfg( not( unix) ) ]
225
+ if let Some ( readonly) = readonly {
226
+ if let Ok ( metadata) = tmp. as_file ( ) . metadata ( ) {
227
+ let mut perms = metadata. permissions ( ) ;
228
+ perms. set_readonly ( readonly) ;
229
+ tmp. as_file ( ) . set_permissions ( perms) ?;
230
+ }
231
+ }
232
+
192
233
tmp. persist ( path) ?;
193
234
Ok ( ( ) )
194
235
}
0 commit comments