deb_rust/shared.rs
1/*
2 deb-rust - Rust library for building and reading Deb packages
3 Copyright (C) 2023 NotSludgeBomb
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19use std::fs;
20use std::io::{Error, ErrorKind};
21#[cfg(unix)]
22use std::os::unix::fs::MetadataExt;
23use std::path::{Path, PathBuf};
24
25/// Represents the [various architectures Deb supports](https://wiki.debian.org/SupportedArchitectures).
26#[derive(Debug, PartialEq, Eq)]
27pub enum DebArchitecture {
28 /// For architecture independent packages, such as interpreted software
29 /// or configuration files.
30 All,
31 Alpha,
32 /// Arm versions 5T and 6
33 Armel,
34 /// Armv7 (hard float)
35 Armhf,
36 /// Armv8
37 Arm64,
38 Hppa,
39 /// 32-bit x86
40 I386,
41 /// 64-bit x86_64
42 Amd64,
43 Ia64,
44 M68k,
45 Mips,
46 /// Little-endian 32-bit
47 Mipsel,
48 /// Little-endian 64-bit
49 Mips64el,
50 PowerPC,
51 Ppc64,
52 Ppc64el,
53 Riscv64,
54 S390x,
55 Sh4,
56 Sparc4,
57 X32,
58 /// 32-bit x86 for GNU/Hurd
59 HurdI386,
60 /// 32-bit x86 for FreeBSD
61 KFreebsdI386,
62 /// 64-bit x86_64 for FreeBSD
63 KFreebsdAmd64,
64}
65
66impl DebArchitecture {
67 /// Converts DebArchitecture to &str.
68 pub fn as_str(&self) -> &str {
69 match self {
70 DebArchitecture::All => "all",
71 DebArchitecture::Alpha => "Alpha",
72 DebArchitecture::Armel => "Armel",
73 DebArchitecture::Armhf => "armhf",
74 DebArchitecture::Arm64 => "arm64",
75 DebArchitecture::Hppa => "hppa",
76 DebArchitecture::I386 => "i386",
77 DebArchitecture::Amd64 => "amd64",
78 DebArchitecture::Ia64 => "ia64",
79 DebArchitecture::M68k => "m68k",
80 DebArchitecture::Mips => "mips",
81 DebArchitecture::Mipsel => "mipsel",
82 DebArchitecture::Mips64el => "mips64el",
83 DebArchitecture::PowerPC => "PowerPC",
84 DebArchitecture::Ppc64 => "PPC64",
85 DebArchitecture::Ppc64el => "ppc64el",
86 DebArchitecture::Riscv64 => "riscv64",
87 DebArchitecture::S390x => "s390x",
88 DebArchitecture::Sh4 => "SH4",
89 DebArchitecture::Sparc4 => "sparc4",
90 DebArchitecture::X32 => "x32",
91 DebArchitecture::HurdI386 => "hurd-i386",
92 DebArchitecture::KFreebsdI386 => "kfreebsd-i386",
93 DebArchitecture::KFreebsdAmd64 => "kfreebsd-amd64",
94 }
95 }
96
97 /// Converts &str to DebArchitecture.
98 ///
99 /// This function will return an error if the given string doesn't match
100 /// any architecture name.
101 pub fn from(input: &str) -> std::io::Result<Self> {
102 match input {
103 "all" => Ok(DebArchitecture::All),
104 "Alpha" => Ok(DebArchitecture::Alpha),
105 "Armel" => Ok(DebArchitecture::Armel),
106 "armhf" => Ok(DebArchitecture::Armhf),
107 "arm64" => Ok(DebArchitecture::Arm64),
108 "hppa" => Ok(DebArchitecture::Hppa),
109 "i386" => Ok(DebArchitecture::I386),
110 "amd64" => Ok(DebArchitecture::Amd64),
111 "ia64" => Ok(DebArchitecture::Ia64),
112 "m68k" => Ok(DebArchitecture::M68k),
113 "mips" => Ok(DebArchitecture::Mips),
114 "mipsel" => Ok(DebArchitecture::Mipsel),
115 "mips64el" => Ok(DebArchitecture::Mips64el),
116 "PowerPC" => Ok(DebArchitecture::PowerPC),
117 "PPC64" => Ok(DebArchitecture::Ppc64),
118 "ppc64el" => Ok(DebArchitecture::Ppc64el),
119 "riscv64" => Ok(DebArchitecture::Riscv64),
120 "s390x" => Ok(DebArchitecture::S390x),
121 "SH4" => Ok(DebArchitecture::Sh4),
122 "sparc4" => Ok(DebArchitecture::Sparc4),
123 "x32" => Ok(DebArchitecture::X32),
124 "hurd-i386" => Ok(DebArchitecture::HurdI386),
125 "kfreebsd-i386" => Ok(DebArchitecture::KFreebsdI386),
126 "kfreebsd-amd64" => Ok(DebArchitecture::KFreebsdAmd64),
127 &_ => Err(Error::new(ErrorKind::Other, "invalid architecture name")),
128 }
129 }
130}
131
132/// Used for [Deb's Priority field](https://www.debian.org/doc/debian-policy/ch-archive.html#s-priorities).
133#[derive(Debug, PartialEq, Eq)]
134pub enum DebPriority {
135 Required,
136 Important,
137 Standard,
138 Optional,
139 Extra,
140}
141
142impl DebPriority {
143 /// Converts DebPriority to &str.
144 pub fn as_str(&self) -> &str {
145 match self {
146 DebPriority::Required => "required",
147 DebPriority::Important => "important",
148 DebPriority::Standard => "standard",
149 DebPriority::Optional => "optional",
150 DebPriority::Extra => "extra",
151 }
152 }
153
154 /// Converts &str to DebPriority.
155 ///
156 /// This function will return in error if the given string doesn't match
157 /// any priority name.
158 pub fn from(input: &str) -> std::io::Result<Self> {
159 match input {
160 "required" => Ok(DebPriority::Required),
161 "important" => Ok(DebPriority::Important),
162 "standard" => Ok(DebPriority::Standard),
163 "optional" => Ok(DebPriority::Optional),
164 "extra" => Ok(DebPriority::Extra),
165 &_ => Err(Error::new(ErrorKind::Other, "invalid priority name")),
166 }
167 }
168}
169
170/// Used to configure which compression format is used for data and control archives.
171///
172/// Zstd is preferred, though XZ is available as a legacy option.
173#[derive(Debug, PartialEq, Eq)]
174pub enum DebCompression {
175 Xz,
176 Zstd,
177}
178
179/// Used in the DebPackage struct to represent files in a package's archives.
180///
181/// This struct contains the file's contents, permissions, and it's path in
182/// the final package.
183#[derive(Debug)]
184pub struct DebFile {
185 contents: Vec<u8>, // The contents of the file
186 mode: u32, // The file's permissions in octal form
187 path: PathBuf, // The path the file goes to in the archive
188}
189
190impl DebFile {
191 /// Creates a DebFile from a path.
192 ///
193 /// `from` is a path to a file on your system that you're trying to add to the package.
194 /// `to` is where the file will go once the package is installed on a user's system.
195 ///
196 /// On Unix systems, the file's mode will automatically be set based on `from`.
197 /// On Windows, the file's mode will be set to `33188`.
198 ///
199 /// # Errors
200 ///
201 /// This function will return an error if `from` does not exist or can't be read.
202 ///
203 /// # Example
204 ///
205 /// ```
206 /// use deb_rust::DebFile;
207 /// use deb_rust::binary::DebPackage;
208 ///
209 /// let mut package = DebPackage::new("example")
210 /// .with_file(DebFile::from_path(
211 /// "target/release/example",
212 /// "/usr/bin/example",
213 /// ).unwrap());
214 /// ```
215 #[cfg(unix)]
216 pub fn from_path<F, T>(from: F, to: T) -> std::io::Result<Self>
217 where
218 F: AsRef<Path>,
219 T: AsRef<std::ffi::OsStr>,
220 {
221 Ok(Self {
222 contents: fs::read(&from)?,
223 mode: fs::File::open(&from)?.metadata()?.mode(),
224 path: PathBuf::from(&to),
225 })
226 }
227
228 // Same function but for Windows, as file modes are a Unix feature
229 #[cfg(windows)]
230 pub fn from_path<F, T>(from: F, to: T) -> std::io::Result<Self>
231 where
232 F: AsRef<Path>,
233 T: AsRef<std::ffi::OsStr>,
234 {
235 Ok(Self {
236 contents: fs::read(&from)?,
237 mode: 33188,
238 path: PathBuf::from(&to),
239 })
240 }
241
242 /// Creates a DebFile from a buffer.
243 ///
244 /// `buf` is a buffer which will be added as the file's contents.
245 /// `to` is where the file will go once the package is installed on a user's system.
246 ///
247 /// The file's mode is set to 33188. Permission's must be managed manually.
248 ///
249 /// # Example
250 ///
251 /// ```
252 /// use deb_rust::DebFile;
253 /// use deb_rust::binary::DebPackage;
254 ///
255 /// let mut package = DebPackage::new("example")
256 /// .with_file(DebFile::from_buf(
257 /// "#!/usr/bin/bash\necho Hello world!"
258 /// .as_bytes()
259 /// .to_vec(),
260 /// "/usr/bin/example",
261 /// ).is_exec());
262 /// ```
263 pub fn from_buf<T>(buf: Vec<u8>, to: T) -> Self
264 where
265 T: AsRef<std::ffi::OsStr>,
266 {
267 Self {
268 contents: buf,
269 mode: 33188,
270 path: PathBuf::from(&to),
271 }
272 }
273
274 /// Sets the file's mode to have executable permissions.
275 pub fn is_exec(mut self) -> Self {
276 self.mode = 33261;
277 self
278 }
279
280 /// Sets the file's mode to have read/write permissions, without executable.
281 pub fn is_conf(mut self) -> Self {
282 self.mode = 33188;
283 self
284 }
285
286 /// Sets the file's contents to `contents`.
287 pub fn set_contents(mut self, contents: Vec<u8>) -> Self {
288 self.contents = contents;
289 self
290 }
291
292 /// Sets the file's mode to `mode`.
293 pub fn set_mode(mut self, mode: u32) -> Self {
294 self.mode = mode;
295 self
296 }
297
298 /// Sets the file's path to `to`.
299 pub fn set_path<T: AsRef<std::ffi::OsStr>>(mut self, to: T) -> Self {
300 self.path = PathBuf::from(&to);
301 self
302 }
303
304 /// Returns the file's contents.
305 pub fn contents(&self) -> &Vec<u8> {
306 &self.contents
307 }
308
309 /// Returns the file's mode.
310 pub fn mode(&self) -> &u32 {
311 &self.mode
312 }
313
314 /// Returns the file's path.
315 pub fn path(&self) -> &PathBuf {
316 &self.path
317 }
318}