@@ -68,9 +68,17 @@ fn new_tempfile_linux(d: &Dir, anonymous: bool) -> io::Result<Option<File>> {
6868 if anonymous {
6969 oflags |= OFlags :: EXCL ;
7070 }
71- // We default to 0o666, same as main rust when creating new files; this will be
72- // modified by umask: <https://github.com/rust-lang/rust/blob/44628f7273052d0bb8e8218518dacab210e1fe0d/library/std/src/sys/unix/fs.rs#L762>
73- let mode = Mode :: from_raw_mode ( 0o666 ) ;
71+ // For anonymous files, open with no permissions to discourage other
72+ // processes from opening them.
73+ //
74+ // For named files, default to 0o666, same as main rust when creating new
75+ // files; this will be modified by umask:
76+ // <https://github.com/rust-lang/rust/blob/44628f7273052d0bb8e8218518dacab210e1fe0d/library/std/src/sys/unix/fs.rs#L762>
77+ let mode = if anonymous {
78+ Mode :: from_raw_mode ( 0o000 )
79+ } else {
80+ Mode :: from_raw_mode ( 0o666 )
81+ } ;
7482 // Happy path - Linux with O_TMPFILE
7583 match rustix:: fs:: openat ( d, "." , oflags, mode) {
7684 Ok ( r) => Ok ( Some ( File :: from ( r) ) ) ,
@@ -111,11 +119,29 @@ fn new_tempfile(d: &Dir, anonymous: bool) -> io::Result<(File, Option<String>)>
111119 opts. read ( true ) ;
112120 opts. write ( true ) ;
113121 opts. create_new ( true ) ;
122+ #[ cfg( unix) ]
123+ if anonymous {
124+ use cap_std:: fs:: OpenOptionsExt ;
125+ opts. mode ( 0 ) ;
126+ }
127+ #[ cfg( windows) ]
128+ if anonymous {
129+ use cap_std:: fs:: OpenOptionsExt ;
130+ use windows_sys:: Win32 :: Storage :: FileSystem :: {
131+ FILE_ATTRIBUTE_TEMPORARY , FILE_FLAG_DELETE_ON_CLOSE ,
132+ } ;
133+ opts. share_mode ( 0 ) ;
134+ opts. custom_flags ( FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE ) ;
135+ }
114136 let ( f, name) = super :: retry_with_name_ignoring ( io:: ErrorKind :: AlreadyExists , |name| {
115137 d. open_with ( name, & opts)
116138 } ) ?;
117139 if anonymous {
118- d. remove_file ( name) ?;
140+ // On Windows we use `FILE_FLAG_DELETE_ON_CLOSE` instead.
141+ #[ cfg( not( windows) ) ]
142+ {
143+ d. remove_file ( name) ?;
144+ }
119145 Ok ( ( f, None ) )
120146 } else {
121147 Ok ( ( f, Some ( name) ) )
@@ -217,26 +243,22 @@ mod test {
217243 use super :: * ;
218244
219245 /// On Unix, calling `umask()` actually *mutates* the process global state.
220- /// This uses Linux `/proc` to read the current value .
221- #[ cfg( any ( target_os = "android" , target_os = "linux" ) ) ]
246+ /// This uses a temporary file instead .
247+ #[ cfg( unix ) ]
222248 fn get_process_umask ( ) -> io:: Result < u32 > {
223- use io:: BufRead ;
224- let status = std:: fs:: File :: open ( "/proc/self/status" ) ?;
225- let bufr = io:: BufReader :: new ( status) ;
226- for line in bufr. lines ( ) {
227- let line = line?;
228- let l = if let Some ( v) = line. split_once ( ':' ) {
229- v
230- } else {
231- continue ;
232- } ;
233- let ( k, v) = l;
234- if k != "Umask" {
235- continue ;
236- }
237- return Ok ( u32:: from_str_radix ( v. trim ( ) , 8 ) . unwrap ( ) ) ;
238- }
239- panic ! ( "Could not determine process umask" )
249+ use std:: os:: unix:: fs:: { MetadataExt , OpenOptionsExt } ;
250+
251+ let d = :: tempfile:: tempdir ( ) . unwrap ( ) ;
252+ let p = d. path ( ) . join ( "file" ) ;
253+
254+ let mut opts = std:: fs:: OpenOptions :: new ( ) ;
255+ opts. read ( true ) ;
256+ opts. write ( true ) ;
257+ opts. create_new ( true ) ;
258+ opts. mode ( 0o777 ) ;
259+ let f = opts. open ( p) . unwrap ( ) ;
260+ let m = f. metadata ( ) . unwrap ( ) ;
261+ Ok ( !m. mode ( ) & 0o777 )
240262 }
241263
242264 /// Older Windows versions don't support removing open files
@@ -262,15 +284,15 @@ mod test {
262284
263285 let mut tf = TempFile :: new ( & td) ?;
264286 // Test that we created with the right permissions
265- #[ cfg( any ( target_os = "android" , target_os = "linux" ) ) ]
287+ #[ cfg( unix ) ]
266288 {
267289 use cap_std:: fs_utf8:: MetadataExt ;
268290 use rustix:: fs:: Mode ;
269291 let umask = get_process_umask ( ) ?;
270292 let metadata = tf. as_file ( ) . metadata ( ) . unwrap ( ) ;
271293 let mode = metadata. mode ( ) ;
272- let mode = Mode :: from_bits_truncate ( mode) ;
273- assert_eq ! ( 0o666 & !umask, mode. bits( ) & 0o777 ) ;
294+ let mode = Mode :: from_bits_truncate ( mode as _ ) ;
295+ assert_eq ! ( 0o666 & !umask, ( mode. bits( ) & 0o777 ) as _ ) ;
274296 }
275297 // And that we can write
276298 tf. write_all ( b"hello world" ) ?;
@@ -291,6 +313,17 @@ mod test {
291313 let mut buf = String :: new ( ) ;
292314 tf. read_to_string ( & mut buf) . unwrap ( ) ;
293315 assert_eq ! ( & buf, "hello world, I'm anonymous" ) ;
316+
317+ // Test that we created with the right permissions
318+ #[ cfg( unix) ]
319+ {
320+ use cap_std:: fs_utf8:: MetadataExt ;
321+ use rustix:: fs:: Mode ;
322+ let metadata = tf. metadata ( ) . unwrap ( ) ;
323+ let mode = metadata. mode ( ) ;
324+ let mode = Mode :: from_bits_truncate ( mode as _ ) ;
325+ assert_eq ! ( 0o000 , mode. bits( ) & 0o777 ) ;
326+ }
294327 } else if cfg ! ( windows) {
295328 eprintln ! ( "notice: Detected older Windows" ) ;
296329 }
0 commit comments