(bytes: &[u8], f: F)
| 946 | #[allow(unsafe_code, clippy::int_plus_one)] |
| 947 | #[inline] |
| 948 | fn with_c_str<T, F>(bytes: &[u8], f: F) -> io::Result<T> |
| 949 | where |
| 950 | F: FnOnce(&CStr) -> io::Result<T>, |
| 951 | { |
| 952 | // Most paths are less than `SMALL_PATH_BUFFER_SIZE` long. The rest can go |
| 953 | // through the dynamic allocation path. If you're opening many files in a |
| 954 | // directory with a long path, consider opening the directory and using |
| 955 | // `openat` to open the files under it, which will avoid this, and is often |
| 956 | // faster in the OS as well. |
| 957 | |
| 958 | // Test with `>=` so that we have room for the trailing NUL. |
| 959 | if bytes.len() >= SMALL_PATH_BUFFER_SIZE { |
| 960 | return with_c_str_slow_path(bytes, f); |
| 961 | } |
| 962 | |
| 963 | // Taken from |
| 964 | // <https://github.com/rust-lang/rust/blob/a00f8ba7fcac1b27341679c51bf5a3271fa82df3/library/std/src/sys/common/small_c_string.rs> |
| 965 | let mut buf = MaybeUninit::<[u8; SMALL_PATH_BUFFER_SIZE]>::uninit(); |
| 966 | let buf_ptr = buf.as_mut_ptr().cast::<u8>(); |
| 967 | |
| 968 | // This helps test our safety condition below. |
| 969 | debug_assert!(bytes.len() + 1 <= SMALL_PATH_BUFFER_SIZE); |
| 970 | |
| 971 | // SAFETY: `bytes.len() < SMALL_PATH_BUFFER_SIZE` which means we have space |
| 972 | // for `bytes.len() + 1` `u8`s: |
| 973 | unsafe { |
| 974 | ptr::copy_nonoverlapping(bytes.as_ptr(), buf_ptr, bytes.len()); |
| 975 | buf_ptr.add(bytes.len()).write(b'\0'); |
| 976 | } |
| 977 | |
| 978 | // SAFETY: We just wrote the bytes above and they will remain valid for the |
| 979 | // duration of `f` because `buf` doesn't get dropped until the end of the |
| 980 | // function. |
| 981 | match CStr::from_bytes_with_nul(unsafe { slice::from_raw_parts(buf_ptr, bytes.len() + 1) }) { |
| 982 | Ok(s) => f(s), |
| 983 | Err(_) => Err(io::Errno::INVAL), |
| 984 | } |
| 985 | } |
| 986 | |
| 987 | /// The slow path which handles any length. In theory OS's only support up to |
| 988 | /// `PATH_MAX`, but we let the OS enforce that. |
no test coverage detected