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