• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use std::fmt::{Debug, Formatter};
15 use std::fs::{File as SyncFile, Metadata, Permissions};
16 use std::future::Future;
17 use std::io;
18 use std::io::{Seek, SeekFrom};
19 use std::path::Path;
20 use std::pin::Pin;
21 use std::sync::Arc;
22 use std::task::{Context, Poll};
23 
24 use crate::fs::file_buf::FileBuf;
25 use crate::fs::{async_op, poll_ready};
26 use crate::futures::poll_fn;
27 use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
28 use crate::spawn::spawn_blocking;
29 use crate::sync::Mutex;
30 use crate::task::{JoinHandle, TaskBuilder};
31 
32 /// An asynchronous wrapping of [`std::fs::File`]. Provides async read/write
33 /// methods.
34 pub struct File {
35     file: Arc<SyncFile>,
36     inner: Mutex<FileInner>,
37     // controls how many bytes the buffer could reserve during read
38     // and how many bytes the buffer could extend per time during write
39     buf_size_limit: usize,
40 }
41 
42 struct FileInner {
43     state: FileState,
44     write_err: Option<io::ErrorKind>,
45     idx: u64,
46 }
47 
48 type RWJoinHandle = JoinHandle<(FileBuf, io::Result<()>)>;
49 
50 type SeekJoinHandle = JoinHandle<(FileBuf, io::Result<u64>)>;
51 
52 enum FileState {
53     Idle(Option<FileBuf>),
54     Reading(RWJoinHandle),
55     Writing(RWJoinHandle),
56     Seeking(SeekJoinHandle),
57 }
58 
59 enum FileOp {
60     Reading,
61     Writing,
62     Seeking,
63 }
64 
65 impl Future for FileState {
66     type Output = io::Result<u64>;
67 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>68     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
69         let state = self.get_mut();
70         match state {
71             FileState::Idle(_) => unreachable!(),
72             FileState::Reading(x) | FileState::Writing(x) => {
73                 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
74                 *state = FileState::Idle(Some(file_buf));
75                 // For read and write, we dont care about the output
76                 Poll::Ready(res.map(|_| 0_u64))
77             }
78             FileState::Seeking(x) => {
79                 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
80                 *state = FileState::Idle(Some(file_buf));
81                 Poll::Ready(res)
82             }
83         }
84     }
85 }
86 
87 impl FileState {
88     #[inline]
get_op(&self) -> FileOp89     fn get_op(&self) -> FileOp {
90         match self {
91             FileState::Idle(_) => unreachable!(),
92             FileState::Reading(_) => FileOp::Reading,
93             FileState::Writing(_) => FileOp::Writing,
94             FileState::Seeking(_) => FileOp::Seeking,
95         }
96     }
97 }
98 
99 const DEFAULT_BUF_LIMIT: usize = 2 * 1024 * 1024;
100 
101 impl Debug for File {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result102     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103         f.debug_tuple("YlongFile").field(&self.file).finish()
104     }
105 }
106 
107 impl File {
108     /// Creates a new [`File`] struct.
new(file: SyncFile) -> File109     pub fn new(file: SyncFile) -> File {
110         File {
111             file: Arc::new(file),
112             inner: Mutex::new(FileInner {
113                 state: FileState::Idle(Some(FileBuf::with_capacity(0))),
114                 write_err: None,
115                 idx: 0,
116             }),
117             buf_size_limit: DEFAULT_BUF_LIMIT,
118         }
119     }
120 
121     /// Attempts to open a file in read-only mode asynchronously.
122     ///
123     /// See the [`super::OpenOptions::open`] method for more details.
124     ///
125     /// # Errors
126     ///
127     /// This function will return an error if `path` does not already exist.
128     ///
129     /// # Examples
130     ///
131     /// ```no_run
132     /// use ylong_runtime::fs::File;
133     ///
134     /// async fn open() -> std::io::Result<()> {
135     ///     let mut f = File::open("foo.txt").await?;
136     ///     Ok(())
137     /// }
138     /// ```
open<P: AsRef<Path>>(path: P) -> io::Result<File>139     pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
140         let path = path.as_ref().to_owned();
141         let file = async_op(|| SyncFile::open(path)).await?;
142         Ok(File::new(file))
143     }
144 
145     /// Opens a file in write-only mode asynchronously.
146     ///
147     /// This function will create a file if it does not exist
148     /// and truncate it if it does.
149     ///
150     ///
151     /// # Examples
152     ///
153     /// ```no_run
154     /// use ylong_runtime::fs::File;
155     ///
156     /// async fn create() -> std::io::Result<()> {
157     ///     let mut f = File::create("foo.txt").await?;
158     ///     Ok(())
159     /// }
160     /// ```
create<P: AsRef<Path>>(path: P) -> io::Result<File>161     pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
162         let path = path.as_ref().to_owned();
163         let file = async_op(|| SyncFile::create(path)).await?;
164         Ok(File::new(file))
165     }
166 
167     /// Changes the permissions on the underlying file asynchronously.
168     ///
169     /// # Errors
170     /// This function will return an error if the user lacks permission change
171     /// attributes on the underlying file. It may also return an error in other
172     /// os-specific unspecified cases.
173     ///
174     /// # Examples
175     ///
176     /// ```no_run
177     /// use ylong_runtime::fs::File;
178     ///
179     /// async fn set_permissions() -> std::io::Result<()> {
180     ///     let file = File::open("foo.txt").await?;
181     ///     let mut perms = file.metadata().await?.permissions();
182     ///     perms.set_readonly(true);
183     ///     file.set_permissions(perms).await?;
184     ///     Ok(())
185     /// }
186     /// ```
187     ///
188     /// Note that this method alters the permissions of the underlying file,
189     /// even though it takes `&self` rather than `&mut self`.
set_permissions(&self, perm: Permissions) -> io::Result<()>190     pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
191         let file = self.file.clone();
192         async_op(move || file.set_permissions(perm)).await
193     }
194 
195     /// Attempts to sync all OS-internal metadata to disk asynchronously.
196     ///
197     /// This function will attempt to ensure that all in-memory data reaches the
198     /// filesystem before returning.
199     ///
200     /// This can be used to handle errors that would otherwise only be caught
201     /// when the `File` is closed. Dropping a file will ignore errors in
202     /// synchronizing this in-memory data.
203     ///
204     /// # Examples
205     ///
206     /// ```no_run
207     /// use ylong_runtime::fs::File;
208     /// use ylong_runtime::io::AsyncWriteExt;
209     ///
210     /// async fn sync_all() -> std::io::Result<()> {
211     ///     let mut f = File::create("foo.txt").await?;
212     ///     f.write_all(b"Hello, world!").await?;
213     ///
214     ///     f.sync_all().await?;
215     ///     Ok(())
216     /// }
217     /// ```
sync_all(&self) -> io::Result<()>218     pub async fn sync_all(&self) -> io::Result<()> {
219         let mut file = self.inner.lock().await;
220         file.flush().await;
221         let file = self.file.clone();
222         async_op(move || file.sync_all()).await
223     }
224 
225     /// This function is similar to [`File::sync_all`], except that it might not
226     /// synchronize file metadata to the filesystem.
227     ///
228     /// This is intended for use cases that must synchronize content, but don't
229     /// need the metadata on disk. The goal of this method is to reduce disk
230     /// operations.
231     ///
232     /// # Examples
233     ///
234     /// ```no_run
235     /// use ylong_runtime::fs::File;
236     /// use ylong_runtime::io::AsyncWriteExt;
237     ///
238     /// async fn sync_data() -> std::io::Result<()> {
239     ///     let mut f = File::create("foo.txt").await?;
240     ///     f.write_all(b"Hello, world!").await?;
241     ///
242     ///     f.sync_data().await?;
243     ///     Ok(())
244     /// }
245     /// ```
sync_data(&self) -> io::Result<()>246     pub async fn sync_data(&self) -> io::Result<()> {
247         let mut file = self.inner.lock().await;
248         file.flush().await;
249         let file = self.file.clone();
250         async_op(move || file.sync_data()).await
251     }
252 
253     /// Truncates or extends the underlying file, updating the size of this file
254     /// to become size. If the size is less than the current file's size,
255     /// then the file will be shrunk. If it is greater than the current file's
256     /// size, then the file will be extended to size and have all of the
257     /// intermediate data filled in with 0s. The file's cursor isn't
258     /// changed. In particular, if the cursor was at the end and the file is
259     /// shrunk using this operation, the cursor will now be past the end.
260     ///
261     /// # Errors
262     ///
263     /// This function will return an error if the file is not opened for
264     /// writing.
265     ///
266     /// # Example
267     ///
268     /// ```no_run
269     /// use ylong_runtime::fs::File;
270     ///
271     /// async fn set_len() -> std::io::Result<()> {
272     ///     let mut f = File::create("foo.txt").await?;
273     ///     f.set_len(10).await?;
274     ///
275     ///     Ok(())
276     /// }
277     /// ```
set_len(&self, size: u64) -> io::Result<()>278     pub async fn set_len(&self, size: u64) -> io::Result<()> {
279         let mut file = self.inner.lock().await;
280         file.flush().await;
281 
282         let mut buf = match file.state {
283             // after each take, buf will be set right back
284             FileState::Idle(ref mut buf) => buf.take().unwrap(),
285             _ => unreachable!(),
286         };
287 
288         let arc_file = self.file.clone();
289 
290         let (buf, res) = spawn_blocking(&TaskBuilder::new(), move || {
291             let res = if buf.remaining() == 0 {
292                 (&*arc_file)
293                     .seek(SeekFrom::Current(buf.drop_unread()))
294                     .and_then(|_| arc_file.set_len(size))
295             } else {
296                 arc_file.set_len(size)
297             }
298             .map(|_| 0);
299 
300             (buf, res)
301         })
302         .await?;
303 
304         file.state = FileState::Idle(Some(buf));
305 
306         res.map(|u| file.idx = u)
307     }
308 
309     /// Queries metadata about the underlying file asynchronously.
310     ///
311     /// # Examples
312     ///
313     /// ```no_run
314     /// use ylong_runtime::fs::File;
315     ///
316     /// async fn metadata() -> std::io::Result<()> {
317     ///     let mut f = File::open("foo.txt").await?;
318     ///     let metadata = f.metadata().await?;
319     ///     Ok(())
320     /// }
321     /// ```
metadata(&self) -> io::Result<Metadata>322     pub async fn metadata(&self) -> io::Result<Metadata> {
323         let file = self.file.clone();
324         async_op(move || file.metadata()).await
325     }
326 
327     /// Creates a new File instance that shares the same underlying file handle
328     /// as the existing File instance. Reads, writes, and seeks will affect both
329     /// File instances simultaneously.
330     ///
331     /// # Example
332     ///
333     /// ```no_run
334     /// use ylong_runtime::fs::File;
335     ///
336     /// async fn try_clone() -> std::io::Result<()> {
337     ///     let mut f = File::open("foo.txt").await?;
338     ///     let file_copy = f.try_clone().await?;
339     ///     Ok(())
340     /// }
341     /// ```
try_clone(&self) -> io::Result<File>342     pub async fn try_clone(&self) -> io::Result<File> {
343         let file = self.file.clone();
344         let file = async_op(move || file.try_clone()).await?;
345         Ok(Self::new(file))
346     }
347 
348     /// Sets the buffer size limit for [`AsyncRead`] and [`AsyncWrite`]
349     /// operation of this file.
350     ///
351     /// # Examples
352     ///
353     /// ```no_run
354     /// # async fn set_file_buffer_limit() {
355     /// use ylong_runtime::fs::File;
356     /// use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
357     /// let mut file = File::open("foo.txt").await.unwrap();
358     /// file.set_buffer_size_limit(1024 * 1024 * 2);
359     /// let mut buf = vec![0; 1024 * 1024 * 16];
360     /// // write the buffer in chunks up to 2MB each
361     /// let _ = file.write_all(&mut buf).await;
362     /// let _ = file.sync_all().await;
363     ///
364     /// let mut file = File::open("foo.txt").await.unwrap();
365     /// file.set_buffer_size_limit(1024 * 1024 * 2);
366     /// let mut read_buf = vec![];
367     /// // read the file in chunks up to 2MB each
368     /// let _ = file.read_to_end(&mut read_buf);
369     /// # }
370     /// ```
set_buffer_size_limit(&mut self, buf_size_limit: usize)371     pub fn set_buffer_size_limit(&mut self, buf_size_limit: usize) {
372         self.buf_size_limit = buf_size_limit;
373     }
374 
375     /// Takes the ownership of the `File` and turns it into a [`std::fs::File`].
376     /// Before the transition, any in-flight operations will be completed.
377     ///
378     /// # Examples
379     ///
380     /// ```no_run
381     /// use ylong_runtime::fs::File;
382     ///
383     /// # async fn file_into_std() -> std::io::Result<()> {
384     /// let file = File::open("foo.txt").await?;
385     /// let std = file.into_std().await;
386     /// # Ok(())
387     /// # }
into_std(mut self) -> SyncFile388     pub async fn into_std(mut self) -> SyncFile {
389         let file = self.inner.get_mut();
390         file.flush().await;
391         Arc::try_unwrap(self.file).expect("into_std Arc::try_unwrap failed")
392     }
393 
394     /// Turns the `File` into [`std::fs::File`] immediately without awaiting any
395     /// in-flight operation to complete.
396     ///
397     /// # Errors
398     /// This method wil return an error containing the file if some operation
399     /// is still in-flight
400     ///
401     /// # Examples
402     ///
403     /// ```no_run
404     /// use ylong_runtime::fs::File;
405     ///
406     /// # async fn file_try_into_std() -> std::io::Result<()> {
407     /// let file = File::open("foo.txt").await?;
408     /// let std = file.try_into_std().unwrap();
409     /// # Ok(())
410     /// # }
try_into_std(mut self) -> Result<SyncFile, Self>411     pub fn try_into_std(mut self) -> Result<SyncFile, Self> {
412         match Arc::try_unwrap(self.file) {
413             Ok(file) => Ok(file),
414             Err(arc_file) => {
415                 self.file = arc_file;
416                 Err(self)
417             }
418         }
419     }
420 }
421 
422 impl From<SyncFile> for File {
from(file: SyncFile) -> Self423     fn from(file: SyncFile) -> Self {
424         Self::new(file)
425     }
426 }
427 
428 cfg_unix! {
429     use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, BorrowedFd, RawFd};
430 
431     impl AsRawFd for File {
432         fn as_raw_fd(&self) -> RawFd {
433             self.file.as_raw_fd()
434         }
435     }
436 
437     impl AsFd for File {
438         fn as_fd(&self) -> BorrowedFd<'_> {
439             unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
440         }
441     }
442 
443     impl FromRawFd for File {
444         unsafe fn from_raw_fd(fd: RawFd) -> Self {
445             SyncFile::from_raw_fd(fd).into()
446         }
447     }
448 }
449 
450 cfg_windows! {
451     use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle, AsHandle, BorrowedHandle};
452 
453     impl AsRawHandle for File {
454         fn as_raw_handle(&self) -> RawHandle {
455             self.file.as_raw_handle()
456         }
457     }
458 
459     impl AsHandle for File {
460         fn as_handle(&self) -> BorrowedHandle<'_> {
461             unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) }
462         }
463     }
464 
465     impl FromRawHandle for File {
466         unsafe fn from_raw_handle(handle: RawHandle) -> Self {
467             SyncFile::from_raw_handle(handle).into()
468         }
469     }
470 }
471 
472 impl AsyncSeek for File {
poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, mut pos: SeekFrom, ) -> Poll<io::Result<u64>>473     fn poll_seek(
474         self: Pin<&mut Self>,
475         cx: &mut Context<'_>,
476         mut pos: SeekFrom,
477     ) -> Poll<io::Result<u64>> {
478         let file = self.get_mut();
479         let inner = file.inner.get_mut();
480         loop {
481             match inner.state {
482                 FileState::Idle(ref mut buf) => {
483                     // after each take, buf will be set right back
484                     let mut r_buf = buf.take().unwrap();
485 
486                     // move the cursor back since there's unread data in the buf
487                     let unread = r_buf.drop_unread();
488                     if unread != 0 {
489                         if let SeekFrom::Current(ref mut idx) = pos {
490                             *idx -= unread
491                         }
492                     }
493 
494                     let file = file.file.clone();
495                     inner.state =
496                         FileState::Seeking(spawn_blocking(&TaskBuilder::new(), move || {
497                             let ret = (&*file).seek(pos);
498                             (r_buf, ret)
499                         }));
500                 }
501                 ref mut state => {
502                     let op = state.get_op();
503                     let res = poll_ready!(Pin::new(state).poll(cx));
504                     match op {
505                         FileOp::Reading => {}
506                         FileOp::Writing => {
507                             if let Err(e) = res {
508                                 // Save the error for the next write.
509                                 inner.write_err = Some(e.kind());
510                             }
511                         }
512                         FileOp::Seeking => {
513                             if let Ok(idx) = res {
514                                 inner.idx = idx;
515                             }
516                             return Poll::Ready(res);
517                         }
518                     }
519                 }
520             }
521         }
522     }
523 }
524 
525 impl AsyncRead for File {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>526     fn poll_read(
527         self: Pin<&mut Self>,
528         cx: &mut Context<'_>,
529         buf: &mut ReadBuf<'_>,
530     ) -> Poll<io::Result<()>> {
531         let file = self.get_mut();
532         let inner = file.inner.get_mut();
533 
534         loop {
535             match inner.state {
536                 FileState::Idle(ref mut file_buf) => {
537                     // after each take, buf will be set right back
538                     let mut r_buf = file_buf.take().unwrap();
539                     // There is still remaining data from the last read, append it to read buf
540                     // directly
541                     if r_buf.remaining() != 0 {
542                         r_buf.append_to(buf);
543                         *file_buf = Some(r_buf);
544                         return Poll::Ready(Ok(()));
545                     }
546 
547                     // Make sure there is enough space to read. File_buf's size might be bigger than
548                     // the read_buf's size since other thread might also read into the read_buf.
549                     r_buf.reserve(buf.remaining(), file.buf_size_limit);
550 
551                     // State transition
552                     let file = file.file.clone();
553                     inner.state =
554                         FileState::Reading(spawn_blocking(&TaskBuilder::new(), move || {
555                             let ret = r_buf.read(&mut &*file).map(|_| ());
556                             (r_buf, ret)
557                         }));
558                 }
559                 FileState::Reading(ref mut x) => {
560                     let (mut file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
561                     // Append the data inside the file to the read buffer
562                     if res.is_ok() {
563                         file_buf.append_to(buf);
564                     }
565                     inner.state = FileState::Idle(Some(file_buf));
566                     return Poll::Ready(res);
567                 }
568                 FileState::Writing(ref mut x) => {
569                     let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
570 
571                     // Save the error for the next write
572                     if let Err(e) = res {
573                         inner.write_err = Some(e.kind());
574                     }
575                     inner.state = FileState::Idle(Some(file_buf))
576                 }
577                 FileState::Seeking(ref mut x) => {
578                     let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
579                     inner.state = FileState::Idle(Some(file_buf));
580                     if let Ok(idx) = res {
581                         inner.idx = idx;
582                     }
583                 }
584             }
585         }
586     }
587 }
588 
589 impl AsyncWrite for File {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>590     fn poll_write(
591         self: Pin<&mut Self>,
592         cx: &mut Context<'_>,
593         buf: &[u8],
594     ) -> Poll<io::Result<usize>> {
595         let file = self.get_mut();
596         let inner = file.inner.get_mut();
597 
598         if let Some(e) = inner.write_err {
599             return Poll::Ready(Err(e.into()));
600         }
601 
602         loop {
603             match inner.state {
604                 FileState::Idle(ref mut file_buf) => {
605                     // after each take, buf will be set right back
606                     let mut w_buf = file_buf.take().unwrap();
607 
608                     let unread = w_buf.drop_unread();
609                     let n = w_buf.append(buf, file.buf_size_limit);
610                     let file = file.file.clone();
611 
612                     inner.state =
613                         FileState::Writing(spawn_blocking(&TaskBuilder::new(), move || {
614                             // Move the cursor back since there's unread data in the buf.
615                             if unread != 0 {
616                                 if let Err(e) = (&*file).seek(SeekFrom::Current(-unread)) {
617                                     return (w_buf, Err(e));
618                                 }
619                             }
620                             let res = w_buf.write(&mut &*file);
621                             (w_buf, res)
622                         }));
623                     return Poll::Ready(Ok(n));
624                 }
625                 ref mut state => {
626                     let op = state.get_op();
627                     if let Poll::Ready(Err(e)) = Pin::new(state).poll(cx) {
628                         if let FileOp::Writing = op {
629                             return Poll::Ready(Err(e));
630                         }
631                     }
632                 }
633             }
634         }
635     }
636 
poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>637     fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
638         self.inner.get_mut().poll_flush(cx)
639     }
640 
poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>641     fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
642         self.poll_flush(cx)
643     }
644 }
645 
646 impl FileInner {
flush(&mut self)647     async fn flush(&mut self) {
648         if let Err(e) = poll_fn(|cx| self.poll_flush(cx)).await {
649             self.write_err = Some(e.kind());
650         }
651     }
652 
poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>>653     fn poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
654         if let Some(e) = self.write_err {
655             return Poll::Ready(Err(e.into()));
656         }
657 
658         match self.state {
659             FileState::Idle(_) => Poll::Ready(Ok(())),
660             ref mut state => {
661                 let op = state.get_op();
662                 let res = poll_ready!(Pin::new(state).poll(cx));
663 
664                 match op {
665                     FileOp::Writing => Poll::Ready(res.map(|_| ())),
666                     _ => Poll::Ready(Ok(())),
667                 }
668             }
669         }
670     }
671 }
672 
673 #[cfg(test)]
674 mod test {
675     use std::io;
676     use std::io::SeekFrom;
677 
678     use crate::fs::async_file::DEFAULT_BUF_LIMIT;
679     use crate::fs::{remove_file, File, OpenOptions};
680     use crate::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
681 
682     /// UT test for `set_len`
683     ///
684     /// # Brief
685     ///
686     /// 1. Creates a new file.
687     /// 2. Removes the file with `set_len()`, check result is Ok(()).
688     /// 3. Deletes the file.
689     #[test]
ut_fs_file_set_len()690     fn ut_fs_file_set_len() {
691         crate::block_on(async {
692             let file_path = "file11.txt";
693 
694             let file = File::create(file_path).await.unwrap();
695             let res = file.set_len(10).await;
696             assert!(res.is_ok());
697 
698             let res = remove_file(file_path).await;
699             assert!(res.is_ok());
700         });
701     }
702 
703     /// UT test for `try_clone`
704     ///
705     /// # Brief
706     ///
707     /// 1. Creates a new file.
708     /// 2. Creates a new File instance with `try_clone()`, check result is
709     ///    Ok(()).
710     /// 3. Deletes the file.
711     #[test]
ut_fs_file_try_clone()712     fn ut_fs_file_try_clone() {
713         crate::block_on(async {
714             let file_path = "file12.txt";
715 
716             let file = File::create(file_path).await.unwrap();
717             let res = file.try_clone().await;
718             assert!(res.is_ok());
719 
720             let res = remove_file(file_path).await;
721             assert!(res.is_ok());
722         });
723     }
724 
725     /// UT test cases for asynchronous file Seek
726     ///
727     /// # Brief
728     /// 1. Generate an asynchronous file IO with create.
729     /// 2. Start a task to perform a write operation.
730     /// 3. Start another task for seek and read operations.
731     #[test]
ut_fs_file_seek()732     fn ut_fs_file_seek() {
733         let file_path = "file13.txt";
734         let handle = crate::spawn(async move {
735             let mut file = File::create(file_path).await.unwrap();
736             let buf = vec![65, 66, 67, 68, 69, 70, 71, 72, 73];
737             let res = file.write(&buf).await.unwrap();
738             assert_eq!(res, 9);
739             file.sync_all().await.unwrap();
740         });
741         crate::block_on(handle).unwrap();
742 
743         let handle2 = crate::spawn(async move {
744             let mut file = File::open(file_path).await.unwrap();
745             let ret = file.seek(SeekFrom::Current(3)).await.unwrap();
746             assert_eq!(ret, 3);
747 
748             let mut buf = [0; 1];
749             let ret = file.read(&mut buf).await.unwrap();
750             assert_eq!(ret, 1);
751             assert_eq!(buf, [68]);
752 
753             let ret = file.seek(SeekFrom::Current(1)).await.unwrap();
754             assert_eq!(ret, 5);
755 
756             let mut buf = [0; 1];
757             let ret = file.read(&mut buf).await.unwrap();
758             assert_eq!(ret, 1);
759             assert_eq!(buf, [70]);
760 
761             let ret = file.seek(SeekFrom::Current(2)).await.unwrap();
762             assert_eq!(ret, 8);
763 
764             let mut buf = [0; 2];
765             let ret = file.read(&mut buf).await.unwrap();
766             assert_eq!(ret, 1);
767             assert_eq!(buf, [73, 0]);
768 
769             let ret = file.seek(SeekFrom::Start(0)).await.unwrap();
770             assert_eq!(ret, 0);
771             let mut buf = [0; 9];
772             let ret = file.read(&mut buf).await.unwrap();
773             assert_eq!(ret, 9);
774             assert_eq!(buf, [65, 66, 67, 68, 69, 70, 71, 72, 73]);
775 
776             let ret = file.seek(SeekFrom::End(-1)).await.unwrap();
777             assert_eq!(ret, 8);
778             let mut buf = [0; 2];
779             let ret = file.read(&mut buf).await.unwrap();
780             assert_eq!(ret, 1);
781             assert_eq!(buf, [73, 0]);
782         });
783 
784         crate::block_on(handle2).unwrap();
785         std::fs::remove_file(file_path).unwrap();
786     }
787 
788     /// UT test cases for Asynchronous file set permission
789     ///
790     /// # Brief
791     /// 1. Generate an asynchronous file IO with create.
792     /// 2. Asynchronously get the permissions of the file.
793     /// 3. Change the permission to read only, set it to this file.
794     #[test]
ut_fs_file_set_permission()795     fn ut_fs_file_set_permission() {
796         let file_path = "file14.txt";
797         let handle = crate::spawn(async move {
798             let file = File::create(file_path).await.unwrap();
799             let mut perms = file.metadata().await.unwrap().permissions();
800             perms.set_readonly(true);
801             let ret = file.set_permissions(perms).await;
802             assert!(ret.is_ok());
803             let mut perms = file.metadata().await.unwrap().permissions();
804             #[allow(clippy::permissions_set_readonly_false)]
805             perms.set_readonly(false);
806             let ret = file.set_permissions(perms).await;
807             assert!(ret.is_ok());
808         });
809         crate::block_on(handle).unwrap();
810         std::fs::remove_file(file_path).unwrap();
811     }
812 
813     /// UT test cases for asynchronous file sync
814     ///
815     /// # Brief
816     /// 1. Generate an asynchronous file IO with create.
817     /// 2. Call sync_all and sync_data after asynchronous write.
818     #[test]
ut_fs_file_sync_all()819     fn ut_fs_file_sync_all() {
820         let file_path = "file15.txt";
821         let handle = crate::spawn(async move {
822             let mut file = File::create(file_path).await.unwrap();
823             let buf = [2; 20000];
824             let ret = file.write_all(&buf).await;
825             assert!(ret.is_ok());
826             let ret = file.sync_all().await;
827             assert!(ret.is_ok());
828 
829             let buf = [2; 20000];
830             let ret = file.write_all(&buf).await;
831             assert!(ret.is_ok());
832             let ret = file.sync_data().await;
833             assert!(ret.is_ok());
834         });
835         crate::block_on(handle).unwrap();
836         std::fs::remove_file(file_path).unwrap();
837     }
838 
839     /// UT for setting the buffer's size limit
840     ///
841     /// # Brief
842     /// 1. Creates a new file, checks if its buffer size limit equals to
843     /// DEFAULT_BUF_LIMIT 2. Sets a new limit for file buffer
844     /// 3. Writes the entire buffer into the file
845     #[test]
ut_fs_set_buf_size_limit()846     fn ut_fs_set_buf_size_limit() {
847         let file_path = "file16.txt";
848         let handle = crate::spawn(async move {
849             let mut file = File::create(file_path).await.unwrap();
850             assert_eq!(file.buf_size_limit, DEFAULT_BUF_LIMIT);
851 
852             file.set_buffer_size_limit(1024 * 1024 * 4);
853             assert_eq!(file.buf_size_limit, 1024 * 1024 * 4);
854 
855             let buf = [2; 20000];
856             let ret = file.write_all(&buf).await;
857             assert!(ret.is_ok());
858             let ret = file.sync_all().await;
859             assert!(ret.is_ok());
860         });
861         crate::block_on(handle).unwrap();
862         std::fs::remove_file(file_path).unwrap();
863     }
864 
865     /// UT for opening an non-existed file
866     ///
867     /// # Brief
868     /// 1. Open a file that does not exist
869     /// 2. Check if the returned error is NotFound
870     #[test]
ut_fs_open_fail()871     fn ut_fs_open_fail() {
872         let handle = crate::spawn(async move {
873             let file = File::open("file_not_exist").await;
874             assert_eq!(file.unwrap_err().kind(), io::ErrorKind::NotFound);
875         });
876         crate::block_on(handle).unwrap();
877     }
878 
879     /// UT for `into_std`
880     ///
881     /// # Brief
882     /// 1. Creates an async File
883     /// 2. Turns the async File into a std File
884     /// 3. Check if the std file functions correctly
885     #[test]
ut_file_into_std()886     fn ut_file_into_std() {
887         use std::io::{Read, Seek};
888 
889         let file_path = "file17.txt";
890         let handle = crate::spawn(async move {
891             let mut file = OpenOptions::new()
892                 .read(true)
893                 .write(true)
894                 .create(true)
895                 .open(file_path)
896                 .await
897                 .unwrap();
898 
899             let res = file.write_all(b"hello").await;
900             assert!(res.is_ok());
901 
902             let mut std = file.into_std().await;
903             let ret = std.seek(SeekFrom::Start(0)).unwrap();
904             assert_eq!(ret, 0);
905             let mut buf = [0; 5];
906             let ret = std.read_exact(&mut buf);
907             assert!(ret.is_ok());
908             assert_eq!(&buf, b"hello");
909         });
910         crate::block_on(handle).unwrap();
911         std::fs::remove_file(file_path).unwrap();
912     }
913 
914     /// UT for `try_into_std`
915     ///
916     /// # Brief
917     /// 1. Creates an async File
918     /// 2. Uses the async file to write without flushing
919     /// 3. Tries to turn the async file into a std file
920     /// 4. Check if the attempt fails
921     /// 5. Flushes the file
922     /// 6. Tries to turn the async file into a std file
923     /// 7. Check if the attempt succeeds
924     #[test]
ut_file_try_into_std()925     fn ut_file_try_into_std() {
926         let file_path = "file18.txt";
927         let handle = crate::spawn(async move {
928             let mut file = File::create(file_path).await.unwrap();
929             let res = file.write_all(b"hello").await;
930             assert!(res.is_ok());
931 
932             let std = file.try_into_std();
933             assert!(std.is_err());
934 
935             let mut file = std.unwrap_err();
936             let ret = file.flush().await;
937             assert!(ret.is_ok());
938 
939             let std = file.try_into_std();
940             assert!(std.is_ok());
941         });
942         crate::block_on(handle).unwrap();
943         std::fs::remove_file(file_path).unwrap();
944     }
945 
946     /// UT for `as_raw_fd`
947     ///
948     /// # Brief
949     /// 1. Creates an async File and turns it into a std file
950     /// 2. Gets the raw fd from the std file
951     /// 3. Turns the std file back to an async file
952     /// 4. Check if the fds are equal
953     /// 5. Creates a new async file from the raw fd
954     /// 6. Check if the fd of the new async file is correct
955     #[test]
956     #[cfg(unix)]
ut_file_as_raw_fd()957     fn ut_file_as_raw_fd() {
958         use std::os::fd::{AsFd, AsRawFd};
959         use std::os::unix::io::FromRawFd;
960 
961         let file_path = "file19.txt";
962         let handle = crate::spawn(async move {
963             let file = File::create(file_path).await.unwrap();
964             let std = file.into_std().await;
965             let fd = std.as_raw_fd();
966             let file = File::from(std);
967             let fd2 = file.as_raw_fd();
968             assert_eq!(fd, fd2);
969             let fd3 = file.as_fd().as_raw_fd();
970             assert_eq!(fd, fd3);
971 
972             let file2 = unsafe { File::from_raw_fd(fd) };
973             let fd4 = file2.as_raw_fd();
974             assert_eq!(fd, fd4);
975         });
976 
977         crate::block_on(handle).unwrap();
978         std::fs::remove_file(file_path).unwrap();
979     }
980 }
981