cap_std/fs_utf8/
file.rs

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