1use crate::{fs::asyncify, util::as_ref::OwnedBuf};
2
3use std::{io, path::Path};
4
5pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
27 let path = path.as_ref();
28 let contents = crate::util::as_ref::upgrade(contents);
29
30 #[cfg(all(
31 tokio_unstable,
32 feature = "io-uring",
33 feature = "rt",
34 feature = "fs",
35 target_os = "linux"
36 ))]
37 {
38 let handle = crate::runtime::Handle::current();
39 let driver_handle = handle.inner.driver().io();
40 if driver_handle
41 .check_and_init(io_uring::opcode::Write::CODE)
42 .await?
43 {
44 return write_uring(path, contents).await;
45 }
46 }
47
48 write_spawn_blocking(path, contents).await
49}
50
51#[cfg(all(
52 tokio_unstable,
53 feature = "io-uring",
54 feature = "rt",
55 feature = "fs",
56 target_os = "linux"
57))]
58async fn write_uring(path: &Path, mut buf: OwnedBuf) -> io::Result<()> {
59 use crate::{fs::OpenOptions, runtime::driver::op::Op};
60 use std::os::fd::OwnedFd;
61
62 let file = OpenOptions::new()
63 .write(true)
64 .create(true)
65 .truncate(true)
66 .open(path)
67 .await?;
68
69 let mut fd: OwnedFd = file
70 .try_into_std()
71 .expect("unexpected in-flight operation detected")
72 .into();
73
74 let total: usize = buf.as_ref().len();
75 let mut buf_offset: usize = 0;
76 let mut file_offset: u64 = 0;
77 while buf_offset < total {
78 let (res, _buf, _fd) = Op::write_at(fd, buf, buf_offset, file_offset)?.await;
79
80 let n = match res {
81 Ok(0) => return Err(io::ErrorKind::WriteZero.into()),
82 Ok(n) => n,
83 Err(e) if e.kind() == io::ErrorKind::Interrupted => 0,
84 Err(e) => return Err(e),
85 };
86
87 buf = _buf;
88 fd = _fd;
89 buf_offset += n as usize;
90 file_offset += n as u64;
91 }
92
93 Ok(())
94}
95
96async fn write_spawn_blocking(path: &Path, contents: OwnedBuf) -> io::Result<()> {
97 let path = path.to_owned();
98 asyncify(move || std::fs::write(path, contents)).await
99}