Coverage Report

Created: 2025-07-12 06:48

/rust/registry/src/index.crates.io-6f17d22bba15001f/cap-primitives-3.4.4/src/fs/metadata.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::fs::{FileType, ImplFileTypeExt, ImplMetadataExt, Permissions};
2
use crate::time::SystemTime;
3
use std::{fs, io};
4
5
/// Metadata information about a file.
6
///
7
/// This corresponds to [`std::fs::Metadata`].
8
///
9
/// <details>
10
/// We need to define our own version because the libstd `Metadata` doesn't
11
/// have a public constructor that we can use.
12
/// </details>
13
#[derive(Debug, Clone)]
14
pub 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)]
25
impl Metadata {
26
    /// Constructs a new instance of `Self` from the given [`std::fs::File`].
27
    #[inline]
28
144k
    pub fn from_file(file: &fs::File) -> io::Result<Self> {
29
144k
        let std = file.metadata()?;
30
144k
        let ext = ImplMetadataExt::from(file, &std)?;
31
144k
        let file_type = ImplFileTypeExt::from(file, &std)?;
32
144k
        Ok(Self::from_parts(std, ext, file_type))
33
144k
    }
Unexecuted instantiation: <cap_primitives::fs::metadata::Metadata>::from_file
<cap_primitives::fs::metadata::Metadata>::from_file
Line
Count
Source
28
144k
    pub fn from_file(file: &fs::File) -> io::Result<Self> {
29
144k
        let std = file.metadata()?;
30
144k
        let ext = ImplMetadataExt::from(file, &std)?;
31
144k
        let file_type = ImplFileTypeExt::from(file, &std)?;
32
144k
        Ok(Self::from_parts(std, ext, file_type))
33
144k
    }
34
35
    /// Constructs a new instance of `Self` from the given
36
    /// [`std::fs::Metadata`].
37
    ///
38
    /// As with the comments in [`std::fs::Metadata::volume_serial_number`] and
39
    /// nearby functions, some fields of the resulting metadata will be `None`.
40
    ///
41
    /// [`std::fs::Metadata::volume_serial_number`]: https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html#tymethod.volume_serial_number
42
    #[inline]
43
0
    pub fn from_just_metadata(std: fs::Metadata) -> Self {
44
0
        let ext = ImplMetadataExt::from_just_metadata(&std);
45
0
        let file_type = ImplFileTypeExt::from_just_metadata(&std);
46
0
        Self::from_parts(std, ext, file_type)
47
0
    }
48
49
    #[inline]
50
144k
    fn from_parts(std: fs::Metadata, ext: ImplMetadataExt, file_type: FileType) -> Self {
51
144k
        Self {
52
144k
            file_type,
53
144k
            len: std.len(),
54
144k
            permissions: Permissions::from_std(std.permissions()),
55
144k
            modified: std.modified().ok().map(SystemTime::from_std),
56
144k
            accessed: std.accessed().ok().map(SystemTime::from_std),
57
144k
            created: std.created().ok().map(SystemTime::from_std),
58
144k
            ext,
59
144k
        }
60
144k
    }
Unexecuted instantiation: <cap_primitives::fs::metadata::Metadata>::from_parts
<cap_primitives::fs::metadata::Metadata>::from_parts
Line
Count
Source
50
144k
    fn from_parts(std: fs::Metadata, ext: ImplMetadataExt, file_type: FileType) -> Self {
51
144k
        Self {
52
144k
            file_type,
53
144k
            len: std.len(),
54
144k
            permissions: Permissions::from_std(std.permissions()),
55
144k
            modified: std.modified().ok().map(SystemTime::from_std),
56
144k
            accessed: std.accessed().ok().map(SystemTime::from_std),
57
144k
            created: std.created().ok().map(SystemTime::from_std),
58
144k
            ext,
59
144k
        }
60
144k
    }
61
62
    /// Returns the file type for this metadata.
63
    ///
64
    /// This corresponds to [`std::fs::Metadata::file_type`].
65
    #[inline]
66
0
    pub const fn file_type(&self) -> FileType {
67
0
        self.file_type
68
0
    }
69
70
    /// Returns `true` if this metadata is for a directory.
71
    ///
72
    /// This corresponds to [`std::fs::Metadata::is_dir`].
73
    #[inline]
74
144k
    pub fn is_dir(&self) -> bool {
75
144k
        self.file_type.is_dir()
76
144k
    }
<cap_primitives::fs::metadata::Metadata>::is_dir
Line
Count
Source
74
144k
    pub fn is_dir(&self) -> bool {
75
144k
        self.file_type.is_dir()
76
144k
    }
Unexecuted instantiation: <cap_primitives::fs::metadata::Metadata>::is_dir
77
78
    /// Returns `true` if this metadata is for a regular file.
79
    ///
80
    /// This corresponds to [`std::fs::Metadata::is_file`].
81
    #[inline]
82
0
    pub fn is_file(&self) -> bool {
83
0
        self.file_type.is_file()
84
0
    }
85
86
    /// Returns `true` if this metadata is for a symbolic link.
87
    ///
88
    /// This corresponds to [`std::fs::Metadata::is_symlink`].
89
    #[inline]
90
0
    pub fn is_symlink(&self) -> bool {
91
0
        self.file_type.is_symlink()
92
0
    }
93
94
    /// Returns the size of the file, in bytes, this metadata is for.
95
    ///
96
    /// This corresponds to [`std::fs::Metadata::len`].
97
    #[inline]
98
0
    pub const fn len(&self) -> u64 {
99
0
        self.len
100
0
    }
Unexecuted instantiation: <cap_primitives::fs::metadata::Metadata>::len
Unexecuted instantiation: <cap_primitives::fs::metadata::Metadata>::len
101
102
    /// Returns the permissions of the file this metadata is for.
103
    ///
104
    /// This corresponds to [`std::fs::Metadata::permissions`].
105
    #[inline]
106
0
    pub fn permissions(&self) -> Permissions {
107
0
        self.permissions.clone()
108
0
    }
109
110
    /// Returns the last modification time listed in this metadata.
111
    ///
112
    /// This corresponds to [`std::fs::Metadata::modified`].
113
    #[inline]
114
0
    pub fn modified(&self) -> io::Result<SystemTime> {
115
0
        #[cfg(io_error_uncategorized)]
116
0
        {
117
0
            self.modified.ok_or_else(|| {
118
0
                io::Error::new(
119
0
                    io::ErrorKind::Unsupported,
120
0
                    "modified time metadata not available on this platform",
121
0
                )
122
0
            })
123
0
        }
124
0
        #[cfg(not(io_error_uncategorized))]
125
0
        {
126
0
            self.modified.ok_or_else(|| {
127
0
                io::Error::new(
128
0
                    io::ErrorKind::Other,
129
0
                    "modified time metadata not available on this platform",
130
0
                )
131
0
            })
132
0
        }
133
0
    }
134
135
    /// Returns the last access time of this metadata.
136
    ///
137
    /// This corresponds to [`std::fs::Metadata::accessed`].
138
    #[inline]
139
0
    pub fn accessed(&self) -> io::Result<SystemTime> {
140
0
        #[cfg(io_error_uncategorized)]
141
0
        {
142
0
            self.accessed.ok_or_else(|| {
143
0
                io::Error::new(
144
0
                    io::ErrorKind::Unsupported,
145
0
                    "accessed time metadata not available on this platform",
146
0
                )
147
0
            })
148
0
        }
149
0
        #[cfg(not(io_error_uncategorized))]
150
0
        {
151
0
            self.accessed.ok_or_else(|| {
152
0
                io::Error::new(
153
0
                    io::ErrorKind::Other,
154
0
                    "accessed time metadata not available on this platform",
155
0
                )
156
0
            })
157
0
        }
158
0
    }
159
160
    /// Returns the creation time listed in this metadata.
161
    ///
162
    /// This corresponds to [`std::fs::Metadata::created`].
163
    #[inline]
164
0
    pub fn created(&self) -> io::Result<SystemTime> {
165
0
        #[cfg(io_error_uncategorized)]
166
0
        {
167
0
            self.created.ok_or_else(|| {
168
0
                io::Error::new(
169
0
                    io::ErrorKind::Unsupported,
170
0
                    "created time metadata not available on this platform",
171
0
                )
172
0
            })
173
0
        }
174
0
        #[cfg(not(io_error_uncategorized))]
175
0
        {
176
0
            self.created.ok_or_else(|| {
177
0
                io::Error::new(
178
0
                    io::ErrorKind::Other,
179
0
                    "created time metadata not available on this platform",
180
0
                )
181
0
            })
182
0
        }
183
0
    }
184
185
    /// Determine if `self` and `other` refer to the same inode on the same
186
    /// device.
187
    #[cfg(any(not(windows), windows_by_handle))]
188
0
    pub(crate) fn is_same_file(&self, other: &Self) -> bool {
189
0
        self.ext.is_same_file(&other.ext)
190
0
    }
191
192
    /// `MetadataExt` requires nightly to be implemented, but we sometimes
193
    /// just need the file attributes.
194
    #[cfg(windows)]
195
    #[inline]
196
    pub(crate) fn file_attributes(&self) -> u32 {
197
        self.ext.file_attributes()
198
    }
199
}
200
201
/// Unix-specific extensions for [`MetadataExt`].
202
///
203
/// This corresponds to [`std::os::unix::fs::MetadataExt`].
204
#[cfg(any(unix, target_os = "vxworks"))]
205
pub trait MetadataExt {
206
    /// Returns the ID of the device containing the file.
207
    fn dev(&self) -> u64;
208
    /// Returns the inode number.
209
    fn ino(&self) -> u64;
210
    /// Returns the rights applied to this file.
211
    fn mode(&self) -> u32;
212
    /// Returns the number of hard links pointing to this file.
213
    fn nlink(&self) -> u64;
214
    /// Returns the user ID of the owner of this file.
215
    fn uid(&self) -> u32;
216
    /// Returns the group ID of the owner of this file.
217
    fn gid(&self) -> u32;
218
    /// Returns the device ID of this file (if it is a special one).
219
    fn rdev(&self) -> u64;
220
    /// Returns the total size of this file in bytes.
221
    fn size(&self) -> u64;
222
    /// Returns the last access time of the file, in seconds since Unix Epoch.
223
    fn atime(&self) -> i64;
224
    /// Returns the last access time of the file, in nanoseconds since [`atime`].
225
    fn atime_nsec(&self) -> i64;
226
    /// Returns the last modification time of the file, in seconds since Unix Epoch.
227
    fn mtime(&self) -> i64;
228
    /// Returns the last modification time of the file, in nanoseconds since [`mtime`].
229
    fn mtime_nsec(&self) -> i64;
230
    /// Returns the last status change time of the file, in seconds since Unix Epoch.
231
    fn ctime(&self) -> i64;
232
    /// Returns the last status change time of the file, in nanoseconds since [`ctime`].
233
    fn ctime_nsec(&self) -> i64;
234
    /// Returns the block size for filesystem I/O.
235
    fn blksize(&self) -> u64;
236
    /// Returns the number of blocks allocated to the file, in 512-byte units.
237
    fn blocks(&self) -> u64;
238
    #[cfg(target_os = "vxworks")]
239
    fn attrib(&self) -> u8;
240
}
241
242
/// WASI-specific extensions for [`MetadataExt`].
243
///
244
/// This corresponds to [`std::os::wasi::fs::MetadataExt`].
245
#[cfg(target_os = "wasi")]
246
pub trait MetadataExt {
247
    /// Returns the ID of the device containing the file.
248
    fn dev(&self) -> u64;
249
    /// Returns the inode number.
250
    fn ino(&self) -> u64;
251
    /// Returns the number of hard links pointing to this file.
252
    fn nlink(&self) -> u64;
253
    /// Returns the total size of this file in bytes.
254
    fn size(&self) -> u64;
255
    /// Returns the last access time of the file, in seconds since Unix Epoch.
256
    fn atim(&self) -> u64;
257
    /// Returns the last modification time of the file, in seconds since Unix Epoch.
258
    fn mtim(&self) -> u64;
259
    /// Returns the last status change time of the file, in seconds since Unix Epoch.
260
    fn ctim(&self) -> u64;
261
}
262
263
/// Windows-specific extensions to [`Metadata`].
264
///
265
/// This corresponds to [`std::os::windows::fs::MetadataExt`].
266
#[cfg(windows)]
267
pub trait MetadataExt {
268
    /// Returns the value of the `dwFileAttributes` field of this metadata.
269
    fn file_attributes(&self) -> u32;
270
    /// Returns the value of the `ftCreationTime` field of this metadata.
271
    fn creation_time(&self) -> u64;
272
    /// Returns the value of the `ftLastAccessTime` field of this metadata.
273
    fn last_access_time(&self) -> u64;
274
    /// Returns the value of the `ftLastWriteTime` field of this metadata.
275
    fn last_write_time(&self) -> u64;
276
    /// Returns the value of the `nFileSize{High,Low}` fields of this metadata.
277
    fn file_size(&self) -> u64;
278
    /// Returns the value of the `dwVolumeSerialNumber` field of this metadata.
279
    #[cfg(windows_by_handle)]
280
    fn volume_serial_number(&self) -> Option<u32>;
281
    /// Returns the value of the `nNumberOfLinks` field of this metadata.
282
    #[cfg(windows_by_handle)]
283
    fn number_of_links(&self) -> Option<u32>;
284
    /// Returns the value of the `nFileIndex{Low,High}` fields of this metadata.
285
    #[cfg(windows_by_handle)]
286
    fn file_index(&self) -> Option<u64>;
287
}
288
289
#[cfg(unix)]
290
impl MetadataExt for Metadata {
291
    #[inline]
292
0
    fn dev(&self) -> u64 {
293
0
        crate::fs::MetadataExt::dev(&self.ext)
294
0
    }
295
296
    #[inline]
297
0
    fn ino(&self) -> u64 {
298
0
        crate::fs::MetadataExt::ino(&self.ext)
299
0
    }
300
301
    #[inline]
302
0
    fn mode(&self) -> u32 {
303
0
        crate::fs::MetadataExt::mode(&self.ext)
304
0
    }
305
306
    #[inline]
307
0
    fn nlink(&self) -> u64 {
308
0
        crate::fs::MetadataExt::nlink(&self.ext)
309
0
    }
310
311
    #[inline]
312
0
    fn uid(&self) -> u32 {
313
0
        crate::fs::MetadataExt::uid(&self.ext)
314
0
    }
315
316
    #[inline]
317
0
    fn gid(&self) -> u32 {
318
0
        crate::fs::MetadataExt::gid(&self.ext)
319
0
    }
320
321
    #[inline]
322
0
    fn rdev(&self) -> u64 {
323
0
        crate::fs::MetadataExt::rdev(&self.ext)
324
0
    }
325
326
    #[inline]
327
0
    fn size(&self) -> u64 {
328
0
        crate::fs::MetadataExt::size(&self.ext)
329
0
    }
330
331
    #[inline]
332
0
    fn atime(&self) -> i64 {
333
0
        crate::fs::MetadataExt::atime(&self.ext)
334
0
    }
335
336
    #[inline]
337
0
    fn atime_nsec(&self) -> i64 {
338
0
        crate::fs::MetadataExt::atime_nsec(&self.ext)
339
0
    }
340
341
    #[inline]
342
0
    fn mtime(&self) -> i64 {
343
0
        crate::fs::MetadataExt::mtime(&self.ext)
344
0
    }
345
346
    #[inline]
347
0
    fn mtime_nsec(&self) -> i64 {
348
0
        crate::fs::MetadataExt::mtime_nsec(&self.ext)
349
0
    }
350
351
    #[inline]
352
0
    fn ctime(&self) -> i64 {
353
0
        crate::fs::MetadataExt::ctime(&self.ext)
354
0
    }
355
356
    #[inline]
357
0
    fn ctime_nsec(&self) -> i64 {
358
0
        crate::fs::MetadataExt::ctime_nsec(&self.ext)
359
0
    }
360
361
    #[inline]
362
0
    fn blksize(&self) -> u64 {
363
0
        crate::fs::MetadataExt::blksize(&self.ext)
364
0
    }
365
366
    #[inline]
367
0
    fn blocks(&self) -> u64 {
368
0
        crate::fs::MetadataExt::blocks(&self.ext)
369
0
    }
370
}
371
372
#[cfg(target_os = "wasi")]
373
impl 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")]
411
impl 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)]
494
impl 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
/// Extension trait to allow `volume_serial_number` etc. to be exposed by
540
/// the `cap-fs-ext` crate.
541
///
542
/// This is hidden from the main API since this functionality isn't present in
543
/// `std`. Use `cap_fs_ext::MetadataExt` instead of calling this directly.
544
#[cfg(windows)]
545
#[doc(hidden)]
546
pub 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
}