@@ -698,12 +698,80 @@ pub fn page_size() -> usize {
698
698
unsafe { libc:: sysconf ( libc:: _SC_PAGESIZE) as usize }
699
699
}
700
700
701
+ // Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only
702
+ // used on Darwin, but should work on any unix (in case we need to get
703
+ // `_CS_PATH` or `_CS_V[67]_ENV` in the future).
704
+ //
705
+ // [posix_confstr]:
706
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html
707
+ #[ cfg( any( target_os = "macos" , target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ]
708
+ fn confstr ( key : c_int , size_hint : Option < usize > ) -> io:: Result < OsString > {
709
+ let mut buf: Vec < u8 > = Vec :: new ( ) ;
710
+ let mut bytes_needed_including_nul = size_hint
711
+ . unwrap_or_else ( || {
712
+ // Treat "None" as "do an extra call to get the length". In theory
713
+ // we could move this into the loop below, but it's hard to do given
714
+ // that it isn't 100% clear if it's legal to pass 0 for `len` when
715
+ // the buffer isn't null.
716
+ unsafe { libc:: confstr ( key, core:: ptr:: null_mut ( ) , 0 ) }
717
+ } )
718
+ . max ( 1 ) ;
719
+ // If the value returned by `confstr` is greater than the len passed into
720
+ // it, then the value was truncated, meaning we need to retry. Note that
721
+ // while `confstr` results don't seem to change for a process, it's unclear
722
+ // if this is guaranteed anywhere, so looping does seem required.
723
+ while bytes_needed_including_nul > buf. capacity ( ) {
724
+ // We write into the spare capacity of `buf`. This lets us avoid
725
+ // changing buf's `len`, which both simplifies `reserve` computation,
726
+ // allows working with `Vec<u8>` instead of `Vec<MaybeUninit<u8>>`, and
727
+ // may avoid a copy, since the Vec knows that none of the bytes are needed
728
+ // when reallocating (well, in theory anyway).
729
+ buf. reserve ( bytes_needed_including_nul) ;
730
+ // `confstr` returns
731
+ // - 0 in the case of errors: we break and return an error.
732
+ // - The number of bytes written, iff the provided buffer is enough to
733
+ // hold the entire value: we break and return the data in `buf`.
734
+ // - Otherwise, the number of bytes needed (including nul): we go
735
+ // through the loop again.
736
+ bytes_needed_including_nul =
737
+ unsafe { libc:: confstr ( key, buf. as_mut_ptr ( ) . cast :: < c_char > ( ) , buf. capacity ( ) ) } ;
738
+ }
739
+ // `confstr` returns 0 in the case of an error.
740
+ if bytes_needed_including_nul == 0 {
741
+ return Err ( io:: Error :: last_os_error ( ) ) ;
742
+ }
743
+ // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a
744
+ // non-zero value, meaning `bytes_needed_including_nul` bytes were
745
+ // initialized.
746
+ unsafe {
747
+ buf. set_len ( bytes_needed_including_nul) ;
748
+ // Remove the NUL-terminator.
749
+ let last_byte = buf. pop ( ) ;
750
+ // ... and smoke-check that it *was* a NUL-terminator.
751
+ assert_eq ! ( last_byte, Some ( 0 ) , "`confstr` provided a string which wasn't nul-terminated" ) ;
752
+ } ;
753
+ Ok ( OsString :: from_vec ( buf) )
754
+ }
755
+
756
+ #[ cfg( target_vendor = "apple" ) ]
757
+ fn darwin_temp_dir ( ) -> PathBuf {
758
+ confstr ( libc:: _CS_DARWIN_USER_TEMP_DIR, Some ( 64 ) ) . map ( PathBuf :: from) . unwrap_or_else ( |_| {
759
+ // It failed for whatever reason (there are several possible reasons),
760
+ // so return the global one.
761
+ PathBuf :: from ( "/tmp" )
762
+ } )
763
+ }
764
+
701
765
pub fn temp_dir ( ) -> PathBuf {
702
766
crate :: env:: var_os ( "TMPDIR" ) . map ( PathBuf :: from) . unwrap_or_else ( || {
703
- if cfg ! ( target_os = "android" ) {
704
- PathBuf :: from ( "/data/local/tmp" )
705
- } else {
706
- PathBuf :: from ( "/tmp" )
767
+ cfg_if:: cfg_if! {
768
+ if #[ cfg( any( target_os = "macos" , target_os = "ios" , target_os = "tvos" , target_os = "watchos" ) ) ] {
769
+ darwin_temp_dir( )
770
+ } else if #[ cfg( target_os = "android" ) ] {
771
+ PathBuf :: from( "/data/local/tmp" )
772
+ } else {
773
+ PathBuf :: from( "/tmp" )
774
+ }
707
775
}
708
776
} )
709
777
}
0 commit comments