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::collections::VecDeque;
15 use std::ffi::OsString;
16 use std::fs::{FileType, Metadata, Permissions};
17 use std::future::Future;
18 use std::io;
19 use std::iter::Fuse;
20 use std::path::{Path, PathBuf};
21 use std::pin::Pin;
22 use std::sync::Arc;
23 use std::task::Poll::Ready;
24 use std::task::{Context, Poll};
25 
26 use crate::fs::{async_op, poll_ready};
27 use crate::futures::poll_fn;
28 use crate::spawn::spawn_blocking;
29 use crate::task::{JoinHandle, TaskBuilder};
30 
31 const BLOCK_SIZE: usize = 32;
32 
33 /// Creates a new directory at the given path.
34 ///
35 /// The async version of [`std::fs::create_dir`]
36 ///
37 /// # Errors
38 ///
39 /// In the following situations, the function will return an error, but is not
40 /// limited to just these cases:
41 ///
42 /// * The path has already been used.
43 /// * No permission to create directory at the given path.
44 /// * A parent directory in the path does not exist. In this case, use
45 ///   [`create_dir_all`] to create the missing parent directory and the target
46 ///   directory at the same time.
47 ///
48 /// # Examples
49 ///
50 /// ```no_run
51 /// use std::io;
52 ///
53 /// use ylong_runtime::fs;
54 /// async fn fs_func() -> io::Result<()> {
55 ///     fs::create_dir("/parent/dir").await?;
56 ///     Ok(())
57 /// }
58 /// ```
create_dir<P: AsRef<Path>>(path: P) -> io::Result<()>59 pub async fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
60     let path = path.as_ref().to_owned();
61     async_op(move || std::fs::create_dir(path)).await
62 }
63 
64 /// Creates a new directory and all of its missing parent directories.
65 ///
66 /// The async version of [`std::fs::create_dir_all`]
67 ///
68 /// # Errors
69 ///
70 /// In the following situations, the function will return an error, but is not
71 /// limited to just these cases:
72 ///
73 /// * The path has already been used.
74 /// * No permission to create directory at the given path.
75 /// * The missing parent directories can't not be created.
76 ///
77 /// # Examples
78 ///
79 /// ```no_run
80 /// use std::io;
81 ///
82 /// use ylong_runtime::fs;
83 /// async fn fs_func() -> io::Result<()> {
84 ///     fs::create_dir_all("/parent/dir").await?;
85 ///     Ok(())
86 /// }
87 /// ```
create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()>88 pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
89     let path = path.as_ref().to_owned();
90     async_op(move || std::fs::create_dir_all(path)).await
91 }
92 
93 /// Removes an empty directory.
94 ///
95 /// The async version of [`std::fs::remove_dir`]
96 ///
97 /// # Errors
98 ///
99 /// In the following situations, the function will return an error, but is not
100 /// limited to just these cases:
101 ///
102 /// * The directory does not exist.
103 /// * The given path is not a directory.
104 /// * No permission to remove directory at the given path.
105 /// * The directory isn't empty.
106 ///
107 /// # Examples
108 ///
109 /// ```no_run
110 /// use std::io;
111 ///
112 /// use ylong_runtime::fs;
113 /// async fn fs_func() -> io::Result<()> {
114 ///     fs::remove_dir("/parent/dir").await?;
115 ///     Ok(())
116 /// }
117 /// ```
remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()>118 pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
119     let path = path.as_ref().to_owned();
120     async_op(move || std::fs::remove_dir(path)).await
121 }
122 
123 /// Removes a directory and all its contents at the given path.
124 ///
125 /// The async version of [`std::fs::remove_dir_all`]
126 ///
127 /// # Errors
128 ///
129 /// * The directory does not exist.
130 /// * The given path is not a directory.
131 /// * No permission to remove directory or its contents at the given path.
132 ///
133 /// # Examples
134 ///
135 /// ```no_run
136 /// use std::io;
137 ///
138 /// use ylong_runtime::fs;
139 /// async fn fs_func() -> io::Result<()> {
140 ///     fs::remove_dir_all("/parent/dir").await?;
141 ///     Ok(())
142 /// }
143 /// ```
remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()>144 pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
145     let path = path.as_ref().to_owned();
146     async_op(move || std::fs::remove_dir_all(path)).await
147 }
148 
149 /// Returns an iterator over the entries within a directory.
150 ///
151 /// The async version of [`std::fs::read_dir`]
152 ///
153 /// # Errors
154 ///
155 /// * The directory does not exist.
156 /// * The given path is not a directory.
157 /// * No permission to view the contents at the given path.
158 ///
159 /// # Examples
160 ///
161 /// ```no_run
162 /// use std::io;
163 ///
164 /// use ylong_runtime::fs;
165 /// async fn fs_func() -> io::Result<()> {
166 ///     let mut dir = fs::read_dir("/parent/dir").await?;
167 ///     assert!(dir.next().await.is_ok());
168 ///     Ok(())
169 /// }
170 /// ```
read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir>171 pub async fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
172     let path = path.as_ref().to_owned();
173     async_op(|| {
174         let mut std_dir = std::fs::read_dir(path)?.fuse();
175         let mut block = VecDeque::with_capacity(BLOCK_SIZE);
176         ReadDir::fill_block(&mut std_dir, &mut block);
177         Ok(ReadDir::new(std_dir, block))
178     })
179     .await
180 }
181 
182 /// Removes a file from the filesystem.
183 ///
184 /// The async version of [`std::fs::remove_file`]
185 ///
186 /// # Errors
187 ///
188 /// This function will return an error in the following situations, but is not
189 /// limited to just these cases:
190 ///
191 /// * Path points to a directory.
192 /// * The file doesn't exist.
193 /// * The user lacks permissions to remove the file.
194 ///
195 /// # Examples
196 ///
197 /// ```no_run
198 /// use std::io;
199 ///
200 /// use ylong_runtime::fs;
201 /// async fn fs_func() -> io::Result<()> {
202 ///     fs::remove_file("file.txt").await?;
203 ///     Ok(())
204 /// }
205 /// ```
remove_file<P: AsRef<Path>>(path: P) -> io::Result<()>206 pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
207     let path = path.as_ref().to_owned();
208     async_op(move || std::fs::remove_file(path)).await
209 }
210 
211 /// Rename a file or directory to a new name, replacing the original file if to
212 /// already exists. This will not work if the new name is on a different mount
213 /// point.
214 ///
215 /// The async version of [`std::fs::rename`]
216 ///
217 /// # Errors
218 ///
219 /// This function will return an error in the following situations, but is not
220 /// limited to just these cases:
221 ///
222 /// * from does not exist.
223 /// * The user lacks permissions to view contents.
224 /// * from and to are on separate filesystems.
225 ///
226 /// # Examples
227 ///
228 /// ```no_run
229 /// use std::io;
230 ///
231 /// use ylong_runtime::fs;
232 /// async fn fs_func() -> io::Result<()> {
233 ///     fs::rename("file.txt", "new_file.txt").await?;
234 ///     Ok(())
235 /// }
236 /// ```
rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>237 pub async fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
238     let from = from.as_ref().to_owned();
239     let to = to.as_ref().to_owned();
240     async_op(move || std::fs::rename(from, to)).await
241 }
242 
243 /// Copies the contents of one file to another. This function will also copy the
244 /// permission bits of the original file to the destination file. This function
245 /// will overwrite the contents of to. Note that if from and to both point to
246 /// the same file, then the file will likely get truncated by this operation. On
247 /// success, the total number of bytes copied is returned and it is equal to the
248 /// length of the to file as reported by metadata.
249 ///
250 /// The async version of [`std::fs::copy`]
251 ///
252 /// # Errors
253 ///
254 /// This function will return an error in the following situations, but is not
255 /// limited to just these cases:
256 ///
257 /// * from is neither a regular file nor a symlink to a regular file.
258 /// * from does not exist.
259 /// * The current process does not have the permission rights to read from or
260 ///   write to.
261 ///
262 /// # Examples
263 ///
264 /// ```no_run
265 /// use std::io;
266 ///
267 /// use ylong_runtime::fs;
268 /// async fn fs_func() -> io::Result<()> {
269 ///     fs::copy("file.txt", "new_file.txt").await?;
270 ///     Ok(())
271 /// }
272 /// ```
copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64>273 pub async fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
274     let from = from.as_ref().to_owned();
275     let to = to.as_ref().to_owned();
276     async_op(move || std::fs::copy(from, to)).await
277 }
278 
279 /// Reads the entire contents of a file into a string.
280 ///
281 /// The async version of [`std::fs::read_to_string`]
282 ///
283 /// # Errors
284 ///
285 /// This function will return an error if path does not already exist.
286 ///
287 /// # Examples
288 ///
289 /// ```no_run
290 /// use std::io;
291 ///
292 /// use ylong_runtime::fs;
293 /// async fn read_to_string() -> io::Result<()> {
294 ///     let foo = fs::read_to_string("file.txt").await?;
295 ///     Ok(())
296 /// }
297 /// ```
read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String>298 pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
299     let path = path.as_ref().to_owned();
300     async_op(move || std::fs::read_to_string(path)).await
301 }
302 
303 /// Reads the entire contents of a file into a bytes vector.
304 ///
305 /// The async version of [`std::fs::read`]
306 ///
307 /// # Errors
308 ///
309 /// This function will return an error if path does not already exist.
310 ///
311 /// # Examples
312 ///
313 /// ```no_run
314 /// use std::io;
315 ///
316 /// use ylong_runtime::fs;
317 /// async fn read() -> io::Result<()> {
318 ///     let foo = fs::read("file.txt").await?;
319 ///     Ok(())
320 /// }
321 /// ```
read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>>322 pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
323     let path = path.as_ref().to_owned();
324     async_op(move || std::fs::read(path)).await
325 }
326 
327 /// Writes a slice as the entire contents of a file.
328 /// This function will create a file if it does not exist, and will entirely
329 /// replace its contents if it does.
330 ///
331 /// The async version of [`std::fs::write`]
332 ///
333 /// # Examples
334 ///
335 /// ```no_run
336 /// use std::io;
337 ///
338 /// use ylong_runtime::fs;
339 /// async fn write() -> io::Result<()> {
340 ///     fs::write("file.txt", b"Hello world").await?;
341 ///     Ok(())
342 /// }
343 /// ```
write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()>344 pub async fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
345     let path = path.as_ref().to_owned();
346     let contents = contents.as_ref().to_owned();
347 
348     async_op(move || std::fs::write(path, contents)).await
349 }
350 
351 /// Reads a symbolic link, returning the file that the link points to.
352 ///
353 /// The async version of [`std::fs::read_link`]
354 ///
355 /// # Errors
356 ///
357 /// This function will return an error in the following situations, but is not
358 /// limited to just these cases:
359 ///
360 /// * path is not a symbolic link.
361 /// * path does not exist.
362 ///
363 /// # Examples
364 ///
365 /// ```no_run
366 /// use std::io;
367 ///
368 /// use ylong_runtime::fs;
369 /// async fn read_link() -> io::Result<()> {
370 ///     fs::read_link("file.txt").await?;
371 ///     Ok(())
372 /// }
373 /// ```
read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf>374 pub async fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
375     let path = path.as_ref().to_owned();
376     async_op(move || std::fs::read_link(path)).await
377 }
378 
379 /// Creates a new hard link on the filesystem.
380 ///
381 /// The async version of [`std::fs::hard_link`]
382 ///
383 /// # Errors
384 ///
385 /// This function will return an error in the following situations, but is not
386 /// limited to just these cases:
387 ///
388 /// * The original path is not a file or doesn't exist.
389 ///
390 /// # Examples
391 ///
392 /// ```no_run
393 /// use std::io;
394 ///
395 /// use ylong_runtime::fs;
396 /// async fn hard_link() -> io::Result<()> {
397 ///     fs::hard_link("file1.txt", "file2.txt").await?;
398 ///     Ok(())
399 /// }
400 /// ```
hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()>401 pub async fn hard_link<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
402     let original = original.as_ref().to_owned();
403     let link = link.as_ref().to_owned();
404     async_op(move || std::fs::hard_link(original, link)).await
405 }
406 
407 /// Given a path, query the file system to get information about a file,
408 /// directory, etc. This function will traverse symbolic links to query
409 /// information about the destination file.
410 ///
411 /// The async version of [`std::fs::metadata`]
412 ///
413 /// # Errors
414 ///
415 /// This function will return an error in the following situations, but is not
416 /// limited to just these cases:
417 ///
418 /// * The original path is not a file or doesn't exist.
419 ///
420 /// # Examples
421 ///
422 /// ```no_run
423 /// use std::io;
424 ///
425 /// use ylong_runtime::fs;
426 /// async fn metadata() -> io::Result<()> {
427 ///     let data = fs::metadata("/path/file.txt").await?;
428 ///     Ok(())
429 /// }
430 /// ```
metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata>431 pub async fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
432     let path = path.as_ref().to_owned();
433     async_op(move || std::fs::metadata(path)).await
434 }
435 
436 /// Queries the metadata about a file without following symlinks.
437 ///
438 /// The async version of [`std::fs::symlink_metadata`]
439 ///
440 /// # Errors
441 ///
442 /// This function will return an error in the following situations, but is not
443 /// limited to just these cases:
444 ///
445 /// * The user lacks permissions to perform metadata call on path.
446 /// * path does not exist.
447 ///
448 /// # Examples
449 ///
450 /// ```no_run
451 /// use std::io;
452 ///
453 /// use ylong_runtime::fs;
454 /// async fn symlink_metadata() -> io::Result<()> {
455 ///     fs::symlink_metadata("/path/file.txt").await?;
456 ///     Ok(())
457 /// }
458 /// ```
symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata>459 pub async fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
460     let path = path.as_ref().to_owned();
461     async_op(move || std::fs::symlink_metadata(path)).await
462 }
463 
464 /// Returns the canonical, absolute form of a path with all intermediate
465 /// components normalized and symbolic links resolved.
466 ///
467 /// The async version of [`std::fs::canonicalize`]
468 ///
469 /// # Errors
470 ///
471 /// This function will return an error in the following situations, but is not
472 /// limited to just these cases:
473 ///
474 /// * path does not exist.
475 /// * A non-final component in path is not a directory.
476 ///
477 /// # Examples
478 ///
479 /// ```no_run
480 /// use std::io;
481 ///
482 /// use ylong_runtime::fs;
483 /// async fn canonicalize() -> io::Result<()> {
484 ///     fs::canonicalize("../path/../file.txt").await?;
485 ///     Ok(())
486 /// }
487 /// ```
canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf>488 pub async fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
489     let path = path.as_ref().to_owned();
490     async_op(move || std::fs::canonicalize(path)).await
491 }
492 
493 /// Changes the permissions found on a file or a directory.
494 ///
495 /// The async version of [`std::fs::set_permissions`]
496 ///
497 /// # Errors
498 ///
499 /// This function will return an error in the following situations, but is not
500 /// limited to just these cases:
501 ///
502 /// * path does not exist.
503 /// * The user lacks the permission to change attributes of the file.
504 ///
505 /// # Examples
506 ///
507 /// ```no_run
508 /// use std::{fs, io};
509 /// async fn set_permissions() -> io::Result<()> {
510 ///     let mut perms = ylong_runtime::fs::metadata("file.txt").await?.permissions();
511 ///     perms.set_readonly(true);
512 ///     ylong_runtime::fs::set_permissions("file.txt", perms).await?;
513 ///     Ok(())
514 /// }
515 /// ```
set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()>516 pub async fn set_permissions<P: AsRef<Path>>(path: P, perm: Permissions) -> io::Result<()> {
517     let path = path.as_ref().to_owned();
518     async_op(move || std::fs::set_permissions(path, perm)).await
519 }
520 
521 type Entries = (Fuse<std::fs::ReadDir>, VecDeque<io::Result<DirEntry>>);
522 
523 enum State {
524     Available(Box<Option<Entries>>),
525     Empty(JoinHandle<Entries>),
526 }
527 /// Directory for reading file entries.
528 ///
529 /// Returned from the [`read_dir`] function of this module and
530 /// will yield instances of [`io::Result`]<[`DirEntry`]>. A [`DirEntry`]
531 /// contains information like the entry's path and possibly other metadata.
532 ///
533 /// # Errors
534 ///
535 /// Returns [`Err`] if an IO error occurs during iteration.
536 pub struct ReadDir(State);
537 
538 impl ReadDir {
new(std_dir: Fuse<std::fs::ReadDir>, block: VecDeque<io::Result<DirEntry>>) -> ReadDir539     fn new(std_dir: Fuse<std::fs::ReadDir>, block: VecDeque<io::Result<DirEntry>>) -> ReadDir {
540         ReadDir(State::Available(Box::new(Some((std_dir, block)))))
541     }
542 
fill_block( std_dir: &mut Fuse<std::fs::ReadDir>, block: &mut VecDeque<io::Result<DirEntry>>, )543     fn fill_block(
544         std_dir: &mut Fuse<std::fs::ReadDir>,
545         block: &mut VecDeque<io::Result<DirEntry>>,
546     ) {
547         for res in std_dir.by_ref().take(BLOCK_SIZE) {
548             match res {
549                 Ok(entry) => block.push_back(Ok(DirEntry(Arc::new(entry)))),
550                 Err(e) => block.push_back(Err(e)),
551             }
552         }
553     }
554 
poll_next(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Option<DirEntry>>>555     fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<Option<DirEntry>>> {
556         loop {
557             match self.0 {
558                 State::Available(ref mut dir) => {
559                     // before each take, the dir is set
560                     let (mut std_dir, mut block) = dir.take().unwrap();
561                     match block.pop_front() {
562                         Some(Ok(entry)) => {
563                             self.0 = State::Available(Box::new(Some((std_dir, block))));
564                             return Ready(Ok(Some(entry)));
565                         }
566                         Some(Err(e)) => {
567                             self.0 = State::Available(Box::new(Some((std_dir, block))));
568                             return Ready(Err(e));
569                         }
570                         None => {}
571                     }
572 
573                     self.0 = State::Empty(spawn_blocking(&TaskBuilder::new(), move || {
574                         ReadDir::fill_block(&mut std_dir, &mut block);
575                         (std_dir, block)
576                     }));
577                 }
578                 State::Empty(ref mut handle) => {
579                     let (std_dir, mut block) = poll_ready!(Pin::new(handle).poll(cx))?;
580                     let res = match block.pop_front() {
581                         Some(Ok(entry)) => Ok(Some(entry)),
582                         Some(Err(e)) => Err(e),
583                         None => Ok(None),
584                     };
585                     self.0 = State::Available(Box::new(Some((std_dir, block))));
586                     return Ready(res);
587                 }
588             }
589         }
590     }
591 
592     /// Returns the next entry in the directory.
593     ///
594     /// # Return value
595     /// The function returns:
596     /// * `Ok(Some(entry))` entry is an entry in the directory.
597     /// * `Ok(None)` if there is no more entries in the directory.
598     /// * `Err(e)` if an IO error occurred.
599     ///
600     /// # Examples
601     ///
602     /// ```no_run
603     /// use std::io;
604     ///
605     /// use ylong_runtime::fs;
606     /// async fn fs_func() -> io::Result<()> {
607     ///     let mut dir = fs::read_dir("/parent/dir").await?;
608     ///     assert!(dir.next().await.is_ok());
609     ///     Ok(())
610     /// }
611     /// ```
next(&mut self) -> io::Result<Option<DirEntry>>612     pub async fn next(&mut self) -> io::Result<Option<DirEntry>> {
613         poll_fn(|cx| self.poll_next(cx)).await
614     }
615 }
616 
617 /// Entries returned by the [`ReadDir::next`].
618 ///
619 /// Represents an entry inside of a directory on the filesystem.
620 /// Each entry can be inspected via methods to learn about the full path
621 /// or possibly other metadata through per-platform extension traits.
622 pub struct DirEntry(Arc<std::fs::DirEntry>);
623 
624 impl DirEntry {
625     /// Returns the full path to the file represented by this entry.
626     ///
627     /// # Examples
628     ///
629     /// ```no_run
630     /// use std::io;
631     ///
632     /// use ylong_runtime::fs;
633     ///
634     /// async fn fs_func() -> io::Result<()> {
635     ///     let mut dir = fs::read_dir("/parent/dir").await?;
636     ///     while let Some(entry) = dir.next().await? {
637     ///         println!("{:?}", entry.path());
638     ///     }
639     ///     Ok(())
640     /// }
641     /// ```
642     ///
643     /// This prints output like:
644     ///
645     /// ```text
646     /// "/parent/dir/some.txt"
647     /// "/parent/dir/rust.rs"
648     /// ```
path(&self) -> PathBuf649     pub fn path(&self) -> PathBuf {
650         self.0.path()
651     }
652 
653     /// Returns the name of the file represented by this entry.
654     ///
655     /// # Examples
656     ///
657     /// ```no_run
658     /// use std::io;
659     ///
660     /// use ylong_runtime::fs;
661     ///
662     /// async fn fs_func() -> io::Result<()> {
663     ///     let mut dir = fs::read_dir("/parent/dir").await?;
664     ///     while let Some(entry) = dir.next().await? {
665     ///         println!("{:?}", entry.file_name());
666     ///     }
667     ///     Ok(())
668     /// }
669     /// ```
file_name(&self) -> OsString670     pub fn file_name(&self) -> OsString {
671         self.0.file_name()
672     }
673 
674     /// Returns the metadata for the file represented by this entry.
675     ///
676     /// This function won't traverse symlinks if this entry points
677     /// at a symlink.
678     ///
679     /// # Examples
680     ///
681     /// ```no_run
682     /// use std::io;
683     ///
684     /// use ylong_runtime::fs;
685     ///
686     /// async fn fs_func() -> io::Result<()> {
687     ///     let mut dir = fs::read_dir("/parent/dir").await?;
688     ///     while let Some(entry) = dir.next().await? {
689     ///         if let Ok(metadata) = entry.metadata().await {
690     ///             println!("{:?}", metadata.permissions());
691     ///         }
692     ///     }
693     ///     Ok(())
694     /// }
695     /// ```
metadata(&self) -> io::Result<Metadata>696     pub async fn metadata(&self) -> io::Result<Metadata> {
697         let entry = self.0.clone();
698         async_op(move || entry.metadata()).await
699     }
700 
701     /// Returns the file type for the file represented by this entry.
702     ///
703     /// This function won't traverse symlinks if this entry points
704     /// at a symlink.
705     ///
706     /// # Examples
707     ///
708     /// ```no_run
709     /// use std::io;
710     ///
711     /// use ylong_runtime::fs;
712     ///
713     /// async fn fs_func() -> io::Result<()> {
714     ///     let mut dir = fs::read_dir("/parent/dir").await?;
715     ///     while let Some(entry) = dir.next().await? {
716     ///         if let Ok(file_type) = entry.file_type().await {
717     ///             println!("{:?}", file_type);
718     ///         }
719     ///     }
720     ///     Ok(())
721     /// }
722     /// ```
file_type(&self) -> io::Result<FileType>723     pub async fn file_type(&self) -> io::Result<FileType> {
724         let entry = self.0.clone();
725         async_op(move || entry.file_type()).await
726     }
727 }
728 
729 #[cfg(test)]
730 mod test {
731     use std::io;
732 
733     use crate::fs::{
734         canonicalize, copy, create_dir, hard_link, metadata, read, read_dir, read_link,
735         read_to_string, remove_dir_all, remove_file, rename, set_permissions, symlink_metadata,
736         write, File,
737     };
738 
739     /// UT test for `remove_file`
740     ///
741     /// # Brief
742     ///
743     /// 1. Create a new file.
744     /// 2. Remove the file with `remove_file()`, check result is Ok(()).
745     #[test]
ut_fs_create_remove_file()746     fn ut_fs_create_remove_file() {
747         crate::block_on(async {
748             let file_path = "file0.txt";
749 
750             File::create(file_path).await.unwrap();
751             let res = remove_file(file_path).await;
752 
753             assert!(res.is_ok());
754         });
755     }
756 
757     /// UT test for creating
758     ///
759     /// # Brief
760     ///
761     /// 1. Create a new directory whose parent doesn't exist.
762     /// 2. Check if the returned error is NotFound.
763     #[test]
ut_fs_create_dir_fail()764     fn ut_fs_create_dir_fail() {
765         crate::block_on(async {
766             let ret = create_dir("non-existed_parent/non_existed_child").await;
767             assert_eq!(ret.unwrap_err().kind(), io::ErrorKind::NotFound);
768         })
769     }
770 
771     /// UT test for `rename`
772     ///
773     /// # Brief
774     ///
775     /// 1. Create a new file.
776     /// 2. Rename the file with `rename()`.
777     /// 3. Delete the new file.
778     #[test]
ut_fs_rename()779     fn ut_fs_rename() {
780         crate::block_on(async {
781             let file_path = "file1.txt";
782 
783             File::create(file_path).await.unwrap();
784             let res = rename(file_path, "new_file1.txt").await;
785             assert!(res.is_ok());
786 
787             let res = remove_file("new_file1.txt").await;
788             assert!(res.is_ok());
789         });
790     }
791 
792     /// UT test for `write()` and `read_to_string()`
793     ///
794     /// # Brief
795     ///
796     /// 1. Create a new file.
797     /// 2. Write the file with `write()`.
798     /// 3. Read the file with `read_to_string()`, check whether it's correct.
799     /// 4. Delete the file.
800     #[test]
ut_fs_write_and_read_to_string()801     fn ut_fs_write_and_read_to_string() {
802         crate::block_on(async {
803             let input = "Hello world";
804             let file_path = "file2.txt";
805 
806             File::create(file_path).await.unwrap();
807 
808             let res = write(file_path, input.as_bytes()).await;
809             assert!(res.is_ok());
810             let s = read_to_string(file_path).await.unwrap();
811             assert_eq!(s, input);
812 
813             let res = remove_file(file_path).await;
814             assert!(res.is_ok());
815         });
816     }
817 
818     /// UT test for `read()` and `write()`
819     ///
820     /// # Brief
821     ///
822     /// 1. Create a new file.
823     /// 2. Write the file with `write()`.
824     /// 3. Read the file with `read()`, check whether it's correct.
825     /// 4. Delete the file.
826     #[test]
ut_fs_write_and_read()827     fn ut_fs_write_and_read() {
828         crate::block_on(async {
829             let input = "Hello world";
830             let file_path = "file3.txt";
831 
832             File::create(file_path).await.unwrap();
833 
834             let res = write(file_path, input.as_bytes()).await;
835             assert!(res.is_ok());
836             let buf = read(file_path).await.unwrap();
837             let s = String::from_utf8(buf).expect("Found invalid UTF-8");
838             assert_eq!(s, input);
839 
840             let res = remove_file(file_path).await;
841             assert!(res.is_ok());
842         });
843     }
844 
845     /// UT test for `read_link()`
846     ///
847     /// # Brief
848     ///
849     /// 1. Read a symbolic link with read_link().
850     /// 2. Check whether the result is correct.
851     #[test]
ut_fs_read_link()852     fn ut_fs_read_link() {
853         crate::block_on(async {
854             let file_path = "file4.txt";
855 
856             let res = read_link(file_path).await;
857             assert!(res.is_err());
858         });
859     }
860 
861     /// UT test for `copy()`
862     ///
863     /// # Brief
864     ///
865     /// 1. Create a new file.
866     /// 2. Copy the file with `copy()`.
867     /// 3. Check whether the result is correct.
868     /// 4. Delete two files.
869     #[test]
ut_fs_copy()870     fn ut_fs_copy() {
871         crate::block_on(async {
872             let file_path = "file5.txt";
873 
874             File::create(file_path).await.unwrap();
875 
876             let res = copy(file_path, "new_file5.txt").await;
877             assert!(res.is_ok());
878 
879             let res = remove_file(file_path).await;
880             assert!(res.is_ok());
881             let res = remove_file("new_file5.txt").await;
882             assert!(res.is_ok());
883         });
884     }
885 
886     /// UT test for `hard_link()`
887     ///
888     /// # Brief
889     ///
890     /// 1. Create a new file.
891     /// 2. Create a new hard link on the filesystem with `hard_link()`.
892     /// 3. Check whether the result is correct.
893     /// 4. Delete two files.
894     #[test]
ut_fs_hard_link()895     fn ut_fs_hard_link() {
896         crate::block_on(async {
897             let file_path = "file6.txt";
898 
899             File::create(file_path).await.unwrap();
900 
901             let res = hard_link(file_path, "new_file6.txt").await;
902             assert!(res.is_ok());
903 
904             let res = remove_file(file_path).await;
905             assert!(res.is_ok());
906             let res = remove_file("new_file6.txt").await;
907             assert!(res.is_ok());
908         });
909     }
910 
911     /// UT test for `metadata()`
912     ///
913     /// # Brief
914     ///
915     /// 1. Create a new file.
916     /// 2. Get information about this file with `metadata()`.
917     /// 3. Check whether the result is correct.
918     /// 4. Delete the file.
919     #[test]
ut_fs_metadata()920     fn ut_fs_metadata() {
921         crate::block_on(async {
922             let file_path = "file7.txt";
923 
924             File::create(file_path).await.unwrap();
925 
926             let res = metadata(file_path).await;
927             assert!(res.is_ok());
928 
929             let res = remove_file(file_path).await;
930             assert!(res.is_ok());
931         });
932     }
933 
934     /// UT test for `canonicalize()`
935     ///
936     /// # Brief
937     ///
938     /// 1. Create a new file.
939     /// 2. Get the canonical, absolute form of a path with all intermediate
940     ///    components normalized and symbolic links resolved with
941     ///    `canonicalize()`.
942     /// 3. Check whether the result is correct.
943     /// 4. Delete the file.
944     #[test]
ut_fs_canonicalize()945     fn ut_fs_canonicalize() {
946         crate::block_on(async {
947             let file_path = "file8.txt";
948             File::create(file_path).await.unwrap();
949 
950             let res = canonicalize(file_path).await;
951             assert!(res.is_ok());
952 
953             let res = remove_file(file_path).await;
954             assert!(res.is_ok());
955         });
956     }
957 
958     /// UT test for `symlink_metadata()`
959     ///
960     /// # Brief
961     ///
962     /// 1. Create a new file.
963     /// 2. Query the metadata about a file without following symlinks with
964     ///    `symlink_metadata()`.
965     /// 3. Check whether the result is correct.
966     /// 4. Delete the file.
967     #[test]
ut_fs_symlink_metadata()968     fn ut_fs_symlink_metadata() {
969         crate::block_on(async {
970             let file_path = "file9.txt";
971             File::create(file_path).await.unwrap();
972 
973             let res = symlink_metadata(file_path).await;
974             assert!(res.is_ok());
975 
976             let res = remove_file(file_path).await;
977             assert!(res.is_ok());
978         });
979     }
980 
981     /// UT test for `set_permissions()`
982     ///
983     /// # Brief
984     ///
985     /// 1. Create a new file.
986     /// 2. Set file as readonly with `set_permissions()`.
987     /// 3. Check whether the result is correct.
988     /// 4. Delete the file.
989     #[test]
ut_fs_set_permissions()990     fn ut_fs_set_permissions() {
991         crate::block_on(async {
992             let file_path = "file10.txt";
993             File::create(file_path).await.unwrap();
994 
995             let mut perms = metadata(file_path).await.unwrap().permissions();
996             perms.set_readonly(true);
997             let res = set_permissions(file_path, perms).await;
998             assert!(res.is_ok());
999 
1000             let mut perms = metadata(file_path).await.unwrap().permissions();
1001             #[allow(clippy::permissions_set_readonly_false)]
1002             perms.set_readonly(false);
1003             let res = set_permissions(file_path, perms).await;
1004             assert!(res.is_ok());
1005 
1006             let res = remove_file(file_path).await;
1007             assert!(res.is_ok());
1008         });
1009     }
1010 
1011     /// UT test cases for directory operations.
1012     ///
1013     /// # Brief
1014     /// 1. Create a new directory.
1015     /// 2. Create two files to read.
1016     /// 3. Read the directory and check the name of files.
1017     /// 4. Delete the directory and files in it.
1018     #[test]
ut_async_dir_read()1019     fn ut_async_dir_read() {
1020         let handle = crate::spawn(async move {
1021             let _ = create_dir("dir_test1").await;
1022             File::create("dir_test1/test1.txt").await.unwrap();
1023             File::create("dir_test1/test2.txt").await.unwrap();
1024             let mut dir = read_dir("dir_test1").await.unwrap();
1025             let entry = dir.next().await.unwrap().unwrap();
1026             assert!(!entry.file_type().await.unwrap().is_dir());
1027             assert!(entry.file_type().await.unwrap().is_file());
1028             assert!(entry.file_name().into_string().unwrap().contains("test"));
1029             let entry = dir.next().await.unwrap().unwrap();
1030             assert!(!entry.metadata().await.unwrap().is_dir());
1031             assert!(entry.metadata().await.unwrap().is_file());
1032             assert!(!entry.metadata().await.unwrap().permissions().readonly());
1033             assert!(entry.file_name().into_string().unwrap().contains("test"));
1034             assert!(dir.next().await.unwrap().is_none());
1035             assert!(remove_dir_all("dir_test1").await.is_ok());
1036         });
1037         crate::block_on(handle).unwrap();
1038     }
1039 }
1040