linux_io/
fd.rs

1use linux_unsafe::args::AsRawV;
2use linux_unsafe::void;
3
4use crate::result::{self, Result};
5use crate::seek::SeekFrom;
6
7use core::cell::UnsafeCell;
8use core::ffi::CStr;
9use core::mem::MaybeUninit;
10
11use self::ioctl::SubDevice;
12
13pub mod fcntl;
14pub mod ioctl;
15pub mod sockopt;
16
17mod direntry;
18pub use direntry::*;
19
20/// An encapsulated Linux file descriptor.
21///
22/// The methods of `File` are largely just thin wrappers around Linux system
23/// calls that work with file descriptors. Aside from type conversions to make
24/// the API safer and more ergonomic there are no additional userspace
25/// abstractions such as buffering.
26///
27/// When the `std` crate feature is enabled, a `File` also implements the
28/// `std:io` traits `Read`, `Write`, and `Seek`.
29///
30/// A `File` can have an optional `Device` type parameter, which if set to
31/// an implementation of `IODevice` enables the `ioctl` method to accept
32/// request constants that are declared as being compatible with that device.
33/// Otherwise, the `ioctl` method is unavailable.
34#[repr(transparent)]
35pub struct File<Device = ()> {
36    pub(crate) fd: linux_unsafe::int,
37    _phantom: core::marker::PhantomData<Device>,
38}
39
40impl File<()> {
41    /// Open an existing file.
42    ///
43    /// Use this function for `OpenOptions` that don't require a mode. If you
44    /// set the "create" option then you will need to use
45    /// [`Self::open_with_mode`] instead, to specify the mode of the new file.
46    #[inline(always)]
47    pub fn open(path: &CStr, options: OpenOptions<OpenWithoutMode>) -> Result<Self> {
48        Self::open_raw(path, options.flags, 0)
49    }
50
51    /// Open a file, creating it if necessary using the given file mode.
52    ///
53    /// Use this function only for `OpenOptions` that require a mode. For
54    /// most options you can use [`Self::open`] instead.
55    #[inline(always)]
56    pub fn open_with_mode(
57        path: &CStr,
58        options: OpenOptions<OpenWithMode>,
59        mode: linux_unsafe::mode_t,
60    ) -> Result<Self> {
61        Self::open_raw(path, options.flags, mode)
62    }
63
64    /// Open a file using the `openat` system call.
65    ///
66    /// This function exposes the raw `flags` and `mode` arguments from the
67    /// underlying system call, which the caller must populate appropriately.
68    #[inline]
69    pub fn open_raw(
70        path: &CStr,
71        flags: linux_unsafe::int,
72        mode: linux_unsafe::mode_t,
73    ) -> Result<Self> {
74        let path_raw = path.as_ptr() as *const linux_unsafe::char;
75        let result = unsafe {
76            linux_unsafe::openat(
77                linux_unsafe::AT_FDCWD,
78                path_raw,
79                flags as linux_unsafe::int,
80                mode as linux_unsafe::mode_t,
81            )
82        };
83        result
84            .map(|fd| unsafe { Self::from_raw_fd(fd as linux_unsafe::int) })
85            .map_err(|e| e.into())
86    }
87
88    /// Create a new file using the `openat` system call.
89    ///
90    /// This function exposes the raw `mode` argument from the underlying
91    /// system call, which the caller must populate appropriately.
92    #[inline]
93    pub fn create_raw(path: &CStr, mode: linux_unsafe::mode_t) -> Result<Self> {
94        let path_raw = path.as_ptr() as *const linux_unsafe::char;
95        let result = unsafe {
96            linux_unsafe::openat(
97                linux_unsafe::AT_FDCWD,
98                path_raw,
99                linux_unsafe::O_CREAT | linux_unsafe::O_WRONLY | linux_unsafe::O_TRUNC,
100                mode as linux_unsafe::mode_t,
101            )
102        };
103        result
104            .map(|fd| unsafe { Self::from_raw_fd(fd as linux_unsafe::int) })
105            .map_err(|e| e.into())
106    }
107
108    /// Create a new socket using the `socket` system call.
109    ///
110    /// The protocol is specifed as a special typed constant which carries
111    /// both the protocol number expected by the kernel and the device type
112    /// to use for the returned file, so the result can accept `ioctl`
113    /// requests that are defined for that specific protocol.
114    #[inline]
115    pub fn socket<Protocol: super::socket::SocketProtocol>(
116        domain: linux_unsafe::sa_family_t,
117        typ: crate::socket::sock_type,
118        protocol: Protocol,
119    ) -> Result<File<Protocol::Device>> {
120        let result = unsafe { linux_unsafe::socket(domain, typ, protocol.raw_protocol_num()) };
121        result
122            .map(|fd| unsafe { File::from_raw_fd(fd as linux_unsafe::int) })
123            .map_err(|e| e.into())
124    }
125
126    /// Create a new socket using the `socket` system call without automatically
127    /// assigning a device type based on the protocol.
128    ///
129    /// This is similar to [`Self::socket`] but allows specifying any arbitrary
130    /// protocol number without needing a special implementation of
131    /// [`super::socket::SocketProtocol`]. However, that means that the result
132    /// will be typed only as a generic socket and so will not accept any
133    /// protocol-specific `ioctl` requests.
134    #[inline]
135    pub fn socket_raw<Protocol: super::socket::SocketProtocol>(
136        domain: linux_unsafe::sa_family_t,
137        typ: crate::socket::sock_type,
138        protocol: linux_unsafe::int,
139    ) -> Result<File<crate::socket::SocketDevice>> {
140        let result = unsafe { linux_unsafe::socket(domain, typ, protocol) };
141        result
142            .map(|fd| unsafe { File::from_raw_fd(fd as linux_unsafe::int) })
143            .map_err(|e| e.into())
144    }
145}
146
147impl<Device> File<Device> {
148    /// Wrap an existing raw file descriptor into a [`File`].
149    ///
150    /// Safety:
151    /// - The given file descriptor must not belong to an active standard
152    ///   library file or any similar wrapping abstraction.
153    /// - The file descriptor must remain open and valid for the full lifetime
154    ///   of the `File` object.
155    /// - The same file descriptor must not be wrapped in instances of
156    ///   `File`, because the first one to be dropped will close the file
157    ///   descriptor.
158    #[inline]
159    pub unsafe fn from_raw_fd(fd: linux_unsafe::int) -> Self {
160        File {
161            fd,
162            _phantom: core::marker::PhantomData,
163        }
164    }
165
166    /// Creates a new file descriptor referring to the same underlying file
167    /// description as `self`.
168    ///
169    /// Note that the read/write position of a file is a property of its file
170    /// description rather than its descriptor, and so modifying the position
171    /// (and some other aspects) of the new file will also affect the original.
172    #[inline]
173    pub fn duplicate(&self) -> Result<Self> {
174        let result = unsafe { linux_unsafe::dup(self.fd) };
175        result
176            .map(|fd| unsafe { Self::from_raw_fd(fd) })
177            .map_err(|e| e.into())
178    }
179
180    /// Open a file relative to the current file, which must represent a
181    /// directory.
182    #[inline]
183    pub fn open_relative(
184        &self,
185        path: &CStr,
186        options: OpenOptions<OpenWithoutMode>,
187    ) -> Result<File<()>> {
188        self.open_relative_raw(path, options.flags, 0)
189    }
190
191    /// Open a file relative to the current file, which must represent a
192    /// directory.
193    #[inline]
194    pub fn open_relative_with_mode(
195        &self,
196        path: &CStr,
197        options: OpenOptions<OpenWithMode>,
198        mode: linux_unsafe::mode_t,
199    ) -> Result<File<()>> {
200        self.open_relative_raw(path, options.flags, mode)
201    }
202
203    /// Open a file using the `openat` system call.
204    ///
205    /// This function exposes the raw `flags` and `mode` arguments from the
206    /// underlying system call, which the caller must populate appropriately.
207    #[inline]
208    pub fn open_relative_raw(
209        &self,
210        path: &CStr,
211        flags: linux_unsafe::int,
212        mode: linux_unsafe::mode_t,
213    ) -> Result<File<()>> {
214        let path_raw = path.as_ptr() as *const linux_unsafe::char;
215        let result = unsafe {
216            linux_unsafe::openat(
217                self.fd,
218                path_raw,
219                flags as linux_unsafe::int,
220                mode as linux_unsafe::mode_t,
221            )
222        };
223        result
224            .map(|fd| unsafe { File::from_raw_fd(fd as linux_unsafe::int) })
225            .map_err(|e| e.into())
226    }
227
228    #[inline(always)]
229    pub fn fd(&self) -> linux_unsafe::int {
230        self.fd
231    }
232
233    /// Consumes the file object and returns the underlying file descriptor
234    /// without closing it.
235    #[inline(always)]
236    pub fn into_raw_fd(self) -> linux_unsafe::int {
237        let ret = self.fd;
238        core::mem::forget(self);
239        ret
240    }
241
242    /// Consumes the file object and closes the underlying file descriptor.
243    ///
244    /// If `close` fails then the file descriptor is always leaked, because
245    /// there is no way to recover it once consumed.
246    #[inline]
247    pub fn close(mut self) -> Result<()> {
248        unsafe { self.close_mut() }?;
249        // Must "forget" the file because otherwise the Drop impl will
250        // try to close it again, and perhaps close an unrelated file that
251        // has been allocated the same fd in the meantime.
252        core::mem::forget(self);
253        Ok(())
254    }
255
256    /// Closes the underlying file descriptor without consuming it.
257    ///
258    /// Safety:
259    /// - Callers must pass the file to [`core::mem::forget`] immediately
260    ///   after calling this function to prevent the implicit `close` in
261    ///   the [`Drop`] implementation.
262    /// - Callers must not use the file object again after calling this
263    ///   method; file descriptor will either be dangling or will be referring
264    ///   to some other unrelated file.
265    #[inline(always)]
266    pub unsafe fn close_mut(&mut self) -> Result<()> {
267        let result = unsafe { linux_unsafe::close(self.fd) };
268        result.map(|_| ()).map_err(|e| e.into())
269    }
270
271    /// Read some bytes from the file into the given buffer, returning the
272    /// number of bytes that were read.
273    #[inline(always)]
274    pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
275        let buf_ptr = buf.as_mut_ptr() as *mut linux_unsafe::void;
276        let buf_size = buf.len();
277        unsafe { self.read_raw(buf_ptr, buf_size) }.map(|v| v as _)
278    }
279
280    /// A thin wrapper around the raw `read` system call against this file's
281    /// file descriptor.
282    ///
283    /// Use [`File::read`] as a safe alternative.
284    #[inline]
285    pub unsafe fn read_raw(
286        &self,
287        buf: *mut linux_unsafe::void,
288        count: linux_unsafe::size_t,
289    ) -> Result<linux_unsafe::size_t> {
290        let result = unsafe { linux_unsafe::read(self.fd, buf, count) };
291        result.map(|v| v as _).map_err(|e| e.into())
292    }
293
294    /// Read some directory entries from the directory into the given buffer,
295    /// and obtain an iterator over those directory entries.
296    ///
297    /// The caller **must** fully-consume the returned iterator; any items
298    /// not retrieved will be lost.
299    ///
300    /// Once the iterator is dropped the original buffer contains the raw
301    /// directory entries returned from the kernel, and can be used again for
302    /// a subsequent call to this function.
303    #[inline(always)]
304    pub fn getdents<'a>(&self, buf: &'a mut [u8]) -> Result<DirEntries<'a>> {
305        let buf_ptr = buf.as_mut_ptr() as *mut linux_unsafe::void;
306        let buf_size = buf.len();
307        if buf_size > (linux_unsafe::int::MAX as usize) {
308            return Err(result::EINVAL);
309        }
310        let populated_size =
311            unsafe { self.getdents_raw(buf_ptr, buf_size as linux_unsafe::int) }? as usize;
312        Ok(DirEntries::from_getdents64_buffer(&buf[..populated_size]))
313    }
314
315    /// Read a transformation of every directory entry from the directory.
316    ///
317    /// This wrapper around [`Self::getdents`] returns an iterator that can
318    /// call `Self::getdents` multiple times to visit all of the entries in
319    /// the directory.
320    ///
321    /// However, since all of the calls to `Self::getdents` write into the
322    /// same buffer `buf` it isn't possible for the iterator to directly
323    /// return the borrowed directory entries. Instead, each entry is passed
324    /// to the given function `transform`, which must then return a
325    /// representation of that entry that can outlive the buffer contents.
326    ///
327    /// This admittedly-awkward compromise means that the caller can decide
328    /// how and whether to allocate memory to retain ownership of the directory
329    /// entry names, so that this crate can avoid imposing any particular
330    /// opinion about that.
331    #[inline(always)]
332    pub fn getdents_all<'file, 'buf, TF, R>(
333        &'file self,
334        buf: &'buf mut [u8],
335        transform: TF,
336    ) -> AllDirEntries<TF, R, Device>
337    where
338        TF: for<'tmp> FnMut(DirEntry<'tmp>) -> R,
339        'buf: 'file,
340    {
341        AllDirEntries::new(self, buf, transform)
342    }
343
344    /// A thin wrapper around the raw `getdents64` system call against this
345    /// file's file descriptor.
346    ///
347    /// Use [`File::getdents`] as a more convenient alternative.
348    #[inline]
349    pub unsafe fn getdents_raw(
350        &self,
351        buf: *mut linux_unsafe::void,
352        buf_len: linux_unsafe::int,
353    ) -> Result<linux_unsafe::size_t> {
354        let result = unsafe { linux_unsafe::getdents64(self.fd, buf, buf_len) };
355        result.map(|v| v as _).map_err(|e| e.into())
356    }
357
358    /// Read the content of the symbolic link that the file refers to.
359    ///
360    /// This makes sense only for a file that was opened with the "path only"
361    /// and "no follow symlinks" options.
362    #[inline(always)]
363    pub fn readlink<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
364        let path = c"";
365        let path_raw = path.as_ptr() as *const linux_unsafe::char;
366        let buf_ptr = buf.as_mut_ptr() as *mut linux_unsafe::char;
367        let buf_size = buf.len();
368        if buf_size > (linux_unsafe::int::MAX as usize) {
369            return Err(result::EINVAL);
370        }
371        let result = unsafe { linux_unsafe::readlinkat(self.fd, path_raw, buf_ptr, buf_size) };
372        match result {
373            Ok(populated_size) => Ok(&buf[..populated_size as usize]),
374            Err(e) => Err(e.into()),
375        }
376    }
377
378    /// Read the content of a symbolic link relative to the file, which
379    /// must represent a directory.
380    #[inline(always)]
381    pub fn readlink_relative<'a>(&self, path: &CStr, buf: &'a mut [u8]) -> Result<&'a [u8]> {
382        let path_raw = path.as_ptr() as *const linux_unsafe::char;
383        let buf_ptr = buf.as_mut_ptr() as *mut linux_unsafe::char;
384        let buf_size = buf.len();
385        if buf_size > (linux_unsafe::int::MAX as usize) {
386            return Err(result::EINVAL);
387        }
388        let result = unsafe { linux_unsafe::readlinkat(self.fd, path_raw, buf_ptr, buf_size) };
389        match result {
390            Ok(populated_size) => Ok(&buf[..populated_size as usize]),
391            Err(e) => Err(e.into()),
392        }
393    }
394
395    /// Use a `statx` system call to determine whether a particular path exists
396    /// relative to the file, which must represent a directory.
397    #[inline(always)]
398    pub fn exists_relative(&self, path: &CStr) -> Result<bool> {
399        let path_raw = path.as_ptr() as *const linux_unsafe::char;
400        let mut tmp = unsafe { core::mem::zeroed::<linux_unsafe::statx>() };
401        let result = unsafe { linux_unsafe::statx(self.fd, path_raw, 0, 0, &mut tmp as *mut _) };
402        match result {
403            Ok(_) => Ok(true),
404            Err(e) => {
405                if e.0 == linux_unsafe::result::ENOENT {
406                    Ok(false)
407                } else {
408                    Err(e.into())
409                }
410            }
411        }
412    }
413
414    /// Change the current read/write position of the file.
415    #[inline]
416    pub fn seek(&self, pos: impl Into<SeekFrom>) -> Result<u64> {
417        let pos = pos.into();
418        let raw_offs = pos.for_raw_offset();
419
420        #[cfg(not(target_pointer_width = "32"))]
421        {
422            // For 64-bit platforms we can just use lseek, because off_t is
423            // bit enough for all offsets.
424            let raw_whence = pos.for_raw_whence();
425            let result = unsafe { linux_unsafe::lseek(self.fd, raw_offs, raw_whence) };
426            result.map(|v| v as u64).map_err(|e| e.into())
427        }
428
429        #[cfg(target_pointer_width = "32")]
430        {
431            // For 32-bit platforms we need to use _llseek instead, which
432            // splits the offset across two arguments.
433            let raw_offs_high = ((raw_offs as u64) >> 32) as linux_unsafe::ulong;
434            let raw_offs_low = (raw_offs as u64) as linux_unsafe::ulong;
435            let result: UnsafeCell<linux_unsafe::loff_t> = UnsafeCell::new(0);
436            let result_ptr = result.get();
437            let raw_whence = pos.for_raw_uwhence();
438            let result = unsafe {
439                linux_unsafe::_llseek(self.fd, raw_offs_high, raw_offs_low, result_ptr, raw_whence)
440            };
441            match result {
442                Ok(_) => {
443                    let result_offs = unsafe { *result_ptr } as u64;
444                    Ok(result_offs)
445                }
446                Err(e) => Err(e.into()),
447            }
448        }
449    }
450
451    /// Tell the kernel to flush any in-memory buffers and caches for the
452    /// file.
453    #[inline]
454    pub fn sync(&self) -> Result<()> {
455        let result = unsafe { linux_unsafe::fsync(self.fd) };
456        result.map(|_| ()).map_err(|e| e.into())
457    }
458
459    /// Write bytes from the given buffer to the file, returning how many bytes
460    /// were written.
461    #[inline(always)]
462    pub fn write(&self, buf: &[u8]) -> Result<usize> {
463        let buf_ptr = buf.as_ptr() as *const linux_unsafe::void;
464        let buf_size = buf.len();
465        unsafe { self.write_raw(buf_ptr, buf_size) }.map(|v| v as _)
466    }
467
468    /// A thin wrapper around the raw `write` system call against this file's
469    /// file descriptor.
470    ///
471    /// Use [`File::write`] as a safe alternative.
472    #[inline]
473    pub unsafe fn write_raw(
474        &self,
475        buf: *const linux_unsafe::void,
476        count: linux_unsafe::size_t,
477    ) -> Result<linux_unsafe::size_t> {
478        let result = unsafe { linux_unsafe::write(self.fd, buf, count) };
479        result.map(|v| v as _).map_err(|e| e.into())
480    }
481
482    /// Safe wrapper for the `fcntl` system call.
483    ///
484    /// The safety of this wrapper relies on being passed only correct
485    /// implementations of [`fcntl::FcntlCmd`], some of which are predefined
486    /// as constants in the [`fcntl`] module.
487    ///
488    /// The type of the argument depends on which `cmd` you choose.
489    #[inline]
490    pub fn fcntl<'a, Cmd: fcntl::FcntlCmd<'a>>(
491        &'a self,
492        cmd: Cmd,
493        arg: Cmd::ExtArg,
494    ) -> Result<Cmd::Result> {
495        let (raw_cmd, raw_arg) = cmd.prepare_fcntl_args(arg);
496        let raw_result = unsafe { self.fcntl_raw(raw_cmd, raw_arg) };
497        raw_result.map(|r| cmd.prepare_fcntl_result(r))
498    }
499
500    /// Direct wrapper around the raw `fcntl` system call.
501    ///
502    /// This system call is particularly unsafe because it interprets its
503    /// last argument differently depending on the value of `cmd`.
504    /// [`Self::fcntl`] provides a slightly safer abstraction around this
505    /// operation.
506    #[inline]
507    pub unsafe fn fcntl_raw(
508        &self,
509        cmd: linux_unsafe::int,
510        arg: impl AsRawV,
511    ) -> Result<linux_unsafe::int> {
512        let result = unsafe { linux_unsafe::fcntl(self.fd, cmd, arg) };
513        result.map(|v| v as _).map_err(|e| e.into())
514    }
515
516    /// Adds a device type parameter to the type of a file, allowing the
517    /// [`Self::ioctl`] method to accept request constants that are compatible
518    /// with that device type.
519    ///
520    /// **Safety:**
521    /// - Caller must guarantee that the underlying file descriptor really
522    ///   is representing a device of the given type, because the kernel
523    ///   has some overloaded ioctl request numbers that have different meaning
524    ///   depending on driver and using the wrong one can corrupt memory.
525    pub unsafe fn to_device<T: ioctl::IoDevice>(
526        self,
527        #[allow(unused_variables)] devty: T,
528    ) -> File<T> {
529        let ret = File {
530            fd: self.fd,
531            _phantom: core::marker::PhantomData,
532        };
533        core::mem::forget(self); // don't call self's "drop" implementation
534        ret
535    }
536
537    /// Direct wrapper around the raw `ioctl` system call.
538    ///
539    /// This system call is particularly unsafe because it interprets its
540    /// last argument differently depending on the value of `request`.
541    /// [`Self::ioctl`] provides a slightly safer abstraction around this
542    /// operation.
543    #[inline]
544    pub unsafe fn ioctl_raw(
545        &self,
546        request: linux_unsafe::ulong,
547        arg: impl AsRawV,
548    ) -> Result<linux_unsafe::int> {
549        let result = unsafe { linux_unsafe::ioctl(self.fd, request, arg) };
550        result.map(|v| v as _).map_err(|e| e.into())
551    }
552
553    /// Bind an address to a socket.
554    #[inline]
555    pub fn bind(&self, addr: impl crate::socket::SockAddr) -> Result<()> {
556        let (raw_ptr, raw_len) = unsafe { addr.sockaddr_raw_const() };
557        unsafe { self.bind_raw(raw_ptr, raw_len) }
558    }
559
560    /// Bind an address to a socket using a raw pointer.
561    #[inline]
562    pub unsafe fn bind_raw(
563        &self,
564        addr: *const linux_unsafe::sockaddr,
565        addrlen: linux_unsafe::socklen_t,
566    ) -> Result<()> {
567        let result = unsafe { linux_unsafe::bind(self.fd, addr, addrlen) };
568        result.map(|_| ()).map_err(|e| e.into())
569    }
570
571    /// Initiate a connection on a socket.
572    #[inline]
573    pub fn connect(&self, addr: impl crate::socket::SockAddr) -> Result<()> {
574        let (raw_ptr, raw_len) = unsafe { addr.sockaddr_raw_const() };
575        unsafe { self.connect_raw(raw_ptr, raw_len) }
576    }
577
578    /// Initiate a connection on a socket using a raw pointer.
579    #[inline]
580    pub unsafe fn connect_raw(
581        &self,
582        addr: *const linux_unsafe::sockaddr,
583        addrlen: linux_unsafe::socklen_t,
584    ) -> Result<()> {
585        let result = unsafe { linux_unsafe::connect(self.fd, addr, addrlen) };
586        result.map(|_| ()).map_err(|e| e.into())
587    }
588
589    /// Listen for incoming connections on this socket.
590    #[inline]
591    pub fn listen(&self, backlog: linux_unsafe::int) -> Result<()> {
592        let result = unsafe { linux_unsafe::listen(self.fd, backlog) };
593        result.map(|_| ()).map_err(|e| e.into())
594    }
595
596    /// Get a socket option for a file descriptor representing a socket.
597    ///
598    /// The value for `opt` is typically a constant defined elsewhere in this
599    /// crate, or possibly in another crate, which describes both the level
600    /// and optname for the underlying call and the type of the result.
601    #[inline(always)]
602    pub fn getsockopt<'a, O: sockopt::GetSockOpt<'a>>(&self, opt: O) -> Result<O::Result> {
603        let (level, optname) = opt.prepare_getsockopt_args();
604        let mut buf: MaybeUninit<O::OptVal> = MaybeUninit::zeroed();
605        let optlen = core::mem::size_of::<O::OptVal>() as linux_unsafe::socklen_t;
606        let mut optlen_out = UnsafeCell::new(optlen);
607        let result = unsafe {
608            self.getsockopt_raw(
609                level,
610                optname,
611                buf.as_mut_ptr() as *mut linux_unsafe::void,
612                optlen_out.get(),
613            )
614        }?;
615        if *optlen_out.get_mut() != optlen {
616            // If the length isn't what we expected then we'll assume this
617            // was an invalid GetSockOpt implementation.
618            return Err(crate::result::Error::new(22)); // EINVAL
619        }
620        let buf = unsafe { buf.assume_init() };
621        Ok(opt.prepare_getsockopt_result(result, buf))
622    }
623
624    /// Get a socket option for a file descriptor representing a socket using
625    /// the raw arguments to the `getsockopt` system call.
626    #[inline]
627    pub unsafe fn getsockopt_raw(
628        &self,
629        level: linux_unsafe::int,
630        optname: linux_unsafe::int,
631        optval: *mut linux_unsafe::void,
632        optlen: *mut linux_unsafe::socklen_t,
633    ) -> Result<linux_unsafe::int> {
634        let result = unsafe { linux_unsafe::getsockopt(self.fd, level, optname, optval, optlen) };
635        result.map_err(|e| e.into())
636    }
637
638    /// Set a socket option for a file descriptor representing a socket.
639    ///
640    /// The value for `opt` is typically a constant defined elsewhere in this
641    /// crate, or possibly in another crate, which describes both the level
642    /// and optname for the underlying call and the type of the argument.
643    #[inline(always)]
644    pub fn setsockopt<'a, O: sockopt::SetSockOpt<'a>>(
645        &self,
646        opt: O,
647        arg: O::ExtArg,
648    ) -> Result<O::Result> {
649        let (level, optname, optval, optlen) = opt.prepare_setsockopt_args(&arg);
650        let result = unsafe {
651            self.setsockopt_raw(level, optname, optval as *mut linux_unsafe::void, optlen)
652        }?;
653        Ok(opt.prepare_setsockopt_result(result))
654    }
655
656    /// Set a socket option for a file descriptor representing a socket using
657    /// the raw arguments to the `setsockopt` system call.
658    #[inline]
659    pub unsafe fn setsockopt_raw(
660        &self,
661        level: linux_unsafe::int,
662        optname: linux_unsafe::int,
663        optval: *const linux_unsafe::void,
664        optlen: linux_unsafe::socklen_t,
665    ) -> Result<linux_unsafe::int> {
666        let result = unsafe { linux_unsafe::setsockopt(self.fd, level, optname, optval, optlen) };
667        result.map_err(|e| e.into())
668    }
669
670    /// Map the file into memory using the `mmap` system call.
671    ///
672    /// There is no safe wrapper for this because mapping a file into memory
673    /// is inherently unsafe. Callers must take care to ensure they use the
674    /// returned pointer in a safe way and to release the mapping with
675    /// [`linux_unsafe::munmap`] when it's no longer needed.
676    #[inline(always)]
677    pub unsafe fn mmap_raw(
678        &self,
679        offset: linux_unsafe::off_t,
680        length: linux_unsafe::size_t,
681        addr: *mut void,
682        prot: linux_unsafe::int,
683        flags: linux_unsafe::int,
684    ) -> Result<*mut void> {
685        let result = unsafe { linux_unsafe::mmap(addr, length, prot, flags, self.fd, offset) };
686        result.map_err(|e| e.into())
687    }
688}
689
690/// Files that have been marked as representing a particular device type using
691/// [`File::to_device`] can support `ioctl` requests that are designated for
692/// that device.
693impl<Device: ioctl::IoDevice> File<Device> {
694    /// Safe wrapper for the `ioctl` system call.
695    ///
696    /// The safety of this wrapper relies on being passed only correct
697    /// implementations of [`ioctl::IoctlReq`], some of which are predefined
698    /// as constants elsewhere in this crate, while others will appear in
699    /// device-specific support crates.
700    ///
701    /// The type of the argument depends on which `request` you choose.
702    /// Some requests expect no argument, in which case you should pass
703    /// `()`.
704    #[inline]
705    pub fn ioctl<'a, ReqDevice: ioctl::IoDevice, Req: ioctl::IoctlReq<'a, ReqDevice>>(
706        &'a self,
707        request: Req,
708        arg: Req::ExtArg,
709    ) -> Result<Req::Result>
710    where
711        Device: SubDevice<ReqDevice>,
712    {
713        // Some ioctl requests need some temporary memory space for the
714        // kernel to write data into. It's the request implementation's
715        // responsibility to initialize it if needed, but we'll at least
716        // zero it so that any unused padding will start as zero.
717        let mut temp_mem: MaybeUninit<Req::TempMem> = MaybeUninit::zeroed();
718        let (raw_req, raw_arg) = request.prepare_ioctl_args(&arg, &mut temp_mem);
719        let raw_result = unsafe { self.ioctl_raw(raw_req, raw_arg) };
720        raw_result.map(|r| request.prepare_ioctl_result(r, &arg, &temp_mem))
721    }
722}
723
724impl<Device> Drop for File<Device> {
725    /// Attempts to close the file when it's no longer in scope.
726    ///
727    /// This implicit close ignores errors, which might cause data loss if
728    /// the final commit of data to disk fails. Use [`File::close`] explicitly
729    /// if you need to detect errors.
730    #[allow(unused_must_use)] // intentionally discarding close result
731    fn drop(&mut self) {
732        unsafe { self.close_mut() };
733    }
734}
735
736impl<Device> core::fmt::Debug for File<Device> {
737    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
738        f.debug_struct("File").field("fd", &self.fd).finish()
739    }
740}
741
742/// [`File`] implements [`core::fmt::Write`] by passing UTF-8 encoded bytes
743/// directly to the `write` method.
744impl<T> core::fmt::Write for File<T> {
745    fn write_str(&mut self, s: &str) -> core::fmt::Result {
746        let mut bytes = s.as_bytes();
747        while !bytes.is_empty() {
748            let n = match self.write(bytes) {
749                Ok(n) => n,
750                Err(e) => return Err(e.into()),
751            };
752            bytes = &bytes[n..];
753        }
754        Ok(())
755    }
756}
757
758#[cfg(feature = "std")]
759extern crate std;
760
761#[cfg(feature = "std")]
762impl<Device> std::io::Read for File<Device> {
763    #[inline(always)]
764    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
765        Self::read(self, buf).map_err(|e| e.into())
766    }
767}
768
769#[cfg(feature = "std")]
770impl<Device> std::io::Write for File<Device> {
771    #[inline(always)]
772    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
773        Self::write(self, buf).map_err(|e| e.into())
774    }
775
776    #[inline(always)]
777    fn flush(&mut self) -> std::io::Result<()> {
778        Self::sync(self).map_err(|e| e.into())
779    }
780}
781
782#[cfg(feature = "std")]
783impl<Device> std::io::Seek for File<Device> {
784    #[inline(always)]
785    fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
786        Self::seek(self, pos).map_err(|e| e.into())
787    }
788}
789
790#[cfg(feature = "std")]
791impl From<std::os::fd::OwnedFd> for File<()> {
792    fn from(value: std::os::fd::OwnedFd) -> Self {
793        use std::os::fd::IntoRawFd;
794
795        Self {
796            fd: value.into_raw_fd().into(),
797            _phantom: core::marker::PhantomData,
798        }
799    }
800}
801
802#[cfg(feature = "std")]
803impl<Device> std::os::fd::AsFd for File<Device> {
804    fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
805        unsafe { std::os::fd::BorrowedFd::borrow_raw(self.fd) }
806    }
807}
808
809/// Use with [`File::open`] to open a file only for reading.
810///
811/// Use the methods of this type to add additional options for `open`.
812pub const OPEN_READ_ONLY: OpenOptions<OpenWithoutMode> =
813    OpenOptions::<OpenWithoutMode>::read_only();
814
815/// Use with [`File::open`] to open a file only for writing.
816///
817/// Use the methods of this type to add additional options for `open`.
818pub const OPEN_WRITE_ONLY: OpenOptions<OpenWithoutMode> =
819    OpenOptions::<OpenWithoutMode>::write_only();
820
821/// Use with [`File::open`] to open a file for both reading and writing.
822///
823/// Use the methods of this type to add additional options for `open`.
824pub const OPEN_READ_WRITE: OpenOptions<OpenWithoutMode> =
825    OpenOptions::<OpenWithoutMode>::read_write();
826
827/// Encapsulates the various options for the `open` system call behind a
828/// builder API.
829///
830/// Use [`OPEN_READ_ONLY`], [`OPEN_WRITE_ONLY`], or [`OPEN_READ_WRITE`] as
831/// a starting value of this type and then refine as necessary using the
832/// methods to set additional flags.
833#[derive(Clone, Copy, PartialEq, Eq)]
834#[repr(transparent)]
835pub struct OpenOptions<NeedMode: OpenMode> {
836    flags: linux_unsafe::int,
837    _phantom: core::marker::PhantomData<NeedMode>,
838}
839
840impl OpenOptions<OpenWithoutMode> {
841    #[inline(always)]
842    pub const fn read_only() -> Self {
843        Self {
844            flags: linux_unsafe::O_RDONLY, // NOTE: This is really just zero
845            _phantom: core::marker::PhantomData,
846        }
847    }
848
849    #[inline(always)]
850    pub const fn write_only() -> Self {
851        Self {
852            flags: linux_unsafe::O_WRONLY,
853            _phantom: core::marker::PhantomData,
854        }
855    }
856
857    #[inline(always)]
858    pub const fn read_write() -> Self {
859        Self {
860            flags: linux_unsafe::O_RDWR,
861            _phantom: core::marker::PhantomData,
862        }
863    }
864}
865
866impl<NeedMode: OpenMode> OpenOptions<NeedMode> {
867    #[inline(always)]
868    const fn bit_or(self, new: linux_unsafe::int) -> Self {
869        Self {
870            flags: self.flags | new,
871            _phantom: core::marker::PhantomData,
872        }
873    }
874
875    #[inline(always)]
876    pub const fn append(self) -> Self {
877        self.bit_or(linux_unsafe::O_APPEND)
878    }
879
880    #[inline(always)]
881    pub const fn close_on_exec(self) -> Self {
882        self.bit_or(linux_unsafe::O_CLOEXEC)
883    }
884
885    #[inline(always)]
886    pub const fn create(self) -> OpenOptions<OpenWithMode> {
887        OpenOptions {
888            flags: self.bit_or(linux_unsafe::O_CREAT).flags,
889            _phantom: core::marker::PhantomData,
890        }
891    }
892
893    #[inline(always)]
894    pub const fn direct(self) -> Self {
895        self.bit_or(linux_unsafe::O_DIRECT)
896    }
897
898    #[inline(always)]
899    pub const fn directory(self) -> Self {
900        self.bit_or(linux_unsafe::O_DIRECTORY)
901    }
902
903    #[inline(always)]
904    pub const fn excl(self) -> Self {
905        self.bit_or(linux_unsafe::O_EXCL)
906    }
907
908    #[inline(always)]
909    pub const fn no_atime(self) -> Self {
910        self.bit_or(linux_unsafe::O_NOATIME)
911    }
912
913    #[inline(always)]
914    pub const fn no_controlling_tty(self) -> Self {
915        self.bit_or(linux_unsafe::O_NOCTTY)
916    }
917
918    #[inline(always)]
919    pub const fn no_follow_symlinks(self) -> Self {
920        self.bit_or(linux_unsafe::O_NOFOLLOW)
921    }
922
923    #[inline(always)]
924    pub const fn nonblocking(self) -> Self {
925        self.bit_or(linux_unsafe::O_NONBLOCK)
926    }
927
928    #[inline(always)]
929    pub const fn path_only(self) -> Self {
930        self.bit_or(linux_unsafe::O_PATH)
931    }
932
933    #[inline(always)]
934    pub const fn sync(self) -> Self {
935        self.bit_or(linux_unsafe::O_SYNC)
936    }
937
938    #[inline(always)]
939    pub const fn temp_file(self) -> OpenOptions<OpenWithMode> {
940        OpenOptions {
941            flags: self.bit_or(linux_unsafe::O_TMPFILE).flags,
942            _phantom: core::marker::PhantomData,
943        }
944    }
945
946    #[inline(always)]
947    pub const fn truncate(self) -> Self {
948        self.bit_or(linux_unsafe::O_TRUNC)
949    }
950
951    /// Convert the options wrapper into the corresponding raw flags value
952    /// to use with the `open` system call.
953    #[inline(always)]
954    pub const fn into_raw_flags(self) -> linux_unsafe::int {
955        self.flags
956    }
957}
958
959impl<NeedMode: OpenMode> Into<linux_unsafe::int> for OpenOptions<NeedMode> {
960    #[inline(always)]
961    fn into(self) -> linux_unsafe::int {
962        self.into_raw_flags()
963    }
964}
965
966/// A marker type used with [`OpenOptions`] to represent situations where
967/// opening the file would require a `mode` argument.
968pub enum OpenWithMode {}
969
970/// A marker type used with [`OpenOptions`] to represent situations where
971/// opening the file would require a `mode` argument.
972pub enum OpenWithoutMode {}
973
974/// A marker trait used with [`OpenOptions`] to represent whether a particular
975/// set of options must be opened with an additional `mode` argument.
976pub trait OpenMode {}
977
978impl OpenMode for OpenWithMode {}
979impl OpenMode for OpenWithoutMode {}