Skip to content

Commit b5ee610

Browse files
bors[bot]andrenth
andauthored
Merge #1195
1195: Implement open file descriptor locks in fcntl r=asomers a=andrenth Hello This PR updates libc to 0.2.68, which adds the `F_OFD_*` fcntl commands, and uses them in `nix::fcntl::fcntl`. Co-authored-by: Andre Nathan <[email protected]>
2 parents 5c8cdd0 + f7f1d09 commit b5ee610

File tree

4 files changed

+103
-4
lines changed

4 files changed

+103
-4
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased] - ReleaseDate
77
### Added
8+
- Added support for `F_OFD_*` `fcntl` commands on Linux and Android.
9+
(#[1195](https://github.com/nix-rust/nix/pull/1195))
810
- Added `env::clearenv()`: calls `libc::clearenv` on platforms
911
where it's available, and clears the environment of all variables
1012
via `std::env::vars` and `std::env::remove_var` on others.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = [
1616
]
1717

1818
[dependencies]
19-
libc = { version = "0.2.60", features = [ "extra_traits" ] }
19+
libc = { version = "0.2.68", features = [ "extra_traits" ] }
2020
bitflags = "1.1"
2121
cfg-if = "0.1.10"
2222
void = "1.0.2"

src/fcntl.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
286286
F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
287287
F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
288288
#[cfg(any(target_os = "android", target_os = "linux"))]
289+
F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
290+
#[cfg(any(target_os = "android", target_os = "linux"))]
291+
F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
292+
#[cfg(any(target_os = "android", target_os = "linux"))]
293+
F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
294+
#[cfg(any(target_os = "android", target_os = "linux"))]
289295
F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
290296
#[cfg(any(target_os = "android", target_os = "linux"))]
291297
F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
@@ -295,8 +301,6 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
295301
F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
296302
#[cfg(any(target_os = "linux", target_os = "android"))]
297303
F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
298-
#[cfg(any(target_os = "linux", target_os = "android"))]
299-
_ => unimplemented!()
300304
}
301305
};
302306

test/test_fcntl.rs

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ fn test_readlink() {
6565

6666
#[cfg(any(target_os = "linux", target_os = "android"))]
6767
mod linux_android {
68+
use std::fs::File;
6869
use std::io::prelude::*;
69-
use std::io::SeekFrom;
70+
use std::io::{BufRead, BufReader, SeekFrom};
7071
use std::os::unix::prelude::*;
7172

7273
use libc::loff_t;
7374

7475
use nix::fcntl::*;
76+
use nix::sys::stat::fstat;
7577
use nix::sys::uio::IoVec;
7678
use nix::unistd::{close, pipe, read, write};
7779

@@ -197,6 +199,97 @@ mod linux_android {
197199
let mut buf = [0u8; 200];
198200
assert_eq!(100, read(fd, &mut buf).unwrap());
199201
}
202+
203+
// The tests below are disabled for the listed targets
204+
// due to OFD locks not being available in the kernel/libc
205+
// versions used in the CI environment, probably because
206+
// they run under QEMU.
207+
208+
#[test]
209+
#[cfg(not(any(target_arch = "aarch64",
210+
target_arch = "arm",
211+
target_arch = "armv7",
212+
target_arch = "x86",
213+
target_arch = "mips",
214+
target_arch = "mips64",
215+
target_arch = "mips64el",
216+
target_arch = "powerpc64",
217+
target_arch = "powerpc64le")))]
218+
fn test_ofd_write_lock() {
219+
let tmp = NamedTempFile::new().unwrap();
220+
221+
let fd = tmp.as_raw_fd();
222+
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
223+
224+
let mut flock = libc::flock {
225+
l_type: libc::F_WRLCK as libc::c_short,
226+
l_whence: libc::SEEK_SET as libc::c_short,
227+
l_start: 0,
228+
l_len: 0,
229+
l_pid: 0,
230+
};
231+
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed");
232+
assert_eq!(
233+
Some(("OFDLCK".to_string(), "WRITE".to_string())),
234+
lock_info(inode)
235+
);
236+
237+
flock.l_type = libc::F_UNLCK as libc::c_short;
238+
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
239+
assert_eq!(None, lock_info(inode));
240+
}
241+
242+
#[test]
243+
#[cfg(not(any(target_arch = "aarch64",
244+
target_arch = "arm",
245+
target_arch = "armv7",
246+
target_arch = "x86",
247+
target_arch = "mips",
248+
target_arch = "mips64",
249+
target_arch = "mips64el",
250+
target_arch = "powerpc64",
251+
target_arch = "powerpc64le")))]
252+
fn test_ofd_read_lock() {
253+
let tmp = NamedTempFile::new().unwrap();
254+
255+
let fd = tmp.as_raw_fd();
256+
let inode = fstat(fd).expect("fstat failed").st_ino as usize;
257+
258+
let mut flock = libc::flock {
259+
l_type: libc::F_RDLCK as libc::c_short,
260+
l_whence: libc::SEEK_SET as libc::c_short,
261+
l_start: 0,
262+
l_len: 0,
263+
l_pid: 0,
264+
};
265+
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed");
266+
assert_eq!(
267+
Some(("OFDLCK".to_string(), "READ".to_string())),
268+
lock_info(inode)
269+
);
270+
271+
flock.l_type = libc::F_UNLCK as libc::c_short;
272+
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
273+
assert_eq!(None, lock_info(inode));
274+
}
275+
276+
fn lock_info(inode: usize) -> Option<(String, String)> {
277+
let file = File::open("/proc/locks").expect("open /proc/locks failed");
278+
let buf = BufReader::new(file);
279+
280+
for line in buf.lines() {
281+
let line = line.unwrap();
282+
let parts: Vec<_> = line.split_whitespace().collect();
283+
let lock_type = parts[1];
284+
let lock_access = parts[3];
285+
let ino_parts: Vec<_> = parts[5].split(':').collect();
286+
let ino: usize = ino_parts[2].parse().unwrap();
287+
if ino == inode {
288+
return Some((lock_type.to_string(), lock_access.to_string()));
289+
}
290+
}
291+
None
292+
}
200293
}
201294

202295
#[cfg(any(target_os = "linux",

0 commit comments

Comments
 (0)