1use std::path::{Path, PathBuf};
2
3#[derive(Clone, Debug)]
5pub struct FsMetadata {
6 pub is_dir: bool,
8 pub is_symlink: bool,
10}
11
12#[derive(Clone, Debug)]
14pub struct FsEntry {
15 pub name: String,
17 pub path: PathBuf,
19 pub is_dir: bool,
21 pub is_symlink: bool,
23 pub size: Option<u64>,
25 pub modified: Option<std::time::SystemTime>,
27}
28
29pub trait FileSystem {
34 fn read_dir(&self, dir: &Path) -> std::io::Result<Vec<FsEntry>>;
36 fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf>;
38 fn metadata(&self, path: &Path) -> std::io::Result<FsMetadata>;
40 fn create_dir(&self, path: &Path) -> std::io::Result<()>;
42 fn rename(&self, from: &Path, to: &Path) -> std::io::Result<()>;
44 fn remove_file(&self, path: &Path) -> std::io::Result<()>;
46 fn remove_dir(&self, path: &Path) -> std::io::Result<()>;
48 fn remove_dir_all(&self, path: &Path) -> std::io::Result<()>;
50 fn copy_file(&self, from: &Path, to: &Path) -> std::io::Result<u64>;
54}
55
56#[derive(Clone, Copy, Debug, Default)]
58pub struct StdFileSystem;
59
60impl FileSystem for StdFileSystem {
61 fn read_dir(&self, dir: &Path) -> std::io::Result<Vec<FsEntry>> {
62 let mut out = Vec::new();
63 let rd = std::fs::read_dir(dir)?;
64 for e in rd {
65 let e = match e {
66 Ok(v) => v,
67 Err(_) => continue,
68 };
69 let ft = match e.file_type() {
70 Ok(v) => v,
71 Err(_) => continue,
72 };
73 let name = e.file_name().to_string_lossy().to_string();
74 let path = e.path();
75 let meta = e.metadata().ok();
76 let modified = meta.as_ref().and_then(|m| m.modified().ok());
77 let is_dir = ft.is_dir();
78 let is_symlink = ft.is_symlink();
79 let size = if is_dir {
80 None
81 } else {
82 meta.as_ref().filter(|m| m.is_file()).map(|m| m.len())
83 };
84 out.push(FsEntry {
85 name,
86 path,
87 is_dir,
88 is_symlink,
89 size,
90 modified,
91 });
92 }
93 Ok(out)
94 }
95
96 fn canonicalize(&self, path: &Path) -> std::io::Result<PathBuf> {
97 std::fs::canonicalize(path)
98 }
99
100 fn metadata(&self, path: &Path) -> std::io::Result<FsMetadata> {
101 let md = std::fs::metadata(path)?;
102 let link_md = std::fs::symlink_metadata(path)?;
103 Ok(FsMetadata {
104 is_dir: md.is_dir(),
105 is_symlink: link_md.file_type().is_symlink(),
106 })
107 }
108
109 fn create_dir(&self, path: &Path) -> std::io::Result<()> {
110 std::fs::create_dir(path)
111 }
112
113 fn rename(&self, from: &Path, to: &Path) -> std::io::Result<()> {
114 std::fs::rename(from, to)
115 }
116
117 fn remove_file(&self, path: &Path) -> std::io::Result<()> {
118 std::fs::remove_file(path)
119 }
120
121 fn remove_dir(&self, path: &Path) -> std::io::Result<()> {
122 std::fs::remove_dir(path)
123 }
124
125 fn remove_dir_all(&self, path: &Path) -> std::io::Result<()> {
126 std::fs::remove_dir_all(path)
127 }
128
129 fn copy_file(&self, from: &Path, to: &Path) -> std::io::Result<u64> {
130 std::fs::copy(from, to)
131 }
132}