use std::io;
use std::path::Path;
use tokio_uring::fs;
fn tests() -> std::slice::Iter<'static, Expected<'static>> {
[
Expected::Fail(Op::create_dir("/no-good")),
Expected::Fail(Op::create_dir("/no-good/lots/more")),
Expected::Fail(Op::create_dir_all("/no-good")),
Expected::Fail(Op::create_dir_all("/no-good/lots/more")),
Expected::Fail(Op::DirBuilder("/no-good")),
Expected::Fail(Op::DirBuilder2("/no-good/lots/more", false, 0o777)),
Expected::Fail(Op::DirBuilder2("/no-good/lots/more", true, 0o777)),
Expected::Pass(Op::create_dir("/tmp/test-good")),
Expected::Pass(Op::statx("/tmp/test-good")),
Expected::Pass(Op::StatxBuilder("/tmp/test-good")),
Expected::Pass(Op::StatxBuilder2("/tmp", "test-good")),
Expected::Pass(Op::StatxBuilder2("/tmp", "./test-good")),
Expected::Pass(Op::StatxBuilder2("/tmp/", "./test-good")),
Expected::Pass(Op::StatxBuilder2("/etc/", "/tmp/test-good")),
Expected::Pass(Op::is_dir("/tmp/test-good")),
Expected::Fail(Op::is_regfile("/tmp/test-good")),
Expected::Pass(Op::create_dir("/tmp/test-good/x1")),
Expected::Fail(Op::create_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good/x1")),
Expected::Fail(Op::remove_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good")),
Expected::Pass(Op::create_dir_all("/tmp/test-good/lots/lots/more")),
Expected::Pass(Op::create_dir_all("/tmp/test-good/lots/lots/more")),
Expected::Pass(Op::remove_dir("/tmp/test-good/lots/lots/more")),
Expected::Pass(Op::remove_dir("/tmp/test-good/lots/lots")),
Expected::Pass(Op::remove_dir("/tmp/test-good/lots")),
Expected::Pass(Op::remove_dir("/tmp/test-good")),
Expected::Fail(Op::statx("/tmp/test-good")),
Expected::Fail(Op::StatxBuilder("/tmp/test-good")),
Expected::Pass(Op::DirBuilder2("/tmp/test-good", true, 0)),
Expected::Pass(Op::matches_mode("/tmp/test-good", 0)),
Expected::Fail(Op::create_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good")),
Expected::Pass(Op::DirBuilder2("/tmp/test-good", true, 0o700)),
Expected::Pass(Op::matches_mode("/tmp/test-good", 0o700)),
Expected::Pass(Op::create_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good")),
Expected::Pass(Op::DirBuilder2("/tmp/test-good", false, 0)),
Expected::Fail(Op::create_dir("/tmp/test-good/x1")),
Expected::Pass(Op::remove_dir("/tmp/test-good")),
Expected::Pass(Op::touch_file("/tmp/test-good-file")),
Expected::Pass(Op::is_regfile("/tmp/test-good-file")),
Expected::Fail(Op::is_dir("/tmp/test-good-file")),
Expected::Pass(Op::remove_file("/tmp/test-good-file")),
Expected::Fail(Op::is_regfile("/tmp/test-good-file")),
Expected::Fail(Op::is_dir("/tmp/test-good-file")),
]
.iter()
}
type OpPath<'a> = &'a str;
#[allow(non_camel_case_types)]
#[allow(dead_code)]
#[derive(Debug)]
enum Op<'a> {
statx(OpPath<'a>),
StatxBuilder(OpPath<'a>),
StatxBuilder2(OpPath<'a>, OpPath<'a>),
matches_mode(OpPath<'a>, u16),
is_regfile(OpPath<'a>),
is_dir(OpPath<'a>),
touch_file(OpPath<'a>),
create_dir(OpPath<'a>),
create_dir_all(OpPath<'a>),
DirBuilder(OpPath<'a>),
DirBuilder2(OpPath<'a>, bool, u32),
remove_file(OpPath<'a>),
remove_dir(OpPath<'a>),
}
#[derive(Debug)]
enum Expected<'a> {
Pass(Op<'a>),
Fail(Op<'a>),
}
async fn main1() -> io::Result<()> {
let (mut as_expected, mut unexpected) = (0, 0);
for test in tests() {
let (expect_to_pass, op) = match test {
Expected::Pass(op) => (true, op),
Expected::Fail(op) => (false, op),
};
let res = match op {
Op::statx(path) => statx(path).await,
Op::StatxBuilder(path) => statx_builder(path).await,
Op::StatxBuilder2(path, rel_path) => statx_builder2(path, rel_path).await,
Op::matches_mode(path, mode) => matches_mode(path, *mode).await,
Op::is_regfile(path) => is_regfile(path).await,
Op::is_dir(path) => is_dir(path).await,
Op::touch_file(path) => touch_file(path).await,
Op::create_dir(path) => fs::create_dir(path).await,
Op::create_dir_all(path) => fs::create_dir_all(path).await,
Op::DirBuilder(path) => fs::DirBuilder::new().create(path).await,
Op::DirBuilder2(path, recursive, mode) => {
fs::DirBuilder::new()
.recursive(*recursive)
.mode(*mode)
.create(path)
.await
}
Op::remove_file(path) => fs::remove_file(path).await,
Op::remove_dir(path) => fs::remove_dir(path).await,
};
let verbose = true;
match res {
Ok(_) => {
if expect_to_pass {
as_expected += 1;
if verbose {
println!("Success: {op:?} passed.");
}
} else {
unexpected += 1;
println!("Failure: {op:?} expected to fail but passed.");
}
}
Err(e) => {
if expect_to_pass {
unexpected += 1;
println!("Failure: {op:?} expected to pass but failed with error \"{e}\".");
} else {
as_expected += 1;
if verbose {
println!("Success: {op:?} expected to fail and did with error \"{e}\".");
}
}
}
}
}
println!("{as_expected} as_expected, {unexpected} unexpected");
if unexpected == 0 {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("{unexpected} unexpected result(s)"),
))
}
}
async fn statx<P: AsRef<Path>>(path: P) -> io::Result<()> {
let _statx = tokio_uring::fs::statx(path).await?;
Ok(())
}
async fn statx_builder<P: AsRef<Path>>(path: P) -> io::Result<()> {
let _statx = tokio_uring::fs::StatxBuilder::new()
.pathname(path)?
.statx()
.await?;
Ok(())
}
async fn statx_builder2<P: AsRef<Path>>(dir_path: P, rel_path: P) -> io::Result<()> {
let f = tokio_uring::fs::File::open(dir_path).await?;
let res = f.statx_builder().pathname(rel_path)?.statx().await;
f.close().await?;
res.map(|_| ())
}
async fn matches_mode<P: AsRef<Path>>(path: P, want_mode: u16) -> io::Result<()> {
let statx = tokio_uring::fs::StatxBuilder::new()
.mask(libc::STATX_MODE)
.pathname(path)?
.statx()
.await?;
let got_mode = statx.stx_mode & 0o7777;
if want_mode == got_mode {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("want mode {want_mode:#o}, got mode {got_mode:#o}"),
))
}
}
async fn touch_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let file = tokio_uring::fs::OpenOptions::new()
.append(true)
.create(true)
.open(path)
.await?;
file.close().await
}
async fn is_regfile<P: AsRef<Path>>(path: P) -> io::Result<()> {
let (_is_dir, is_regfile) = tokio_uring::fs::is_dir_regfile(path).await;
if is_regfile {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"not regular file",
))
}
}
async fn is_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let (is_dir, _is_regfile) = tokio_uring::fs::is_dir_regfile(path).await;
if is_dir {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"not directory",
))
}
}
fn main() {
tokio_uring::start(async {
if let Err(e) = main1().await {
println!("error: {}", e);
}
});
}