From 645579430a6d6c176d45ee26b857291b0724cd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ci=C4=99=C5=BCarkiewicz?= Date: Thu, 16 Nov 2023 14:35:08 -0800 Subject: [PATCH] feat(fs-lock): new_try_exclusive and new_try_shared (#1496) In certain situations it's useful to attempt to lock the file. --- crates/fs-lock/src/lib.rs | 56 +++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 11 deletions(-) diff --git a/crates/fs-lock/src/lib.rs b/crates/fs-lock/src/lib.rs index 9adb4927..af209ff5 100644 --- a/crates/fs-lock/src/lib.rs +++ b/crates/fs-lock/src/lib.rs @@ -4,7 +4,7 @@ use std::{ fs::File, - io::{self, IoSlice, IoSliceMut, Result, SeekFrom}, + io::{self, IoSlice, IoSliceMut, SeekFrom}, ops, }; @@ -18,20 +18,54 @@ impl FileLock { /// Take an exclusive lock on a [`File`]. /// /// Note that this operation is blocking, and should not be called in async contexts. - pub fn new_exclusive(file: File) -> Result { + pub fn new_exclusive(file: File) -> io::Result { file.lock_exclusive()?; Ok(Self(file)) } + /// Try to take an exclusive lock on a [`File`]. + /// + /// On success returns [`Self`]. On error the original [`File`] and optionally + /// an [`io::Error`] if the the failure was caused by anything other than + /// the lock being taken already. + /// + /// Note that this operation is blocking, and should not be called in async contexts. + pub fn new_try_exclusive(file: File) -> Result)> { + match file.try_lock_exclusive() { + Ok(()) => Ok(Self(file)), + Err(e) if e.raw_os_error() == fs4::lock_contended_error().raw_os_error() => { + Err((file, None)) + } + Err(e) => Err((file, Some(e))), + } + } + /// Take a shared lock on a [`File`]. /// /// Note that this operation is blocking, and should not be called in async contexts. - pub fn new_shared(file: File) -> Result { + pub fn new_shared(file: File) -> io::Result { file.lock_shared()?; Ok(Self(file)) } + + /// Try to take a shared lock on a [`File`]. + /// + /// On success returns [`Self`]. On error the original [`File`] and optionally + /// an [`io::Error`] if the the failure was caused by anything other than + /// the lock being taken already. + /// + /// Note that this operation is blocking, and should not be called in async contexts. + pub fn new_try_shared(file: File) -> Result)> { + match file.try_lock_shared() { + Ok(()) => Ok(Self(file)), + Err(e) if e.raw_os_error() == fs4::lock_contended_error().raw_os_error() => { + Err((file, None)) + } + Err(e) => Err((file, Some(e))), + } + } } impl Drop for FileLock { @@ -54,37 +88,37 @@ impl ops::DerefMut for FileLock { } impl io::Write for FileLock { - fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - fn flush(&mut self) -> Result<()> { + fn flush(&mut self) -> io::Result<()> { self.0.flush() } - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result { + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.0.write_vectored(bufs) } } impl io::Read for FileLock { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } } impl io::Seek for FileLock { - fn seek(&mut self, pos: SeekFrom) -> Result { + fn seek(&mut self, pos: SeekFrom) -> io::Result { self.0.seek(pos) } - fn rewind(&mut self) -> Result<()> { + fn rewind(&mut self) -> io::Result<()> { self.0.rewind() } - fn stream_position(&mut self) -> Result { + fn stream_position(&mut self) -> io::Result { self.0.stream_position() } }