From 86dbc063ab15e67b2b7ed5411eb9fec9f7afbcb4 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 18 May 2021 04:18:46 +0100 Subject: [PATCH] Windows implementation of `fs::try_exists` --- library/std/src/sys/windows/c.rs | 1 + library/std/src/sys/windows/fs.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index e91c489361ea6..50d6e8cf27a40 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -173,6 +173,7 @@ pub const ERROR_INVALID_HANDLE: DWORD = 6; pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; pub const ERROR_OUTOFMEMORY: DWORD = 14; pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_SHARING_VIOLATION: u32 = 32; pub const ERROR_HANDLE_EOF: DWORD = 38; pub const ERROR_FILE_EXISTS: DWORD = 80; pub const ERROR_INVALID_PARAMETER: DWORD = 87; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 36b395507b129..2b6143de96056 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -11,7 +11,6 @@ use crate::sync::Arc; use crate::sys::handle::Handle; use crate::sys::time::SystemTime; use crate::sys::{c, cvt}; -pub use crate::sys_common::fs::try_exists; use crate::sys_common::FromInner; use super::to_u16s; @@ -945,3 +944,32 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { .map(drop) } } + +// Try to see if a file exists but, unlike `exists`, report I/O errors. +pub fn try_exists(path: &Path) -> io::Result { + // Open the file to ensure any symlinks are followed to their target. + let mut opts = OpenOptions::new(); + // No read, write, etc access rights are needed. + opts.access_mode(0); + // Backup semantics enables opening directories as well as files. + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); + match File::open(path, &opts) { + Err(e) => match e.kind() { + // The file definitely does not exist + io::ErrorKind::NotFound => Ok(false), + + // `ERROR_SHARING_VIOLATION` means that the file has been locked by + // another process. This is often temporary so we simply report it + // as the file existing. + io::ErrorKind::Other if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => { + Ok(true) + } + // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the + // file exists. However, these types of errors are usually more + // permanent so we report them here. + _ => Err(e), + }, + // The file was opened successfully therefore it must exist, + Ok(_) => Ok(true), + } +}