Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
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