Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from winapi to official windows crate #18

Merged
merged 4 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: obi1kenobi/cargo-semver-checks-action@v2
with:
verbose: true

rustfmt:
name: Check formatting
Expand Down
12 changes: 5 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "clircle"
version = "0.6.0"
version = "0.6.1"
authors = ["Niklas Mohrin <[email protected]>"]
license = "MIT OR Apache-2.0"
rust-version = "1.69"
Expand All @@ -24,12 +24,10 @@ serde_derive = { version = "1.0.117", optional = true }
cfg-if = "1.0.0"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["winnt", "winbase", "processenv", "handleapi", "ntdef", "fileapi", "std"] }
windows = { version = "0.56.0", features = ["Win32_Storage_FileSystem", "Win32_System_Console"] }

[dev-dependencies]
tempfile = "3.1.0"
tempfile = "3.4.0"

[target.'cfg(unix)'.dev-dependencies.nix]
version = "0.29"
default-features = false
features = ["term"]
[target.'cfg(unix)'.dev-dependencies]
nix = { version = "0.29", default-features = false, features = ["term"] }
58 changes: 27 additions & 31 deletions src/clircle_windows.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
use crate::{Clircle, Stdio};

use winapi::shared::ntdef::NULL;
use winapi::um::{
fileapi::{GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION},
handleapi::INVALID_HANDLE_VALUE,
processenv::GetStdHandle,
winbase::{FILE_TYPE_DISK, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
use windows::Win32::{
Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE},
Storage::FileSystem::{
GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION, FILE_TYPE_DISK,
},
System::Console::{GetStdHandle, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
};

use std::convert::TryFrom;
use std::fs::File;
use std::mem::MaybeUninit;
use std::os::windows::io::{FromRawHandle, IntoRawHandle, RawHandle};
use std::os::windows::io::{FromRawHandle, IntoRawHandle};
use std::{cmp, hash, io, mem, ops};

/// Implementation of `Clircle` for Windows.
#[derive(Debug)]
pub(crate) struct Identifier {
volume_serial: u32,
file_index: u64,
handle: RawHandle,
handle: HANDLE,
owns_handle: bool,
}

impl Identifier {
unsafe fn try_from_raw_handle(handle: RawHandle, owns_handle: bool) -> Result<Self, io::Error> {
if handle == INVALID_HANDLE_VALUE || handle == NULL {
unsafe fn try_from_raw_handle(handle: HANDLE, owns_handle: bool) -> Result<Self, io::Error> {
if handle.is_invalid() {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Tried to convert handle to Identifier that was invalid or null.",
Expand All @@ -42,24 +42,20 @@ impl Identifier {
let mut fi = MaybeUninit::<BY_HANDLE_FILE_INFORMATION>::uninit();
// SAFETY: This function is safe to call, if the handle is valid and a handle to a file.
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileinformationbyhandle
let success = GetFileInformationByHandle(handle, fi.as_mut_ptr());
if success == 0 {
Err(io::Error::last_os_error())
} else {
// SAFETY: If the return value of GetFileInformationByHandle is non-zero, the struct
// has successfully been initialized (see link above).
let fi = fi.assume_init();

Ok(Self {
volume_serial: fi.dwVolumeSerialNumber,
file_index: u64::from(fi.nFileIndexHigh) << 32 | u64::from(fi.nFileIndexLow),
handle,
owns_handle,
})
}
GetFileInformationByHandle(handle, fi.as_mut_ptr())?;

// SAFETY: GetFileInformationByHandle returned successfully.
let fi = fi.assume_init();

Ok(Self {
volume_serial: fi.dwVolumeSerialNumber,
file_index: u64::from(fi.nFileIndexHigh) << 32 | u64::from(fi.nFileIndexLow),
handle,
owns_handle,
})
}

unsafe fn take_handle(&mut self) -> Option<RawHandle> {
unsafe fn take_handle(&mut self) -> Option<HANDLE> {
if self.owns_handle {
self.owns_handle = false;
Some(mem::replace(&mut self.handle, INVALID_HANDLE_VALUE))
Expand All @@ -72,7 +68,7 @@ impl Identifier {
impl Clircle for Identifier {
#[must_use]
fn into_inner(mut self) -> Option<File> {
Some(unsafe { File::from_raw_handle(self.take_handle()?) })
Some(unsafe { File::from_raw_handle(self.take_handle()?.0 as _) })
}
}

Expand All @@ -88,8 +84,8 @@ impl TryFrom<Stdio> for Identifier {

// SAFETY: This method can safely be called with one of the above constants.
// https://docs.microsoft.com/en-us/windows/console/getstdhandle
let handle = unsafe { GetStdHandle(std_handle_id) };
if handle == INVALID_HANDLE_VALUE || handle == NULL {
let handle = unsafe { GetStdHandle(std_handle_id) }?;
if handle.is_invalid() {
return Err(io::Error::last_os_error());
}

Expand All @@ -100,15 +96,15 @@ impl TryFrom<File> for Identifier {
type Error = io::Error;

fn try_from(file: File) -> Result<Self, Self::Error> {
unsafe { Self::try_from_raw_handle(file.into_raw_handle(), true) }
unsafe { Self::try_from_raw_handle(HANDLE(file.into_raw_handle() as _), true) }
}
}

impl ops::Drop for Identifier {
fn drop(&mut self) {
unsafe {
if let Some(handle) = self.take_handle() {
drop(File::from_raw_handle(handle));
let _ = CloseHandle(handle);
}
}
}
Expand Down