Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/same-file/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/same-file/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"COPYING":"01c266bced4a434da0051174d6bee16a4c82cf634e2679b6155d40d75012390f","Cargo.lock":"fa40407b035c7abffe97d267d2ff95d22d83e5b916aca876bec49a56a9067c73","Cargo.toml":"991f8df8fa5a259801900a56908cf21a66c5cf7b238bc81ba9bdf348e233252e","LICENSE-MIT":"cb3c929a05e6cbc9de9ab06a4c57eeb60ca8c724bef6c138c87d3a577e27aa14","README.md":"70c109d9c89b4479016142f2a4ad6963b6fe5793bcdd997add3d3af3d2baf36b","UNLICENSE":"7e12e5df4bae12cb21581ba157ced20e1986a0508dd10d0e8a4ab9a4cf94e85c","examples/is_same_file.rs":"7b3eeb27a15051667d97615fc7a2339cbff5630df3bca6ac19ab81d5be22f329","examples/is_stderr.rs":"e1c5d1a0f36d7aa0020bb5b87c2f45c7176033f03c52cf395be55dd8debfc413","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/lib.rs":"b22c2f0b5cad2248f16f4f42add52b2dc0c627631f71ee67a8c38fe305048f85","src/unix.rs":"69abed9fade151247696c6d4a442ef299554f3722e23a2d08053598a52a27d62","src/unknown.rs":"bfde4e9ac88f500c0ccb69165383682ddd24bf7d7ddaf5859426e1fd4b2f9359","src/win.rs":"94f912cc3734f60608d0ee2b0c664afb65fc96e5b0b223a53565fb8998c03fa3"},"package":"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"}
|
||||
3
third-party/vendor/same-file/COPYING
vendored
Normal file
3
third-party/vendor/same-file/COPYING
vendored
Normal file
|
|
@ -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.
|
||||
48
third-party/vendor/same-file/Cargo.lock
generated
vendored
Normal file
48
third-party/vendor/same-file/Cargo.lock
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
|
||||
"checksum winapi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "890b38836c01d72fdb636d15c9cfc52ec7fd783b330abc93cd1686f4308dfccc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668"
|
||||
29
third-party/vendor/same-file/Cargo.toml
vendored
Normal file
29
third-party/vendor/same-file/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# 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 = "same-file"
|
||||
version = "1.0.6"
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
exclude = ["/.github"]
|
||||
description = "A simple crate for determining whether two file paths point to the same file.\n"
|
||||
homepage = "https://github.com/BurntSushi/same-file"
|
||||
documentation = "https://docs.rs/same-file"
|
||||
readme = "README.md"
|
||||
keywords = ["same", "file", "equal", "inode"]
|
||||
license = "Unlicense/MIT"
|
||||
repository = "https://github.com/BurntSushi/same-file"
|
||||
[dev-dependencies.doc-comment]
|
||||
version = "0.3"
|
||||
[target."cfg(windows)".dependencies.winapi-util]
|
||||
version = "0.1.1"
|
||||
21
third-party/vendor/same-file/LICENSE-MIT
vendored
Normal file
21
third-party/vendor/same-file/LICENSE-MIT
vendored
Normal file
|
|
@ -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.
|
||||
49
third-party/vendor/same-file/README.md
vendored
Normal file
49
third-party/vendor/same-file/README.md
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
same-file
|
||||
=========
|
||||
A safe and cross platform crate to determine whether two files or directories
|
||||
are the same.
|
||||
|
||||
[](https://github.com/BurntSushi/same-file/actions)
|
||||
[](https://crates.io/crates/same-file)
|
||||
|
||||
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
||||
|
||||
### Documentation
|
||||
|
||||
https://docs.rs/same-file
|
||||
|
||||
### Usage
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
same-file = "1"
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
The simplest use of this crate is to use the `is_same_file` function, which
|
||||
takes two file paths and returns true if and only if they refer to the same
|
||||
file:
|
||||
|
||||
```rust,no_run
|
||||
use same_file::is_same_file;
|
||||
|
||||
fn main() {
|
||||
assert!(is_same_file("/bin/sh", "/usr/bin/sh").unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
### 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 minor 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.
|
||||
24
third-party/vendor/same-file/UNLICENSE
vendored
Normal file
24
third-party/vendor/same-file/UNLICENSE
vendored
Normal file
|
|
@ -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/>
|
||||
11
third-party/vendor/same-file/examples/is_same_file.rs
vendored
Normal file
11
third-party/vendor/same-file/examples/is_same_file.rs
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use same_file::is_same_file;
|
||||
use std::io;
|
||||
|
||||
fn try_main() -> Result<(), io::Error> {
|
||||
assert!(is_same_file("/bin/sh", "/usr/bin/sh")?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
try_main().unwrap();
|
||||
}
|
||||
31
third-party/vendor/same-file/examples/is_stderr.rs
vendored
Normal file
31
third-party/vendor/same-file/examples/is_stderr.rs
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
use std::io;
|
||||
use std::process;
|
||||
|
||||
use same_file::Handle;
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = run() {
|
||||
println!("{}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> io::Result<()> {
|
||||
// Run with `cargo run --example is_stderr 2> examples/stderr` to see
|
||||
// interesting output.
|
||||
let candidates = &[
|
||||
"examples/is_same_file.rs",
|
||||
"examples/is_stderr.rs",
|
||||
"examples/stderr",
|
||||
];
|
||||
let stderr_handle = Handle::stderr()?;
|
||||
for candidate in candidates {
|
||||
let handle = Handle::from_path(candidate)?;
|
||||
if stderr_handle == handle {
|
||||
println!("{:?} is stderr!", candidate);
|
||||
} else {
|
||||
println!("{:?} is NOT stderr!", candidate);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
2
third-party/vendor/same-file/rustfmt.toml
vendored
Normal file
2
third-party/vendor/same-file/rustfmt.toml
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
max_width = 79
|
||||
use_small_heuristics = "max"
|
||||
572
third-party/vendor/same-file/src/lib.rs
vendored
Normal file
572
third-party/vendor/same-file/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,572 @@
|
|||
/*!
|
||||
This crate provides a safe and simple **cross platform** way to determine
|
||||
whether two file paths refer to the same file or directory.
|
||||
|
||||
Most uses of this crate should be limited to the top-level [`is_same_file`]
|
||||
function, which takes two file paths and returns true if they refer to the
|
||||
same file or directory:
|
||||
|
||||
```rust,no_run
|
||||
# use std::error::Error;
|
||||
use same_file::is_same_file;
|
||||
|
||||
# fn try_main() -> Result<(), Box<Error>> {
|
||||
assert!(is_same_file("/bin/sh", "/usr/bin/sh")?);
|
||||
# Ok(())
|
||||
# }
|
||||
#
|
||||
# fn main() {
|
||||
# try_main().unwrap();
|
||||
# }
|
||||
```
|
||||
|
||||
Additionally, this crate provides a [`Handle`] type that permits a more efficient
|
||||
equality check depending on your access pattern. For example, if one wanted to
|
||||
check whether any path in a list of paths corresponded to the process' stdout
|
||||
handle, then one could build a handle once for stdout. The equality check for
|
||||
each file in the list then only requires one stat call instead of two. The code
|
||||
might look like this:
|
||||
|
||||
```rust,no_run
|
||||
# use std::error::Error;
|
||||
use same_file::Handle;
|
||||
|
||||
# fn try_main() -> Result<(), Box<Error>> {
|
||||
let candidates = &[
|
||||
"examples/is_same_file.rs",
|
||||
"examples/is_stderr.rs",
|
||||
"examples/stderr",
|
||||
];
|
||||
let stdout_handle = Handle::stdout()?;
|
||||
for candidate in candidates {
|
||||
let handle = Handle::from_path(candidate)?;
|
||||
if stdout_handle == handle {
|
||||
println!("{:?} is stdout!", candidate);
|
||||
} else {
|
||||
println!("{:?} is NOT stdout!", candidate);
|
||||
}
|
||||
}
|
||||
# Ok(())
|
||||
# }
|
||||
#
|
||||
# fn main() {
|
||||
# try_main().unwrap();
|
||||
# }
|
||||
```
|
||||
|
||||
See [`examples/is_stderr.rs`] for a runnable example and compare the output of:
|
||||
|
||||
- `cargo run --example is_stderr 2> examples/stderr` and
|
||||
- `cargo run --example is_stderr`.
|
||||
|
||||
[`is_same_file`]: fn.is_same_file.html
|
||||
[`Handle`]: struct.Handle.html
|
||||
[`examples/is_stderr.rs`]: https://github.com/BurntSushi/same-file/blob/master/examples/is_same_file.rs
|
||||
|
||||
*/
|
||||
|
||||
#![allow(bare_trait_objects, unknown_lints)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)]
|
||||
doc_comment::doctest!("../README.md");
|
||||
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(any(target_os = "redox", unix))]
|
||||
use crate::unix as imp;
|
||||
#[cfg(not(any(target_os = "redox", unix, windows)))]
|
||||
use unknown as imp;
|
||||
#[cfg(windows)]
|
||||
use win as imp;
|
||||
|
||||
#[cfg(any(target_os = "redox", unix))]
|
||||
mod unix;
|
||||
#[cfg(not(any(target_os = "redox", unix, windows)))]
|
||||
mod unknown;
|
||||
#[cfg(windows)]
|
||||
mod win;
|
||||
|
||||
/// A handle to a file that can be tested for equality with other handles.
|
||||
///
|
||||
/// If two files are the same, then any two handles of those files will compare
|
||||
/// equal. If two files are not the same, then any two handles of those files
|
||||
/// will compare not-equal.
|
||||
///
|
||||
/// A handle consumes an open file resource as long as it exists.
|
||||
///
|
||||
/// Equality is determined by comparing inode numbers on Unix and a combination
|
||||
/// of identifier, volume serial, and file size on Windows. Note that it's
|
||||
/// possible for comparing two handles to produce a false positive on some
|
||||
/// platforms. Namely, two handles can compare equal even if the two handles
|
||||
/// *don't* point to the same file. Check the [source] for specific
|
||||
/// implementation details.
|
||||
///
|
||||
/// [source]: https://github.com/BurntSushi/same-file/tree/master/src
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Handle(imp::Handle);
|
||||
|
||||
impl Handle {
|
||||
/// Construct a handle from a path.
|
||||
///
|
||||
/// Note that the underlying [`File`] is opened in read-only mode on all
|
||||
/// platforms.
|
||||
///
|
||||
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
|
||||
///
|
||||
/// # Errors
|
||||
/// This method will return an [`io::Error`] if the path cannot
|
||||
/// be opened, or the file's metadata cannot be obtained.
|
||||
/// The most common reasons for this are: the path does not
|
||||
/// exist, or there were not enough permissions.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
///
|
||||
/// # Examples
|
||||
/// Check that two paths are not the same file:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use std::error::Error;
|
||||
/// use same_file::Handle;
|
||||
///
|
||||
/// # fn try_main() -> Result<(), Box<Error>> {
|
||||
/// let source = Handle::from_path("./source")?;
|
||||
/// let target = Handle::from_path("./target")?;
|
||||
/// assert_ne!(source, target, "The files are the same.");
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
|
||||
imp::Handle::from_path(p).map(Handle)
|
||||
}
|
||||
|
||||
/// Construct a handle from a file.
|
||||
///
|
||||
/// # Errors
|
||||
/// This method will return an [`io::Error`] if the metadata for
|
||||
/// the given [`File`] cannot be obtained.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
/// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
|
||||
///
|
||||
/// # Examples
|
||||
/// Check that two files are not in fact the same file:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use std::error::Error;
|
||||
/// # use std::fs::File;
|
||||
/// use same_file::Handle;
|
||||
///
|
||||
/// # fn try_main() -> Result<(), Box<Error>> {
|
||||
/// let source = File::open("./source")?;
|
||||
/// let target = File::open("./target")?;
|
||||
///
|
||||
/// assert_ne!(
|
||||
/// Handle::from_file(source)?,
|
||||
/// Handle::from_file(target)?,
|
||||
/// "The files are the same."
|
||||
/// );
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn from_file(file: File) -> io::Result<Handle> {
|
||||
imp::Handle::from_file(file).map(Handle)
|
||||
}
|
||||
|
||||
/// Construct a handle from stdin.
|
||||
///
|
||||
/// # Errors
|
||||
/// This method will return an [`io::Error`] if stdin cannot
|
||||
/// be opened due to any I/O-related reason.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use std::error::Error;
|
||||
/// use same_file::Handle;
|
||||
///
|
||||
/// # fn try_main() -> Result<(), Box<Error>> {
|
||||
/// let stdin = Handle::stdin()?;
|
||||
/// let stdout = Handle::stdout()?;
|
||||
/// let stderr = Handle::stderr()?;
|
||||
///
|
||||
/// if stdin == stdout {
|
||||
/// println!("stdin == stdout");
|
||||
/// }
|
||||
/// if stdin == stderr {
|
||||
/// println!("stdin == stderr");
|
||||
/// }
|
||||
/// if stdout == stderr {
|
||||
/// println!("stdout == stderr");
|
||||
/// }
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// The output differs depending on the platform.
|
||||
///
|
||||
/// On Linux:
|
||||
///
|
||||
/// ```text
|
||||
/// $ ./example
|
||||
/// stdin == stdout
|
||||
/// stdin == stderr
|
||||
/// stdout == stderr
|
||||
/// $ ./example > result
|
||||
/// $ cat result
|
||||
/// stdin == stderr
|
||||
/// $ ./example > result 2>&1
|
||||
/// $ cat result
|
||||
/// stdout == stderr
|
||||
/// ```
|
||||
///
|
||||
/// Windows:
|
||||
///
|
||||
/// ```text
|
||||
/// > example
|
||||
/// > example > result 2>&1
|
||||
/// > type result
|
||||
/// stdout == stderr
|
||||
/// ```
|
||||
pub fn stdin() -> io::Result<Handle> {
|
||||
imp::Handle::stdin().map(Handle)
|
||||
}
|
||||
|
||||
/// Construct a handle from stdout.
|
||||
///
|
||||
/// # Errors
|
||||
/// This method will return an [`io::Error`] if stdout cannot
|
||||
/// be opened due to any I/O-related reason.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
///
|
||||
/// # Examples
|
||||
/// See the example for [`stdin()`].
|
||||
///
|
||||
/// [`stdin()`]: #method.stdin
|
||||
pub fn stdout() -> io::Result<Handle> {
|
||||
imp::Handle::stdout().map(Handle)
|
||||
}
|
||||
|
||||
/// Construct a handle from stderr.
|
||||
///
|
||||
/// # Errors
|
||||
/// This method will return an [`io::Error`] if stderr cannot
|
||||
/// be opened due to any I/O-related reason.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
///
|
||||
/// # Examples
|
||||
/// See the example for [`stdin()`].
|
||||
///
|
||||
/// [`stdin()`]: #method.stdin
|
||||
pub fn stderr() -> io::Result<Handle> {
|
||||
imp::Handle::stderr().map(Handle)
|
||||
}
|
||||
|
||||
/// Return a reference to the underlying file.
|
||||
///
|
||||
/// # Examples
|
||||
/// Ensure that the target file is not the same as the source one,
|
||||
/// and copy the data to it:
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use std::error::Error;
|
||||
/// use std::io::prelude::*;
|
||||
/// use std::io::Write;
|
||||
/// use std::fs::File;
|
||||
/// use same_file::Handle;
|
||||
///
|
||||
/// # fn try_main() -> Result<(), Box<Error>> {
|
||||
/// let source = File::open("source")?;
|
||||
/// let target = File::create("target")?;
|
||||
///
|
||||
/// let source_handle = Handle::from_file(source)?;
|
||||
/// let mut target_handle = Handle::from_file(target)?;
|
||||
/// assert_ne!(source_handle, target_handle, "The files are the same.");
|
||||
///
|
||||
/// let mut source = source_handle.as_file();
|
||||
/// let target = target_handle.as_file_mut();
|
||||
///
|
||||
/// let mut buffer = Vec::new();
|
||||
/// // data copy is simplified for the purposes of the example
|
||||
/// source.read_to_end(&mut buffer)?;
|
||||
/// target.write_all(&buffer)?;
|
||||
/// #
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # try_main().unwrap();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn as_file(&self) -> &File {
|
||||
self.0.as_file()
|
||||
}
|
||||
|
||||
/// Return a mutable reference to the underlying file.
|
||||
///
|
||||
/// # Examples
|
||||
/// See the example for [`as_file()`].
|
||||
///
|
||||
/// [`as_file()`]: #method.as_file
|
||||
pub fn as_file_mut(&mut self) -> &mut File {
|
||||
self.0.as_file_mut()
|
||||
}
|
||||
|
||||
/// Return the underlying device number of this handle.
|
||||
///
|
||||
/// Note that this only works on unix platforms.
|
||||
#[cfg(any(target_os = "redox", unix))]
|
||||
pub fn dev(&self) -> u64 {
|
||||
self.0.dev()
|
||||
}
|
||||
|
||||
/// Return the underlying inode number of this handle.
|
||||
///
|
||||
/// Note that this only works on unix platforms.
|
||||
#[cfg(any(target_os = "redox", unix))]
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.0.ino()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the two file paths may correspond to the same file.
|
||||
///
|
||||
/// Note that it's possible for this to produce a false positive on some
|
||||
/// platforms. Namely, this can return true even if the two file paths *don't*
|
||||
/// resolve to the same file.
|
||||
/// # Errors
|
||||
/// This function will return an [`io::Error`] if any of the two paths cannot
|
||||
/// be opened. The most common reasons for this are: the path does not exist,
|
||||
/// or there were not enough permissions.
|
||||
///
|
||||
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use same_file::is_same_file;
|
||||
///
|
||||
/// assert!(is_same_file("./foo", "././foo").unwrap_or(false));
|
||||
/// ```
|
||||
pub fn is_same_file<P, Q>(path1: P, path2: Q) -> io::Result<bool>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
Q: AsRef<Path>,
|
||||
{
|
||||
Ok(Handle::from_path(path1)? == Handle::from_path(path2)?)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::env;
|
||||
use std::error;
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::result;
|
||||
|
||||
use super::is_same_file;
|
||||
|
||||
type Result<T> = result::Result<T, Box<error::Error + Send + Sync>>;
|
||||
|
||||
/// Create an error from a format!-like syntax.
|
||||
macro_rules! err {
|
||||
($($tt:tt)*) => {
|
||||
Box::<error::Error + Send + Sync>::from(format!($($tt)*))
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple wrapper for creating a temporary directory that is
|
||||
/// automatically deleted when it's dropped.
|
||||
///
|
||||
/// We use this in lieu of tempfile because tempfile brings in too many
|
||||
/// dependencies.
|
||||
#[derive(Debug)]
|
||||
struct TempDir(PathBuf);
|
||||
|
||||
impl Drop for TempDir {
|
||||
fn drop(&mut self) {
|
||||
fs::remove_dir_all(&self.0).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl TempDir {
|
||||
/// Create a new empty temporary directory under the system's
|
||||
/// configured temporary directory.
|
||||
fn new() -> Result<TempDir> {
|
||||
#![allow(deprecated)]
|
||||
|
||||
use std::sync::atomic::{
|
||||
AtomicUsize, Ordering, ATOMIC_USIZE_INIT,
|
||||
};
|
||||
|
||||
static TRIES: usize = 100;
|
||||
static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
let tmpdir = env::temp_dir();
|
||||
for _ in 0..TRIES {
|
||||
let count = COUNTER.fetch_add(1, Ordering::SeqCst);
|
||||
let path = tmpdir.join("rust-walkdir").join(count.to_string());
|
||||
if path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
fs::create_dir_all(&path).map_err(|e| {
|
||||
err!("failed to create {}: {}", path.display(), e)
|
||||
})?;
|
||||
return Ok(TempDir(path));
|
||||
}
|
||||
Err(err!("failed to create temp dir after {} tries", TRIES))
|
||||
}
|
||||
|
||||
/// Return the underlying path to this temporary directory.
|
||||
fn path(&self) -> &Path {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn tmpdir() -> TempDir {
|
||||
TempDir::new().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
src: P,
|
||||
dst: Q,
|
||||
) -> io::Result<()> {
|
||||
use std::os::unix::fs::symlink;
|
||||
symlink(src, dst)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
src: P,
|
||||
dst: Q,
|
||||
) -> io::Result<()> {
|
||||
soft_link_dir(src, dst)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn soft_link_dir<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
src: P,
|
||||
dst: Q,
|
||||
) -> io::Result<()> {
|
||||
use std::os::windows::fs::symlink_dir;
|
||||
symlink_dir(src, dst)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn soft_link_file<P: AsRef<Path>, Q: AsRef<Path>>(
|
||||
src: P,
|
||||
dst: Q,
|
||||
) -> io::Result<()> {
|
||||
use std::os::windows::fs::symlink_file;
|
||||
symlink_file(src, dst)
|
||||
}
|
||||
|
||||
// These tests are rather uninteresting. The really interesting tests
|
||||
// would stress the edge cases. On Unix, this might be comparing two files
|
||||
// on different mount points with the same inode number. On Windows, this
|
||||
// might be comparing two files whose file indices are the same on file
|
||||
// systems where such things aren't guaranteed to be unique.
|
||||
//
|
||||
// Alas, I don't know how to create those environmental conditions. ---AG
|
||||
|
||||
#[test]
|
||||
fn same_file_trivial() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
File::create(dir.join("a")).unwrap();
|
||||
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_dir_trivial() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
fs::create_dir(dir.join("a")).unwrap();
|
||||
assert!(is_same_file(dir.join("a"), dir.join("a")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_same_file_trivial() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
File::create(dir.join("a")).unwrap();
|
||||
File::create(dir.join("b")).unwrap();
|
||||
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_same_dir_trivial() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
fs::create_dir(dir.join("a")).unwrap();
|
||||
fs::create_dir(dir.join("b")).unwrap();
|
||||
assert!(!is_same_file(dir.join("a"), dir.join("b")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_file_hard() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
File::create(dir.join("a")).unwrap();
|
||||
fs::hard_link(dir.join("a"), dir.join("alink")).unwrap();
|
||||
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_file_soft() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
File::create(dir.join("a")).unwrap();
|
||||
soft_link_file(dir.join("a"), dir.join("alink")).unwrap();
|
||||
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_dir_soft() {
|
||||
let tdir = tmpdir();
|
||||
let dir = tdir.path();
|
||||
|
||||
fs::create_dir(dir.join("a")).unwrap();
|
||||
soft_link_dir(dir.join("a"), dir.join("alink")).unwrap();
|
||||
assert!(is_same_file(dir.join("a"), dir.join("alink")).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_send() {
|
||||
fn assert_send<T: Send>() {}
|
||||
assert_send::<super::Handle>();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sync() {
|
||||
fn assert_sync<T: Sync>() {}
|
||||
assert_sync::<super::Handle>();
|
||||
}
|
||||
}
|
||||
112
third-party/vendor/same-file/src/unix.rs
vendored
Normal file
112
third-party/vendor/same-file/src/unix.rs
vendored
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use std::fs::{File, OpenOptions};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Handle {
|
||||
file: Option<File>,
|
||||
// If is_std is true, then we don't drop the corresponding File since it
|
||||
// will close the handle.
|
||||
is_std: bool,
|
||||
dev: u64,
|
||||
ino: u64,
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
if self.is_std {
|
||||
// unwrap() will not panic. Since we were able to open an
|
||||
// std stream successfully, then `file` is guaranteed to be Some()
|
||||
self.file.take().unwrap().into_raw_fd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Handle {}
|
||||
|
||||
impl PartialEq for Handle {
|
||||
fn eq(&self, other: &Handle) -> bool {
|
||||
(self.dev, self.ino) == (other.dev, other.ino)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for crate::Handle {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
// unwrap() will not panic. Since we were able to open the
|
||||
// file successfully, then `file` is guaranteed to be Some()
|
||||
self.0.file.as_ref().take().unwrap().as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for crate::Handle {
|
||||
fn into_raw_fd(mut self) -> RawFd {
|
||||
// unwrap() will not panic. Since we were able to open the
|
||||
// file successfully, then `file` is guaranteed to be Some()
|
||||
self.0.file.take().unwrap().into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Handle {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.dev.hash(state);
|
||||
self.ino.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
|
||||
Handle::from_file(OpenOptions::new().read(true).open(p)?)
|
||||
}
|
||||
|
||||
pub fn from_file(file: File) -> io::Result<Handle> {
|
||||
let md = file.metadata()?;
|
||||
Ok(Handle {
|
||||
file: Some(file),
|
||||
is_std: false,
|
||||
dev: md.dev(),
|
||||
ino: md.ino(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_std(file: File) -> io::Result<Handle> {
|
||||
Handle::from_file(file).map(|mut h| {
|
||||
h.is_std = true;
|
||||
h
|
||||
})
|
||||
}
|
||||
|
||||
pub fn stdin() -> io::Result<Handle> {
|
||||
Handle::from_std(unsafe { File::from_raw_fd(0) })
|
||||
}
|
||||
|
||||
pub fn stdout() -> io::Result<Handle> {
|
||||
Handle::from_std(unsafe { File::from_raw_fd(1) })
|
||||
}
|
||||
|
||||
pub fn stderr() -> io::Result<Handle> {
|
||||
Handle::from_std(unsafe { File::from_raw_fd(2) })
|
||||
}
|
||||
|
||||
pub fn as_file(&self) -> &File {
|
||||
// unwrap() will not panic. Since we were able to open the
|
||||
// file successfully, then `file` is guaranteed to be Some()
|
||||
self.file.as_ref().take().unwrap()
|
||||
}
|
||||
|
||||
pub fn as_file_mut(&mut self) -> &mut File {
|
||||
// unwrap() will not panic. Since we were able to open the
|
||||
// file successfully, then `file` is guaranteed to be Some()
|
||||
self.file.as_mut().take().unwrap()
|
||||
}
|
||||
|
||||
pub fn dev(&self) -> u64 {
|
||||
self.dev
|
||||
}
|
||||
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.ino
|
||||
}
|
||||
}
|
||||
52
third-party/vendor/same-file/src/unknown.rs
vendored
Normal file
52
third-party/vendor/same-file/src/unknown.rs
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
static ERROR_MESSAGE: &str = "same-file is not supported on this platform.";
|
||||
// This implementation is to allow same-file to be compiled on
|
||||
// unsupported platforms in case it was incidentally included
|
||||
// as a transitive, unused dependency
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct Handle;
|
||||
|
||||
impl Eq for Handle {}
|
||||
|
||||
impl PartialEq for Handle {
|
||||
fn eq(&self, _other: &Handle) -> bool {
|
||||
unreachable!(ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn from_path<P: AsRef<Path>>(_p: P) -> io::Result<Handle> {
|
||||
error()
|
||||
}
|
||||
|
||||
pub fn from_file(_file: File) -> io::Result<Handle> {
|
||||
error()
|
||||
}
|
||||
|
||||
pub fn stdin() -> io::Result<Handle> {
|
||||
error()
|
||||
}
|
||||
|
||||
pub fn stdout() -> io::Result<Handle> {
|
||||
error()
|
||||
}
|
||||
|
||||
pub fn stderr() -> io::Result<Handle> {
|
||||
error()
|
||||
}
|
||||
|
||||
pub fn as_file(&self) -> &File {
|
||||
unreachable!(ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
pub fn as_file_mut(&self) -> &mut File {
|
||||
unreachable!(ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
fn error<T>() -> io::Result<T> {
|
||||
Err(io::Error::new(io::ErrorKind::Other, ERROR_MESSAGE))
|
||||
}
|
||||
172
third-party/vendor/same-file/src/win.rs
vendored
Normal file
172
third-party/vendor/same-file/src/win.rs
vendored
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
use std::fs::File;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io;
|
||||
use std::os::windows::io::{AsRawHandle, IntoRawHandle, RawHandle};
|
||||
use std::path::Path;
|
||||
|
||||
use winapi_util as winutil;
|
||||
|
||||
// For correctness, it is critical that both file handles remain open while
|
||||
// their attributes are checked for equality. In particular, the file index
|
||||
// numbers on a Windows stat object are not guaranteed to remain stable over
|
||||
// time.
|
||||
//
|
||||
// See the docs and remarks on MSDN:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788(v=vs.85).aspx
|
||||
//
|
||||
// It gets worse. It appears that the index numbers are not always
|
||||
// guaranteed to be unique. Namely, ReFS uses 128 bit numbers for unique
|
||||
// identifiers. This requires a distinct syscall to get `FILE_ID_INFO`
|
||||
// documented here:
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/hh802691(v=vs.85).aspx
|
||||
//
|
||||
// It seems straight-forward enough to modify this code to use
|
||||
// `FILE_ID_INFO` when available (minimum Windows Server 2012), but I don't
|
||||
// have access to such Windows machines.
|
||||
//
|
||||
// Two notes.
|
||||
//
|
||||
// 1. Java's NIO uses the approach implemented here and appears to ignore
|
||||
// `FILE_ID_INFO` altogether. So Java's NIO and this code are
|
||||
// susceptible to bugs when running on a file system where
|
||||
// `nFileIndex{Low,High}` are not unique.
|
||||
//
|
||||
// 2. LLVM has a bug where they fetch the id of a file and continue to use
|
||||
// it even after the handle has been closed, so that uniqueness is no
|
||||
// longer guaranteed (when `nFileIndex{Low,High}` are unique).
|
||||
// bug report: http://lists.llvm.org/pipermail/llvm-bugs/2014-December/037218.html
|
||||
//
|
||||
// All said and done, checking whether two files are the same on Windows
|
||||
// seems quite tricky. Moreover, even if the code is technically incorrect,
|
||||
// it seems like the chances of actually observing incorrect behavior are
|
||||
// extremely small. Nevertheless, we mitigate this by checking size too.
|
||||
//
|
||||
// In the case where this code is erroneous, two files will be reported
|
||||
// as equivalent when they are in fact distinct. This will cause the loop
|
||||
// detection code to report a false positive, which will prevent descending
|
||||
// into the offending directory. As far as failure modes goes, this isn't
|
||||
// that bad.
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Handle {
|
||||
kind: HandleKind,
|
||||
key: Option<Key>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum HandleKind {
|
||||
/// Used when opening a file or acquiring ownership of a file.
|
||||
Owned(winutil::Handle),
|
||||
/// Used for stdio.
|
||||
Borrowed(winutil::HandleRef),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Hash)]
|
||||
struct Key {
|
||||
volume: u64,
|
||||
index: u64,
|
||||
}
|
||||
|
||||
impl Eq for Handle {}
|
||||
|
||||
impl PartialEq for Handle {
|
||||
fn eq(&self, other: &Handle) -> bool {
|
||||
// Need this branch to satisfy `Eq` since `Handle`s with
|
||||
// `key.is_none()` wouldn't otherwise.
|
||||
if self as *const Handle == other as *const Handle {
|
||||
return true;
|
||||
} else if self.key.is_none() || other.key.is_none() {
|
||||
return false;
|
||||
}
|
||||
self.key == other.key
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawHandle for crate::Handle {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
match self.0.kind {
|
||||
HandleKind::Owned(ref h) => h.as_raw_handle(),
|
||||
HandleKind::Borrowed(ref h) => h.as_raw_handle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawHandle for crate::Handle {
|
||||
fn into_raw_handle(self) -> RawHandle {
|
||||
match self.0.kind {
|
||||
HandleKind::Owned(h) => h.into_raw_handle(),
|
||||
HandleKind::Borrowed(h) => h.as_raw_handle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Handle {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.key.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
pub fn from_path<P: AsRef<Path>>(p: P) -> io::Result<Handle> {
|
||||
let h = winutil::Handle::from_path_any(p)?;
|
||||
let info = winutil::file::information(&h)?;
|
||||
Ok(Handle::from_info(HandleKind::Owned(h), info))
|
||||
}
|
||||
|
||||
pub fn from_file(file: File) -> io::Result<Handle> {
|
||||
let h = winutil::Handle::from_file(file);
|
||||
let info = winutil::file::information(&h)?;
|
||||
Ok(Handle::from_info(HandleKind::Owned(h), info))
|
||||
}
|
||||
|
||||
fn from_std_handle(h: winutil::HandleRef) -> io::Result<Handle> {
|
||||
match winutil::file::information(&h) {
|
||||
Ok(info) => Ok(Handle::from_info(HandleKind::Borrowed(h), info)),
|
||||
// In a Windows console, if there is no pipe attached to a STD
|
||||
// handle, then GetFileInformationByHandle will return an error.
|
||||
// We don't really care. The only thing we care about is that
|
||||
// this handle is never equivalent to any other handle, which is
|
||||
// accomplished by setting key to None.
|
||||
Err(_) => Ok(Handle { kind: HandleKind::Borrowed(h), key: None }),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_info(
|
||||
kind: HandleKind,
|
||||
info: winutil::file::Information,
|
||||
) -> Handle {
|
||||
Handle {
|
||||
kind: kind,
|
||||
key: Some(Key {
|
||||
volume: info.volume_serial_number(),
|
||||
index: info.file_index(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdin() -> io::Result<Handle> {
|
||||
Handle::from_std_handle(winutil::HandleRef::stdin())
|
||||
}
|
||||
|
||||
pub fn stdout() -> io::Result<Handle> {
|
||||
Handle::from_std_handle(winutil::HandleRef::stdout())
|
||||
}
|
||||
|
||||
pub fn stderr() -> io::Result<Handle> {
|
||||
Handle::from_std_handle(winutil::HandleRef::stderr())
|
||||
}
|
||||
|
||||
pub fn as_file(&self) -> &File {
|
||||
match self.kind {
|
||||
HandleKind::Owned(ref h) => h.as_file(),
|
||||
HandleKind::Borrowed(ref h) => h.as_file(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_file_mut(&mut self) -> &mut File {
|
||||
match self.kind {
|
||||
HandleKind::Owned(ref mut h) => h.as_file_mut(),
|
||||
HandleKind::Borrowed(ref mut h) => h.as_file_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue