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}