cap_primitives/fs/
metadata.rs1use crate::fs::{FileType, ImplFileTypeExt, ImplMetadataExt, Permissions};
2use crate::time::SystemTime;
3use std::{fs, io};
4
5#[derive(Debug, Clone)]
14pub struct Metadata {
15    pub(crate) file_type: FileType,
16    pub(crate) len: u64,
17    pub(crate) permissions: Permissions,
18    pub(crate) modified: Option<SystemTime>,
19    pub(crate) accessed: Option<SystemTime>,
20    pub(crate) created: Option<SystemTime>,
21    pub(crate) ext: ImplMetadataExt,
22}
23
24#[allow(clippy::len_without_is_empty)]
25impl Metadata {
26    #[inline]
28    pub fn from_file(file: &fs::File) -> io::Result<Self> {
29        let std = file.metadata()?;
30        let ext = ImplMetadataExt::from(file, &std)?;
31        let file_type = ImplFileTypeExt::from(file, &std)?;
32        Ok(Self::from_parts(std, ext, file_type))
33    }
34
35    #[inline]
43    pub fn from_just_metadata(std: fs::Metadata) -> Self {
44        let ext = ImplMetadataExt::from_just_metadata(&std);
45        let file_type = ImplFileTypeExt::from_just_metadata(&std);
46        Self::from_parts(std, ext, file_type)
47    }
48
49    #[inline]
50    fn from_parts(std: fs::Metadata, ext: ImplMetadataExt, file_type: FileType) -> Self {
51        Self {
52            file_type,
53            len: std.len(),
54            permissions: Permissions::from_std(std.permissions()),
55            modified: std.modified().ok().map(SystemTime::from_std),
56            accessed: std.accessed().ok().map(SystemTime::from_std),
57            created: std.created().ok().map(SystemTime::from_std),
58            ext,
59        }
60    }
61
62    #[inline]
66    pub const fn file_type(&self) -> FileType {
67        self.file_type
68    }
69
70    #[inline]
74    pub fn is_dir(&self) -> bool {
75        self.file_type.is_dir()
76    }
77
78    #[inline]
82    pub fn is_file(&self) -> bool {
83        self.file_type.is_file()
84    }
85
86    #[inline]
90    pub fn is_symlink(&self) -> bool {
91        self.file_type.is_symlink()
92    }
93
94    #[inline]
98    pub const fn len(&self) -> u64 {
99        self.len
100    }
101
102    #[inline]
106    pub fn permissions(&self) -> Permissions {
107        self.permissions.clone()
108    }
109
110    #[inline]
114    pub fn modified(&self) -> io::Result<SystemTime> {
115        #[cfg(io_error_uncategorized)]
116        {
117            self.modified.ok_or_else(|| {
118                io::Error::new(
119                    io::ErrorKind::Unsupported,
120                    "modified time metadata not available on this platform",
121                )
122            })
123        }
124        #[cfg(not(io_error_uncategorized))]
125        {
126            self.modified.ok_or_else(|| {
127                io::Error::new(
128                    io::ErrorKind::Other,
129                    "modified time metadata not available on this platform",
130                )
131            })
132        }
133    }
134
135    #[inline]
139    pub fn accessed(&self) -> io::Result<SystemTime> {
140        #[cfg(io_error_uncategorized)]
141        {
142            self.accessed.ok_or_else(|| {
143                io::Error::new(
144                    io::ErrorKind::Unsupported,
145                    "accessed time metadata not available on this platform",
146                )
147            })
148        }
149        #[cfg(not(io_error_uncategorized))]
150        {
151            self.accessed.ok_or_else(|| {
152                io::Error::new(
153                    io::ErrorKind::Other,
154                    "accessed time metadata not available on this platform",
155                )
156            })
157        }
158    }
159
160    #[inline]
164    pub fn created(&self) -> io::Result<SystemTime> {
165        #[cfg(io_error_uncategorized)]
166        {
167            self.created.ok_or_else(|| {
168                io::Error::new(
169                    io::ErrorKind::Unsupported,
170                    "created time metadata not available on this platform",
171                )
172            })
173        }
174        #[cfg(not(io_error_uncategorized))]
175        {
176            self.created.ok_or_else(|| {
177                io::Error::new(
178                    io::ErrorKind::Other,
179                    "created time metadata not available on this platform",
180                )
181            })
182        }
183    }
184
185    #[cfg(any(not(windows), windows_by_handle))]
188    pub(crate) fn is_same_file(&self, other: &Self) -> bool {
189        self.ext.is_same_file(&other.ext)
190    }
191
192    #[cfg(windows)]
195    #[inline]
196    pub(crate) fn file_attributes(&self) -> u32 {
197        self.ext.file_attributes()
198    }
199}
200
201#[cfg(any(unix, target_os = "vxworks"))]
205pub trait MetadataExt {
206    fn dev(&self) -> u64;
208    fn ino(&self) -> u64;
210    fn mode(&self) -> u32;
212    fn nlink(&self) -> u64;
214    fn uid(&self) -> u32;
216    fn gid(&self) -> u32;
218    fn rdev(&self) -> u64;
220    fn size(&self) -> u64;
222    fn atime(&self) -> i64;
224    fn atime_nsec(&self) -> i64;
226    fn mtime(&self) -> i64;
228    fn mtime_nsec(&self) -> i64;
230    fn ctime(&self) -> i64;
232    fn ctime_nsec(&self) -> i64;
234    fn blksize(&self) -> u64;
236    fn blocks(&self) -> u64;
238    #[cfg(target_os = "vxworks")]
239    fn attrib(&self) -> u8;
240}
241
242#[cfg(target_os = "wasi")]
246pub trait MetadataExt {
247    fn dev(&self) -> u64;
249    fn ino(&self) -> u64;
251    fn nlink(&self) -> u64;
253    fn size(&self) -> u64;
255    fn atim(&self) -> u64;
257    fn mtim(&self) -> u64;
259    fn ctim(&self) -> u64;
261}
262
263#[cfg(windows)]
267pub trait MetadataExt {
268    fn file_attributes(&self) -> u32;
270    fn creation_time(&self) -> u64;
272    fn last_access_time(&self) -> u64;
274    fn last_write_time(&self) -> u64;
276    fn file_size(&self) -> u64;
278    #[cfg(windows_by_handle)]
280    fn volume_serial_number(&self) -> Option<u32>;
281    #[cfg(windows_by_handle)]
283    fn number_of_links(&self) -> Option<u32>;
284    #[cfg(windows_by_handle)]
286    fn file_index(&self) -> Option<u64>;
287}
288
289#[cfg(unix)]
290impl MetadataExt for Metadata {
291    #[inline]
292    fn dev(&self) -> u64 {
293        crate::fs::MetadataExt::dev(&self.ext)
294    }
295
296    #[inline]
297    fn ino(&self) -> u64 {
298        crate::fs::MetadataExt::ino(&self.ext)
299    }
300
301    #[inline]
302    fn mode(&self) -> u32 {
303        crate::fs::MetadataExt::mode(&self.ext)
304    }
305
306    #[inline]
307    fn nlink(&self) -> u64 {
308        crate::fs::MetadataExt::nlink(&self.ext)
309    }
310
311    #[inline]
312    fn uid(&self) -> u32 {
313        crate::fs::MetadataExt::uid(&self.ext)
314    }
315
316    #[inline]
317    fn gid(&self) -> u32 {
318        crate::fs::MetadataExt::gid(&self.ext)
319    }
320
321    #[inline]
322    fn rdev(&self) -> u64 {
323        crate::fs::MetadataExt::rdev(&self.ext)
324    }
325
326    #[inline]
327    fn size(&self) -> u64 {
328        crate::fs::MetadataExt::size(&self.ext)
329    }
330
331    #[inline]
332    fn atime(&self) -> i64 {
333        crate::fs::MetadataExt::atime(&self.ext)
334    }
335
336    #[inline]
337    fn atime_nsec(&self) -> i64 {
338        crate::fs::MetadataExt::atime_nsec(&self.ext)
339    }
340
341    #[inline]
342    fn mtime(&self) -> i64 {
343        crate::fs::MetadataExt::mtime(&self.ext)
344    }
345
346    #[inline]
347    fn mtime_nsec(&self) -> i64 {
348        crate::fs::MetadataExt::mtime_nsec(&self.ext)
349    }
350
351    #[inline]
352    fn ctime(&self) -> i64 {
353        crate::fs::MetadataExt::ctime(&self.ext)
354    }
355
356    #[inline]
357    fn ctime_nsec(&self) -> i64 {
358        crate::fs::MetadataExt::ctime_nsec(&self.ext)
359    }
360
361    #[inline]
362    fn blksize(&self) -> u64 {
363        crate::fs::MetadataExt::blksize(&self.ext)
364    }
365
366    #[inline]
367    fn blocks(&self) -> u64 {
368        crate::fs::MetadataExt::blocks(&self.ext)
369    }
370}
371
372#[cfg(target_os = "wasi")]
373impl MetadataExt for Metadata {
374    #[inline]
375    fn dev(&self) -> u64 {
376        crate::fs::MetadataExt::dev(&self.ext)
377    }
378
379    #[inline]
380    fn ino(&self) -> u64 {
381        crate::fs::MetadataExt::ino(&self.ext)
382    }
383
384    #[inline]
385    fn nlink(&self) -> u64 {
386        crate::fs::MetadataExt::nlink(&self.ext)
387    }
388
389    #[inline]
390    fn size(&self) -> u64 {
391        crate::fs::MetadataExt::size(&self.ext)
392    }
393
394    #[inline]
395    fn atim(&self) -> u64 {
396        crate::fs::MetadataExt::atim(&self.ext)
397    }
398
399    #[inline]
400    fn mtim(&self) -> u64 {
401        crate::fs::MetadataExt::mtim(&self.ext)
402    }
403
404    #[inline]
405    fn ctim(&self) -> u64 {
406        crate::fs::MetadataExt::ctim(&self.ext)
407    }
408}
409
410#[cfg(target_os = "vxworks")]
411impl MetadataExt for Metadata {
412    #[inline]
413    fn dev(&self) -> u64 {
414        self.ext.dev()
415    }
416
417    #[inline]
418    fn ino(&self) -> u64 {
419        self.ext.ino()
420    }
421
422    #[inline]
423    fn mode(&self) -> u32 {
424        self.ext.mode()
425    }
426
427    #[inline]
428    fn nlink(&self) -> u64 {
429        self.ext.nlink()
430    }
431
432    #[inline]
433    fn uid(&self) -> u32 {
434        self.ext.uid()
435    }
436
437    #[inline]
438    fn gid(&self) -> u32 {
439        self.ext.gid()
440    }
441
442    #[inline]
443    fn rdev(&self) -> u64 {
444        self.ext.rdev()
445    }
446
447    #[inline]
448    fn size(&self) -> u64 {
449        self.ext.size()
450    }
451
452    #[inline]
453    fn atime(&self) -> i64 {
454        self.ext.atime()
455    }
456
457    #[inline]
458    fn atime_nsec(&self) -> i64 {
459        self.ext.atime_nsec()
460    }
461
462    #[inline]
463    fn mtime(&self) -> i64 {
464        self.ext.mtime()
465    }
466
467    #[inline]
468    fn mtime_nsec(&self) -> i64 {
469        self.ext.mtime_nsec()
470    }
471
472    #[inline]
473    fn ctime(&self) -> i64 {
474        self.ext.ctime()
475    }
476
477    #[inline]
478    fn ctime_nsec(&self) -> i64 {
479        self.ext.ctime_nsec()
480    }
481
482    #[inline]
483    fn blksize(&self) -> u64 {
484        self.ext.blksize()
485    }
486
487    #[inline]
488    fn blocks(&self) -> u64 {
489        self.ext.blocks()
490    }
491}
492
493#[cfg(windows)]
494impl MetadataExt for Metadata {
495    #[inline]
496    fn file_attributes(&self) -> u32 {
497        self.ext.file_attributes()
498    }
499
500    #[inline]
501    fn creation_time(&self) -> u64 {
502        self.ext.creation_time()
503    }
504
505    #[inline]
506    fn last_access_time(&self) -> u64 {
507        self.ext.last_access_time()
508    }
509
510    #[inline]
511    fn last_write_time(&self) -> u64 {
512        self.ext.last_write_time()
513    }
514
515    #[inline]
516    fn file_size(&self) -> u64 {
517        self.ext.file_size()
518    }
519
520    #[inline]
521    #[cfg(windows_by_handle)]
522    fn volume_serial_number(&self) -> Option<u32> {
523        self.ext.volume_serial_number()
524    }
525
526    #[inline]
527    #[cfg(windows_by_handle)]
528    fn number_of_links(&self) -> Option<u32> {
529        self.ext.number_of_links()
530    }
531
532    #[inline]
533    #[cfg(windows_by_handle)]
534    fn file_index(&self) -> Option<u64> {
535        self.ext.file_index()
536    }
537}
538
539#[cfg(windows)]
545#[doc(hidden)]
546pub trait _WindowsByHandle {
547    fn file_attributes(&self) -> u32;
548    fn volume_serial_number(&self) -> Option<u32>;
549    fn number_of_links(&self) -> Option<u32>;
550    fn file_index(&self) -> Option<u64>;
551}