use proc::*;
use std::{
collections::HashSet,
io::{IoSlice, IoSliceMut, Write},
};
use testutils::*;
use uapi::{c::open_how, *};
#[test]
fn read_write1() {
let tmp = Tempdir::new();
let path1 = &*format!("{}/a", tmp);
let file = open(path1, c::O_CREAT | c::O_RDWR, 0o777).unwrap();
fallocate(*file, 0, 1, 2).unwrap();
let xstat = fstat(*file).unwrap();
assert_eq!(xstat.st_size, 3);
std::fs::write(path1, "abc").unwrap();
fallocate(
*file,
c::FALLOC_FL_PUNCH_HOLE | c::FALLOC_FL_KEEP_SIZE,
1,
1,
)
.unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "a\0c");
let f2 = dup(*file).unwrap();
assert_eq!(fcntl_getfd(*f2).unwrap() & c::FD_CLOEXEC, 0);
dup3(*file, *f2, c::O_CLOEXEC).unwrap();
assert_eq!(fcntl_getfd(*f2).unwrap() & c::FD_CLOEXEC, c::FD_CLOEXEC);
pwritev2(*file, &[IoSlice::new(b"x")][..], 1, 0).unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "axc");
pwritev2(*file, &[IoSlice::new(b"x")][..], 1, 0).unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "axc");
let mut buf = [0; 128];
let mut iovec = [IoSliceMut::new(&mut buf)];
let buf = preadv2(*file, &mut iovec[..], 2, 0).unwrap();
assert_eq!(buf.iter().next(), Some(&b"c"[..]));
assert!(statfs(path1).is_ok());
assert!(fstatfs(*file).is_ok());
}
#[test_if(linux_4_16)]
fn read_write2() {
let tmp = Tempdir::new();
let path1 = &*format!("{}/a", tmp);
let file = open(path1, c::O_CREAT | c::O_RDWR, 0o777).unwrap();
pwritev2(*file, &[IoSlice::new(b"a")][..], 0, 0).unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "a");
pwritev2(*file, &[IoSlice::new(b"x")][..], 1, c::RWF_APPEND).unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "ax");
write(*file, b"y").unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "yx");
pwritev2(*file, &[IoSlice::new(b"y")][..], -1, c::RWF_APPEND).unwrap();
assert_eq!(std::fs::read_to_string(path1).unwrap(), "yxy");
}
#[test]
fn copy_file_range_() {
let tmp = Tempdir::new();
let path1 = &*format!("{}/a", tmp);
let path2 = &*format!("{}/b", tmp);
let mut f1 = open(path1, c::O_CREAT | c::O_RDWR, 0).unwrap();
let mut f2 = open(path2, c::O_CREAT | c::O_RDWR, 0).unwrap();
f1.write_all(b"hello world").unwrap();
let n = copy_file_range(*f1, Some(&mut 3), *f2, Some(&mut 2), 5, 0).unwrap();
assert_eq!(n, 5);
let res = f2.read_to_new_ustring().unwrap();
assert_eq!(&res, "\0\0lo wo");
}
#[test]
fn renameat_() {
let tmp = Tempdir::new();
let dir = open(tmp.bstr(), c::O_PATH, 0).unwrap();
let path1 = "a";
let path2 = "b";
let f1 = openat(*dir, path1, c::O_CREAT | c::O_RDWR, 0).unwrap();
renameat2(*dir, path1, *dir, path2, 0).unwrap();
assert!(faccessat(*dir, path1, 0, 0).is_err());
assert!(faccessat(*dir, path2, 0, 0).is_ok());
assert_eq!(
fstatat(*dir, path2, 0).unwrap().st_ino,
fstat(*f1).unwrap().st_ino
);
let f2 = openat(*dir, path1, c::O_CREAT | c::O_RDWR, 0).unwrap();
renameat2(*dir, path1, *dir, path2, c::RENAME_EXCHANGE).unwrap();
assert_eq!(
fstatat(*dir, path2, 0).unwrap().st_ino,
fstat(*f2).unwrap().st_ino
);
assert_eq!(
fstatat(*dir, path1, 0).unwrap().st_ino,
fstat(*f1).unwrap().st_ino
);
}
#[test]
fn splice_() {
let (mut r, mut w) = pipe().unwrap();
let mut fd = memfd_create("", 0).unwrap();
w.write_all(b"abcdefghi").unwrap();
splice(*r, None, *fd, Some(&mut 3), 3, 0).unwrap();
drop(w);
let res = r.read_to_new_ustring().unwrap();
assert_eq!(&res, "defghi");
let res = fd.read_to_new_ustring().unwrap();
assert_eq!(&res, "\0\0\0abc");
}
#[test]
fn tee_() {
let (mut r1, mut w1) = pipe().unwrap();
let (mut r2, w2) = pipe().unwrap();
w1.write_all(b"abcdefghi").unwrap();
tee(*r1, *w2, 3, 0).unwrap();
drop(w1);
drop(w2);
let res = r1.read_to_new_ustring().unwrap();
assert_eq!(&res, "abcdefghi");
let res = r2.read_to_new_ustring().unwrap();
assert_eq!(&res, "abc");
}
#[test]
fn inotify() {
let e = inotify_init1(0).unwrap();
assert_ne!(fcntl_getfd(*e).unwrap() & c::FD_CLOEXEC, c::FD_CLOEXEC);
let e = inotify_init1(c::IN_CLOEXEC | c::IN_NONBLOCK).unwrap();
assert_eq!(fcntl_getfd(*e).unwrap() & c::FD_CLOEXEC, c::FD_CLOEXEC);
let tmp = Tempdir::new();
let mut buf = [0; 128];
assert_eq!(
inotify_read(*e, &mut buf[..]).err().unwrap(),
Errno(c::EAGAIN)
);
let w = inotify_add_watch(*e, tmp.bstr(), c::IN_CREATE).unwrap();
assert_eq!(
inotify_read(*e, &mut buf[..]).err().unwrap(),
Errno(c::EAGAIN)
);
let path1 = &*format!("{}/a", tmp);
let path2 = &*format!("{}/b", tmp);
let path3 = &*format!("{}/c", tmp);
open(path1, c::O_CREAT | c::O_RDONLY, 0).unwrap();
open(path2, c::O_CREAT | c::O_RDONLY, 0).unwrap();
let mut names = HashSet::new();
names.insert(ustr!("a"));
names.insert(ustr!("b"));
for ev in inotify_read(*e, &mut buf[..]).unwrap() {
assert_eq!(ev.mask, c::IN_CREATE);
assert_eq!(ev.wd, w);
assert!(names.remove(ev.name().as_ustr()));
}
assert!(names.is_empty());
inotify_rm_watch(*e, w).unwrap();
let events: Vec<InotifyEvent> = inotify_read(*e, &mut buf[..])
.unwrap()
.into_iter()
.collect();
assert_eq!(events.len(), 1);
assert_eq!(events[0].mask, c::IN_IGNORED);
assert_eq!(events[0].wd, w);
open(path3, c::O_CREAT | c::O_RDONLY, 0).unwrap();
assert_eq!(
inotify_read(*e, &mut buf[..]).err().unwrap(),
Errno(c::EAGAIN)
);
}
#[test]
fn sendfile_() {
let mut m = memfd_create("", 0).unwrap();
let (mut r2, w2) = pipe().unwrap();
m.write_all(b"hello world").unwrap();
sendfile(*w2, *m, Some(&mut 3), 5).unwrap();
close(w2).unwrap();
assert_eq!(&r2.read_to_new_ustring().unwrap(), "lo wo");
}
#[test]
fn makedev_() {
assert_eq!(makedev(22222, 333333), 87962295914005);
assert_eq!(major(makedev(22222, 333333)), 22222);
assert_eq!(minor(makedev(22222, 333333)), 333333);
}
#[test_if(linux_5_6)]
fn openat2_() {
let tmp = Tempdir::new();
let dir = &*format!("{}/a", tmp);
mkdir(dir, 0o777).unwrap();
let dfd = open(dir, c::O_PATH, 0).unwrap();
{
let mut how: open_how = pod_zeroed();
how.mode = 0o777;
how.flags = (c::O_CREAT | c::O_WRONLY | c::O_CLOEXEC) as u64;
let mut file = openat2(*dfd, "../b", &how).unwrap();
assert_eq!(fcntl_getfd(*file).unwrap(), c::FD_CLOEXEC);
write!(file, "abc").unwrap();
}
{
let mut how: open_how = pod_zeroed();
how.flags = c::O_RDONLY as u64;
let file = openat2(*dfd, "../b", &how).unwrap();
assert_eq!(fcntl_getfd(*file).unwrap(), 0);
assert_eq!(read_file(file.into()), "abc");
}
{
let mut how: open_how = pod_zeroed();
how.flags = c::O_RDONLY as u64;
how.resolve = c::RESOLVE_IN_ROOT;
let err = openat2(*dfd, "../b", &how).unwrap_err();
assert_eq!(err.0, c::ENOENT);
}
}