Skip to content

Commit

Permalink
Add fs::symlink (#300)
Browse files Browse the repository at this point in the history
* chore: add fs::symlink

* chore: add fs::symlink

* remove println

* detect uring add symlinkat

* rename symlink structure field

* assert file is symlink

* cargo fmt
  • Loading branch information
misssonder authored Sep 15, 2024
1 parent c3cb780 commit d8855e9
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 0 deletions.
2 changes: 2 additions & 0 deletions monoio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ mkdirat = []
unlinkat = []
# renameat op(requires kernel 5.11+)
renameat = []
# symlinkat op(requires kernel 5.15+)
symlinkat = []
# enable `async main` macros support
macros = ["monoio-macros"]
# allow waker to be sent across threads
Expand Down
3 changes: 3 additions & 0 deletions monoio/src/driver/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ mod unlink;
#[cfg(all(unix, feature = "renameat"))]
mod rename;

#[cfg(all(unix, feature = "symlinkat"))]
mod symlink;

#[cfg(all(target_os = "linux", feature = "splice"))]
mod splice;

Expand Down
43 changes: 43 additions & 0 deletions monoio/src/driver/op/symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::{ffi::CString, io, path::Path};

use super::{Op, OpAble};
use crate::driver::util::cstr;

pub(crate) struct Symlink {
pub(crate) from: CString,
pub(crate) to: CString,
}
impl Op<Symlink> {
pub(crate) fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(
from: P,
to: Q,
) -> io::Result<Op<Symlink>> {
let from = cstr(from.as_ref())?;
let to = cstr(to.as_ref())?;
Op::submit_with(Symlink { from, to })
}
}

impl OpAble for Symlink {
#[cfg(all(target_os = "linux", feature = "iouring"))]
fn uring_op(&mut self) -> io_uring::squeue::Entry {
use io_uring::{opcode, types};
let from_ref = self.from.as_c_str().as_ptr();
let to_ref = self.to.as_c_str().as_ptr();
opcode::SymlinkAt::new(types::Fd(libc::AT_FDCWD), from_ref, to_ref).build()
}

#[cfg(any(feature = "legacy", feature = "poll-io"))]
fn legacy_interest(&self) -> Option<(crate::driver::ready::Direction, usize)> {
None
}

#[cfg(any(feature = "legacy", feature = "poll-io"))]
fn legacy_call(&mut self) -> std::io::Result<u32> {
use crate::syscall_u32;
syscall_u32!(symlink(
self.from.as_c_str().as_ptr(),
self.to.as_c_str().as_ptr()
))
}
}
5 changes: 5 additions & 0 deletions monoio/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ mod create_dir;
#[cfg(all(unix, feature = "mkdirat"))]
pub use create_dir::*;

#[cfg(all(unix, feature = "symlinkat"))]
mod symlink;
#[cfg(all(unix, feature = "symlinkat"))]
pub use symlink::symlink;

mod open_options;
pub use open_options::OpenOptions;

Expand Down
11 changes: 11 additions & 0 deletions monoio/src/fs/symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::{io, path::Path};

use crate::driver::op::Op;

/// Creates a new symbolic link on the filesystem.
/// The dst path will be a symbolic link pointing to the src path.
/// This is an async version of std::os::unix::fs::symlink.
pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
Op::symlink(src, dst)?.await.meta.result?;
Ok(())
}
2 changes: 2 additions & 0 deletions monoio/src/utils/uring_detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ fn detect_uring_inner() -> bool {
RecvMsg::CODE,
#[cfg(feature = "splice")]
Splice::CODE,
#[cfg(feature = "symlinkat")]
SymlinkAt::CODE,
Timeout::CODE,
Write::CODE,
Writev::CODE,
Expand Down
28 changes: 28 additions & 0 deletions monoio/tests/fs_symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![cfg(all(unix, feature = "symlinkat"))]

use std::{io, path::PathBuf};

use monoio::fs::File;
use tempfile::tempdir;

const TEST_PAYLOAD: &[u8] = b"I am data in the source file";

async fn create_file(path: &PathBuf) -> io::Result<File> {
File::create(path).await
}

#[monoio::test_all]
async fn create_symlink() {
let tmpdir = tempdir().unwrap();
let src_file_path = tmpdir.path().join("src");
let dst_file_path = tmpdir.path().join("dst");
let src_file = create_file(&src_file_path).await.unwrap();
src_file.write_all_at(TEST_PAYLOAD, 0).await.0.unwrap();
monoio::fs::symlink(src_file_path.as_path(), dst_file_path.as_path())
.await
.unwrap();

let content = monoio::fs::read(dst_file_path).await.unwrap();
assert_eq!(content, TEST_PAYLOAD);
assert(dst_file_path.is_symlink());

Check failure on line 27 in monoio/tests/fs_symlink.rs

View workflow job for this annotation

GitHub Actions / Run cargo coverage

expected function, found macro `assert`
}

0 comments on commit d8855e9

Please sign in to comment.