unplugged-system/external/crosvm/devices/tests/passthroughfs/unix.rs

141 lines
4.0 KiB
Rust

// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::ffi::CString;
use std::fs::File;
use std::io;
use std::path::Path;
use devices::virtio::fs::passthrough::Config;
use devices::virtio::fs::passthrough::Inode;
use devices::virtio::fs::passthrough::PassthroughFs;
use fuse::filesystem::Context;
use fuse::filesystem::FileSystem;
use fuse::filesystem::FsOptions;
use tempfile::TempDir;
/// Creates the given directories and files under `temp_dir`.
fn create_test_data(temp_dir: &TempDir, dirs: &[&str], files: &[&str]) {
let path = temp_dir.path();
for d in dirs {
std::fs::create_dir_all(path.join(d)).unwrap();
}
for f in files {
File::create(path.join(f)).unwrap();
}
}
/// Looks up the given `path` in `fs`.
fn lookup(fs: &PassthroughFs, path: &Path) -> io::Result<Inode> {
let mut inode = 1;
let ctx = Context {
uid: 0,
gid: 0,
pid: 0,
};
for name in path.iter() {
let name = CString::new(name.to_str().unwrap()).unwrap();
let ent = match fs.lookup(ctx, inode, &name) {
Ok(ent) => ent,
Err(e) => {
return Err(e);
}
};
inode = ent.inode;
}
Ok(inode)
}
fn test_lookup() {
let temp_dir = TempDir::new().unwrap();
create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/b.txt"]);
let cfg = Default::default();
let fs = PassthroughFs::new("tag", cfg).unwrap();
let capable = FsOptions::empty();
fs.init(capable).unwrap();
assert!(lookup(&fs, &temp_dir.path().join("a.txt")).is_ok());
assert!(lookup(&fs, &temp_dir.path().join("dir")).is_ok());
assert!(lookup(&fs, &temp_dir.path().join("dir/b.txt")).is_ok());
assert_eq!(
lookup(&fs, &temp_dir.path().join("nonexistent-file"))
.expect_err("file must not exist")
.kind(),
io::ErrorKind::NotFound
);
// "A.txt" is different from "a.txt".
assert_eq!(
lookup(&fs, &temp_dir.path().join("A.txt"))
.expect_err("file must not exist")
.kind(),
io::ErrorKind::NotFound
);
}
fn test_lookup_ascii_casefold() {
let temp_dir = TempDir::new().unwrap();
create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/b.txt"]);
let cfg = Config {
ascii_casefold: true,
..Default::default()
};
let fs = PassthroughFs::new("tag", cfg).unwrap();
let capable = FsOptions::empty();
fs.init(capable).unwrap();
// Ensure that "A.txt" is equated with "a.txt".
let a_inode = lookup(&fs, &temp_dir.path().join("a.txt")).expect("a.txt must be found");
assert_eq!(
lookup(&fs, &temp_dir.path().join("A.txt")).expect("A.txt must exist"),
a_inode
);
let dir_inode = lookup(&fs, &temp_dir.path().join("dir")).expect("dir must be found");
assert_eq!(
lookup(&fs, &temp_dir.path().join("DiR")).expect("DiR must exist"),
dir_inode
);
let b_inode = lookup(&fs, &temp_dir.path().join("dir/b.txt")).expect("dir/b.txt must be found");
assert_eq!(
lookup(&fs, &temp_dir.path().join("dIr/B.TxT")).expect("dIr/B.TxT must exist"),
b_inode
);
assert_eq!(
lookup(&fs, &temp_dir.path().join("nonexistent-file"))
.expect_err("file must not exist")
.kind(),
io::ErrorKind::NotFound
);
}
pub fn main() {
// Use `libtest_mimic` to force to run each test in single thread, as PassthroughFS can execute
// process-wide fs operations such as fchdir.
let args = libtest_mimic::Arguments {
test_threads: Some(1),
..libtest_mimic::Arguments::from_args()
};
let tests = vec![
libtest_mimic::Trial::test("test_lookup", move || {
test_lookup();
Ok(())
}),
libtest_mimic::Trial::test("test_lookup_ascii_casefold", move || {
test_lookup_ascii_casefold();
Ok(())
}),
];
libtest_mimic::run(&args, tests).exit();
}