-
Notifications
You must be signed in to change notification settings - Fork 666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement open file descriptor locks in fcntl #1195
Changes from 10 commits
08be41e
360bdfb
b56fb4c
2ae45b8
8252142
ef01f46
6075ce0
87f33c3
2d90033
3332c08
1478315
4c4df3c
5e2d14b
f7f1d09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,27 @@ | ||
use nix::Error; | ||
use nix::errno::*; | ||
use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat}; | ||
use nix::fcntl::{open, openat, readlink, readlinkat, renameat, OFlag}; | ||
use nix::sys::stat::Mode; | ||
use nix::unistd::{close, read}; | ||
use tempfile::{self, NamedTempFile}; | ||
use nix::Error; | ||
use std::fs::File; | ||
use std::io::prelude::*; | ||
use std::os::unix::fs; | ||
use tempfile::{self, NamedTempFile}; | ||
|
||
#[test] | ||
fn test_openat() { | ||
const CONTENTS: &[u8] = b"abcd"; | ||
let mut tmp = NamedTempFile::new().unwrap(); | ||
tmp.write_all(CONTENTS).unwrap(); | ||
|
||
let dirfd = open(tmp.path().parent().unwrap(), | ||
OFlag::empty(), | ||
Mode::empty()).unwrap(); | ||
let fd = openat(dirfd, | ||
tmp.path().file_name().unwrap(), | ||
OFlag::O_RDONLY, | ||
Mode::empty()).unwrap(); | ||
let dirfd = open(tmp.path().parent().unwrap(), OFlag::empty(), Mode::empty()).unwrap(); | ||
let fd = openat( | ||
dirfd, | ||
tmp.path().file_name().unwrap(), | ||
OFlag::O_RDONLY, | ||
Mode::empty(), | ||
) | ||
.unwrap(); | ||
|
||
let mut buf = [0u8; 1024]; | ||
assert_eq!(4, read(fd, &mut buf).unwrap()); | ||
|
@@ -39,8 +40,10 @@ fn test_renameat() { | |
let new_dir = tempfile::tempdir().unwrap(); | ||
let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); | ||
renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap(); | ||
assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), | ||
Error::Sys(Errno::ENOENT)); | ||
assert_eq!( | ||
renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(), | ||
Error::Sys(Errno::ENOENT) | ||
); | ||
close(old_dirfd).unwrap(); | ||
close(new_dirfd).unwrap(); | ||
assert!(new_dir.path().join("new").exists()); | ||
|
@@ -53,25 +56,27 @@ fn test_readlink() { | |
let dst = tempdir.path().join("b"); | ||
println!("a: {:?}, b: {:?}", &src, &dst); | ||
fs::symlink(&src.as_path(), &dst.as_path()).unwrap(); | ||
let dirfd = open(tempdir.path(), | ||
OFlag::empty(), | ||
Mode::empty()).unwrap(); | ||
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); | ||
let expected_dir = src.to_str().unwrap(); | ||
|
||
assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir); | ||
assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir); | ||
|
||
assert_eq!( | ||
readlinkat(dirfd, "b").unwrap().to_str().unwrap(), | ||
expected_dir | ||
); | ||
} | ||
|
||
#[cfg(any(target_os = "linux", target_os = "android"))] | ||
mod linux_android { | ||
use std::fs::File; | ||
use std::io::prelude::*; | ||
use std::io::SeekFrom; | ||
use std::io::{BufRead, BufReader, SeekFrom}; | ||
use std::os::unix::prelude::*; | ||
|
||
use libc::loff_t; | ||
|
||
use nix::fcntl::*; | ||
use nix::sys::stat::fstat; | ||
use nix::sys::uio::IoVec; | ||
use nix::unistd::{close, pipe, read, write}; | ||
|
||
|
@@ -123,8 +128,15 @@ mod linux_android { | |
|
||
let (rd, wr) = pipe().unwrap(); | ||
let mut offset: loff_t = 5; | ||
let res = splice(tmp.as_raw_fd(), Some(&mut offset), | ||
wr, None, 2, SpliceFFlags::empty()).unwrap(); | ||
let res = splice( | ||
tmp.as_raw_fd(), | ||
Some(&mut offset), | ||
wr, | ||
None, | ||
2, | ||
SpliceFFlags::empty(), | ||
) | ||
.unwrap(); | ||
|
||
assert_eq!(2, res); | ||
|
||
|
@@ -197,22 +209,87 @@ mod linux_android { | |
let mut buf = [0u8; 200]; | ||
assert_eq!(100, read(fd, &mut buf).unwrap()); | ||
} | ||
|
||
#[test] | ||
#[cfg(not(any(target_arch = "aarch64", | ||
target_arch = "arm", | ||
target_arch = "armv7", | ||
target_arch = "i686", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try "x86" instead of "i686". Also, please explain in a comment why the test is disabled on certain architectures. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a comment and switched to x86. |
||
target_arch = "mips", | ||
target_arch = "mips64", | ||
target_arch = "mips64el", | ||
target_arch = "powerpc64", | ||
target_arch = "powerpc64le")))] | ||
fn test_ofd_locks() { | ||
let tmp = NamedTempFile::new().unwrap(); | ||
|
||
let fd = tmp.as_raw_fd(); | ||
let inode = fstat(fd).expect("fstat failed").st_ino as usize; | ||
|
||
let mut flock = libc::flock { | ||
l_type: libc::F_WRLCK as libc::c_short, | ||
l_whence: libc::SEEK_SET as libc::c_short, | ||
l_start: 0, | ||
l_len: 0, | ||
l_pid: 0, | ||
}; | ||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed"); | ||
assert_eq!( | ||
Some(("OFDLCK".to_string(), "WRITE".to_string())), | ||
lock_info(inode) | ||
); | ||
|
||
flock.l_type = libc::F_UNLCK as libc::c_short; | ||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed"); | ||
assert_eq!(None, lock_info(inode)); | ||
|
||
flock.l_type = libc::F_RDLCK as libc::c_short; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like this test is doing two separate things: setting and clearing a write lock, and setting and clearing a read lock. Please split it up into two separate tests. That will make it easier to debug. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed"); | ||
assert_eq!( | ||
Some(("OFDLCK".to_string(), "READ".to_string())), | ||
lock_info(inode) | ||
); | ||
|
||
flock.l_type = libc::F_UNLCK as libc::c_short; | ||
fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed"); | ||
assert_eq!(None, lock_info(inode)); | ||
} | ||
|
||
fn lock_info(inode: usize) -> Option<(String, String)> { | ||
let file = File::open("/proc/locks").expect("open /proc/locks failed"); | ||
let buf = BufReader::new(file); | ||
|
||
for line in buf.lines() { | ||
let line = line.unwrap(); | ||
let parts: Vec<_> = line.split_whitespace().collect(); | ||
let lock_type = parts[1]; | ||
let lock_access = parts[3]; | ||
let ino_parts: Vec<_> = parts[5].split(':').collect(); | ||
let ino: usize = ino_parts[2].parse().unwrap(); | ||
if ino == inode { | ||
return Some((lock_type.to_string(), lock_access.to_string())); | ||
} | ||
} | ||
None | ||
} | ||
} | ||
|
||
#[cfg(any(target_os = "linux", | ||
target_os = "android", | ||
target_os = "emscripten", | ||
target_os = "fuchsia", | ||
any(target_os = "wasi", target_env = "wasi"), | ||
target_env = "uclibc", | ||
target_env = "freebsd"))] | ||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "android", | ||
target_os = "emscripten", | ||
target_os = "fuchsia", | ||
any(target_os = "wasi", target_env = "wasi"), | ||
target_env = "uclibc", | ||
target_env = "freebsd" | ||
))] | ||
mod test_posix_fadvise { | ||
|
||
use tempfile::NamedTempFile; | ||
use std::os::unix::io::{RawFd, AsRawFd}; | ||
use nix::errno::Errno; | ||
use nix::fcntl::*; | ||
use nix::unistd::pipe; | ||
use std::os::unix::io::{AsRawFd, RawFd}; | ||
use tempfile::NamedTempFile; | ||
|
||
#[test] | ||
fn test_success() { | ||
|
@@ -226,25 +303,30 @@ mod test_posix_fadvise { | |
#[test] | ||
fn test_errno() { | ||
let (rd, _wr) = pipe().unwrap(); | ||
let errno = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED) | ||
.unwrap(); | ||
let errno = | ||
posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED).unwrap(); | ||
assert_eq!(errno, Errno::ESPIPE as i32); | ||
} | ||
} | ||
|
||
#[cfg(any(target_os = "linux", | ||
target_os = "android", | ||
target_os = "emscripten", | ||
target_os = "fuchsia", | ||
any(target_os = "wasi", target_env = "wasi"), | ||
target_os = "freebsd"))] | ||
#[cfg(any( | ||
target_os = "linux", | ||
target_os = "android", | ||
target_os = "emscripten", | ||
target_os = "fuchsia", | ||
any(target_os = "wasi", target_env = "wasi"), | ||
target_os = "freebsd" | ||
))] | ||
mod test_posix_fallocate { | ||
|
||
use tempfile::NamedTempFile; | ||
use std::{io::Read, os::unix::io::{RawFd, AsRawFd}}; | ||
use nix::errno::Errno; | ||
use nix::fcntl::*; | ||
use nix::unistd::pipe; | ||
use std::{ | ||
io::Read, | ||
os::unix::io::{AsRawFd, RawFd}, | ||
}; | ||
use tempfile::NamedTempFile; | ||
|
||
#[test] | ||
fn success() { | ||
|
@@ -276,15 +358,8 @@ mod test_posix_fallocate { | |
let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err(); | ||
use nix::Error::Sys; | ||
match err { | ||
Sys(Errno::EINVAL) | ||
| Sys(Errno::ENODEV) | ||
| Sys(Errno::ESPIPE) | ||
| Sys(Errno::EBADF) => (), | ||
errno => | ||
panic!( | ||
"unexpected errno {}", | ||
errno, | ||
), | ||
Sys(Errno::EINVAL) | Sys(Errno::ENODEV) | Sys(Errno::ESPIPE) | Sys(Errno::EBADF) => (), | ||
errno => panic!("unexpected errno {}", errno,), | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like you made some formatting changes unrelated to this PR. Could you please back those out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, forgot to disable rustfmt while editing. It's fixed.