Skip to content
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