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// ========================================================================= //