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}