limine/
file.rs

1//! File structure and related functions.
2
3use core::{
4    ffi::{c_char, c_void, CStr},
5    mem::MaybeUninit,
6    num::NonZeroU32,
7};
8
9#[cfg(feature = "ipaddr")]
10use core::net::{Ipv4Addr, SocketAddrV4};
11
12/// A UUID. With the `uuid` feature, this can be converted directly to
13/// [`uuid::Uuid`] via [`Into`], and the reverse via [`From`].
14#[repr(C)]
15#[derive(PartialEq, Eq, Clone, Copy)]
16pub struct Uuid {
17    /// The first 32 bits of the UUID.
18    pub a: u32,
19    /// The next 16 bits of the UUID.
20    pub b: u16,
21    /// The next 16 bits of the UUID.
22    pub c: u16,
23    /// The last 64 bits of the UUID.
24    pub d: [u8; 8],
25}
26impl Uuid {
27    fn non_zero(&self) -> Option<Self> {
28        (self.a != 0 || self.b != 0 || self.c != 0 || self.d != [0; 8]).then_some(*self)
29    }
30}
31#[cfg(feature = "uuid")]
32impl From<uuid::Uuid> for Uuid {
33    fn from(uuid: uuid::Uuid) -> Self {
34        Self {
35            a: uuid.as_fields().0,
36            b: uuid.as_fields().1,
37            c: uuid.as_fields().2,
38            d: *uuid.as_fields().3,
39        }
40    }
41}
42#[cfg(feature = "uuid")]
43impl From<Uuid> for uuid::Uuid {
44    fn from(uuid: Uuid) -> Self {
45        Self::from_fields(uuid.a, uuid.b, uuid.c, &uuid.d)
46    }
47}
48
49/// A media type for a file.
50#[derive(PartialEq, Eq, Clone, Copy)]
51#[repr(transparent)]
52pub struct MediaType(u32);
53impl MediaType {
54    /// Unknown media type.
55    pub const GENERIC: Self = Self(0);
56    /// A CD-ROM.
57    pub const OPTICAL: Self = Self(1);
58    /// A TFTP server.
59    pub const TFTP: Self = Self(2);
60}
61
62/// A file loaded by the bootloader. Returned from
63/// [`ExecutableFileRequest`](crate::request::ExecutableFileRequest) and
64/// [`ModuleRequest`](crate::request::ModuleRequest).
65#[repr(C)]
66pub struct File {
67    revision: u64,
68    addr: *mut c_void,
69    size: u64,
70    path: *const c_char,
71    string: *const c_char,
72    media_type: MediaType,
73    _unused: MaybeUninit<u32>,
74    tftp_ip: Option<NonZeroU32>,
75    tftp_port: Option<NonZeroU32>,
76    partition_idx: Option<NonZeroU32>,
77    mbr_disk_id: Option<NonZeroU32>,
78    gpt_disk_id: Uuid,
79    gpt_partition_id: Uuid,
80    partition_uuid: Uuid,
81}
82impl File {
83    /// Get the revision of the file. Currently, this is always 0.
84    pub fn revision(&self) -> u64 {
85        self.revision
86    }
87
88    /// The base address of the file. Note that this is not necessarily a
89    /// pointer to executable code. It simply points to the raw file.
90    pub fn addr(&self) -> *mut u8 {
91        self.addr.cast()
92    }
93    /// The size of the file, in bytes.
94    pub fn size(&self) -> u64 {
95        self.size
96    }
97
98    /// The path of the file. This is the path that was passed to the bootloader
99    /// in either the configuration file or the `internal_modules` field of the
100    /// [`ModuleRequest`](crate::request::ModuleRequest).
101    pub fn path(&self) -> &CStr {
102        unsafe { CStr::from_ptr(self.path) }
103    }
104
105    /// The string associated with this file. This is the command line that was passed
106    /// to the bootloader in either the configuration file or the
107    /// `internal_modules` field of the
108    /// [`ModuleRequest`](crate::request::ModuleRequest).
109    ///
110    /// It is returned as a raw byte slice, and the encoding is unspecified.
111    pub fn string(&self) -> &CStr {
112        unsafe { CStr::from_ptr(self.string) }
113    }
114
115    #[deprecated(since = "0.4.0", note = "please use `File::string` instead")]
116    /// The command line of the file. This is the command line that was passed
117    /// to the bootloader in either the configuration file or the
118    /// `internal_modules` field of the
119    /// [`ModuleRequest`](crate::request::ModuleRequest).
120    ///
121    /// It is returned as a raw byte slice, and the encoding is unspecified.
122    pub fn cmdline(&self) -> &[u8] {
123        let c_str = unsafe { CStr::from_ptr(self.string) };
124        c_str.to_bytes()
125    }
126
127    /// The media type of the file. See [`MediaType`] for more information.
128    pub fn media_type(&self) -> MediaType {
129        self.media_type
130    }
131
132    /// The IP address of the TFTP server, if the file was loaded from a TFTP.
133    #[cfg(feature = "ipaddr")]
134    pub fn tftp_ip(&self) -> Option<Ipv4Addr> {
135        self.tftp_ip.map(|v| {
136            let bytes = v.get().to_ne_bytes();
137            Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])
138        })
139    }
140    /// The IP address of the TFTP server, if the file was loaded from a TFTP.
141    #[cfg(not(feature = "ipaddr"))]
142    pub fn tftp_ip(&self) -> Option<NonZeroU32> {
143        self.tftp_ip
144    }
145    /// The port of the TFTP server, if the file was loaded from a TFTP.
146    pub fn tftp_port(&self) -> Option<NonZeroU32> {
147        self.tftp_port
148    }
149    /// The address of the TFTP server, if the file was loaded from a TFTP. This
150    /// is simply a combination of [`tftp_ip`](Self::tftp_ip) and
151    /// [`tftp_port`](Self::tftp_port).
152    #[cfg(feature = "ipaddr")]
153    pub fn tftp_addr(&self) -> Option<SocketAddrV4> {
154        self.tftp_ip()
155            .and_then(|ip| Some(SocketAddrV4::new(ip, self.tftp_port()?.get() as u16)))
156    }
157
158    /// The partition index of the file, if the file was loaded from a partition.
159    pub fn partition_idx(&self) -> Option<NonZeroU32> {
160        self.partition_idx
161    }
162    /// The MBR disk ID of the file, if the file was loaded from an MBR disk.
163    pub fn mbr_disk_id(&self) -> Option<NonZeroU32> {
164        self.mbr_disk_id
165    }
166
167    /// The GPT disk UUID of the file, if the file was loaded from a GPT disk.
168    pub fn gpt_disk_id(&self) -> Option<Uuid> {
169        self.gpt_disk_id.non_zero()
170    }
171    /// The GPT partition UUID of the file, if the file was loaded from a GPT
172    /// partition.
173    pub fn gpt_partition_id(&self) -> Option<Uuid> {
174        self.gpt_partition_id.non_zero()
175    }
176    /// The partition UUID of the file, if the file was loaded from a partition
177    /// with a UUID.
178    pub fn partition_uuid(&self) -> Option<Uuid> {
179        self.partition_uuid.non_zero()
180    }
181}