Skip to content

Commit

Permalink
ops: add fs::symlink function (#308)
Browse files Browse the repository at this point in the history
This change adds the `symlink` function to tokio-uring, with the
identical signature and documentation as in tokio itself. I added one
unit test. I'm merrily doing blocking I/O inside the async block in the
unit test, which I _think_ should be fine because it's just a test.
  • Loading branch information
daniel-levin authored Aug 2, 2024
1 parent bf9906d commit 7761222
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@ mod statx;
pub use statx::is_dir_regfile;
pub use statx::statx;
pub use statx::StatxBuilder;

mod symlink;
pub use symlink::symlink;
10 changes: 10 additions & 0 deletions src/fs/symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::runtime::driver::op::Op;
use std::io;
use std::path::Path;

/// 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
}
2 changes: 2 additions & 0 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub(crate) use socket::Socket;

mod statx;

mod symlink;

mod unlink_at;

mod util;
Expand Down
45 changes: 45 additions & 0 deletions src/io/symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::runtime::driver::op::{Completable, CqeResult, Op};
use crate::runtime::CONTEXT;

use super::util::cstr;

use std::ffi::CString;
use std::io;
use std::path::Path;

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>> {
use io_uring::{opcode, types};

let _from = cstr(from.as_ref())?;
let _to = cstr(to.as_ref())?;

CONTEXT.with(|x| {
x.handle().expect("Not in a runtime context").submit_op(
Symlink { _from, _to },
|symlink| {
let from_ref = symlink._from.as_c_str().as_ptr();
let to_ref = symlink._to.as_c_str().as_ptr();

opcode::SymlinkAt::new(types::Fd(libc::AT_FDCWD), from_ref, to_ref).build()
},
)
})
}
}

impl Completable for Symlink {
type Output = io::Result<()>;

fn complete(self, cqe: CqeResult) -> Self::Output {
cqe.result.map(|_| ())
}
}
28 changes: 28 additions & 0 deletions tests/fs_symlink.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#[path = "../src/future.rs"]
#[allow(warnings)]
mod future;

use std::io::Write;
use tokio_test::assert_ok;
use tokio_uring::fs;

use tempfile::tempdir;
use tempfile::NamedTempFile;

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

#[test]
fn test_create_symlink() {
tokio_uring::start(async {
let mut src_file = NamedTempFile::new().unwrap();
src_file.write_all(TEST_PAYLOAD).unwrap();

let dst_enclosing_dir = tempdir().unwrap();

assert_ok!(fs::symlink(src_file.path(), dst_enclosing_dir.path().join("abc")).await);

let content = std::fs::read(dst_enclosing_dir.path().join("abc")).unwrap();

assert_eq!(content, TEST_PAYLOAD);
});
}

0 comments on commit 7761222

Please sign in to comment.