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::fs::{File as SyncFile, Metadata, Permissions};
15 use std::future::Future;
16 use std::io;
17 use std::io::{Seek, SeekFrom};
18 use std::path::Path;
19 use std::pin::Pin;
20 use std::sync::Arc;
21 use std::task::{Context, Poll};
22 
23 use crate::fs::file_buf::FileBuf;
24 use crate::fs::{async_op, poll_ready};
25 use crate::futures::poll_fn;
26 use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf};
27 use crate::spawn::spawn_blocking;
28 use crate::sync::Mutex;
29 use crate::task::{JoinHandle, TaskBuilder};
30 
31 /// An asynchronous wrapping of [`std::fs::File`]. Provides async read/write
32 /// methods.
33 pub struct File {
34     file: Arc<SyncFile>,
35     inner: Mutex<FileInner>,
36     // controls how many bytes the buffer could reserve during read
37     // and how many bytes the buffer could extend per time during write
38     buf_size_limit: usize,
39 }
40 
41 struct FileInner {
42     state: FileState,
43     write_err: Option<io::ErrorKind>,
44     idx: u64,
45 }
46 
47 type RWJoinHandle = JoinHandle<(FileBuf, io::Result<()>)>;
48 
49 type SeekJoinHandle = JoinHandle<(FileBuf, io::Result<u64>)>;
50 
51 enum FileState {
52     Idle(Option<FileBuf>),
53     Reading(RWJoinHandle),
54     Writing(RWJoinHandle),
55     Seeking(SeekJoinHandle),
56 }
57 
58 enum FileOp {
59     Reading,
60     Writing,
61     Seeking,
62 }
63 
64 impl Future for FileState {
65     type Output = io::Result<u64>;
66 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>67     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
68         let state = self.get_mut();
69         match state {
70             FileState::Idle(_) => unreachable!(),
71             FileState::Reading(x) | FileState::Writing(x) => {
72                 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
73                 *state = FileState::Idle(Some(file_buf));
74                 // For read and write, we dont care about the output
75                 Poll::Ready(res.map(|_| 0_u64))
76             }
77             FileState::Seeking(x) => {
78                 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
79                 *state = FileState::Idle(Some(file_buf));
80                 Poll::Ready(res)
81             }
82         }
83     }
84 }
85 
86 impl FileState {
87     #[inline]
get_op(&self) -> FileOp88     fn get_op(&self) -> FileOp {
89         match self {
90             FileState::Idle(_) => unreachable!(),
91             FileState::Reading(_) => FileOp::Reading,
92             FileState::Writing(_) => FileOp::Writing,
93             FileState::Seeking(_) => FileOp::Seeking,
94         }
95     }
96 }
97 
98 const DEFAULT_BUF_LIMIT: usize = 2 * 1024 * 1024;
99 
100 impl File {
101     /// Creates a new [`File`] struct.
new(file: SyncFile) -> File102     pub fn new(file: SyncFile) -> File {
103         File {
104             file: Arc::new(file),
105             inner: Mutex::new(FileInner {
106                 state: FileState::Idle(Some(FileBuf::with_capacity(0))),
107                 write_err: None,
108                 idx: 0,
109             }),
110             buf_size_limit: DEFAULT_BUF_LIMIT,
111         }
112     }
113 
114     /// Attempts to open a file in read-only mode asynchronously.
115     ///
116     /// See the [`super::OpenOptions::open`] method for more details.
117     ///
118     /// # Errors
119     ///
120     /// This function will return an error if `path` does not already exist.
121     ///
122     /// # Examples
123     ///
124     /// ```no_run
125     /// use ylong_runtime::fs::File;
126     ///
127     /// async fn open() -> std::io::Result<()> {
128     ///     let mut f = File::open("foo.txt").await?;
129     ///     Ok(())
130     /// }
131     /// ```
open<P: AsRef<Path>>(path: P) -> io::Result<File>132     pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
133         let path = path.as_ref().to_owned();
134         let file = async_op(|| SyncFile::open(path)).await?;
135         Ok(File::new(file))
136     }
137 
138     /// Opens a file in write-only mode asynchronously.
139     ///
140     /// This function will create a file if it does not exist
141     /// and truncate it if it does.
142     ///
143     ///
144     /// # Examples
145     ///
146     /// ```no_run
147     /// use ylong_runtime::fs::File;
148     ///
149     /// async fn create() -> std::io::Result<()> {
150     ///     let mut f = File::create("foo.txt").await?;
151     ///     Ok(())
152     /// }
153     /// ```
create<P: AsRef<Path>>(path: P) -> io::Result<File>154     pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
155         let path = path.as_ref().to_owned();
156         let file = async_op(|| SyncFile::create(path)).await?;
157         Ok(File::new(file))
158     }
159 
160     /// Changes the permissions on the underlying file asynchronously.
161     ///
162     /// # Errors
163     /// This function will return an error if the user lacks permission change
164     /// attributes on the underlying file. It may also return an error in other
165     /// os-specific unspecified cases.
166     ///
167     /// # Examples
168     ///
169     /// ```no_run
170     /// use ylong_runtime::fs::File;
171     ///
172     /// async fn set_permissions() -> std::io::Result<()> {
173     ///     let file = File::open("foo.txt").await?;
174     ///     let mut perms = file.metadata().await?.permissions();
175     ///     perms.set_readonly(true);
176     ///     file.set_permissions(perms).await?;
177     ///     Ok(())
178     /// }
179     /// ```
180     ///
181     /// Note that this method alters the permissions of the underlying file,
182     /// even though it takes `&self` rather than `&mut self`.
set_permissions(&self, perm: Permissions) -> io::Result<()>183     pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
184         let file = self.file.clone();
185         async_op(move || file.set_permissions(perm)).await
186     }
187 
188     /// Attempts to sync all OS-internal metadata to disk asynchronously.
189     ///
190     /// This function will attempt to ensure that all in-memory data reaches the
191     /// filesystem before returning.
192     ///
193     /// This can be used to handle errors that would otherwise only be caught
194     /// when the `File` is closed. Dropping a file will ignore errors in
195     /// synchronizing this in-memory data.
196     ///
197     /// # Examples
198     ///
199     /// ```no_run
200     /// use ylong_runtime::fs::File;
201     /// use ylong_runtime::io::AsyncWriteExt;
202     ///
203     /// async fn sync_all() -> std::io::Result<()> {
204     ///     let mut f = File::create("foo.txt").await?;
205     ///     f.write_all(b"Hello, world!").await?;
206     ///
207     ///     f.sync_all().await?;
208     ///     Ok(())
209     /// }
210     /// ```
sync_all(&self) -> io::Result<()>211     pub async fn sync_all(&self) -> io::Result<()> {
212         let mut file = self.inner.lock().await;
213         if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await {
214             file.write_err = Some(e.kind());
215         }
216         let file = self.file.clone();
217         async_op(move || file.sync_all()).await
218     }
219 
220     /// This function is similar to [`File::sync_all`], except that it might not
221     /// synchronize file metadata to the filesystem.
222     ///
223     /// This is intended for use cases that must synchronize content, but don't
224     /// need the metadata on disk. The goal of this method is to reduce disk
225     /// operations.
226     ///
227     /// # Examples
228     ///
229     /// ```no_run
230     /// use ylong_runtime::fs::File;
231     /// use ylong_runtime::io::AsyncWriteExt;
232     ///
233     /// async fn sync_data() -> std::io::Result<()> {
234     ///     let mut f = File::create("foo.txt").await?;
235     ///     f.write_all(b"Hello, world!").await?;
236     ///
237     ///     f.sync_data().await?;
238     ///     Ok(())
239     /// }
240     /// ```
sync_data(&self) -> io::Result<()>241     pub async fn sync_data(&self) -> io::Result<()> {
242         let mut file = self.inner.lock().await;
243         if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await {
244             file.write_err = Some(e.kind());
245         }
246         let file = self.file.clone();
247         async_op(move || file.sync_data()).await
248     }
249 
250     /// Truncates or extends the underlying file, updating the size of this file
251     /// to become size. If the size is less than the current file's size,
252     /// then the file will be shrunk. If it is greater than the current file's
253     /// size, then the file will be extended to size and have all of the
254     /// intermediate data filled in with 0s. The file's cursor isn't
255     /// changed. In particular, if the cursor was at the end and the file is
256     /// shrunk using this operation, the cursor will now be past the end.
257     ///
258     /// # Errors
259     ///
260     /// This function will return an error if the file is not opened for
261     /// writing.
262     ///
263     /// # Example
264     ///
265     /// ```no_run
266     /// use ylong_runtime::fs::File;
267     ///
268     /// async fn set_len() -> std::io::Result<()> {
269     ///     let mut f = File::create("foo.txt").await?;
270     ///     f.set_len(10).await?;
271     ///
272     ///     Ok(())
273     /// }
274     /// ```
set_len(&self, size: u64) -> io::Result<()>275     pub async fn set_len(&self, size: u64) -> io::Result<()> {
276         let mut file = self.inner.lock().await;
277         if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await {
278             file.write_err = Some(e.kind());
279         }
280 
281         let mut buf = match file.state {
282             // after each take, buf will be set right back
283             FileState::Idle(ref mut buf) => buf.take().unwrap(),
284             _ => unreachable!(),
285         };
286 
287         let arc_file = self.file.clone();
288 
289         let (buf, res) = spawn_blocking(&TaskBuilder::new(), move || {
290             let res = if buf.remaining() == 0 {
291                 (&*arc_file)
292                     .seek(SeekFrom::Current(buf.drop_unread()))
293                     .and_then(|_| arc_file.set_len(size))
294             } else {
295                 arc_file.set_len(size)
296             }
297             .map(|_| 0);
298 
299             (buf, res)
300         })
301         .await?;
302 
303         file.state = FileState::Idle(Some(buf));
304 
305         res.map(|u| file.idx = u)
306     }
307 
308     /// Queries metadata about the underlying file asynchronously.
309     ///
310     /// # Examples
311     ///
312     /// ```no_run
313     /// use ylong_runtime::fs::File;
314     ///
315     /// async fn metadata() -> std::io::Result<()> {
316     ///     let mut f = File::open("foo.txt").await?;
317     ///     let metadata = f.metadata().await?;
318     ///     Ok(())
319     /// }
320     /// ```
metadata(&self) -> io::Result<Metadata>321     pub async fn metadata(&self) -> io::Result<Metadata> {
322         let file = self.file.clone();
323         async_op(move || file.metadata()).await
324     }
325 
326     /// Creates a new File instance that shares the same underlying file handle
327     /// as the existing File instance. Reads, writes, and seeks will affect both
328     /// File instances simultaneously.
329     ///
330     /// # Example
331     ///
332     /// ```no_run
333     /// use ylong_runtime::fs::File;
334     ///
335     /// async fn try_clone() -> std::io::Result<()> {
336     ///     let mut f = File::open("foo.txt").await?;
337     ///     let file_copy = f.try_clone().await?;
338     ///     Ok(())
339     /// }
340     /// ```
try_clone(&self) -> io::Result<File>341     pub async fn try_clone(&self) -> io::Result<File> {
342         let file = self.file.clone();
343         let file = async_op(move || file.try_clone()).await?;
344         Ok(Self::new(file))
345     }
346 
347     /// Sets the buffer size limit for [`AsyncRead`] and [`AsyncWrite`]
348     /// operation of this file.
349     ///
350     /// # Examples
351     ///
352     /// ```no_run
353     /// # async fn set_file_buffer_limit() {
354     /// use ylong_runtime::fs::File;
355     /// use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt};
356     /// let mut file = File::open("foo.txt").await.unwrap();
357     /// file.set_buffer_size_limit(1024 * 1024 * 2);
358     /// let mut buf = vec![0; 1024 * 1024 * 16];
359     /// // write the buffer in chunks up to 2MB each
360     /// let _ = file.write_all(&mut buf).await;
361     /// let _ = file.sync_all().await;
362     ///
363     /// let mut file = File::open("foo.txt").await.unwrap();
364     /// file.set_buffer_size_limit(1024 * 1024 * 2);
365     /// let mut read_buf = vec![];
366     /// // read the file in chunks up to 2MB each
367     /// let _ = file.read_to_end(&mut read_buf);
368     /// # }
369     /// ```
set_buffer_size_limit(&mut self, buf_size_limit: usize)370     pub fn set_buffer_size_limit(&mut self, buf_size_limit: usize) {
371         self.buf_size_limit = buf_size_limit;
372     }
373 }
374 
375 impl AsyncSeek for File {
poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, mut pos: SeekFrom, ) -> Poll<io::Result<u64>>376     fn poll_seek(
377         self: Pin<&mut Self>,
378         cx: &mut Context<'_>,
379         mut pos: SeekFrom,
380     ) -> Poll<io::Result<u64>> {
381         let file = self.get_mut();
382         let inner = file.inner.get_mut();
383         loop {
384             match inner.state {
385                 FileState::Idle(ref mut buf) => {
386                     // after each take, buf will be set right back
387                     let mut r_buf = buf.take().unwrap();
388 
389                     // move the cursor back since there's unread data in the buf
390                     let unread = r_buf.drop_unread();
391                     if unread != 0 {
392                         if let SeekFrom::Current(ref mut idx) = pos {
393                             *idx -= unread
394                         }
395                     }
396 
397                     let file = file.file.clone();
398                     inner.state =
399                         FileState::Seeking(spawn_blocking(&TaskBuilder::new(), move || {
400                             let ret = (&*file).seek(pos);
401                             (r_buf, ret)
402                         }));
403                 }
404                 ref mut state => {
405                     let op = state.get_op();
406                     let res = poll_ready!(Pin::new(state).poll(cx));
407                     match op {
408                         FileOp::Reading => {}
409                         FileOp::Writing => {
410                             if let Err(e) = res {
411                                 // Save the error for the next write.
412                                 inner.write_err = Some(e.kind());
413                             }
414                         }
415                         FileOp::Seeking => {
416                             if let Ok(idx) = res {
417                                 inner.idx = idx;
418                             }
419                             return Poll::Ready(res);
420                         }
421                     }
422                 }
423             }
424         }
425     }
426 }
427 
428 impl AsyncRead for File {
poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>429     fn poll_read(
430         self: Pin<&mut Self>,
431         cx: &mut Context<'_>,
432         buf: &mut ReadBuf<'_>,
433     ) -> Poll<io::Result<()>> {
434         let file = self.get_mut();
435         let inner = file.inner.get_mut();
436 
437         loop {
438             match inner.state {
439                 FileState::Idle(ref mut file_buf) => {
440                     // after each take, buf will be set right back
441                     let mut r_buf = file_buf.take().unwrap();
442                     // There is still remaining data from the last read, append it to read buf
443                     // directly
444                     if r_buf.remaining() != 0 {
445                         r_buf.append_to(buf);
446                         *file_buf = Some(r_buf);
447                         return Poll::Ready(Ok(()));
448                     }
449 
450                     // Make sure there is enough space to read. File_buf's size might be bigger than
451                     // the read_buf's size since other thread might also read into the read_buf.
452                     r_buf.reserve(buf.remaining(), file.buf_size_limit);
453 
454                     // State transition
455                     let file = file.file.clone();
456                     inner.state =
457                         FileState::Reading(spawn_blocking(&TaskBuilder::new(), move || {
458                             let ret = r_buf.read(&mut &*file).map(|_| ());
459                             (r_buf, ret)
460                         }));
461                 }
462                 FileState::Reading(ref mut x) => {
463                     let (mut file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
464                     // Append the data inside the file to the read buffer
465                     if res.is_ok() {
466                         file_buf.append_to(buf);
467                     }
468                     inner.state = FileState::Idle(Some(file_buf));
469                     return Poll::Ready(res);
470                 }
471                 FileState::Writing(ref mut x) => {
472                     let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
473 
474                     // Save the error for the next write
475                     if let Err(e) = res {
476                         inner.write_err = Some(e.kind());
477                     }
478                     inner.state = FileState::Idle(Some(file_buf))
479                 }
480                 FileState::Seeking(ref mut x) => {
481                     let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?;
482                     inner.state = FileState::Idle(Some(file_buf));
483                     if let Ok(idx) = res {
484                         inner.idx = idx;
485                     }
486                 }
487             }
488         }
489     }
490 }
491 
492 impl AsyncWrite for File {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>493     fn poll_write(
494         self: Pin<&mut Self>,
495         cx: &mut Context<'_>,
496         buf: &[u8],
497     ) -> Poll<io::Result<usize>> {
498         let file = self.get_mut();
499         let inner = file.inner.get_mut();
500 
501         if let Some(e) = inner.write_err {
502             return Poll::Ready(Err(e.into()));
503         }
504 
505         loop {
506             match inner.state {
507                 FileState::Idle(ref mut file_buf) => {
508                     // after each take, buf will be set right back
509                     let mut w_buf = file_buf.take().unwrap();
510 
511                     let unread = w_buf.drop_unread();
512                     let n = w_buf.append(buf, file.buf_size_limit);
513                     let file = file.file.clone();
514 
515                     inner.state =
516                         FileState::Writing(spawn_blocking(&TaskBuilder::new(), move || {
517                             // Move the cursor back since there's unread data in the buf.
518                             if unread != 0 {
519                                 if let Err(e) = (&*file).seek(SeekFrom::Current(-unread)) {
520                                     return (w_buf, Err(e));
521                                 }
522                             }
523                             let res = w_buf.write(&mut &*file);
524                             (w_buf, res)
525                         }));
526                     return Poll::Ready(Ok(n));
527                 }
528                 ref mut state => {
529                     let op = state.get_op();
530                     if let Poll::Ready(Err(e)) = Pin::new(state).poll(cx) {
531                         if let FileOp::Writing = op {
532                             return Poll::Ready(Err(e));
533                         }
534                     }
535                 }
536             }
537         }
538     }
539 
poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>540     fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
541         self.inner.get_mut().poll_flush(cx)
542     }
543 
poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>544     fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
545         self.poll_flush(cx)
546     }
547 }
548 
549 impl FileInner {
poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>>550     fn poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> {
551         if let Some(e) = self.write_err {
552             return Poll::Ready(Err(e.into()));
553         }
554 
555         match self.state {
556             FileState::Idle(_) => Poll::Ready(Ok(())),
557             ref mut state => {
558                 let op = state.get_op();
559                 let res = poll_ready!(Pin::new(state).poll(cx));
560 
561                 match op {
562                     FileOp::Writing => Poll::Ready(res.map(|_| ())),
563                     _ => Poll::Ready(Ok(())),
564                 }
565             }
566         }
567     }
568 }
569 
570 #[cfg(test)]
571 mod test {
572     use std::io;
573     use std::io::SeekFrom;
574 
575     use crate::fs::async_file::DEFAULT_BUF_LIMIT;
576     use crate::fs::{remove_file, File};
577     use crate::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
578 
579     /// UT test for `set_len`
580     ///
581     /// # Brief
582     ///
583     /// 1. Creates a new file.
584     /// 2. Removes the file with `set_len()`, check result is Ok(()).
585     /// 3. Deletes the file.
586     #[test]
ut_fs_file_set_len()587     fn ut_fs_file_set_len() {
588         crate::block_on(async {
589             let file_path = "file11.txt";
590 
591             let file = File::create(file_path).await.unwrap();
592             let res = file.set_len(10).await;
593             assert!(res.is_ok());
594 
595             let res = remove_file(file_path).await;
596             assert!(res.is_ok());
597         });
598     }
599 
600     /// UT test for `try_clone`
601     ///
602     /// # Brief
603     ///
604     /// 1. Creates a new file.
605     /// 2. Creates a new File instance with `try_clone()`, check result is
606     ///    Ok(()).
607     /// 3. Deletes the file.
608     #[test]
ut_fs_file_try_clone()609     fn ut_fs_file_try_clone() {
610         crate::block_on(async {
611             let file_path = "file12.txt";
612 
613             let file = File::create(file_path).await.unwrap();
614             let res = file.try_clone().await;
615             assert!(res.is_ok());
616 
617             let res = remove_file(file_path).await;
618             assert!(res.is_ok());
619         });
620     }
621 
622     /// UT test cases for asynchronous file Seek
623     ///
624     /// # Brief
625     /// 1. Generate an asynchronous file IO with create.
626     /// 2. Start a task to perform a write operation.
627     /// 3. Start another task for seek and read operations.
628     #[test]
ut_fs_file_seek()629     fn ut_fs_file_seek() {
630         let file_path = "file13.txt";
631         let handle = crate::spawn(async move {
632             let mut file = File::create(file_path).await.unwrap();
633             let buf = vec![65, 66, 67, 68, 69, 70, 71, 72, 73];
634             let res = file.write(&buf).await.unwrap();
635             assert_eq!(res, 9);
636             file.sync_all().await.unwrap();
637         });
638         crate::block_on(handle).unwrap();
639 
640         let handle2 = crate::spawn(async move {
641             let mut file = File::open(file_path).await.unwrap();
642             let ret = file.seek(SeekFrom::Current(3)).await.unwrap();
643             assert_eq!(ret, 3);
644 
645             let mut buf = [0; 1];
646             let ret = file.read(&mut buf).await.unwrap();
647             assert_eq!(ret, 1);
648             assert_eq!(buf, [68]);
649 
650             let ret = file.seek(SeekFrom::Current(1)).await.unwrap();
651             assert_eq!(ret, 5);
652 
653             let mut buf = [0; 1];
654             let ret = file.read(&mut buf).await.unwrap();
655             assert_eq!(ret, 1);
656             assert_eq!(buf, [70]);
657 
658             let ret = file.seek(SeekFrom::Current(2)).await.unwrap();
659             assert_eq!(ret, 8);
660 
661             let mut buf = [0; 2];
662             let ret = file.read(&mut buf).await.unwrap();
663             assert_eq!(ret, 1);
664             assert_eq!(buf, [73, 0]);
665 
666             let ret = file.seek(SeekFrom::Start(0)).await.unwrap();
667             assert_eq!(ret, 0);
668             let mut buf = [0; 9];
669             let ret = file.read(&mut buf).await.unwrap();
670             assert_eq!(ret, 9);
671             assert_eq!(buf, [65, 66, 67, 68, 69, 70, 71, 72, 73]);
672 
673             let ret = file.seek(SeekFrom::End(-1)).await.unwrap();
674             assert_eq!(ret, 8);
675             let mut buf = [0; 2];
676             let ret = file.read(&mut buf).await.unwrap();
677             assert_eq!(ret, 1);
678             assert_eq!(buf, [73, 0]);
679         });
680 
681         crate::block_on(handle2).unwrap();
682         std::fs::remove_file(file_path).unwrap();
683     }
684 
685     /// UT test cases for Asynchronous file set permission
686     ///
687     /// # Brief
688     /// 1. Generate an asynchronous file IO with create.
689     /// 2. Asynchronously get the permissions of the file.
690     /// 3. Change the permission to read only, set it to this file.
691     #[test]
ut_fs_file_set_permission()692     fn ut_fs_file_set_permission() {
693         let file_path = "file14.txt";
694         let handle = crate::spawn(async move {
695             let file = File::create(file_path).await.unwrap();
696             let mut perms = file.metadata().await.unwrap().permissions();
697             perms.set_readonly(true);
698             let ret = file.set_permissions(perms).await;
699             assert!(ret.is_ok());
700             let mut perms = file.metadata().await.unwrap().permissions();
701             #[allow(clippy::permissions_set_readonly_false)]
702             perms.set_readonly(false);
703             let ret = file.set_permissions(perms).await;
704             assert!(ret.is_ok());
705         });
706         crate::block_on(handle).unwrap();
707         std::fs::remove_file(file_path).unwrap();
708     }
709 
710     /// UT test cases for asynchronous file sync
711     ///
712     /// # Brief
713     /// 1. Generate an asynchronous file IO with create.
714     /// 2. Call sync_all and sync_data after asynchronous write.
715     #[test]
ut_fs_file_sync_all()716     fn ut_fs_file_sync_all() {
717         let file_path = "file15.txt";
718         let handle = crate::spawn(async move {
719             let mut file = File::create(file_path).await.unwrap();
720             let buf = [2; 20000];
721             let ret = file.write_all(&buf).await;
722             assert!(ret.is_ok());
723             let ret = file.sync_all().await;
724             assert!(ret.is_ok());
725 
726             let buf = [2; 20000];
727             let ret = file.write_all(&buf).await;
728             assert!(ret.is_ok());
729             let ret = file.sync_data().await;
730             assert!(ret.is_ok());
731         });
732         crate::block_on(handle).unwrap();
733         std::fs::remove_file(file_path).unwrap();
734     }
735 
736     /// UT for setting the buffer's size limit
737     ///
738     /// # Brief
739     /// 1. Creates a new file, checks if its buffer size limit equals to
740     /// DEFAULT_BUF_LIMIT 2. Sets a new limit for file buffer
741     /// 3. Writes the entire buffer into the file
742     #[test]
ut_fs_set_buf_size_limit()743     fn ut_fs_set_buf_size_limit() {
744         let file_path = "file16.txt";
745         let handle = crate::spawn(async move {
746             let mut file = File::create(file_path).await.unwrap();
747             assert_eq!(file.buf_size_limit, DEFAULT_BUF_LIMIT);
748 
749             file.set_buffer_size_limit(1024 * 1024 * 4);
750             assert_eq!(file.buf_size_limit, 1024 * 1024 * 4);
751 
752             let buf = [2; 20000];
753             let ret = file.write_all(&buf).await;
754             assert!(ret.is_ok());
755             let ret = file.sync_all().await;
756             assert!(ret.is_ok());
757         });
758         crate::block_on(handle).unwrap();
759         std::fs::remove_file(file_path).unwrap();
760     }
761 
762     use std::fmt::{Debug, Formatter};
763 
764     impl Debug for File {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result765         fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
766             self.file.fmt(f)
767         }
768     }
769 
770     /// UT for opening an non-existed file
771     ///
772     /// # Brief
773     /// 1. Open a file that does not exist
774     /// 2. Check if the returned error is NotFound
775     #[test]
ut_fs_open_fail()776     fn ut_fs_open_fail() {
777         let handle = crate::spawn(async move {
778             let file = File::open("file_not_exist").await;
779             assert_eq!(file.unwrap_err().kind(), io::ErrorKind::NotFound);
780         });
781         crate::block_on(handle).unwrap();
782     }
783 }
784