1use std::{future::Future, io, mem::ManuallyDrop, panic::resume_unwind, path::Path};
2
3use compio_buf::{BufResult, IntoInner, IoBuf, IoBufMut};
4#[cfg(unix)]
5use compio_driver::op::FileStat;
6use compio_driver::{
7 ToSharedFd, impl_raw_fd,
8 op::{BufResultExt, CloseFile, ReadAt, Sync, WriteAt},
9};
10use compio_io::{AsyncReadAt, AsyncWriteAt};
11use compio_runtime::Attacher;
12#[cfg(all(unix, not(solarish)))]
13use {
14 compio_buf::{IoVectoredBuf, IoVectoredBufMut},
15 compio_driver::op::{ReadVectoredAt, WriteVectoredAt},
16};
17
18use crate::{Metadata, OpenOptions, Permissions};
19
20#[derive(Debug, Clone)]
27pub struct File {
28 inner: Attacher<std::fs::File>,
29}
30
31impl File {
32 pub(crate) fn from_std(file: std::fs::File) -> io::Result<Self> {
33 Ok(Self {
34 inner: Attacher::new(file)?,
35 })
36 }
37
38 pub async fn open(path: impl AsRef<Path>) -> io::Result<Self> {
42 OpenOptions::new().read(true).open(path).await
43 }
44
45 pub async fn create(path: impl AsRef<Path>) -> io::Result<Self> {
52 OpenOptions::new()
53 .create(true)
54 .write(true)
55 .truncate(true)
56 .open(path)
57 .await
58 }
59
60 pub fn close(self) -> impl Future<Output = io::Result<()>> {
63 let this = ManuallyDrop::new(self);
67 async move {
68 let fd = ManuallyDrop::into_inner(this)
69 .inner
70 .into_inner()
71 .take()
72 .await;
73 if let Some(fd) = fd {
74 let op = CloseFile::new(fd.into());
75 compio_runtime::submit(op).await.0?;
76 }
77 Ok(())
78 }
79 }
80
81 #[cfg(windows)]
83 pub async fn metadata(&self) -> io::Result<Metadata> {
84 let file = self.inner.clone();
85 compio_runtime::spawn_blocking(move || file.metadata().map(Metadata::from_std))
86 .await
87 .unwrap_or_else(|e| resume_unwind(e))
88 }
89
90 #[cfg(unix)]
92 pub async fn metadata(&self) -> io::Result<Metadata> {
93 let op = FileStat::new(self.to_shared_fd());
94 let BufResult(res, op) = compio_runtime::submit(op).await;
95 res.map(|_| Metadata::from_stat(op.into_inner()))
96 }
97
98 #[cfg(windows)]
100 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
101 let file = self.inner.clone();
102 compio_runtime::spawn_blocking(move || file.set_permissions(perm.0))
103 .await
104 .unwrap_or_else(|e| resume_unwind(e))
105 }
106
107 #[cfg(unix)]
109 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
110 use std::os::unix::fs::PermissionsExt;
111
112 use compio_driver::{AsRawFd, syscall};
113
114 let file = self.inner.clone();
115 compio_runtime::spawn_blocking(move || {
116 syscall!(libc::fchmod(file.as_raw_fd(), perm.mode() as libc::mode_t))?;
117 Ok(())
118 })
119 .await
120 .unwrap_or_else(|e| resume_unwind(e))
121 }
122
123 async fn sync_impl(&self, datasync: bool) -> io::Result<()> {
124 let op = Sync::new(self.to_shared_fd(), datasync);
125 compio_runtime::submit(op).await.0?;
126 Ok(())
127 }
128
129 pub async fn sync_all(&self) -> io::Result<()> {
134 self.sync_impl(false).await
135 }
136
137 pub async fn sync_data(&self) -> io::Result<()> {
149 self.sync_impl(true).await
150 }
151}
152
153impl AsyncReadAt for File {
154 async fn read_at<T: IoBufMut>(&self, buffer: T, pos: u64) -> BufResult<usize, T> {
155 let fd = self.inner.to_shared_fd();
156 let op = ReadAt::new(fd, pos, buffer);
157 compio_runtime::submit(op).await.into_inner().map_advanced()
158 }
159
160 #[cfg(all(unix, not(solarish)))]
161 async fn read_vectored_at<T: IoVectoredBufMut>(
162 &self,
163 buffer: T,
164 pos: u64,
165 ) -> BufResult<usize, T> {
166 let fd = self.inner.to_shared_fd();
167 let op = ReadVectoredAt::new(fd, pos, buffer);
168 compio_runtime::submit(op).await.into_inner().map_advanced()
169 }
170}
171
172impl AsyncWriteAt for File {
173 #[inline]
174 async fn write_at<T: IoBuf>(&mut self, buf: T, pos: u64) -> BufResult<usize, T> {
175 (&*self).write_at(buf, pos).await
176 }
177
178 #[cfg(all(unix, not(solarish)))]
179 #[inline]
180 async fn write_vectored_at<T: IoVectoredBuf>(
181 &mut self,
182 buf: T,
183 pos: u64,
184 ) -> BufResult<usize, T> {
185 (&*self).write_vectored_at(buf, pos).await
186 }
187}
188
189impl AsyncWriteAt for &File {
190 async fn write_at<T: IoBuf>(&mut self, buffer: T, pos: u64) -> BufResult<usize, T> {
191 let fd = self.inner.to_shared_fd();
192 let op = WriteAt::new(fd, pos, buffer);
193 compio_runtime::submit(op).await.into_inner()
194 }
195
196 #[cfg(all(unix, not(solarish)))]
197 async fn write_vectored_at<T: IoVectoredBuf>(
198 &mut self,
199 buffer: T,
200 pos: u64,
201 ) -> BufResult<usize, T> {
202 let fd = self.inner.to_shared_fd();
203 let op = WriteVectoredAt::new(fd, pos, buffer);
204 compio_runtime::submit(op).await.into_inner()
205 }
206}
207
208impl_raw_fd!(File, std::fs::File, inner, file);