Coverage Report

Created: 2025-11-11 06:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/cap-std-3.4.5/src/fs/file.rs
Line
Count
Source
1
use crate::fs::{Metadata, OpenOptions, Permissions};
2
use cap_primitives::fs::{is_file_read_write, open_ambient};
3
use cap_primitives::AmbientAuthority;
4
#[cfg(not(windows))]
5
use io_extras::os::rustix::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
6
#[cfg(not(windows))]
7
use io_lifetimes::{AsFd, BorrowedFd, OwnedFd};
8
#[cfg(windows)]
9
use io_lifetimes::{AsHandle, BorrowedHandle, OwnedHandle};
10
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
11
use std::path::Path;
12
use std::{fmt, fs, process};
13
#[cfg(windows)]
14
use {
15
    io_extras::os::windows::{
16
        AsHandleOrSocket, AsRawHandleOrSocket, BorrowedHandleOrSocket, IntoRawHandleOrSocket,
17
        OwnedHandleOrSocket, RawHandleOrSocket,
18
    },
19
    std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle},
20
};
21
22
/// A reference to an open file on a filesystem.
23
///
24
/// This corresponds to [`std::fs::File`].
25
///
26
/// This `File` has no `open` or `create` methods. To open or create a file,
27
/// first obtain a [`Dir`] containing the path, and then call [`Dir::open`] or
28
/// [`Dir::create`].
29
///
30
/// [`Dir`]: crate::fs::Dir
31
/// [`Dir::open`]: crate::fs::Dir::open
32
/// [`Dir::create`]: crate::fs::Dir::create
33
pub struct File {
34
    pub(crate) std: fs::File,
35
}
36
37
impl File {
38
    /// Constructs a new instance of `Self` from the given [`std::fs::File`].
39
    ///
40
    /// This grants access the resources the `std::fs::File` instance already
41
    /// has access to.
42
    #[inline]
43
2.23k
    pub fn from_std(std: fs::File) -> Self {
44
2.23k
        Self { std }
45
2.23k
    }
<cap_std::fs::file::File>::from_std
Line
Count
Source
43
2.23k
    pub fn from_std(std: fs::File) -> Self {
44
2.23k
        Self { std }
45
2.23k
    }
Unexecuted instantiation: <cap_std::fs::file::File>::from_std
46
47
    /// Consumes `self` and returns a [`std::fs::File`].
48
    #[inline]
49
0
    pub fn into_std(self) -> fs::File {
50
0
        self.std
51
0
    }
52
53
    /// Attempts to sync all OS-internal metadata to disk.
54
    ///
55
    /// This corresponds to [`std::fs::File::sync_all`].
56
    #[inline]
57
0
    pub fn sync_all(&self) -> io::Result<()> {
58
0
        self.std.sync_all()
59
0
    }
60
61
    /// This function is similar to `sync_all`, except that it may not
62
    /// synchronize file metadata to a filesystem.
63
    ///
64
    /// This corresponds to [`std::fs::File::sync_data`].
65
    #[inline]
66
0
    pub fn sync_data(&self) -> io::Result<()> {
67
0
        self.std.sync_data()
68
0
    }
69
70
    /// Truncates or extends the underlying file, updating the size of this
71
    /// file to become size.
72
    ///
73
    /// This corresponds to [`std::fs::File::set_len`].
74
    #[inline]
75
0
    pub fn set_len(&self, size: u64) -> io::Result<()> {
76
0
        self.std.set_len(size)
77
0
    }
78
79
    /// Queries metadata about the underlying file.
80
    ///
81
    /// This corresponds to [`std::fs::File::metadata`].
82
    #[inline]
83
0
    pub fn metadata(&self) -> io::Result<Metadata> {
84
0
        metadata_from(&self.std)
85
0
    }
86
87
    /// Creates a new `File` instance that shares the same underlying file
88
    /// handle as the existing `File` instance.
89
    ///
90
    /// This corresponds to [`std::fs::File::try_clone`].
91
    #[inline]
92
0
    pub fn try_clone(&self) -> io::Result<Self> {
93
0
        let file = self.std.try_clone()?;
94
0
        Ok(Self::from_std(file))
95
0
    }
96
97
    /// Changes the permissions on the underlying file.
98
    ///
99
    /// This corresponds to [`std::fs::File::set_permissions`].
100
    #[inline]
101
0
    pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
102
0
        self.std
103
0
            .set_permissions(permissions_into_std(&self.std, perm)?)
104
0
    }
105
106
    /// Constructs a new instance of `Self` in read-only mode by opening the
107
    /// given path as a file using the host process' ambient authority.
108
    ///
109
    /// # Ambient Authority
110
    ///
111
    /// This function is not sandboxed and may access any path that the host
112
    /// process has access to.
113
    #[inline]
114
0
    pub fn open_ambient<P: AsRef<Path>>(
115
0
        path: P,
116
0
        ambient_authority: AmbientAuthority,
117
0
    ) -> io::Result<Self> {
118
0
        let std = open_ambient(
119
0
            path.as_ref(),
120
0
            OpenOptions::new().read(true),
121
0
            ambient_authority,
122
0
        )?;
123
0
        Ok(Self::from_std(std))
124
0
    }
125
126
    /// Constructs a new instance of `Self` in write-only mode by opening,
127
    /// creating or truncating, the given path as a file using the host
128
    /// process' ambient authority.
129
    ///
130
    /// # Ambient Authority
131
    ///
132
    /// This function is not sandboxed and may access any path that the host
133
    /// process has access to.
134
    #[inline]
135
0
    pub fn create_ambient<P: AsRef<Path>>(
136
0
        path: P,
137
0
        ambient_authority: AmbientAuthority,
138
0
    ) -> io::Result<Self> {
139
0
        let std = open_ambient(
140
0
            path.as_ref(),
141
0
            OpenOptions::new().write(true).create(true).truncate(true),
142
0
            ambient_authority,
143
0
        )?;
144
0
        Ok(Self::from_std(std))
145
0
    }
146
147
    /// Constructs a new instance of `Self` with the options specified by
148
    /// `options` by opening the given path as a file using the host process'
149
    /// ambient authority.
150
    ///
151
    /// # Ambient Authority
152
    ///
153
    /// This function is not sandboxed and may access any path that the host
154
    /// process has access to.
155
    #[inline]
156
0
    pub fn open_ambient_with<P: AsRef<Path>>(
157
0
        path: P,
158
0
        options: &OpenOptions,
159
0
        ambient_authority: AmbientAuthority,
160
0
    ) -> io::Result<Self> {
161
0
        let std = open_ambient(path.as_ref(), options, ambient_authority)?;
162
0
        Ok(Self::from_std(std))
163
0
    }
164
165
    /// Returns a new `OpenOptions` object.
166
    ///
167
    /// This corresponds to [`std::fs::File::options`].
168
    #[must_use]
169
    #[inline]
170
0
    pub fn options() -> OpenOptions {
171
0
        OpenOptions::new()
172
0
    }
173
}
174
175
#[inline]
176
0
fn metadata_from(file: &fs::File) -> io::Result<Metadata> {
177
0
    Metadata::from_file(file)
178
0
}
179
180
#[inline]
181
0
fn permissions_into_std(file: &fs::File, permissions: Permissions) -> io::Result<fs::Permissions> {
182
0
    permissions.into_std(file)
183
0
}
184
185
// Safety: `FilelikeViewType` is implemented for `std::fs::File`.
186
unsafe impl io_lifetimes::views::FilelikeViewType for File {}
187
188
#[cfg(not(windows))]
189
impl FromRawFd for File {
190
    #[inline]
191
0
    unsafe fn from_raw_fd(fd: RawFd) -> Self {
192
0
        Self::from_std(fs::File::from_raw_fd(fd))
193
0
    }
194
}
195
196
#[cfg(not(windows))]
197
impl From<OwnedFd> for File {
198
    #[inline]
199
0
    fn from(fd: OwnedFd) -> Self {
200
0
        Self::from_std(fs::File::from(fd))
201
0
    }
202
}
203
204
#[cfg(windows)]
205
impl FromRawHandle for File {
206
    #[inline]
207
    unsafe fn from_raw_handle(handle: RawHandle) -> Self {
208
        Self::from_std(fs::File::from_raw_handle(handle))
209
    }
210
}
211
212
#[cfg(windows)]
213
impl From<OwnedHandle> for File {
214
    #[inline]
215
    fn from(handle: OwnedHandle) -> Self {
216
        Self::from_std(fs::File::from(handle))
217
    }
218
}
219
220
#[cfg(not(windows))]
221
impl AsRawFd for File {
222
    #[inline]
223
0
    fn as_raw_fd(&self) -> RawFd {
224
0
        self.std.as_raw_fd()
225
0
    }
226
}
227
228
#[cfg(not(windows))]
229
impl AsFd for File {
230
    #[inline]
231
0
    fn as_fd(&self) -> BorrowedFd<'_> {
232
0
        self.std.as_fd()
233
0
    }
234
}
235
236
#[cfg(windows)]
237
impl AsRawHandle for File {
238
    #[inline]
239
    fn as_raw_handle(&self) -> RawHandle {
240
        self.std.as_raw_handle()
241
    }
242
}
243
244
#[cfg(windows)]
245
impl AsHandle for File {
246
    #[inline]
247
    fn as_handle(&self) -> BorrowedHandle<'_> {
248
        self.std.as_handle()
249
    }
250
}
251
252
#[cfg(windows)]
253
impl AsRawHandleOrSocket for File {
254
    #[inline]
255
    fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
256
        self.std.as_raw_handle_or_socket()
257
    }
258
}
259
260
#[cfg(windows)]
261
impl AsHandleOrSocket for File {
262
    #[inline]
263
    fn as_handle_or_socket(&self) -> BorrowedHandleOrSocket<'_> {
264
        self.std.as_handle_or_socket()
265
    }
266
}
267
268
#[cfg(not(windows))]
269
impl IntoRawFd for File {
270
    #[inline]
271
0
    fn into_raw_fd(self) -> RawFd {
272
0
        self.std.into_raw_fd()
273
0
    }
274
}
275
276
#[cfg(not(windows))]
277
impl From<File> for OwnedFd {
278
    #[inline]
279
0
    fn from(file: File) -> OwnedFd {
280
0
        file.std.into()
281
0
    }
282
}
283
284
#[cfg(windows)]
285
impl IntoRawHandle for File {
286
    #[inline]
287
    fn into_raw_handle(self) -> RawHandle {
288
        self.std.into_raw_handle()
289
    }
290
}
291
292
#[cfg(windows)]
293
impl From<File> for OwnedHandle {
294
    #[inline]
295
    fn from(file: File) -> OwnedHandle {
296
        file.std.into()
297
    }
298
}
299
300
#[cfg(windows)]
301
impl IntoRawHandleOrSocket for File {
302
    #[inline]
303
    fn into_raw_handle_or_socket(self) -> RawHandleOrSocket {
304
        self.std.into_raw_handle_or_socket()
305
    }
306
}
307
308
#[cfg(windows)]
309
impl From<File> for OwnedHandleOrSocket {
310
    #[inline]
311
    fn from(file: File) -> Self {
312
        file.std.into()
313
    }
314
}
315
316
impl Read for File {
317
    #[inline]
318
2.23k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
319
2.23k
        self.std.read(buf)
320
2.23k
    }
<cap_std::fs::file::File as std::io::Read>::read
Line
Count
Source
318
2.23k
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
319
2.23k
        self.std.read(buf)
320
2.23k
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read
321
322
    #[inline]
323
0
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
324
0
        self.std.read_vectored(bufs)
325
0
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_vectored
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_vectored
326
327
    #[inline]
328
0
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
329
0
        self.std.read_exact(buf)
330
0
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_exact
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_exact
331
332
    #[inline]
333
0
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
334
0
        self.std.read_to_end(buf)
335
0
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_to_end
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_to_end
336
337
    #[inline]
338
0
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
339
0
        self.std.read_to_string(buf)
340
0
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_to_string
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::read_to_string
341
342
    #[cfg(can_vector)]
343
    #[inline]
344
0
    fn is_read_vectored(&self) -> bool {
345
0
        self.std.is_read_vectored()
346
0
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::is_read_vectored
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Read>::is_read_vectored
347
}
348
349
impl Read for &File {
350
    #[inline]
351
0
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
352
0
        (&mut &self.std).read(buf)
353
0
    }
354
355
    #[inline]
356
0
    fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
357
0
        (&mut &self.std).read_vectored(bufs)
358
0
    }
359
360
    #[inline]
361
0
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
362
0
        (&mut &self.std).read_exact(buf)
363
0
    }
364
365
    #[inline]
366
0
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
367
0
        (&mut &self.std).read_to_end(buf)
368
0
    }
369
370
    #[inline]
371
0
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
372
0
        (&mut &self.std).read_to_string(buf)
373
0
    }
374
375
    #[cfg(can_vector)]
376
    #[inline]
377
0
    fn is_read_vectored(&self) -> bool {
378
0
        self.std.is_read_vectored()
379
0
    }
380
}
381
382
impl Write for File {
383
    #[inline]
384
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
385
0
        self.std.write(buf)
386
0
    }
387
388
    #[inline]
389
0
    fn flush(&mut self) -> io::Result<()> {
390
0
        self.std.flush()
391
0
    }
392
393
    #[inline]
394
0
    fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
395
0
        self.std.write_vectored(bufs)
396
0
    }
397
398
    #[inline]
399
2.23k
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
400
2.23k
        self.std.write_all(buf)
401
2.23k
    }
<cap_std::fs::file::File as std::io::Write>::write_all
Line
Count
Source
399
2.23k
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
400
2.23k
        self.std.write_all(buf)
401
2.23k
    }
Unexecuted instantiation: <cap_std::fs::file::File as std::io::Write>::write_all
402
403
    #[cfg(can_vector)]
404
    #[inline]
405
0
    fn is_write_vectored(&self) -> bool {
406
0
        self.std.is_write_vectored()
407
0
    }
408
409
    #[cfg(write_all_vectored)]
410
    #[inline]
411
0
    fn write_all_vectored(&mut self, bufs: &mut [IoSlice]) -> io::Result<()> {
412
0
        self.std.write_all_vectored(bufs)
413
0
    }
414
}
415
416
impl Write for &File {
417
    #[inline]
418
0
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
419
0
        (&mut &self.std).write(buf)
420
0
    }
421
422
    #[inline]
423
0
    fn flush(&mut self) -> io::Result<()> {
424
0
        (&mut &self.std).flush()
425
0
    }
426
427
    #[inline]
428
0
    fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
429
0
        (&mut &self.std).write_vectored(bufs)
430
0
    }
431
432
    #[inline]
433
0
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
434
0
        (&mut &self.std).write_all(buf)
435
0
    }
436
437
    #[cfg(can_vector)]
438
    #[inline]
439
0
    fn is_write_vectored(&self) -> bool {
440
0
        self.std.is_write_vectored()
441
0
    }
442
443
    #[cfg(write_all_vectored)]
444
    #[inline]
445
0
    fn write_all_vectored(&mut self, bufs: &mut [IoSlice]) -> io::Result<()> {
446
0
        (&mut &self.std).write_all_vectored(bufs)
447
0
    }
448
}
449
450
impl Seek for File {
451
    #[inline]
452
0
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
453
0
        self.std.seek(pos)
454
0
    }
455
456
    #[inline]
457
0
    fn stream_position(&mut self) -> io::Result<u64> {
458
0
        self.std.stream_position()
459
0
    }
460
}
461
462
impl Seek for &File {
463
    #[inline]
464
0
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
465
0
        (&mut &self.std).seek(pos)
466
0
    }
467
468
    #[inline]
469
0
    fn stream_position(&mut self) -> io::Result<u64> {
470
0
        (&mut &self.std).stream_position()
471
0
    }
472
}
473
474
impl From<File> for process::Stdio {
475
    #[inline]
476
0
    fn from(file: File) -> Self {
477
0
        From::<fs::File>::from(file.std)
478
0
    }
479
}
480
481
#[cfg(unix)]
482
impl crate::fs::FileExt for File {
483
    #[inline]
484
0
    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
485
0
        std::os::unix::fs::FileExt::read_at(&self.std, buf, offset)
486
0
    }
487
488
    #[inline]
489
0
    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
490
0
        std::os::unix::fs::FileExt::write_at(&self.std, buf, offset)
491
0
    }
492
493
    #[inline]
494
0
    fn read_exact_at(&self, buf: &mut [u8], offset: u64) -> io::Result<()> {
495
0
        std::os::unix::fs::FileExt::read_exact_at(&self.std, buf, offset)
496
0
    }
497
498
    #[inline]
499
0
    fn write_all_at(&self, buf: &[u8], offset: u64) -> io::Result<()> {
500
0
        std::os::unix::fs::FileExt::write_all_at(&self.std, buf, offset)
501
0
    }
502
}
503
504
#[cfg(target_os = "wasi")]
505
impl crate::fs::FileExt for File {
506
    #[inline]
507
    fn read_at(&self, bufs: &mut [u8], offset: u64) -> io::Result<usize> {
508
        std::os::wasi::fs::FileExt::read_at(&self.std, bufs, offset)
509
    }
510
511
    #[inline]
512
    fn write_at(&self, bufs: &[u8], offset: u64) -> io::Result<usize> {
513
        std::os::wasi::fs::FileExt::write_at(&self.std, bufs, offset)
514
    }
515
516
    #[inline]
517
    fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result<usize> {
518
        std::os::wasi::fs::FileExt::read_vectored_at(&self.std, bufs, offset)
519
    }
520
521
    #[inline]
522
    fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result<usize> {
523
        std::os::wasi::fs::FileExt::write_vectored_at(&self.std, bufs, offset)
524
    }
525
526
    #[inline]
527
    fn fdstat_set_flags(&self, flags: u16) -> std::result::Result<(), io::Error> {
528
        std::os::wasi::fs::FileExt::fdstat_set_flags(&self.std, flags)
529
    }
530
531
    #[inline]
532
    fn fdstat_set_rights(
533
        &self,
534
        rights: u64,
535
        inheriting: u64,
536
    ) -> std::result::Result<(), io::Error> {
537
        std::os::wasi::fs::FileExt::fdstat_set_rights(&self.std, rights, inheriting)
538
    }
539
540
    #[inline]
541
    fn advise(&self, offset: u64, len: u64, advice: u8) -> std::result::Result<(), io::Error> {
542
        std::os::wasi::fs::FileExt::advise(&self.std, offset, len, advice)
543
    }
544
545
    #[inline]
546
    fn allocate(&self, offset: u64, len: u64) -> std::result::Result<(), io::Error> {
547
        std::os::wasi::fs::FileExt::allocate(&self.std, offset, len)
548
    }
549
550
    #[inline]
551
    fn create_directory<P: AsRef<Path>>(&self, dir: P) -> std::result::Result<(), io::Error> {
552
        std::os::wasi::fs::FileExt::create_directory(&self.std, dir)
553
    }
554
555
    #[inline]
556
    fn read_link<P: AsRef<Path>>(
557
        &self,
558
        path: P,
559
    ) -> std::result::Result<std::path::PathBuf, io::Error> {
560
        std::os::wasi::fs::FileExt::read_link(&self.std, path)
561
    }
562
563
    #[inline]
564
    fn metadata_at<P: AsRef<Path>>(
565
        &self,
566
        lookup_flags: u32,
567
        path: P,
568
    ) -> std::result::Result<std::fs::Metadata, io::Error> {
569
        std::os::wasi::fs::FileExt::metadata_at(&self.std, lookup_flags, path)
570
    }
571
572
    #[inline]
573
    fn remove_file<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), io::Error> {
574
        std::os::wasi::fs::FileExt::remove_file(&self.std, path)
575
    }
576
577
    #[inline]
578
    fn remove_directory<P: AsRef<Path>>(&self, path: P) -> std::result::Result<(), io::Error> {
579
        std::os::wasi::fs::FileExt::remove_directory(&self.std, path)
580
    }
581
}
582
583
#[cfg(windows)]
584
impl crate::fs::FileExt for File {
585
    #[inline]
586
    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
587
        std::os::windows::fs::FileExt::seek_read(&self.std, buf, offset)
588
    }
589
590
    #[inline]
591
    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
592
        std::os::windows::fs::FileExt::seek_write(&self.std, buf, offset)
593
    }
594
}
595
596
impl fmt::Debug for File {
597
    // Like libstd's version, but doesn't print the path.
598
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
599
0
        let mut b = f.debug_struct("File");
600
        #[cfg(not(windows))]
601
0
        b.field("fd", &self.std.as_raw_fd());
602
        #[cfg(windows)]
603
        b.field("handle", &self.std.as_raw_handle());
604
0
        if let Ok((read, write)) = is_file_read_write(&self.std) {
605
0
            b.field("read", &read).field("write", &write);
606
0
        }
607
0
        b.finish()
608
0
    }
609
}