sludge_ar_with_ranlib/
lib.rs

1//! A library for encoding/decoding Unix archive files.
2//!
3//! This library provides utilities necessary to manage [Unix archive
4//! files](https://en.wikipedia.org/wiki/Ar_(Unix)) (as generated by the
5//! standard `ar` command line utility) abstracted over a reader or writer.
6//! This library provides a streaming interface that avoids having to ever load
7//! a full archive entry into memory.
8//!
9//! The API of this crate is meant to be similar to that of the
10//! [`tar`](https://crates.io/crates/tar) crate.
11//!
12//! # Format variants
13//!
14//! Unix archive files come in several variants, of which three are the most
15//! common:
16//!
17//! * The *common variant*, used for Debian package (`.deb`) files among other
18//!   things, which only supports filenames up to 16 characters.
19//! * The *BSD variant*, used by the `ar` utility on BSD systems (including Mac
20//!   OS X), which is backwards-compatible with the common variant, but extends
21//!   it to support longer filenames and filenames containing spaces.
22//! * The *GNU variant*, used by the `ar` utility on GNU and many other systems
23//!   (including Windows), which is similar to the common format, but which
24//!   stores filenames in a slightly different, incompatible way, and has its
25//!   own strategy for supporting long filenames.
26//!
27//! This crate supports reading and writing all three of these variants.
28//!
29//! # Example usage
30//!
31//! Writing an archive:
32//!
33//! ```no_run
34//! use ar::Builder;
35//! use std::collections::BTreeMap;
36//! use std::fs::File;
37//! // Create a new archive that will be written to foo.a:
38//! let mut builder = Builder::new(File::create("foo.a").unwrap(), BTreeMap::new()).unwrap();
39//! // Add foo/bar.txt to the archive, under the name "bar.txt":
40//! builder.append_path("foo/bar.txt").unwrap();
41//! // Add foo/baz.txt to the archive, under the name "hello.txt":
42//! let mut file = File::open("foo/baz.txt").unwrap();
43//! builder.append_file(b"hello.txt", &mut file).unwrap();
44//! ```
45//!
46//! Reading an archive:
47//!
48//! ```no_run
49//! use ar::Archive;
50//! use std::fs::File;
51//! use std::io;
52//! use std::str;
53//! // Read an archive from the file foo.a:
54//! let mut archive = Archive::new(File::open("foo.a").unwrap());
55//! // Iterate over all entries in the archive:
56//! while let Some(entry_result) = archive.next_entry() {
57//!     let mut entry = entry_result.unwrap();
58//!     // Create a new file with the same name as the archive entry:
59//!     let mut file = File::create(
60//!         str::from_utf8(entry.header().identifier()).unwrap(),
61//!     ).unwrap();
62//!     // The Entry object also acts as an io::Read, so we can easily copy the
63//!     // contents of the archive entry into the file:
64//!     io::copy(&mut entry, &mut file).unwrap();
65//! }
66//! ```
67
68#![warn(missing_docs)]
69
70mod read;
71mod write;
72
73pub use read::{Archive, Entry, SymbolTableEntry, Symbols};
74pub use write::{Builder, GnuBuilder, GnuSymbolTableFormat};
75
76use std::fs::Metadata;
77
78#[cfg(unix)]
79use std::os::unix::fs::MetadataExt;
80
81// ========================================================================= //
82
83const GLOBAL_HEADER_LEN: usize = 8;
84const GLOBAL_HEADER: &'static [u8; GLOBAL_HEADER_LEN] = b"!<arch>\n";
85
86const ENTRY_HEADER_LEN: usize = 60;
87
88const BSD_SYMBOL_LOOKUP_TABLE_ID: &str = "__.SYMDEF";
89const BSD_SORTED_SYMBOL_LOOKUP_TABLE_ID: &str = "__.SYMDEF SORTED";
90
91const GNU_NAME_TABLE_ID: &str = "//";
92const GNU_SYMBOL_LOOKUP_TABLE_ID: &str = "/";
93const GNU_SYMBOL_LOOKUP_TABLE_64BIT_ID: &str = "/SYM64";
94
95// ========================================================================= //
96
97/// Variants of the Unix archive format.
98#[derive(Clone, Copy, Debug, Eq, PartialEq)]
99pub enum Variant {
100    /// Used by Debian package files; allows only short filenames.
101    Common,
102    /// Used by BSD `ar` (and OS X); backwards-compatible with common variant.
103    BSD,
104    /// Used by GNU `ar` (and Windows); incompatible with common variant.
105    GNU,
106}
107
108/// Variants of the symbol table if present
109#[derive(Clone, Copy, Debug, Eq, PartialEq)]
110pub enum SymbolTableVariant {
111    /// Used by BSD Archives the more "classical" unix symbol table
112    BSD,
113    /// Used in GNU, SVR4 and others
114    GNU,
115    /// The extended format used when an archive becomes larger than 4gb
116    GNU64BIT,
117}
118
119// ========================================================================= //
120
121/// Representation of an archive entry header.
122#[derive(Clone, Debug, Eq, PartialEq)]
123pub struct Header {
124    identifier: Vec<u8>,
125    mtime: u64,
126    uid: u32,
127    gid: u32,
128    mode: u32,
129    size: u64,
130}
131
132impl Header {
133    /// Creates a header with the given file identifier and size, and all
134    /// other fields set to zero.
135    pub fn new(identifier: Vec<u8>, size: u64) -> Header {
136        Header {
137            identifier,
138            mtime: 0,
139            uid: 0,
140            gid: 0,
141            mode: 0,
142            size,
143        }
144    }
145
146    /// Creates a header with the given file identifier and all other fields
147    /// set from the given filesystem metadata.
148    #[cfg(unix)]
149    pub fn from_metadata(identifier: Vec<u8>, meta: &Metadata) -> Header {
150        Header {
151            identifier,
152            mtime: meta.mtime() as u64,
153            uid: meta.uid(),
154            gid: meta.gid(),
155            mode: meta.mode(),
156            size: meta.len(),
157        }
158    }
159
160    #[cfg(not(unix))]
161    pub fn from_metadata(identifier: Vec<u8>, meta: &Metadata) -> Header {
162        Header::new(identifier, meta.len())
163    }
164
165    /// Returns the file identifier.
166    pub fn identifier(&self) -> &[u8] { &self.identifier }
167
168    /// Sets the file identifier.
169    pub fn set_identifier(&mut self, identifier: Vec<u8>) {
170        self.identifier = identifier;
171    }
172
173    /// Returns the last modification time in Unix time format.
174    pub fn mtime(&self) -> u64 { self.mtime }
175
176    /// Sets the last modification time in Unix time format.
177    pub fn set_mtime(&mut self, mtime: u64) { self.mtime = mtime; }
178
179    /// Returns the value of the owner's user ID field.
180    pub fn uid(&self) -> u32 { self.uid }
181
182    /// Sets the value of the owner's user ID field.
183    pub fn set_uid(&mut self, uid: u32) { self.uid = uid; }
184
185    /// Returns the value of the group's user ID field.
186    pub fn gid(&self) -> u32 { self.gid }
187
188    /// Returns the value of the group's user ID field.
189    pub fn set_gid(&mut self, gid: u32) { self.gid = gid; }
190
191    /// Returns the mode bits for this file.
192    pub fn mode(&self) -> u32 { self.mode }
193
194    /// Sets the mode bits for this file.
195    pub fn set_mode(&mut self, mode: u32) { self.mode = mode; }
196
197    /// Returns the length of the file, in bytes.
198    pub fn size(&self) -> u64 { self.size }
199
200    /// Sets the length of the file, in bytes.
201    pub fn set_size(&mut self, size: u64) { self.size = size; }
202}
203// ========================================================================= //