diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /compiler/rustc_data_structures/src/flock | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_data_structures/src/flock')
-rw-r--r-- | compiler/rustc_data_structures/src/flock/linux.rs | 40 | ||||
-rw-r--r-- | compiler/rustc_data_structures/src/flock/unix.rs | 51 | ||||
-rw-r--r-- | compiler/rustc_data_structures/src/flock/unsupported.rs | 16 | ||||
-rw-r--r-- | compiler/rustc_data_structures/src/flock/windows.rs | 77 |
4 files changed, 184 insertions, 0 deletions
diff --git a/compiler/rustc_data_structures/src/flock/linux.rs b/compiler/rustc_data_structures/src/flock/linux.rs new file mode 100644 index 000000000..bb3ecfbc3 --- /dev/null +++ b/compiler/rustc_data_structures/src/flock/linux.rs @@ -0,0 +1,40 @@ +//! We use `flock` rather than `fcntl` on Linux, because WSL1 does not support +//! `fcntl`-style advisory locks properly (rust-lang/rust#72157). For other Unix +//! targets we still use `fcntl` because it's more portable than `flock`. + +use std::fs::{File, OpenOptions}; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; + +#[derive(Debug)] +pub struct Lock { + _file: File, +} + +impl Lock { + pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> { + let file = OpenOptions::new() + .read(true) + .write(true) + .create(create) + .mode(libc::S_IRWXU as u32) + .open(p)?; + + let mut operation = if exclusive { libc::LOCK_EX } else { libc::LOCK_SH }; + if !wait { + operation |= libc::LOCK_NB + } + + let ret = unsafe { libc::flock(file.as_raw_fd(), operation) }; + if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { _file: file }) } + } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } +} + +// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. A lock acquired by +// `flock` is associated with the file descriptor and closing the file releases it +// automatically. diff --git a/compiler/rustc_data_structures/src/flock/unix.rs b/compiler/rustc_data_structures/src/flock/unix.rs new file mode 100644 index 000000000..4e5297d58 --- /dev/null +++ b/compiler/rustc_data_structures/src/flock/unix.rs @@ -0,0 +1,51 @@ +use std::fs::{File, OpenOptions}; +use std::io; +use std::mem; +use std::os::unix::prelude::*; +use std::path::Path; + +#[derive(Debug)] +pub struct Lock { + file: File, +} + +impl Lock { + pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> { + let file = OpenOptions::new() + .read(true) + .write(true) + .create(create) + .mode(libc::S_IRWXU as u32) + .open(p)?; + + let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK }; + + let mut flock: libc::flock = unsafe { mem::zeroed() }; + flock.l_type = lock_type as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + + let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK }; + let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &flock) }; + if ret == -1 { Err(io::Error::last_os_error()) } else { Ok(Lock { file }) } + } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } +} + +impl Drop for Lock { + fn drop(&mut self) { + let mut flock: libc::flock = unsafe { mem::zeroed() }; + flock.l_type = libc::F_UNLCK as libc::c_short; + flock.l_whence = libc::SEEK_SET as libc::c_short; + flock.l_start = 0; + flock.l_len = 0; + + unsafe { + libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock); + } + } +} diff --git a/compiler/rustc_data_structures/src/flock/unsupported.rs b/compiler/rustc_data_structures/src/flock/unsupported.rs new file mode 100644 index 000000000..9245fca37 --- /dev/null +++ b/compiler/rustc_data_structures/src/flock/unsupported.rs @@ -0,0 +1,16 @@ +use std::io; +use std::path::Path; + +#[derive(Debug)] +pub struct Lock(()); + +impl Lock { + pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool) -> io::Result<Lock> { + let msg = "file locks not supported on this platform"; + Err(io::Error::new(io::ErrorKind::Other, msg)) + } + + pub fn error_unsupported(_err: &io::Error) -> bool { + true + } +} diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs new file mode 100644 index 000000000..43e6caaa1 --- /dev/null +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -0,0 +1,77 @@ +use std::fs::{File, OpenOptions}; +use std::io; +use std::mem; +use std::os::windows::prelude::*; +use std::path::Path; + +use winapi::shared::winerror::ERROR_INVALID_FUNCTION; +use winapi::um::fileapi::LockFileEx; +use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED}; +use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; + +#[derive(Debug)] +pub struct Lock { + _file: File, +} + +impl Lock { + pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> { + assert!( + p.parent().unwrap().exists(), + "Parent directory of lock-file must exist: {}", + p.display() + ); + + let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; + + let mut open_options = OpenOptions::new(); + open_options.read(true).share_mode(share_mode); + + if create { + open_options.create(true).write(true); + } + + debug!("attempting to open lock file `{}`", p.display()); + let file = match open_options.open(p) { + Ok(file) => { + debug!("lock file opened successfully"); + file + } + Err(err) => { + debug!("error opening lock file: {}", err); + return Err(err); + } + }; + + let ret = unsafe { + let mut overlapped: OVERLAPPED = mem::zeroed(); + + let mut dwFlags = 0; + if !wait { + dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; + } + + if exclusive { + dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; + } + + debug!("attempting to acquire lock on lock file `{}`", p.display()); + LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped) + }; + if ret == 0 { + let err = io::Error::last_os_error(); + debug!("failed acquiring file lock: {}", err); + Err(err) + } else { + debug!("successfully acquired lock"); + Ok(Lock { _file: file }) + } + } + + pub fn error_unsupported(err: &io::Error) -> bool { + err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32) + } +} + +// Note that we don't need a Drop impl on Windows: The file is unlocked +// automatically when it's closed. |