Skip to content

Commit 26abc31

Browse files
committed
fix(fs): wrap metadata structs into one API
1 parent 996c3cb commit 26abc31

File tree

5 files changed

+304
-86
lines changed

5 files changed

+304
-86
lines changed

compio-fs/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ compio-driver = { workspace = true }
2121
compio-io = { workspace = true }
2222
compio-runtime = { workspace = true }
2323

24-
cfg-if = { workspace = true }
25-
2624
# Windows specific dependencies
2725
[target.'cfg(windows)'.dependencies]
2826
widestring = { workspace = true }

compio-fs/src/file.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl File {
9696
LastAccessTime: 0,
9797
LastWriteTime: 0,
9898
ChangeTime: 0,
99-
FileAttributes: perm.attrs,
99+
FileAttributes: perm.0.attrs,
100100
};
101101
syscall!(
102102
BOOL,

compio-fs/src/metadata/mod.rs

+303-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,305 @@
1-
cfg_if::cfg_if! {
2-
if #[cfg(windows)] {
3-
mod windows;
4-
pub use windows::*;
5-
} else if #[cfg(unix)] {
6-
mod unix;
7-
pub use unix::*;
1+
#[cfg(unix)]
2+
#[path = "unix.rs"]
3+
mod sys;
4+
5+
#[cfg(windows)]
6+
#[path = "windows.rs"]
7+
mod sys;
8+
9+
use std::{io, path::Path, time::SystemTime};
10+
11+
/// Given a path, query the file system to get information about a file,
12+
/// directory, etc.
13+
pub async fn metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
14+
sys::metadata(path).await.map(Metadata)
15+
}
16+
17+
/// Query the metadata about a file without following symlinks.
18+
pub async fn symlink_metadata(path: impl AsRef<Path>) -> io::Result<Metadata> {
19+
sys::symlink_metadata(path).await.map(Metadata)
20+
}
21+
22+
/// Changes the permissions found on a file or a directory.
23+
pub async fn set_permissions(path: impl AsRef<Path>, perm: Permissions) -> io::Result<()> {
24+
sys::set_permissions(path, perm.0).await
25+
}
26+
27+
/// Metadata information about a file.
28+
#[derive(Clone)]
29+
pub struct Metadata(sys::Metadata);
30+
31+
impl Metadata {
32+
/// Create from inner type of [`FileStat`] or [`PathStat`].
33+
///
34+
/// [`FileStat`]: compio_driver::op::FileStat
35+
/// [`PathStat`]: compio_driver::op::PathStat
36+
pub fn from_stat(stat: <compio_driver::op::FileStat as compio_buf::IntoInner>::Inner) -> Self {
37+
Self(sys::Metadata::from_stat(stat))
38+
}
39+
40+
/// Returns the file type for this metadata.
41+
pub fn file_type(&self) -> FileType {
42+
FileType(self.0.file_type())
43+
}
44+
45+
/// Returns `true` if this metadata is for a directory.
46+
pub fn is_dir(&self) -> bool {
47+
self.0.is_dir()
48+
}
49+
50+
/// Returns `true` if this metadata is for a regular file.
51+
pub fn is_file(&self) -> bool {
52+
self.0.is_file()
53+
}
54+
55+
/// Returns `true` if this metadata is for a symbolic link.
56+
pub fn is_symlink(&self) -> bool {
57+
self.0.is_symlink()
58+
}
59+
60+
/// Returns the size of the file, in bytes, this metadata is for.
61+
#[allow(clippy::len_without_is_empty)]
62+
pub fn len(&self) -> u64 {
63+
self.0.len()
64+
}
65+
66+
/// Returns the permissions of the file this metadata is for.
67+
pub fn permissions(&self) -> Permissions {
68+
Permissions(self.0.permissions())
69+
}
70+
71+
/// Returns the last modification time listed in this metadata.
72+
///
73+
/// ## Platform specific
74+
/// * Windows: The returned value corresponds to the `ftLastWriteTime`
75+
/// field.
76+
/// * Unix: The returned value corresponds to the `mtime` field.
77+
pub fn modified(&self) -> io::Result<SystemTime> {
78+
self.0.modified()
79+
}
80+
81+
/// Returns the last access time of this metadata.
82+
///
83+
/// ## Platform specific
84+
/// * Windows: The returned value corresponds to the `ftLastAccessTime`
85+
/// field.
86+
/// * Unix: The returned value corresponds to the `atime` field.
87+
pub fn accessed(&self) -> io::Result<SystemTime> {
88+
self.0.accessed()
89+
}
90+
91+
/// Returns the creation time listed in this metadata.
92+
///
93+
/// ## Platform specific
94+
/// * Windows: The returned value corresponds to the `ftCreationTime` field.
95+
/// * Unix: The returned value corresponds to the `btime` field of
96+
/// [`libc::statx`] or `birthtime` field.
97+
pub fn created(&self) -> io::Result<SystemTime> {
98+
self.0.created()
99+
}
100+
101+
// The below methods are Windows specific. We cannot impl `MetadataExt` because
102+
// it is going to be sealed.
103+
104+
/// Returns the value of the `dwFileAttributes` field of this metadata.
105+
#[cfg(windows)]
106+
pub fn file_attributes(&self) -> u32 {
107+
self.0.file_attributes()
108+
}
109+
110+
/// Returns the value of the `ftCreationTime` field of this metadata.
111+
#[cfg(windows)]
112+
pub fn creation_time(&self) -> u64 {
113+
self.0.creation_time()
114+
}
115+
116+
/// Returns the value of the `ftLastAccessTime` field of this metadata.
117+
#[cfg(windows)]
118+
pub fn last_access_time(&self) -> u64 {
119+
self.0.last_access_time()
120+
}
121+
122+
/// Returns the value of the `ftLastWriteTime` field of this metadata.
123+
#[cfg(windows)]
124+
pub fn last_write_time(&self) -> u64 {
125+
self.0.last_write_time()
126+
}
127+
128+
/// Returns the value of the `dwVolumeSerialNumber` field of this
129+
/// metadata.
130+
#[cfg(windows)]
131+
pub fn volume_serial_number(&self) -> Option<u32> {
132+
self.0.volume_serial_number()
133+
}
134+
135+
/// Returns the value of the `nNumberOfLinks` field of this
136+
/// metadata.
137+
#[cfg(windows)]
138+
pub fn number_of_links(&self) -> Option<u32> {
139+
self.0.number_of_links()
140+
}
141+
142+
/// Returns the value of the `nFileIndex{Low,High}` fields of this
143+
/// metadata.
144+
#[cfg(windows)]
145+
pub fn file_index(&self) -> Option<u64> {
146+
self.0.file_index()
147+
}
148+
}
149+
150+
#[cfg(unix)]
151+
impl std::os::unix::prelude::MetadataExt for Metadata {
152+
fn dev(&self) -> u64 {
153+
self.0.dev()
154+
}
155+
156+
fn ino(&self) -> u64 {
157+
self.0.ino()
158+
}
159+
160+
fn mode(&self) -> u32 {
161+
self.0.mode()
162+
}
163+
164+
fn nlink(&self) -> u64 {
165+
self.0.nlink()
166+
}
167+
168+
fn uid(&self) -> u32 {
169+
self.0.uid()
170+
}
171+
172+
fn gid(&self) -> u32 {
173+
self.0.gid()
174+
}
175+
176+
fn rdev(&self) -> u64 {
177+
self.0.rdev()
178+
}
179+
180+
fn size(&self) -> u64 {
181+
self.0.size()
182+
}
183+
184+
fn atime(&self) -> i64 {
185+
self.0.atime()
186+
}
187+
188+
fn atime_nsec(&self) -> i64 {
189+
self.0.atime_nsec()
190+
}
191+
192+
fn mtime(&self) -> i64 {
193+
self.0.mtime()
194+
}
195+
196+
fn mtime_nsec(&self) -> i64 {
197+
self.0.mtime_nsec()
198+
}
199+
200+
fn ctime(&self) -> i64 {
201+
self.0.ctime()
202+
}
203+
204+
fn ctime_nsec(&self) -> i64 {
205+
self.0.ctime_nsec()
206+
}
207+
208+
fn blksize(&self) -> u64 {
209+
self.0.blksize()
210+
}
211+
212+
fn blocks(&self) -> u64 {
213+
self.0.blocks()
214+
}
215+
}
216+
217+
/// A structure representing a type of file with accessors for each file type.
218+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
219+
pub struct FileType(sys::FileType);
220+
221+
impl FileType {
222+
/// Tests whether this file type represents a directory.
223+
pub fn is_dir(&self) -> bool {
224+
self.0.is_dir()
225+
}
226+
227+
/// Tests whether this file type represents a regular file.
228+
pub fn is_file(&self) -> bool {
229+
self.0.is_file()
230+
}
231+
232+
/// Tests whether this file type represents a symbolic link.
233+
pub fn is_symlink(&self) -> bool {
234+
self.0.is_symlink()
235+
}
236+
237+
// The below methods are Windows specific. We cannot impl `FileTypeExt` because
238+
// it is sealed.
239+
240+
/// Returns `true` if this file type is a symbolic link that is also a
241+
/// directory.
242+
#[cfg(windows)]
243+
pub fn is_symlink_dir(&self) -> bool {
244+
self.0.is_symlink_dir()
245+
}
246+
247+
/// Returns `true` if this file type is a symbolic link that is also a file.
248+
#[cfg(windows)]
249+
pub fn is_symlink_file(&self) -> bool {
250+
self.0.is_symlink_file()
251+
}
252+
}
253+
254+
#[cfg(unix)]
255+
impl std::os::unix::prelude::FileTypeExt for FileType {
256+
fn is_block_device(&self) -> bool {
257+
self.0.is_block_device()
258+
}
259+
260+
fn is_char_device(&self) -> bool {
261+
self.0.is_char_device()
262+
}
263+
264+
fn is_fifo(&self) -> bool {
265+
self.0.is_fifo()
266+
}
267+
268+
fn is_socket(&self) -> bool {
269+
self.0.is_socket()
270+
}
271+
}
272+
273+
/// Representation of the various permissions on a file.
274+
#[derive(Clone, PartialEq, Eq, Debug)]
275+
pub struct Permissions(pub(crate) sys::Permissions);
276+
277+
impl Permissions {
278+
/// Returns `true` if these permissions describe a readonly (unwritable)
279+
/// file.
280+
pub fn readonly(&self) -> bool {
281+
self.0.readonly()
282+
}
283+
284+
/// Modifies the readonly flag for this set of permissions.
285+
///
286+
/// This operation does **not** modify the files attributes.
287+
pub fn set_readonly(&mut self, readonly: bool) {
288+
self.0.set_readonly(readonly)
289+
}
290+
}
291+
292+
#[cfg(unix)]
293+
impl std::os::unix::prelude::PermissionsExt for Permissions {
294+
fn mode(&self) -> u32 {
295+
self.0.mode()
296+
}
297+
298+
fn set_mode(&mut self, mode: u32) {
299+
self.0.set_mode(mode)
300+
}
301+
302+
fn from_mode(mode: u32) -> Self {
303+
Self(sys::Permissions::from_mode(mode))
8304
}
9305
}

0 commit comments

Comments
 (0)