Skip to content

Commit 7761222

Browse files
authored
ops: add fs::symlink function (#308)
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.
1 parent bf9906d commit 7761222

File tree

5 files changed

+88
-0
lines changed

5 files changed

+88
-0
lines changed

src/fs/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@ mod statx;
2020
pub use statx::is_dir_regfile;
2121
pub use statx::statx;
2222
pub use statx::StatxBuilder;
23+
24+
mod symlink;
25+
pub use symlink::symlink;

src/fs/symlink.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use crate::runtime::driver::op::Op;
2+
use std::io;
3+
use std::path::Path;
4+
5+
/// Creates a new symbolic link on the filesystem.
6+
/// The dst path will be a symbolic link pointing to the src path.
7+
/// This is an async version of std::os::unix::fs::symlink.
8+
pub async fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
9+
Op::symlink(src, dst)?.await
10+
}

src/io/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub(crate) use socket::Socket;
4343

4444
mod statx;
4545

46+
mod symlink;
47+
4648
mod unlink_at;
4749

4850
mod util;

src/io/symlink.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use crate::runtime::driver::op::{Completable, CqeResult, Op};
2+
use crate::runtime::CONTEXT;
3+
4+
use super::util::cstr;
5+
6+
use std::ffi::CString;
7+
use std::io;
8+
use std::path::Path;
9+
10+
pub(crate) struct Symlink {
11+
pub(crate) _from: CString,
12+
pub(crate) _to: CString,
13+
}
14+
15+
impl Op<Symlink> {
16+
pub(crate) fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(
17+
from: P,
18+
to: Q,
19+
) -> io::Result<Op<Symlink>> {
20+
use io_uring::{opcode, types};
21+
22+
let _from = cstr(from.as_ref())?;
23+
let _to = cstr(to.as_ref())?;
24+
25+
CONTEXT.with(|x| {
26+
x.handle().expect("Not in a runtime context").submit_op(
27+
Symlink { _from, _to },
28+
|symlink| {
29+
let from_ref = symlink._from.as_c_str().as_ptr();
30+
let to_ref = symlink._to.as_c_str().as_ptr();
31+
32+
opcode::SymlinkAt::new(types::Fd(libc::AT_FDCWD), from_ref, to_ref).build()
33+
},
34+
)
35+
})
36+
}
37+
}
38+
39+
impl Completable for Symlink {
40+
type Output = io::Result<()>;
41+
42+
fn complete(self, cqe: CqeResult) -> Self::Output {
43+
cqe.result.map(|_| ())
44+
}
45+
}

tests/fs_symlink.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#[path = "../src/future.rs"]
2+
#[allow(warnings)]
3+
mod future;
4+
5+
use std::io::Write;
6+
use tokio_test::assert_ok;
7+
use tokio_uring::fs;
8+
9+
use tempfile::tempdir;
10+
use tempfile::NamedTempFile;
11+
12+
const TEST_PAYLOAD: &[u8] = b"I am data in the source file";
13+
14+
#[test]
15+
fn test_create_symlink() {
16+
tokio_uring::start(async {
17+
let mut src_file = NamedTempFile::new().unwrap();
18+
src_file.write_all(TEST_PAYLOAD).unwrap();
19+
20+
let dst_enclosing_dir = tempdir().unwrap();
21+
22+
assert_ok!(fs::symlink(src_file.path(), dst_enclosing_dir.path().join("abc")).await);
23+
24+
let content = std::fs::read(dst_enclosing_dir.path().join("abc")).unwrap();
25+
26+
assert_eq!(content, TEST_PAYLOAD);
27+
});
28+
}

0 commit comments

Comments
 (0)