apple_flat_package/lib.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Apple flat packages.
6//!
7//! Apple flat packages - often existing as `.pkg` files - are an installer
8//! file format used by macOS.
9//!
10//! # File Format
11//!
12//! Flat packages are Apple-flavored XAR archives. XAR is a tar-like
13//! file format consisting of file records/metadata and raw file data.
14//! See the `apple-xar` crate for more on this file format.
15//!
16//! Flat packages come in 2 flavors: *component* packages and *product*
17//! packages. *Component* packages contain a single *component*. *Product*
18//! installers can contain multiple *components* as well as additional
19//! metadata describing the installer. End-user `.pkg` files are typically
20//! *product* packages. Using Apple tooling, *component* packages are built
21//! using `pkgbuild` and *product* packages using `productbuild`.
22//!
23//! ## Components
24//!
25//! A *component* defines an installable unit. *Components* are comprised of
26//! a set of well-known files:
27//!
28//! `Bom`
29//! A *bill of materials* describing the contents of the component.
30//! `PackageInfo`
31//! An XML file describing the component. See [PackageInfo] for the Rust
32//! struct defining this file format.
33//! `Payload`
34//! A cpio archive containing files comprising the component. See the
35//! `cpio-archive` for more on this file format.
36//! `Scripts`
37//! A cpio archive containing *scripts* files that run as part of component
38//! processing.
39//!
40//! ## Products
41//!
42//! A *product* flat package consists of 1 or more *components* and additional
43//! metadata.
44//!
45//! A *product* flat package is identified by the presence of a `Distribution`
46//! XML file in the root of the archive. See [Distribution] for the Rust type
47//! defining this file format. See also
48//! [Apple's XML documentation](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html).
49//!
50//! Components within a *product* flat package exist in sub-directories which often
51//! have the name `*.pkg/`.
52//!
53//! In addition, a *product* flat package may also have additional *resource* files
54//! in the `Resources/` directory.
55//!
56//! # Cryptographic Signing
57//!
58//! Cryptographic message syntax (CMS) / RFC 5652 signatures can be embedded in
59//! the XAR archive's *table of contents*, which is a data structure at the beginning
60//! of the XAR defining the content within.
61//!
62//! The cryptographic signature is over the *checksum* content digest, which is also
63//! captured in the XAR table of contents. This *checksum* effectively captures the
64//! content of all files within the XAR.
65//!
66//! # Nested Archive Formats
67//!
68//! Flat packages contain multiple data structures that effectively enumerate
69//! lists of files. There are many layers to the onion and there is duplication
70//! of functionality to express file manifests.
71//!
72//! * XAR archives contain a *table of contents* enumerating files within the XAR.
73//! * Each component has `Payload` and/or `Scripts` files, which are cpio archives.
74//! These cpio archives are file manifests containing file metadata and content.
75//! * Each component may have a `Bom`, which is a binary data structure defining
76//! file metadata as well as other attributes.
77//!
78//! There are also multiple layers that involve compression:
79//!
80//! * The XAR table of contents is likely compressed with zlib.
81//! * Individual files within XAR archives can be individually compressed
82//! with a compression format denoted by a MIME type.
83//! * cpio archive files may also be compressed.
84//! * Installed files in components may also be compressed (but this file
85//! content is treated as opaque by the flat package format).
86
87pub mod component_package;
88pub use component_package::ComponentPackageReader;
89pub mod distribution;
90pub use distribution::Distribution;
91pub mod package_info;
92pub use package_info::PackageInfo;
93pub mod reader;
94pub use reader::{PkgFlavor, PkgReader};
95
96#[derive(Debug, thiserror::Error)]
97pub enum Error {
98 #[error("I/O error: {0}")]
99 Io(#[from] std::io::Error),
100
101 #[error("scroll error: {0}")]
102 Scroll(#[from] scroll::Error),
103
104 #[error("XML error: {0}")]
105 SerdeXml(#[from] serde_xml_rs::Error),
106
107 #[error("xar error: {0}")]
108 Xar(#[from] apple_xar::Error),
109
110 #[error("cpio archive error: {0}")]
111 Cpio(#[from] cpio_archive::Error),
112
113 #[error("failed to resolve known component (this should not happen)")]
114 ComponentResolution,
115}
116
117/// Result type for this crate.
118pub type PkgResult<T> = std::result::Result<T, Error>;