From 4578a22297b55f2a663f58936d0d0b624b156239 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 20 Jul 2019 17:08:33 +0000 Subject: [PATCH] Tests --- src/bin/mount.rs | 16 ++++- src/lib.rs | 3 + src/mount/fuse.rs | 38 ++++++++-- src/mount/mod.rs | 32 ++------- src/mount/redox/mod.rs | 19 +++-- src/mount/redox/resource.rs | 2 +- src/tests.rs | 136 ++++++++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+), 44 deletions(-) create mode 100644 src/tests.rs diff --git a/src/bin/mount.rs b/src/bin/mount.rs index 128d2b6590..9ec4d961cd 100644 --- a/src/bin/mount.rs +++ b/src/bin/mount.rs @@ -56,6 +56,11 @@ fn pipe(pipes: &mut [i32; 2]) -> isize { unsafe { libc::pipe(pipes.as_mut_ptr()) as isize } } +#[cfg(not(target_os = "redox"))] +fn capability_mode() { + () +} + #[cfg(target_os = "redox")] fn fork() -> isize { unsafe { syscall::Error::mux(syscall::clone(0)) as isize } @@ -66,6 +71,11 @@ fn pipe(pipes: &mut [usize; 2]) -> isize { syscall::Error::mux(syscall::pipe2(pipes, 0)) as isize } +#[cfg(target_os = "redox")] +fn capability_mode() { + syscall::setrens(0, 0).expect("redoxfs: failed to enter null namespace"); +} + fn usage() { println!("redoxfs [--uuid] [disk or uuid] [mountpoint]"); } @@ -154,8 +164,10 @@ fn daemon(disk_id: &DiskId, mountpoint: &str, mut write: File) -> ! { }; if matches { - match mount(filesystem, &mountpoint, || { - println!("redoxfs: mounted filesystem on {} to {}", path, mountpoint); + match mount(filesystem, &mountpoint, |mounted_path| { + capability_mode(); + + println!("redoxfs: mounted filesystem on {} to {}", path, mounted_path.display()); let _ = write.write(&[0]); }) { Ok(()) => { diff --git a/src/lib.rs b/src/lib.rs index 75fc1112c8..bc9fba2594 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,3 +28,6 @@ mod filesystem; mod header; mod mount; mod node; + +#[cfg(test)] +mod tests; diff --git a/src/mount/fuse.rs b/src/mount/fuse.rs index fb665cc45e..9ea08a7720 100644 --- a/src/mount/fuse.rs +++ b/src/mount/fuse.rs @@ -20,14 +20,40 @@ const TTL: Timespec = Timespec { sec: 1, nsec: 0 }; // 1 second const NULL_TIME: Timespec = Timespec { sec: 0, nsec: 0 }; -pub fn mount, F: FnMut()>(filesystem: filesystem::FileSystem, mountpoint: P, mut callback: F, options: &[&OsStr]) -> io::Result<()> { - let mut session = Session::new(Fuse { - fs: filesystem - }, mountpoint.as_ref(), options)?; +pub fn mount(filesystem: filesystem::FileSystem, mountpoint: P, mut callback: F) + -> io::Result where + D: Disk, + P: AsRef, + F: FnMut(&Path) -> T +{ + let mountpoint = mountpoint.as_ref(); - callback(); + // One of the uses of this redoxfs fuse wrapper is to populate a filesystem + // while building the Redox OS kernel. This means that we need to write on + // a filesystem that belongs to `root`, which in turn means that we need to + // be `root`, thus that we need to allow `root` to have access. + let defer_permissions = [ + OsStr::new("-o"), + OsStr::new("defer_permissions"), + ]; - session.run() + let mut session = Session::new( + Fuse { + fs: filesystem + }, + mountpoint, + if cfg!(target_os = "macos") { + &defer_permissions + } else { + &[] + } + )?; + + let res = callback(&mountpoint); + + session.run()?; + + Ok(res) } pub struct Fuse { diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 22669ee3cb..eff489f3fa 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -1,35 +1,11 @@ -use std::io; -use std::path::Path; - -use disk::Disk; -use filesystem::FileSystem; - #[cfg(not(target_os = "redox"))] mod fuse; +#[cfg(not(target_os = "redox"))] +pub use self::fuse::mount; + #[cfg(target_os = "redox")] mod redox; -#[cfg(target_os = "macos")] -pub fn mount, F: FnMut()>(filesystem: FileSystem, mountpoint: P, callback: F) -> io::Result<()> { - use std::ffi::OsStr; - - fuse::mount(filesystem, mountpoint, callback, &[ - // One of the uses of this redoxfs fuse wrapper is to populate a filesystem - // while building the Redox OS kernel. This means that we need to write on - // a filesystem that belongs to `root`, which in turn means that we need to - // be `root`, thus that we need to allow `root` to have access. - OsStr::new("-o"), - OsStr::new("defer_permissions"), - ]) -} - -#[cfg(all(not(target_os = "macos"), not(target_os = "redox")))] -pub fn mount, F: FnMut()>(filesystem: FileSystem, mountpoint: P, callback: F) -> io::Result<()> { - fuse::mount(filesystem, mountpoint, callback, &[]) -} - #[cfg(target_os = "redox")] -pub fn mount, F: FnMut()>(filesystem: FileSystem, mountpoint: P, callback: F) -> io::Result<()> { - redox::mount(filesystem, mountpoint, callback) -} +pub use self::redox::mount; diff --git a/src/mount/redox/mod.rs b/src/mount/redox/mod.rs index 8d5655b1fa..a7329cb8ef 100644 --- a/src/mount/redox/mod.rs +++ b/src/mount/redox/mod.rs @@ -1,4 +1,3 @@ -use syscall; use syscall::{Packet, Scheme}; use std::fs::File; use std::io::{self, Read, Write}; @@ -14,22 +13,28 @@ use self::scheme::FileScheme; pub mod resource; pub mod scheme; -pub fn mount, F: FnMut()>(filesystem: FileSystem, mountpoint: P, mut callback: F) -> io::Result<()> { +pub fn mount(filesystem: FileSystem, mountpoint: P, mut callback: F) + -> io::Result where + D: Disk, + P: AsRef, + F: FnMut(&Path) -> T +{ let mountpoint = mountpoint.as_ref(); - let mut socket = File::create(format!(":{}", mountpoint.display()))?; + let socket_path = format!(":{}", mountpoint.display()); + let mut socket = File::create(&socket_path)?; - callback(); - - syscall::setrens(0, 0).expect("redoxfs: failed to enter null namespace"); + let mounted_path = format!("{}:", mountpoint.display()); + let res = callback(Path::new(&mounted_path)); let scheme = FileScheme::new(format!("{}", mountpoint.display()), filesystem); loop { if IS_UMT.load(Ordering::SeqCst) > 0 { - break Ok(()); + break Ok(res); } let mut packet = Packet::default(); match socket.read(&mut packet) { + Ok(0) => break Ok(res), Ok(_ok) => (), Err(err) => if err.kind() == io::ErrorKind::Interrupted { continue; diff --git a/src/mount/redox/resource.rs b/src/mount/redox/resource.rs index b5e47bdc08..db17098b8d 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -221,7 +221,7 @@ impl Fmap { block, offset: map.offset, flags: map.flags, - data: &mut buf[..count], + data: buf, }) } diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000000..62d06e8e91 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,136 @@ +use std::{fs, sync, thread, time}; +use std::ops::DerefMut; +use std::path::Path; +use std::process::Command; + +use crate::{DiskSparse, FileSystem}; + +fn with_redoxfs(callback: F) + -> T where + T: Send + Sync + 'static, + F: FnMut(&Path) -> T + Send + Sync + 'static +{ + let disk_path = "image.bin"; + let mount_path = "image"; + + let res = { + let disk = DiskSparse::create(dbg!(disk_path)).unwrap(); + + if cfg!(not(target_os = "redox")) { + if ! Path::new(mount_path).exists() { + dbg!(fs::create_dir(dbg!(mount_path))).unwrap(); + } + } + + let ctime = dbg!(time::SystemTime::now().duration_since(time::UNIX_EPOCH)).unwrap(); + let fs = FileSystem::create_reserved(disk, &[], ctime.as_secs(), ctime.subsec_nanos()).unwrap(); + + let callback_mutex = sync::Arc::new(sync::Mutex::new(callback)); + let join_handle = crate::mount(fs, dbg!(mount_path), move |real_path| { + let callback_mutex = callback_mutex.clone(); + let real_path = real_path.to_owned(); + thread::spawn(move || { + let res = { + let mut callback_guard = callback_mutex.lock().unwrap(); + let callback = callback_guard.deref_mut(); + callback(&real_path) + }; + + if cfg!(target_os = "redox") { + dbg!(fs::remove_file(dbg!(format!(":{}", mount_path)))).unwrap(); + } else { + let status_res = if cfg!(target_os = "linux") { + Command::new("fusermount") + .arg("-u") + .arg(mount_path) + .status() + } else { + Command::new("umount") + .arg(mount_path) + .status() + }; + + let status = dbg!(status_res).unwrap(); + if ! status.success() { + panic!("umount failed"); + } + } + + res + }) + }).unwrap(); + + join_handle.join().unwrap() + }; + + dbg!(fs::remove_file(dbg!(disk_path))).unwrap(); + + if cfg!(not(target_os = "redox")) { + dbg!(fs::remove_dir(dbg!(mount_path))).unwrap(); + } + + res +} + +#[test] +fn simple() { + with_redoxfs(|path| { + dbg!(fs::create_dir(&path.join("test"))).unwrap(); + }) +} + +#[cfg(target_os = "redox")] +#[test] +fn mmap() { + use std::os::unix::ffi::OsStrExt; + use syscall; + + //TODO + with_redoxfs(|path| { + use std::slice; + + let path = dbg!(path.join("test")); + + let mmap_inner = |write: bool| { + let fd = dbg!( + syscall::open( + path.as_os_str().as_bytes(), + syscall::O_CREAT | syscall::O_RDWR | syscall::O_CLOEXEC + ) + ).unwrap(); + + let map = unsafe { + slice::from_raw_parts_mut( + dbg!( + syscall::fmap(fd, &syscall::Map { + offset: 0, + size: 128, + flags: syscall::PROT_READ | syscall::PROT_WRITE + }) + ).unwrap() as *mut u8, + 128 + ) + }; + + // Maps should be available after closing + assert_eq!(dbg!(syscall::close(fd)), Ok(0)); + + for i in 0..128 { + if write { + map[i as usize] = i; + } + assert_eq!(map[i as usize], i); + } + + //TODO: add msync + unsafe { + assert_eq!(dbg!( + syscall::funmap(map.as_mut_ptr() as usize) + ), Ok(0)); + } + }; + + mmap_inner(true); + mmap_inner(false); + }) +}