diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/winapi-util | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/winapi-util')
-rw-r--r-- | third_party/rust/winapi-util/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | third_party/rust/winapi-util/COPYING | 3 | ||||
-rw-r--r-- | third_party/rust/winapi-util/Cargo.toml | 30 | ||||
-rw-r--r-- | third_party/rust/winapi-util/LICENSE-MIT | 21 | ||||
-rw-r--r-- | third_party/rust/winapi-util/README.md | 58 | ||||
-rw-r--r-- | third_party/rust/winapi-util/UNLICENSE | 24 | ||||
-rw-r--r-- | third_party/rust/winapi-util/rustfmt.toml | 2 | ||||
-rw-r--r-- | third_party/rust/winapi-util/src/console.rs | 402 | ||||
-rw-r--r-- | third_party/rust/winapi-util/src/file.rs | 168 | ||||
-rw-r--r-- | third_party/rust/winapi-util/src/lib.rs | 32 | ||||
-rw-r--r-- | third_party/rust/winapi-util/src/win.rs | 246 |
11 files changed, 987 insertions, 0 deletions
diff --git a/third_party/rust/winapi-util/.cargo-checksum.json b/third_party/rust/winapi-util/.cargo-checksum.json new file mode 100644 index 0000000000..deb1761563 --- /dev/null +++ b/third_party/rust/winapi-util/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.toml":"8d5e3ed912b57104e1448a8437c840a5d5b9842e5cbb371429f9e879cb45fc56","LICENSE-MIT":"cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14","README.md":"b97062c8af7a615725a19394c8d26a19460a1840979196f0c119a1c1432d15f1","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/console.rs":"41d3d1d7501e9e4f8836d642bf8a848b690112fb707b040cabe7f8f1f0e4a692","src/file.rs":"5e2b5f60de7f8a2eeeafe165701eb0e442a0bafbf6df6e2e0d92fdccafd7a8bf","src/lib.rs":"36aba07c7bd526e341382b6471212ccfef8030f27b73a607f2539b307ccff8d1","src/win.rs":"146b65eae8fe2fe3c567609d7d7be0a983f607fc9d3fcdb5cd7ca6f2cc7bde33"},"package":"70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"}
\ No newline at end of file diff --git a/third_party/rust/winapi-util/COPYING b/third_party/rust/winapi-util/COPYING new file mode 100644 index 0000000000..bb9c20a094 --- /dev/null +++ b/third_party/rust/winapi-util/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/third_party/rust/winapi-util/Cargo.toml b/third_party/rust/winapi-util/Cargo.toml new file mode 100644 index 0000000000..fe6933cffb --- /dev/null +++ b/third_party/rust/winapi-util/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "winapi-util" +version = "0.1.5" +authors = ["Andrew Gallant <jamslam@gmail.com>"] +description = "A dumping ground for high level safe wrappers over winapi." +homepage = "https://github.com/BurntSushi/winapi-util" +documentation = "https://docs.rs/winapi-util" +readme = "README.md" +keywords = ["windows", "winapi", "util", "win"] +categories = ["os::windows-apis", "external-ffi-bindings"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/winapi-util" +[package.metadata.docs.rs] +targets = ["x86_64-pc-windows-msvc"] +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["std", "consoleapi", "errhandlingapi", "fileapi", "minwindef", "processenv", "winbase", "wincon", "winerror", "winnt"] diff --git a/third_party/rust/winapi-util/LICENSE-MIT b/third_party/rust/winapi-util/LICENSE-MIT new file mode 100644 index 0000000000..3303149e52 --- /dev/null +++ b/third_party/rust/winapi-util/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/third_party/rust/winapi-util/README.md b/third_party/rust/winapi-util/README.md new file mode 100644 index 0000000000..79e47301fc --- /dev/null +++ b/third_party/rust/winapi-util/README.md @@ -0,0 +1,58 @@ +winapi-util +=========== +This crate provides a smattering of safe wrappers around various parts of the +[winapi](https://crates.io/crates/winapi) crate. + +[![Build status](https://github.com/BurntSushi/winapi-util/workflows/ci/badge.svg)](https://github.com/BurntSushi/winapi-util/actions) +[![](http://meritbadge.herokuapp.com/winapi-util)](https://crates.io/crates/winapi-util) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +https://docs.rs/winapi-util + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +winapi-util = "0.1" +``` + + +### Notes + +This crate was born out of frustration with having to write lots of little +ffi utility bindings in a variety of crates in order to get Windows support. +Eventually, I started needing to copy & paste a lot of those utility routines. +Since they are utility routines, they often don't make sense to expose directly +in the crate in which they are defined. Instead of continuing this process, +I decided to make a crate instead. + +Normally, I'm not a huge fan of "utility" crates like this that don't have a +well defined scope, but this is primarily a practical endeavor to make it +easier to isolate Windows specific ffi code. + +While I don't have a long term vision for this crate, I will welcome additional +PRs that add more high level routines/types on an as-needed basis. + +**WARNING:** I am not a Windows developer, so extra review to make sure I've +got things right is most appreciated. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.34.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in non-breaking version updates. For example, if `crate 1.0` +requires Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also +require Rust 1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a +newer minimum version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. diff --git a/third_party/rust/winapi-util/UNLICENSE b/third_party/rust/winapi-util/UNLICENSE new file mode 100644 index 0000000000..68a49daad8 --- /dev/null +++ b/third_party/rust/winapi-util/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to <http://unlicense.org/> diff --git a/third_party/rust/winapi-util/rustfmt.toml b/third_party/rust/winapi-util/rustfmt.toml new file mode 100644 index 0000000000..aa37a218b9 --- /dev/null +++ b/third_party/rust/winapi-util/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 79 +use_small_heuristics = "max" diff --git a/third_party/rust/winapi-util/src/console.rs b/third_party/rust/winapi-util/src/console.rs new file mode 100644 index 0000000000..233d5c9694 --- /dev/null +++ b/third_party/rust/winapi-util/src/console.rs @@ -0,0 +1,402 @@ +use std::io; +use std::mem; + +use winapi::shared::minwindef::WORD; +use winapi::um::consoleapi::{GetConsoleMode, SetConsoleMode}; +use winapi::um::wincon::{ + self, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, + CONSOLE_SCREEN_BUFFER_INFO, FOREGROUND_BLUE as FG_BLUE, + FOREGROUND_GREEN as FG_GREEN, FOREGROUND_INTENSITY as FG_INTENSITY, + FOREGROUND_RED as FG_RED, +}; + +use crate::{AsHandleRef, HandleRef}; + +const FG_CYAN: WORD = FG_BLUE | FG_GREEN; +const FG_MAGENTA: WORD = FG_BLUE | FG_RED; +const FG_YELLOW: WORD = FG_GREEN | FG_RED; +const FG_WHITE: WORD = FG_BLUE | FG_GREEN | FG_RED; + +/// Query the given handle for information about the console's screen buffer. +/// +/// The given handle should represent a console. Otherwise, an error is +/// returned. +/// +/// This corresponds to calling [`GetConsoleScreenBufferInfo`]. +/// +/// [`GetConsoleScreenBufferInfo`]: https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo +pub fn screen_buffer_info<H: AsHandleRef>( + h: H, +) -> io::Result<ScreenBufferInfo> { + unsafe { + let mut info: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed(); + let rc = GetConsoleScreenBufferInfo(h.as_raw(), &mut info); + if rc == 0 { + return Err(io::Error::last_os_error()); + } + Ok(ScreenBufferInfo(info)) + } +} + +/// Set the text attributes of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleTextAttribute`]. +/// +/// [`SetConsoleTextAttribute`]: https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute +pub fn set_text_attributes<H: AsHandleRef>( + h: H, + attributes: u16, +) -> io::Result<()> { + if unsafe { SetConsoleTextAttribute(h.as_raw(), attributes) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Query the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`GetConsoleMode`], which describes the return +/// value. +/// +/// [`GetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/getconsolemode +pub fn mode<H: AsHandleRef>(h: H) -> io::Result<u32> { + let mut mode = 0; + if unsafe { GetConsoleMode(h.as_raw(), &mut mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(mode) + } +} + +/// Set the mode of the console represented by the given handle. +/// +/// This corresponds to calling [`SetConsoleMode`], which describes the format +/// of the mode parameter. +/// +/// [`SetConsoleMode`]: https://docs.microsoft.com/en-us/windows/console/setconsolemode +pub fn set_mode<H: AsHandleRef>(h: H, mode: u32) -> io::Result<()> { + if unsafe { SetConsoleMode(h.as_raw(), mode) } == 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// Represents console screen buffer information such as size, cursor position +/// and styling attributes. +/// +/// This wraps a [`CONSOLE_SCREEN_BUFFER_INFO`]. +/// +/// [`CONSOLE_SCREEN_BUFFER_INFO`]: https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str +#[derive(Clone)] +pub struct ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO); + +impl ScreenBufferInfo { + /// Returns the size of the console screen buffer, in character columns and + /// rows. + /// + /// This corresponds to `dwSize`. + pub fn size(&self) -> (i16, i16) { + (self.0.dwSize.X, self.0.dwSize.Y) + } + + /// Returns the position of the cursor in terms of column and row + /// coordinates of the console screen buffer. + /// + /// This corresponds to `dwCursorPosition`. + pub fn cursor_position(&self) -> (i16, i16) { + (self.0.dwCursorPosition.X, self.0.dwCursorPosition.Y) + } + + /// Returns the character attributes associated with this console. + /// + /// This corresponds to `wAttributes`. + /// + /// See [`char info`] for more details. + /// + /// [`char info`]: https://docs.microsoft.com/en-us/windows/console/char-info-str + pub fn attributes(&self) -> u16 { + self.0.wAttributes + } + + /// Returns the maximum size of the console window, in character columns + /// and rows, given the current screen buffer size and font and the screen + /// size. + pub fn max_window_size(&self) -> (i16, i16) { + (self.0.dwMaximumWindowSize.X, self.0.dwMaximumWindowSize.Y) + } + + /// Returns the console screen buffer coordinates of the upper-left and + /// lower-right corners of the display window. + /// + /// This corresponds to `srWindow`. + pub fn window_rect(&self) -> SmallRect { + SmallRect { + left: self.0.srWindow.Left, + top: self.0.srWindow.Top, + right: self.0.srWindow.Right, + bottom: self.0.srWindow.Bottom, + } + } +} + +/// Defines the coordinates of the upper left and lower right corners of a rectangle. +/// +/// This corresponds to [`SMALL_RECT`]. +/// +/// [`SMALL_RECT`]: https://docs.microsoft.com/en-us/windows/console/small-rect-str +pub struct SmallRect { + pub left: i16, + pub top: i16, + pub right: i16, + pub bottom: i16, +} + +/// A Windows console. +/// +/// This represents a very limited set of functionality available to a Windows +/// console. In particular, it can only change text attributes such as color +/// and intensity. This may grow over time. If you need more routines, please +/// file an issue and/or PR. +/// +/// There is no way to "write" to this console. Simply write to +/// stdout or stderr instead, while interleaving instructions to the console +/// to change text attributes. +/// +/// A common pitfall when using a console is to forget to flush writes to +/// stdout before setting new text attributes. +/// +/// # Example +/// ```no_run +/// # #[cfg(windows)] +/// # { +/// use winapi_util::console::{Console, Color, Intense}; +/// +/// let mut con = Console::stdout().unwrap(); +/// con.fg(Intense::Yes, Color::Cyan).unwrap(); +/// println!("This text will be intense cyan."); +/// con.reset().unwrap(); +/// println!("This text will be normal."); +/// # } +/// ``` +#[derive(Debug)] +pub struct Console { + kind: HandleKind, + start_attr: TextAttributes, + cur_attr: TextAttributes, +} + +#[derive(Clone, Copy, Debug)] +enum HandleKind { + Stdout, + Stderr, +} + +impl HandleKind { + fn handle(&self) -> HandleRef { + match *self { + HandleKind::Stdout => HandleRef::stdout(), + HandleKind::Stderr => HandleRef::stderr(), + } + } +} + +impl Console { + /// Get a console for a standard I/O stream. + fn create_for_stream(kind: HandleKind) -> io::Result<Console> { + let h = kind.handle(); + let info = screen_buffer_info(&h)?; + let attr = TextAttributes::from_word(info.attributes()); + Ok(Console { kind: kind, start_attr: attr, cur_attr: attr }) + } + + /// Create a new Console to stdout. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stdout() -> io::Result<Console> { + Self::create_for_stream(HandleKind::Stdout) + } + + /// Create a new Console to stderr. + /// + /// If there was a problem creating the console, then an error is returned. + pub fn stderr() -> io::Result<Console> { + Self::create_for_stream(HandleKind::Stderr) + } + + /// Applies the current text attributes. + fn set(&mut self) -> io::Result<()> { + set_text_attributes(self.kind.handle(), self.cur_attr.to_word()) + } + + /// Apply the given intensity and color attributes to the console + /// foreground. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn fg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.fg_color = color; + self.cur_attr.fg_intense = intense; + self.set() + } + + /// Apply the given intensity and color attributes to the console + /// background. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn bg(&mut self, intense: Intense, color: Color) -> io::Result<()> { + self.cur_attr.bg_color = color; + self.cur_attr.bg_intense = intense; + self.set() + } + + /// Reset the console text attributes to their original settings. + /// + /// The original settings correspond to the text attributes on the console + /// when this `Console` value was created. + /// + /// If there was a problem setting attributes on the console, then an error + /// is returned. + pub fn reset(&mut self) -> io::Result<()> { + self.cur_attr = self.start_attr; + self.set() + } + + /// Toggle virtual terminal processing. + /// + /// This method attempts to toggle virtual terminal processing for this + /// console. If there was a problem toggling it, then an error returned. + /// On success, the caller may assume that toggling it was successful. + /// + /// When virtual terminal processing is enabled, characters emitted to the + /// console are parsed for VT100 and similar control character sequences + /// that control color and other similar operations. + pub fn set_virtual_terminal_processing( + &mut self, + yes: bool, + ) -> io::Result<()> { + let vt = wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + let handle = self.kind.handle(); + let old_mode = mode(&handle)?; + let new_mode = if yes { old_mode | vt } else { old_mode & !vt }; + if old_mode == new_mode { + return Ok(()); + } + set_mode(&handle, new_mode) + } +} + +/// A representation of text attributes for the Windows console. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +struct TextAttributes { + fg_color: Color, + fg_intense: Intense, + bg_color: Color, + bg_intense: Intense, +} + +impl TextAttributes { + fn to_word(&self) -> WORD { + let mut w = 0; + w |= self.fg_color.to_fg(); + w |= self.fg_intense.to_fg(); + w |= self.bg_color.to_bg(); + w |= self.bg_intense.to_bg(); + w + } + + fn from_word(word: WORD) -> TextAttributes { + TextAttributes { + fg_color: Color::from_fg(word), + fg_intense: Intense::from_fg(word), + bg_color: Color::from_bg(word), + bg_intense: Intense::from_bg(word), + } + } +} + +/// Whether to use intense colors or not. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Intense { + Yes, + No, +} + +impl Intense { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Intense { + Intense::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Intense::No => 0, + Intense::Yes => FG_INTENSITY, + } + } + + fn from_fg(word: WORD) -> Intense { + if word & FG_INTENSITY > 0 { + Intense::Yes + } else { + Intense::No + } + } +} + +/// The set of available colors for use with a Windows console. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Color { + Black, + Blue, + Green, + Red, + Cyan, + Magenta, + Yellow, + White, +} + +impl Color { + fn to_bg(&self) -> WORD { + self.to_fg() << 4 + } + + fn from_bg(word: WORD) -> Color { + Color::from_fg(word >> 4) + } + + fn to_fg(&self) -> WORD { + match *self { + Color::Black => 0, + Color::Blue => FG_BLUE, + Color::Green => FG_GREEN, + Color::Red => FG_RED, + Color::Cyan => FG_CYAN, + Color::Magenta => FG_MAGENTA, + Color::Yellow => FG_YELLOW, + Color::White => FG_WHITE, + } + } + + fn from_fg(word: WORD) -> Color { + match word & 0b111 { + FG_BLUE => Color::Blue, + FG_GREEN => Color::Green, + FG_RED => Color::Red, + FG_CYAN => Color::Cyan, + FG_MAGENTA => Color::Magenta, + FG_YELLOW => Color::Yellow, + FG_WHITE => Color::White, + _ => Color::Black, + } + } +} diff --git a/third_party/rust/winapi-util/src/file.rs b/third_party/rust/winapi-util/src/file.rs new file mode 100644 index 0000000000..56a1e4105f --- /dev/null +++ b/third_party/rust/winapi-util/src/file.rs @@ -0,0 +1,168 @@ +use std::io; +use std::mem; + +use winapi::shared::minwindef::FILETIME; +use winapi::shared::winerror::NO_ERROR; +use winapi::um::errhandlingapi::GetLastError; +use winapi::um::fileapi::{ + GetFileInformationByHandle, GetFileType, BY_HANDLE_FILE_INFORMATION, +}; +use winapi::um::winnt; + +use crate::AsHandleRef; + +/// Return various pieces of information about a file. +/// +/// This includes information such as a file's size, unique identifier and +/// time related fields. +/// +/// This corresponds to calling [`GetFileInformationByHandle`]. +/// +/// [`GetFileInformationByHandle`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfileinformationbyhandle +pub fn information<H: AsHandleRef>(h: H) -> io::Result<Information> { + unsafe { + let mut info: BY_HANDLE_FILE_INFORMATION = mem::zeroed(); + let rc = GetFileInformationByHandle(h.as_raw(), &mut info); + if rc == 0 { + return Err(io::Error::last_os_error()); + }; + Ok(Information(info)) + } +} + +/// Returns the file type of the given handle. +/// +/// If there was a problem querying the file type, then an error is returned. +/// +/// This corresponds to calling [`GetFileType`]. +/// +/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype +pub fn typ<H: AsHandleRef>(h: H) -> io::Result<Type> { + unsafe { + let rc = GetFileType(h.as_raw()); + if rc == 0 && GetLastError() != NO_ERROR { + return Err(io::Error::last_os_error()); + } + Ok(Type(rc)) + } +} + +/// Returns true if and only if the given file attributes contain the +/// `FILE_ATTRIBUTE_HIDDEN` attribute. +pub fn is_hidden(file_attributes: u64) -> bool { + file_attributes & (winnt::FILE_ATTRIBUTE_HIDDEN as u64) > 0 +} + +/// Represents file information such as creation time, file size, etc. +/// +/// This wraps a [`BY_HANDLE_FILE_INFORMATION`]. +/// +/// [`BY_HANDLE_FILE_INFORMATION`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/ns-fileapi-_by_handle_file_information +#[derive(Clone)] +pub struct Information(BY_HANDLE_FILE_INFORMATION); + +impl Information { + /// Returns file attributes. + /// + /// This corresponds to `dwFileAttributes`. + pub fn file_attributes(&self) -> u64 { + self.0.dwFileAttributes as u64 + } + + /// Returns true if and only if this file information has the + /// `FILE_ATTRIBUTE_HIDDEN` attribute. + pub fn is_hidden(&self) -> bool { + is_hidden(self.file_attributes()) + } + + /// Return the creation time, if one exists. + /// + /// This corresponds to `ftCreationTime`. + pub fn creation_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftCreationTime) + } + + /// Return the last access time, if one exists. + /// + /// This corresponds to `ftLastAccessTime`. + pub fn last_access_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftLastAccessTime) + } + + /// Return the last write time, if one exists. + /// + /// This corresponds to `ftLastWriteTime`. + pub fn last_write_time(&self) -> Option<u64> { + filetime_to_u64(self.0.ftLastWriteTime) + } + + /// Return the serial number of the volume that the file is on. + /// + /// This corresponds to `dwVolumeSerialNumber`. + pub fn volume_serial_number(&self) -> u64 { + self.0.dwVolumeSerialNumber as u64 + } + + /// Return the file size, in bytes. + /// + /// This corresponds to `nFileSizeHigh` and `nFileSizeLow`. + pub fn file_size(&self) -> u64 { + ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64) + } + + /// Return the number of links to this file. + /// + /// This corresponds to `nNumberOfLinks`. + pub fn number_of_links(&self) -> u64 { + self.0.nNumberOfLinks as u64 + } + + /// Return the index of this file. The index of a file is a purpotedly + /// unique identifier for a file within a particular volume. + pub fn file_index(&self) -> u64 { + ((self.0.nFileIndexHigh as u64) << 32) | (self.0.nFileIndexLow as u64) + } +} + +/// Represents a Windows file type. +/// +/// This wraps the result of [`GetFileType`]. +/// +/// [`GetFileType`]: https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-getfiletype +#[derive(Clone)] +pub struct Type(u32); + +impl Type { + /// Returns true if this type represents a character file, which is + /// typically an LPT device or a console. + pub fn is_char(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_CHAR + } + + /// Returns true if this type represents a disk file. + pub fn is_disk(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_DISK + } + + /// Returns true if this type represents a sock, named pipe or an + /// anonymous pipe. + pub fn is_pipe(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_PIPE + } + + /// Returns true if this type is not known. + /// + /// Note that this never corresponds to a failure. + pub fn is_unknown(&self) -> bool { + self.0 == ::winapi::um::winbase::FILE_TYPE_UNKNOWN + } +} + +fn filetime_to_u64(t: FILETIME) -> Option<u64> { + let v = ((t.dwHighDateTime as u64) << 32) | (t.dwLowDateTime as u64); + if v == 0 { + None + } else { + Some(v) + } +} diff --git a/third_party/rust/winapi-util/src/lib.rs b/third_party/rust/winapi-util/src/lib.rs new file mode 100644 index 0000000000..0bb259dbae --- /dev/null +++ b/third_party/rust/winapi-util/src/lib.rs @@ -0,0 +1,32 @@ +/*! +This crate provides a smattering of safe routines for parts of winapi. The +primary purpose of this crate is to serve as a dumping ground for various +utility functions that make interactions with winapi safe. This permits the +centralization of `unsafe` when dealing with Windows APIs, and thus makes it +easier to audit. + +A key abstraction in this crate is the combination of the +[`Handle`](struct.Handle.html) +and +[`HandleRef`](struct.HandleRef.html) +types. Both represent a valid Windows handle to an I/O-like object, where +`Handle` is owned (the resource is closed when the handle is dropped) and +`HandleRef` is borrowed (the resource is not closed when the handle is +dropped). Many of the routines in this crate work on handles and accept +anything that can be safely converted into a `HandleRef`. This includes +standard library types such as `File`, `Stdin`, `Stdout` and `Stderr`. + +Note that this crate is completely empty on non-Windows platforms. +*/ + +#[cfg(windows)] +pub use win::*; + +/// Safe routines for dealing with the Windows console. +#[cfg(windows)] +pub mod console; +/// Safe routines for dealing with files and handles on Windows. +#[cfg(windows)] +pub mod file; +#[cfg(windows)] +mod win; diff --git a/third_party/rust/winapi-util/src/win.rs b/third_party/rust/winapi-util/src/win.rs new file mode 100644 index 0000000000..9c77c0da62 --- /dev/null +++ b/third_party/rust/winapi-util/src/win.rs @@ -0,0 +1,246 @@ +use std::fs::File; +use std::io; +use std::os::windows::io::{ + AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle, +}; +use std::path::Path; +use std::process; + +/// A handle represents an owned and valid Windows handle to a file-like +/// object. +/// +/// When an owned handle is dropped, then the underlying raw handle is closed. +/// To get a borrowed handle, use `HandleRef`. +#[derive(Debug)] +pub struct Handle(File); + +impl AsRawHandle for Handle { + fn as_raw_handle(&self) -> RawHandle { + self.0.as_raw_handle() + } +} + +impl FromRawHandle for Handle { + unsafe fn from_raw_handle(handle: RawHandle) -> Handle { + Handle(File::from_raw_handle(handle)) + } +} + +impl IntoRawHandle for Handle { + fn into_raw_handle(self) -> RawHandle { + self.0.into_raw_handle() + } +} + +impl Handle { + /// Create an owned handle to the given file. + /// + /// When the returned handle is dropped, the file is closed. + /// + /// Note that if the given file represents a handle to a directory, then + /// it is generally required that it have been opened with the + /// [`FILE_FLAG_BACKUP_SEMANTICS`] flag in order to use it in various + /// calls such as `information` or `typ`. To have this done automatically + /// for you, use the `from_path_any` constructor. + /// + /// [`FILE_FLAG_BACKUP_SEMANTICS`]: https://docs.microsoft.com/en-us/windows/desktop/api/FileAPI/nf-fileapi-createfilea + pub fn from_file(file: File) -> Handle { + Handle(file) + } + + /// Open a file to the given file path, and return an owned handle to that + /// file. + /// + /// When the returned handle is dropped, the file is closed. + /// + /// If there was a problem opening the file, then the corresponding error + /// is returned. + pub fn from_path<P: AsRef<Path>>(path: P) -> io::Result<Handle> { + Ok(Handle::from_file(File::open(path)?)) + } + + /// Like `from_path`, but supports opening directory handles as well. + /// + /// If you use `from_path` on a directory, then subsequent queries using + /// that handle will fail. + pub fn from_path_any<P: AsRef<Path>>(path: P) -> io::Result<Handle> { + use std::fs::OpenOptions; + use std::os::windows::fs::OpenOptionsExt; + use winapi::um::winbase::FILE_FLAG_BACKUP_SEMANTICS; + + let file = OpenOptions::new() + .read(true) + .custom_flags(FILE_FLAG_BACKUP_SEMANTICS) + .open(path)?; + Ok(Handle::from_file(file)) + } + + /// Return this handle as a standard `File` reference. + pub fn as_file(&self) -> &File { + &self.0 + } + + /// Return this handle as a standard `File` mutable reference. + pub fn as_file_mut(&mut self) -> &mut File { + &mut self.0 + } +} + +/// Represents a borrowed and valid Windows handle to a file-like object, such +/// as stdin/stdout/stderr or an actual file. +/// +/// When a borrowed handle is dropped, then the underlying raw handle is +/// **not** closed. To get an owned handle, use `Handle`. +#[derive(Debug)] +pub struct HandleRef(HandleRefInner); + +/// The representation of a HandleRef, on which we define a custom Drop impl +/// that avoids closing the underlying raw handle. +#[derive(Debug)] +struct HandleRefInner(Option<File>); + +impl Drop for HandleRefInner { + fn drop(&mut self) { + self.0.take().unwrap().into_raw_handle(); + } +} + +impl AsRawHandle for HandleRef { + fn as_raw_handle(&self) -> RawHandle { + self.as_file().as_raw_handle() + } +} + +impl Clone for HandleRef { + fn clone(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl HandleRef { + /// Create a borrowed handle to stdin. + /// + /// When the returned handle is dropped, stdin is not closed. + pub fn stdin() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stdin().as_raw_handle()) } + } + + /// Create a handle to stdout. + /// + /// When the returned handle is dropped, stdout is not closed. + pub fn stdout() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stdout().as_raw_handle()) } + } + + /// Create a handle to stderr. + /// + /// When the returned handle is dropped, stderr is not closed. + pub fn stderr() -> HandleRef { + unsafe { HandleRef::from_raw_handle(io::stderr().as_raw_handle()) } + } + + /// Create a borrowed handle to the given file. + /// + /// When the returned handle is dropped, the file is not closed. + pub fn from_file(file: &File) -> HandleRef { + unsafe { HandleRef::from_raw_handle(file.as_raw_handle()) } + } + + /// Create a borrowed handle from the given raw handle. + /// + /// Note that unlike the `FromRawHandle` trait, this constructor does + /// **not** consume ownership of the given handle. That is, when the + /// borrowed handle created by this constructor is dropped, the underlying + /// handle will not be closed. + /// + /// # Safety + /// + /// This is unsafe because there is no guarantee that the given raw handle + /// is a valid handle. The caller must ensure this is true before invoking + /// this constructor. + pub unsafe fn from_raw_handle(handle: RawHandle) -> HandleRef { + HandleRef(HandleRefInner(Some(File::from_raw_handle(handle)))) + } + + /// Return this handle as a standard `File` reference. + pub fn as_file(&self) -> &File { + (self.0).0.as_ref().unwrap() + } + + /// Return this handle as a standard `File` mutable reference. + pub fn as_file_mut(&mut self) -> &mut File { + (self.0).0.as_mut().unwrap() + } +} + +/// Construct borrowed and valid Windows handles from file-like objects. +pub trait AsHandleRef { + /// A borrowed handle that wraps the raw handle of the `Self` object. + fn as_handle_ref(&self) -> HandleRef; + + /// A convenience routine for extracting a `HandleRef` from `Self`, and + /// then extracting a raw handle from the `HandleRef`. + fn as_raw(&self) -> RawHandle { + self.as_handle_ref().as_raw_handle() + } +} + +impl<'a, T: AsHandleRef> AsHandleRef for &'a T { + fn as_handle_ref(&self) -> HandleRef { + (**self).as_handle_ref() + } +} + +impl AsHandleRef for Handle { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for HandleRef { + fn as_handle_ref(&self) -> HandleRef { + self.clone() + } +} + +impl AsHandleRef for File { + fn as_handle_ref(&self) -> HandleRef { + HandleRef::from_file(self) + } +} + +impl AsHandleRef for io::Stdin { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for io::Stdout { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for io::Stderr { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStdin { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStdout { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} + +impl AsHandleRef for process::ChildStderr { + fn as_handle_ref(&self) -> HandleRef { + unsafe { HandleRef::from_raw_handle(self.as_raw_handle()) } + } +} |