use std::io; use std::path::Path; pub(crate) async fn open(path: &Path) -> io::Result { let mut options = tokio::fs::OpenOptions::new(); options.read(true); configure_open(&mut options); let file = options.open(path).await?; if !is_disk_file(&file) || !file.metadata().await?.is_file() { return Err(io::Error::new( io::ErrorKind::InvalidInput, format!("path `{}` is not a file", path.display()), )); } Ok(file) } #[cfg(unix)] fn configure_open(options: &mut tokio::fs::OpenOptions) { options.custom_flags(libc::O_NONBLOCK); } #[cfg(windows)] fn configure_open(options: &mut tokio::fs::OpenOptions) { use windows_sys::Win32::Storage::FileSystem::SECURITY_IDENTIFICATION; options.security_qos_flags(SECURITY_IDENTIFICATION); } #[cfg(not(any(unix, windows)))] fn configure_open(_options: &mut tokio::fs::OpenOptions) {} #[cfg(windows)] fn is_disk_file(file: &tokio::fs::File) -> bool { use std::os::windows::io::AsRawHandle; use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Storage::FileSystem::FILE_TYPE_DISK; use windows_sys::Win32::Storage::FileSystem::GetFileType; // SAFETY: `file` owns this handle for the duration of the call. unsafe { GetFileType(file.as_raw_handle() as HANDLE) == FILE_TYPE_DISK } } #[cfg(not(windows))] fn is_disk_file(_file: &tokio::fs::File) -> bool { true }