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::{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 let (mut std_dir, mut block) = dir.take().unwrap();
560 match block.pop_front() {
561 Some(Ok(entry)) => {
562 self.0 = State::Available(Box::new(Some((std_dir, block))));
563 return Ready(Ok(Some(entry)));
564 }
565 Some(Err(e)) => {
566 self.0 = State::Available(Box::new(Some((std_dir, block))));
567 return Ready(Err(e));
568 }
569 None => {}
570 }
571
572 self.0 = State::Empty(spawn_blocking(&TaskBuilder::new(), move || {
573 ReadDir::fill_block(&mut std_dir, &mut block);
574 (std_dir, block)
575 }));
576 }
577 State::Empty(ref mut handle) => {
578 let (std_dir, mut block) = poll_ready!(Pin::new(handle).poll(cx))?;
579 let res = match block.pop_front() {
580 Some(Ok(entry)) => Ok(Some(entry)),
581 Some(Err(e)) => Err(e),
582 None => Ok(None),
583 };
584 self.0 = State::Available(Box::new(Some((std_dir, block))));
585 return Ready(res);
586 }
587 }
588 }
589 }
590
591 /// Returns the next entry in the directory.
592 ///
593 /// # Return value
594 /// The function returns:
595 /// * `Ok(Some(entry))` entry is an entry in the directory.
596 /// * `Ok(None)` if there is no more entries in the directory.
597 /// * `Err(e)` if an IO error occurred.
598 ///
599 /// # Examples
600 ///
601 /// ```no_run
602 /// use std::io;
603 ///
604 /// use ylong_runtime::fs;
605 /// async fn fs_func() -> io::Result<()> {
606 /// let mut dir = fs::read_dir("/parent/dir").await?;
607 /// assert!(dir.next().await.is_ok());
608 /// Ok(())
609 /// }
610 /// ```
next(&mut self) -> io::Result<Option<DirEntry>>611 pub async fn next(&mut self) -> io::Result<Option<DirEntry>> {
612 poll_fn(|cx| self.poll_next(cx)).await
613 }
614 }
615
616 /// Entries returned by the [`ReadDir::next_entry`].
617 ///
618 /// Represents an entry inside of a directory on the filesystem.
619 /// Each entry can be inspected via methods to learn about the full path
620 /// or possibly other metadata through per-platform extension traits.
621 pub struct DirEntry(Arc<std::fs::DirEntry>);
622
623 impl DirEntry {
624 /// Returns the full path to the file represented by this entry.
625 ///
626 /// # Examples
627 ///
628 /// ```no_run
629 /// use std::io;
630 ///
631 /// use ylong_runtime::fs;
632 ///
633 /// async fn fs_func() -> io::Result<()> {
634 /// let mut dir = fs::read_dir("/parent/dir").await?;
635 /// while let Some(entry) = dir.next().await? {
636 /// println!("{:?}", entry.path());
637 /// }
638 /// Ok(())
639 /// }
640 /// ```
641 ///
642 /// This prints output like:
643 ///
644 /// ```text
645 /// "/parent/dir/some.txt"
646 /// "/parent/dir/rust.rs"
647 /// ```
path(&self) -> PathBuf648 pub fn path(&self) -> PathBuf {
649 self.0.path()
650 }
651
652 /// Returns the name of the file represented by this entry.
653 ///
654 /// # Examples
655 ///
656 /// ```no_run
657 /// use std::io;
658 ///
659 /// use ylong_runtime::fs;
660 ///
661 /// async fn fs_func() -> io::Result<()> {
662 /// let mut dir = fs::read_dir("/parent/dir").await?;
663 /// while let Some(entry) = dir.next().await? {
664 /// println!("{:?}", entry.file_name());
665 /// }
666 /// Ok(())
667 /// }
668 /// ```
file_name(&self) -> OsString669 pub fn file_name(&self) -> OsString {
670 self.0.file_name()
671 }
672
673 /// Returns the metadata for the file represented by this entry.
674 ///
675 /// This function won't traverse symlinks if this entry points
676 /// at a symlink.
677 ///
678 /// # Examples
679 ///
680 /// ```no_run
681 /// use std::io;
682 ///
683 /// use ylong_runtime::fs;
684 ///
685 /// async fn fs_func() -> io::Result<()> {
686 /// let mut dir = fs::read_dir("/parent/dir").await?;
687 /// while let Some(entry) = dir.next().await? {
688 /// if let Ok(metadata) = entry.metadata().await {
689 /// println!("{:?}", metadata.permissions());
690 /// }
691 /// }
692 /// Ok(())
693 /// }
694 /// ```
metadata(&self) -> io::Result<Metadata>695 pub async fn metadata(&self) -> io::Result<Metadata> {
696 let entry = self.0.clone();
697 async_op(move || entry.metadata()).await
698 }
699
700 /// Returns the file type for the file represented by this entry.
701 ///
702 /// This function won't traverse symlinks if this entry points
703 /// at a symlink.
704 ///
705 /// # Examples
706 ///
707 /// ```no_run
708 /// use std::io;
709 ///
710 /// use ylong_runtime::fs;
711 ///
712 /// async fn fs_func() -> io::Result<()> {
713 /// let mut dir = fs::read_dir("/parent/dir").await?;
714 /// while let Some(entry) = dir.next().await? {
715 /// if let Ok(file_type) = entry.file_type().await {
716 /// println!("{:?}", file_type);
717 /// }
718 /// }
719 /// Ok(())
720 /// }
721 /// ```
file_type(&self) -> io::Result<FileType>722 pub async fn file_type(&self) -> io::Result<FileType> {
723 let entry = self.0.clone();
724 async_op(move || entry.file_type()).await
725 }
726 }
727
728 #[cfg(test)]
729 mod test {
730 use crate::fs::{
731 canonicalize, copy, hard_link, metadata, read, read_link, read_to_string, remove_file,
732 rename, set_permissions, symlink_metadata, write, File,
733 };
734
735 /// UT test for `remove_file`
736 ///
737 /// # Brief
738 ///
739 /// 1. Create a new file.
740 /// 2. Remove the file with `remove_file()`, check result is Ok(()).
741 #[test]
ut_fs_create_remove_file()742 fn ut_fs_create_remove_file() {
743 crate::block_on(async {
744 let file_path = "file0.txt";
745
746 File::create(file_path).await.unwrap();
747 let res = remove_file(file_path).await;
748
749 assert!(res.is_ok());
750 });
751 }
752
753 /// UT test for `rename`
754 ///
755 /// # Brief
756 ///
757 /// 1. Create a new file.
758 /// 2. Rename the file with `rename()`.
759 /// 3. Delete the new file.
760 #[test]
ut_fs_rename()761 fn ut_fs_rename() {
762 crate::block_on(async {
763 let file_path = "file1.txt";
764
765 File::create(file_path).await.unwrap();
766 let res = rename(file_path, "new_file1.txt").await;
767 assert!(res.is_ok());
768
769 let res = remove_file("new_file1.txt").await;
770 assert!(res.is_ok());
771 });
772 }
773
774 /// UT test for `write()` and `read_to_string()`
775 ///
776 /// # Brief
777 ///
778 /// 1. Create a new file.
779 /// 2. Write the file with `write()`.
780 /// 3. Read the file with `read_to_string()`, check whether it's correct.
781 /// 4. Delete the file.
782 #[test]
ut_fs_write_and_read_to_string()783 fn ut_fs_write_and_read_to_string() {
784 crate::block_on(async {
785 let input = "Hello world";
786 let file_path = "file2.txt";
787
788 File::create(file_path).await.unwrap();
789
790 let res = write(file_path, input.as_bytes()).await;
791 assert!(res.is_ok());
792 let s = read_to_string(file_path).await.unwrap();
793 assert_eq!(s, input);
794
795 let res = remove_file(file_path).await;
796 assert!(res.is_ok());
797 });
798 }
799
800 /// UT test for `read()` and `write()`
801 ///
802 /// # Brief
803 ///
804 /// 1. Create a new file.
805 /// 2. Write the file with `write()`.
806 /// 3. Read the file with `read()`, check whether it's correct.
807 /// 4. Delete the file.
808 #[test]
ut_fs_write_and_read()809 fn ut_fs_write_and_read() {
810 crate::block_on(async {
811 let input = "Hello world";
812 let file_path = "file3.txt";
813
814 File::create(file_path).await.unwrap();
815
816 let res = write(file_path, input.as_bytes()).await;
817 assert!(res.is_ok());
818 let buf = read(file_path).await.unwrap();
819 let s = String::from_utf8(buf).expect("Found invalid UTF-8");
820 assert_eq!(s, input);
821
822 let res = remove_file(file_path).await;
823 assert!(res.is_ok());
824 });
825 }
826
827 /// UT test for `read_link()`
828 ///
829 /// # Brief
830 ///
831 /// 1. Read a symbolic link with read_link().
832 /// 2. Check whether the result is correct.
833 #[test]
ut_fs_read_link()834 fn ut_fs_read_link() {
835 crate::block_on(async {
836 let file_path = "file4.txt";
837
838 let res = read_link(file_path).await;
839 assert!(res.is_err());
840 });
841 }
842
843 /// UT test for `copy()`
844 ///
845 /// # Brief
846 ///
847 /// 1. Create a new file.
848 /// 2. Copy the file with `copy()`.
849 /// 3. Check whether the result is correct.
850 /// 4. Delete two files.
851 #[test]
ut_fs_copy()852 fn ut_fs_copy() {
853 crate::block_on(async {
854 let file_path = "file5.txt";
855
856 File::create(file_path).await.unwrap();
857
858 let res = copy(file_path, "new_file5.txt").await;
859 assert!(res.is_ok());
860
861 let res = remove_file(file_path).await;
862 assert!(res.is_ok());
863 let res = remove_file("new_file5.txt").await;
864 assert!(res.is_ok());
865 });
866 }
867
868 /// UT test for `hard_link()`
869 ///
870 /// # Brief
871 ///
872 /// 1. Create a new file.
873 /// 2. Create a new hard link on the filesystem with `hard_link()`.
874 /// 3. Check whether the result is correct.
875 /// 4. Delete two files.
876 #[test]
ut_fs_hard_link()877 fn ut_fs_hard_link() {
878 crate::block_on(async {
879 let file_path = "file6.txt";
880
881 File::create(file_path).await.unwrap();
882
883 let res = hard_link(file_path, "new_file6.txt").await;
884 assert!(res.is_ok());
885
886 let res = remove_file(file_path).await;
887 assert!(res.is_ok());
888 let res = remove_file("new_file6.txt").await;
889 assert!(res.is_ok());
890 });
891 }
892
893 /// UT test for `metadata()`
894 ///
895 /// # Brief
896 ///
897 /// 1. Create a new file.
898 /// 2. Get information about this file with `metadata()`.
899 /// 3. Check whether the result is correct.
900 /// 4. Delete the file.
901 #[test]
ut_fs_metadata()902 fn ut_fs_metadata() {
903 crate::block_on(async {
904 let file_path = "file7.txt";
905
906 File::create(file_path).await.unwrap();
907
908 let res = metadata(file_path).await;
909 assert!(res.is_ok());
910
911 let res = remove_file(file_path).await;
912 assert!(res.is_ok());
913 });
914 }
915
916 /// UT test for `canonicalize()`
917 ///
918 /// # Brief
919 ///
920 /// 1. Create a new file.
921 /// 2. Get the canonical, absolute form of a path with all intermediate
922 /// components normalized and symbolic links resolved with
923 /// `canonicalize()`.
924 /// 3. Check whether the result is correct.
925 /// 4. Delete the file.
926 #[test]
ut_fs_canonicalize()927 fn ut_fs_canonicalize() {
928 crate::block_on(async {
929 let file_path = "file8.txt";
930 File::create(file_path).await.unwrap();
931
932 let res = canonicalize(file_path).await;
933 assert!(res.is_ok());
934
935 let res = remove_file(file_path).await;
936 assert!(res.is_ok());
937 });
938 }
939
940 /// UT test for `symlink_metadata()`
941 ///
942 /// # Brief
943 ///
944 /// 1. Create a new file.
945 /// 2. Query the metadata about a file without following symlinks with
946 /// `symlink_metadata()`.
947 /// 3. Check whether the result is correct.
948 /// 4. Delete the file.
949 #[test]
ut_fs_symlink_metadata()950 fn ut_fs_symlink_metadata() {
951 crate::block_on(async {
952 let file_path = "file9.txt";
953 File::create(file_path).await.unwrap();
954
955 let res = symlink_metadata(file_path).await;
956 assert!(res.is_ok());
957
958 let res = remove_file(file_path).await;
959 assert!(res.is_ok());
960 });
961 }
962
963 /// UT test for `set_permissions()`
964 ///
965 /// # Brief
966 ///
967 /// 1. Create a new file.
968 /// 2. Set file as readonly with `set_permissions()`.
969 /// 3. Check whether the result is correct.
970 /// 4. Delete the file.
971 #[test]
ut_fs_set_permissions()972 fn ut_fs_set_permissions() {
973 crate::block_on(async {
974 let file_path = "file10.txt";
975 File::create(file_path).await.unwrap();
976
977 let mut perms = metadata(file_path).await.unwrap().permissions();
978 perms.set_readonly(true);
979 let res = set_permissions(file_path, perms).await;
980 assert!(res.is_ok());
981
982 let mut perms = metadata(file_path).await.unwrap().permissions();
983 #[allow(clippy::permissions_set_readonly_false)]
984 perms.set_readonly(false);
985 let res = set_permissions(file_path, perms).await;
986 assert!(res.is_ok());
987
988 let res = remove_file(file_path).await;
989 assert!(res.is_ok());
990 });
991 }
992 }
993