Skip to content

Commit

Permalink
feat(fs-lock): new_try_exclusive and new_try_shared (#1496)
Browse files Browse the repository at this point in the history
In certain situations it's useful to attempt to lock the file.
  • Loading branch information
dpc authored Nov 16, 2023
1 parent 9d8dc94 commit 6455794
Showing 1 changed file with 45 additions and 11 deletions.
56 changes: 45 additions & 11 deletions crates/fs-lock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use std::{
fs::File,
io::{self, IoSlice, IoSliceMut, Result, SeekFrom},
io::{self, IoSlice, IoSliceMut, SeekFrom},
ops,
};

Expand All @@ -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<Self> {
pub fn new_exclusive(file: File) -> io::Result<Self> {
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<Self, (File, Option<io::Error>)> {
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<Self> {
pub fn new_shared(file: File) -> io::Result<Self> {
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<Self, (File, Option<io::Error>)> {
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 {
Expand All @@ -54,37 +88,37 @@ impl ops::DerefMut for FileLock {
}

impl io::Write for FileLock {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
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<usize> {
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0.write_vectored(bufs)
}
}

impl io::Read for FileLock {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}

fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0.read_vectored(bufs)
}
}

impl io::Seek for FileLock {
fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
self.0.seek(pos)
}

fn rewind(&mut self) -> Result<()> {
fn rewind(&mut self) -> io::Result<()> {
self.0.rewind()
}
fn stream_position(&mut self) -> Result<u64> {
fn stream_position(&mut self) -> io::Result<u64> {
self.0.stream_position()
}
}

0 comments on commit 6455794

Please sign in to comment.