Skip to content

Commit c5af4ad

Browse files
authored
Add Flock::relock (#2407)
It can upgrade or downgrade a lock. Fixes #2356
1 parent e7acaff commit c5af4ad

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

changelog/2407.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added `Flock::relock` for upgrading and downgrading locks.

src/fcntl.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,30 @@ impl<T: Flockable> Flock<T> {
955955
std::mem::forget(self);
956956
Ok(inner)
957957
}
958+
959+
/// Relock the file. This can upgrade or downgrade the lock type.
960+
///
961+
/// # Example
962+
/// ```
963+
/// # use std::fs::File;
964+
/// # use nix::fcntl::{Flock, FlockArg};
965+
/// # use tempfile::tempfile;
966+
/// let f: std::fs::File = tempfile().unwrap();
967+
/// let locked_file = Flock::lock(f, FlockArg::LockExclusive).unwrap();
968+
/// // Do stuff, then downgrade the lock
969+
/// locked_file.relock(FlockArg::LockShared).unwrap();
970+
/// ```
971+
pub fn relock(&self, arg: FlockArg) -> Result<()> {
972+
let flags = match arg {
973+
FlockArg::LockShared => libc::LOCK_SH,
974+
FlockArg::LockExclusive => libc::LOCK_EX,
975+
FlockArg::LockSharedNonblock => libc::LOCK_SH | libc::LOCK_NB,
976+
FlockArg::LockExclusiveNonblock => libc::LOCK_EX | libc::LOCK_NB,
977+
#[allow(deprecated)]
978+
FlockArg::Unlock | FlockArg::UnlockNonblock => return Err(Errno::EINVAL),
979+
};
980+
Errno::result(unsafe { libc::flock(self.as_raw_fd(), flags) }).map(drop)
981+
}
958982
}
959983

960984
// Safety: `File` is not [std::clone::Clone].

test/test_fcntl.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ mod test_flock {
686686

687687
/// Verify that `Flock::lock()` correctly obtains a lock, and subsequently unlocks upon drop.
688688
#[test]
689-
fn verify_lock_and_drop() {
689+
fn lock_and_drop() {
690690
// Get 2 `File` handles to same underlying file.
691691
let file1 = NamedTempFile::new().unwrap();
692692
let file2 = file1.reopen().unwrap();
@@ -710,9 +710,32 @@ mod test_flock {
710710
}
711711
}
712712

713+
/// An exclusive lock can be downgraded
714+
#[test]
715+
fn downgrade() {
716+
let file1 = NamedTempFile::new().unwrap();
717+
let file2 = file1.reopen().unwrap();
718+
let file1 = file1.into_file();
719+
720+
// Lock first handle
721+
let lock1 = Flock::lock(file1, FlockArg::LockExclusive).unwrap();
722+
723+
// Attempt to lock second handle
724+
let file2 = Flock::lock(file2, FlockArg::LockSharedNonblock)
725+
.unwrap_err()
726+
.0;
727+
728+
// Downgrade the lock
729+
lock1.relock(FlockArg::LockShared).unwrap();
730+
731+
// Attempt to lock second handle again (but successfully)
732+
Flock::lock(file2, FlockArg::LockSharedNonblock)
733+
.expect("Expected locking to be successful.");
734+
}
735+
713736
/// Verify that `Flock::unlock()` correctly obtains unlocks.
714737
#[test]
715-
fn verify_unlock() {
738+
fn unlock() {
716739
// Get 2 `File` handles to same underlying file.
717740
let file1 = NamedTempFile::new().unwrap();
718741
let file2 = file1.reopen().unwrap();
@@ -729,4 +752,29 @@ mod test_flock {
729752
panic!("Expected locking to be successful.");
730753
}
731754
}
755+
756+
/// A shared lock can be upgraded
757+
#[test]
758+
fn upgrade() {
759+
let file1 = NamedTempFile::new().unwrap();
760+
let file2 = file1.reopen().unwrap();
761+
let file3 = file1.reopen().unwrap();
762+
let file1 = file1.into_file();
763+
764+
// Lock first handle
765+
let lock1 = Flock::lock(file1, FlockArg::LockShared).unwrap();
766+
767+
// Attempt to lock second handle
768+
{
769+
Flock::lock(file2, FlockArg::LockSharedNonblock)
770+
.expect("Locking should've succeeded");
771+
}
772+
773+
// Upgrade the lock
774+
lock1.relock(FlockArg::LockExclusive).unwrap();
775+
776+
// Acquiring an additional shared lock should fail
777+
Flock::lock(file3, FlockArg::LockSharedNonblock)
778+
.expect_err("Should not have been able to lock the file");
779+
}
732780
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy