mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
Merge 7302f8eecd
into 65fa0ab924
This commit is contained in:
commit
51c9dca86c
@ -21,7 +21,6 @@
|
||||
mod tests;
|
||||
|
||||
use crate::ffi::OsString;
|
||||
use crate::fmt;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sealed::Sealed;
|
||||
@ -29,6 +28,7 @@ use crate::sync::Arc;
|
||||
use crate::sys::fs as fs_imp;
|
||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
use crate::time::SystemTime;
|
||||
use crate::{error, fmt};
|
||||
|
||||
/// An object providing access to an open file on the filesystem.
|
||||
///
|
||||
@ -116,6 +116,22 @@ pub struct File {
|
||||
inner: fs_imp::File,
|
||||
}
|
||||
|
||||
/// An enumeration of possible errors which can occur while trying to acquire a lock
|
||||
/// from the [`try_lock`] method and [`try_lock_shared`] method on a [`File`].
|
||||
///
|
||||
/// [`try_lock`]: File::try_lock
|
||||
/// [`try_lock_shared`]: File::try_lock_shared
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
pub enum TryLockError {
|
||||
/// The lock could not be acquired due to an I/O error on the file. The standard library will
|
||||
/// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`]
|
||||
///
|
||||
/// [`ErrorKind::WouldBlock`]: io::ErrorKind::WouldBlock
|
||||
Error(io::Error),
|
||||
/// The lock could not be acquired at this time because it is held by another handle/process.
|
||||
WouldBlock,
|
||||
}
|
||||
|
||||
/// Metadata information about a file.
|
||||
///
|
||||
/// This structure is returned from the [`metadata`] or
|
||||
@ -352,6 +368,30 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result
|
||||
inner(path.as_ref(), contents.as_ref())
|
||||
}
|
||||
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
impl error::Error for TryLockError {}
|
||||
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
impl fmt::Debug for TryLockError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TryLockError::Error(err) => err.fmt(f),
|
||||
TryLockError::WouldBlock => "WouldBlock".fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
impl fmt::Display for TryLockError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
TryLockError::Error(_) => "lock acquisition failed due to I/O error",
|
||||
TryLockError::WouldBlock => "lock acquisition failed because the operation would block",
|
||||
}
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
/// Attempts to open a file in read-only mode.
|
||||
///
|
||||
@ -734,8 +774,8 @@ impl File {
|
||||
|
||||
/// Try to acquire an exclusive lock on the file.
|
||||
///
|
||||
/// Returns `Ok(false)` if a different lock is already held on this file (via another
|
||||
/// handle/descriptor).
|
||||
/// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file
|
||||
/// (via another handle/descriptor).
|
||||
///
|
||||
/// This acquires an exclusive lock; no other file handle to this file may acquire another lock.
|
||||
///
|
||||
@ -777,23 +817,27 @@ impl File {
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(file_lock)]
|
||||
/// use std::fs::File;
|
||||
/// use std::fs::{File, TryLockError};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let f = File::create("foo.txt")?;
|
||||
/// f.try_lock()?;
|
||||
/// match f.try_lock() {
|
||||
/// Ok(_) => (),
|
||||
/// Err(TryLockError::WouldBlock) => (), // Lock not acquired
|
||||
/// Err(TryLockError::Error(err)) => return Err(err),
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
self.inner.try_lock()
|
||||
}
|
||||
|
||||
/// Try to acquire a shared (non-exclusive) lock on the file.
|
||||
///
|
||||
/// Returns `Ok(false)` if an exclusive lock is already held on this file (via another
|
||||
/// handle/descriptor).
|
||||
/// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file
|
||||
/// (via another handle/descriptor).
|
||||
///
|
||||
/// This acquires a shared lock; more than one file handle may hold a shared lock, but none may
|
||||
/// hold an exclusive lock at the same time.
|
||||
@ -834,16 +878,21 @@ impl File {
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(file_lock)]
|
||||
/// use std::fs::File;
|
||||
/// use std::fs::{File, TryLockError};
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let f = File::open("foo.txt")?;
|
||||
/// f.try_lock_shared()?;
|
||||
/// match f.try_lock_shared() {
|
||||
/// Ok(_) => (),
|
||||
/// Err(TryLockError::WouldBlock) => (), // Lock not acquired
|
||||
/// Err(TryLockError::Error(err)) => return Err(err),
|
||||
/// }
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "file_lock", issue = "130994")]
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
self.inner.try_lock_shared()
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::char::MAX_LEN_UTF8;
|
||||
use crate::fs::{self, File, FileTimes, OpenOptions};
|
||||
use crate::fs::{self, File, FileTimes, OpenOptions, TryLockError};
|
||||
use crate::io::prelude::*;
|
||||
use crate::io::{BorrowedBuf, ErrorKind, SeekFrom};
|
||||
use crate::mem::MaybeUninit;
|
||||
@ -28,6 +28,16 @@ macro_rules! check {
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! check_would_block {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
Ok(_) => panic!("{} acquired lock when it should have failed", stringify!($e)),
|
||||
Err(TryLockError::WouldBlock) => (),
|
||||
Err(e) => panic!("{} failed with: {e}", stringify!($e)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
macro_rules! error {
|
||||
($e:expr, $s:expr) => {
|
||||
@ -223,8 +233,8 @@ fn file_lock_multiple_shared() {
|
||||
check!(f2.lock_shared());
|
||||
check!(f1.unlock());
|
||||
check!(f2.unlock());
|
||||
assert!(check!(f1.try_lock_shared()));
|
||||
assert!(check!(f2.try_lock_shared()));
|
||||
check!(f1.try_lock_shared());
|
||||
check!(f2.try_lock_shared());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -243,12 +253,12 @@ fn file_lock_blocking() {
|
||||
|
||||
// Check that shared locks block exclusive locks
|
||||
check!(f1.lock_shared());
|
||||
assert!(!check!(f2.try_lock()));
|
||||
check_would_block!(f2.try_lock());
|
||||
check!(f1.unlock());
|
||||
|
||||
// Check that exclusive locks block shared locks
|
||||
check!(f1.lock());
|
||||
assert!(!check!(f2.try_lock_shared()));
|
||||
check_would_block!(f2.try_lock_shared());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -267,9 +277,9 @@ fn file_lock_drop() {
|
||||
|
||||
// Check that locks are released when the File is dropped
|
||||
check!(f1.lock_shared());
|
||||
assert!(!check!(f2.try_lock()));
|
||||
check_would_block!(f2.try_lock());
|
||||
drop(f1);
|
||||
assert!(check!(f2.try_lock()));
|
||||
check!(f2.try_lock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -288,10 +298,10 @@ fn file_lock_dup() {
|
||||
|
||||
// Check that locks are not dropped if the File has been cloned
|
||||
check!(f1.lock_shared());
|
||||
assert!(!check!(f2.try_lock()));
|
||||
check_would_block!(f2.try_lock());
|
||||
let cloned = check!(f1.try_clone());
|
||||
drop(f1);
|
||||
assert!(!check!(f2.try_lock()));
|
||||
check_would_block!(f2.try_lock());
|
||||
drop(cloned)
|
||||
}
|
||||
|
||||
@ -307,9 +317,9 @@ fn file_lock_double_unlock() {
|
||||
// Check that both are released by unlock()
|
||||
check!(f1.lock());
|
||||
check!(f1.lock_shared());
|
||||
assert!(!check!(f2.try_lock()));
|
||||
check_would_block!(f2.try_lock());
|
||||
check!(f1.unlock());
|
||||
assert!(check!(f2.try_lock()));
|
||||
check!(f2.try_lock());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::ffi::{CStr, OsStr, OsString, c_char};
|
||||
use crate::fs::TryLockError;
|
||||
use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::hermit::ffi::OsStringExt;
|
||||
use crate::os::hermit::hermit_abi::{
|
||||
@ -12,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr;
|
||||
use crate::sys::fd::FileDesc;
|
||||
pub use crate::sys::fs::common::{copy, exists};
|
||||
use crate::sys::time::SystemTime;
|
||||
use crate::sys::{cvt, unsupported};
|
||||
use crate::sys::{cvt, unsupported, unsupported_err};
|
||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
use crate::{fmt, mem};
|
||||
|
||||
@ -366,12 +367,12 @@ impl File {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn unlock(&self) -> io::Result<()> {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use crate::ffi::{CStr, CString, OsStr, OsString};
|
||||
use crate::fmt;
|
||||
use crate::fs::TryLockError;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::raw::{c_int, c_short};
|
||||
@ -11,7 +12,7 @@ use crate::sync::Arc;
|
||||
pub use crate::sys::fs::common::exists;
|
||||
use crate::sys::pal::{abi, error};
|
||||
use crate::sys::time::SystemTime;
|
||||
use crate::sys::unsupported;
|
||||
use crate::sys::{unsupported, unsupported_err};
|
||||
use crate::sys_common::ignore_notfound;
|
||||
|
||||
type CIntNotMinusOne = core::num::niche_types::NotAllOnes<c_int>;
|
||||
@ -352,12 +353,12 @@ impl File {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn unlock(&self) -> io::Result<()> {
|
||||
|
@ -2,6 +2,7 @@ use r_efi::protocols::file;
|
||||
|
||||
use crate::ffi::OsString;
|
||||
use crate::fmt;
|
||||
use crate::fs::TryLockError;
|
||||
use crate::hash::Hash;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::path::{Path, PathBuf};
|
||||
@ -227,11 +228,11 @@ impl File {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
self.0
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,7 @@ use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, st
|
||||
|
||||
use crate::ffi::{CStr, OsStr, OsString};
|
||||
use crate::fmt::{self, Write as _};
|
||||
use crate::fs::TryLockError;
|
||||
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
|
||||
use crate::os::unix::prelude::*;
|
||||
@ -1307,15 +1308,17 @@ impl File {
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
))]
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) });
|
||||
if let Err(ref err) = result {
|
||||
if let Err(err) = result {
|
||||
if err.kind() == io::ErrorKind::WouldBlock {
|
||||
return Ok(false);
|
||||
Err(TryLockError::WouldBlock)
|
||||
} else {
|
||||
Err(TryLockError::Error(err))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
result?;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
@ -1325,8 +1328,11 @@ impl File {
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
)))]
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock() not supported"))
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(io::const_error!(
|
||||
io::ErrorKind::Unsupported,
|
||||
"try_lock() not supported"
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
@ -1336,15 +1342,17 @@ impl File {
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
))]
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) });
|
||||
if let Err(ref err) = result {
|
||||
if let Err(err) = result {
|
||||
if err.kind() == io::ErrorKind::WouldBlock {
|
||||
return Ok(false);
|
||||
Err(TryLockError::WouldBlock)
|
||||
} else {
|
||||
Err(TryLockError::Error(err))
|
||||
}
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
result?;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
@ -1354,8 +1362,11 @@ impl File {
|
||||
target_os = "netbsd",
|
||||
target_vendor = "apple",
|
||||
)))]
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported"))
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(io::const_error!(
|
||||
io::ErrorKind::Unsupported,
|
||||
"try_lock_shared() not supported"
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::ffi::OsString;
|
||||
use crate::fmt;
|
||||
use crate::fs::TryLockError;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::path::{Path, PathBuf};
|
||||
@ -206,11 +207,11 @@ impl File {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
self.0
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::ffi::{CStr, OsStr, OsString};
|
||||
use crate::fs::TryLockError;
|
||||
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem::{self, ManuallyDrop};
|
||||
use crate::os::raw::c_int;
|
||||
@ -10,7 +11,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr;
|
||||
use crate::sys::fd::WasiFd;
|
||||
pub use crate::sys::fs::common::exists;
|
||||
use crate::sys::time::SystemTime;
|
||||
use crate::sys::unsupported;
|
||||
use crate::sys::{unsupported, unsupported_err};
|
||||
use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound};
|
||||
use crate::{fmt, iter, ptr};
|
||||
|
||||
@ -461,12 +462,12 @@ impl File {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
unsupported()
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
Err(TryLockError::Error(unsupported_err()))
|
||||
}
|
||||
|
||||
pub fn unlock(&self) -> io::Result<()> {
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::alloc::{Layout, alloc, dealloc};
|
||||
use crate::borrow::Cow;
|
||||
use crate::ffi::{OsStr, OsString, c_void};
|
||||
use crate::fs::TryLockError;
|
||||
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem::{self, MaybeUninit, offset_of};
|
||||
use crate::os::windows::io::{AsHandle, BorrowedHandle};
|
||||
@ -397,7 +398,7 @@ impl File {
|
||||
self.acquire_lock(0)
|
||||
}
|
||||
|
||||
pub fn try_lock(&self) -> io::Result<bool> {
|
||||
pub fn try_lock(&self) -> Result<(), TryLockError> {
|
||||
let result = cvt(unsafe {
|
||||
let mut overlapped = mem::zeroed();
|
||||
c::LockFileEx(
|
||||
@ -411,18 +412,18 @@ impl File {
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(true),
|
||||
Ok(_) => Ok(()),
|
||||
Err(err)
|
||||
if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
|
||||
|| err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
|
||||
{
|
||||
Ok(false)
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(err) => Err(TryLockError::Error(err)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_lock_shared(&self) -> io::Result<bool> {
|
||||
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
|
||||
let result = cvt(unsafe {
|
||||
let mut overlapped = mem::zeroed();
|
||||
c::LockFileEx(
|
||||
@ -436,14 +437,14 @@ impl File {
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(true),
|
||||
Ok(_) => Ok(()),
|
||||
Err(err)
|
||||
if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32)
|
||||
|| err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) =>
|
||||
{
|
||||
Ok(false)
|
||||
Err(TryLockError::WouldBlock)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
Err(err) => Err(TryLockError::Error(err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user