]>
git.proxmox.com Git - rustc.git/blob - vendor/object-0.22.0/src/read/archive.rs
1 //! Support for archive files.
3 use crate::read
::{self, Error, ReadError}
;
4 use crate::{archive, Bytes}
;
6 /// The kind of archive format.
7 // TODO: Gnu64 and Darwin64 (and Darwin for writing)
8 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10 /// There are no special files that indicate the archive format.
12 /// The GNU (or System V) archive format.
14 /// The BSD archive format.
16 /// The Windows COFF archive format.
20 /// A partially parsed archive file.
22 pub struct ArchiveFile
<'data
> {
25 symbols
: Bytes
<'data
>,
29 impl<'data
> ArchiveFile
<'data
> {
30 /// Parse the archive header and special members.
31 pub fn parse(data
: &'data
[u8]) -> read
::Result
<Self> {
32 let data
= Bytes(data
);
36 .read_bytes(archive
::MAGIC
.len())
37 .read_error("Invalid archive size")?
;
38 if magic
.0 != &archive
::MAGIC
[..] {
39 return Err(Error("Unsupported archive identifier"));
42 let mut file
= ArchiveFile
{
44 kind
: ArchiveKind
::Unknown
,
49 // The first few members may be special, so parse them.
51 // - "/": symbol table (optional)
52 // - "//": names table (optional)
54 // - "/": first linker member
55 // - "/": second linker member
56 // - "//": names table
58 // - "__.SYMDEF" or "__.SYMDEF SORTED": symbol table (optional)
60 let member
= ArchiveMember
::parse(&mut tail
, Bytes(&[]))?
;
61 if member
.name
== b
"/" {
62 // GNU symbol table (unless we later determine this is COFF).
63 file
.kind
= ArchiveKind
::Gnu
;
64 file
.symbols
= member
.data
;
68 let member
= ArchiveMember
::parse(&mut tail
, Bytes(&[]))?
;
69 if member
.name
== b
"/" {
70 // COFF linker member.
71 file
.kind
= ArchiveKind
::Coff
;
72 file
.symbols
= member
.data
;
76 let member
= ArchiveMember
::parse(&mut tail
, Bytes(&[]))?
;
77 if member
.name
== b
"//" {
79 file
.names
= member
.data
;
83 } else if member
.name
== b
"//" {
85 file
.names
= member
.data
;
89 } else if member
.name
== b
"//" {
91 file
.kind
= ArchiveKind
::Gnu
;
92 file
.names
= member
.data
;
94 } else if member
.name
== b
"__.SYMDEF" || member
.name
== b
"__.SYMDEF SORTED" {
96 file
.kind
= ArchiveKind
::Bsd
;
97 file
.symbols
= member
.data
;
100 // TODO: This could still be a BSD file. We leave this as unknown for now.
106 /// Return the archive format.
108 pub fn kind(&self) -> ArchiveKind
{
112 /// Iterate over the members of the archive.
114 /// This does not return special members.
116 pub fn members(&self) -> ArchiveMemberIterator
<'data
> {
117 ArchiveMemberIterator
{
124 /// An iterator over the members of an archive.
126 pub struct ArchiveMemberIterator
<'data
> {
131 impl<'data
> Iterator
for ArchiveMemberIterator
<'data
> {
132 type Item
= read
::Result
<ArchiveMember
<'data
>>;
134 fn next(&mut self) -> Option
<Self::Item
> {
135 if self.data
.is_empty() {
138 let member
= ArchiveMember
::parse(&mut self.data
, self.names
);
140 self.data
= Bytes(&[]);
146 /// A partially parsed archive member.
148 pub struct ArchiveMember
<'data
> {
149 header
: &'data archive
::Header
,
154 impl<'data
> ArchiveMember
<'data
> {
155 /// Parse the archive member header, name, and file data.
157 /// This reads the extended name (if any) and adjusts the file size.
158 fn parse(data
: &mut Bytes
<'data
>, names
: Bytes
<'data
>) -> read
::Result
<Self> {
160 .read
::<archive
::Header
>()
161 .read_error("Invalid archive member header")?
;
162 if header
.terminator
!= archive
::TERMINATOR
{
163 return Err(Error("Invalid archive terminator"));
167 parse_usize_digits(&header
.size
, 10).read_error("Invalid archive member size")?
;
168 let mut file_data
= data
170 .read_error("Archive member size is too large")?
;
171 // Entries are padded to an even number of bytes.
176 let name
= if header
.name
[0] == b'
/'
&& (header
.name
[1] as char).is_digit(10) {
177 // Read file name from the names table.
178 parse_sysv_extended_name(&header
.name
[1..], names
)
179 .read_error("Invalid archive extended name offset")?
180 } else if &header
.name
[..3] == b
"#1/" && (header
.name
[3] as char).is_digit(10) {
181 // Read file name from the start of the file data.
182 parse_bsd_extended_name(&header
.name
[3..], &mut file_data
)
183 .read_error("Invalid archive extended name length")?
184 } else if header
.name
[0] == b'
/'
{
186 (header
.name
.iter().position(|&x
| x
== b' '
)).unwrap_or_else(|| header
.name
.len());
187 &header
.name
[..name_len
]
189 let name_len
= (header
.name
.iter().position(|&x
| x
== b'
/'
))
190 .or_else(|| header
.name
.iter().position(|&x
| x
== b' '
))
191 .unwrap_or_else(|| header
.name
.len());
192 &header
.name
[..name_len
]
202 /// Return the raw header.
204 pub fn header(&self) -> &'data archive
::Header
{
208 /// Return the parsed file name.
210 /// This may be an extended file name.
212 pub fn name(&self) -> &'data
[u8] {
216 /// Parse the file modification timestamp from the header.
218 pub fn date(&self) -> Option
<usize> {
219 parse_usize_digits(&self.header
.date
, 10)
222 /// Parse the user ID from the header.
224 pub fn uid(&self) -> Option
<usize> {
225 parse_usize_digits(&self.header
.uid
, 10)
228 /// Parse the group ID from the header.
230 pub fn gid(&self) -> Option
<usize> {
231 parse_usize_digits(&self.header
.gid
, 10)
234 /// Parse the file mode from the header.
236 pub fn mode(&self) -> Option
<usize> {
237 parse_usize_digits(&self.header
.mode
, 8)
240 /// Return the file data.
242 pub fn data(&self) -> &'data
[u8] {
247 // Ignores bytes starting from the first space.
248 fn parse_usize_digits(digits
: &[u8], radix
: u32) -> Option
<usize> {
251 .position(|&x
| x
== b' '
)
252 .unwrap_or_else(|| digits
.len());
253 let digits
= &digits
[..len
];
254 if digits
.is_empty() {
257 let mut result
: usize = 0;
259 let x
= (c
as char).to_digit(radix
)?
;
261 .checked_mul(radix
as usize)?
262 .checked_add(x
as usize)?
;
267 fn parse_sysv_extended_name
<'data
>(
269 mut names
: Bytes
<'data
>,
270 ) -> Result
<&'data
[u8], ()> {
271 let offset
= parse_usize_digits(digits
, 10).ok_or(())?
;
273 let name
= match names
.0.iter
().position(|&x
| x
== b'
/'
|| x
== 0) {
274 Some(len
) => names
.read_bytes(len
)?
,
280 /// Modifies `data` to start after the extended name.
281 fn parse_bsd_extended_name
<'data
>(
283 data
: &mut Bytes
<'data
>,
284 ) -> Result
<&'data
[u8], ()> {
285 let len
= parse_usize_digits(digits
, 10).ok_or(())?
;
286 let mut name_data
= data
.read_bytes(len
)?
;
287 let name
= match name_data
.0.iter
().position(|&x
| x
== 0) {
288 Some(len
) => name_data
.read_bytes(len
)?
,
300 let data
= b
"!<arch>\n";
301 let archive
= ArchiveFile
::parse(data
).unwrap();
302 assert_eq
!(archive
.kind(), ArchiveKind
::Unknown
);
308 let archive
= ArchiveFile
::parse(data
).unwrap();
309 assert_eq
!(archive
.kind(), ArchiveKind
::Gnu
);
315 let archive
= ArchiveFile
::parse(data
).unwrap();
316 assert_eq
!(archive
.kind(), ArchiveKind
::Gnu
);
324 let archive
= ArchiveFile
::parse(data
).unwrap();
325 assert_eq
!(archive
.kind(), ArchiveKind
::Gnu
);
331 let archive
= ArchiveFile
::parse(data
).unwrap();
332 assert_eq
!(archive
.kind(), ArchiveKind
::Bsd
);
338 let archive
= ArchiveFile
::parse(data
).unwrap();
339 assert_eq
!(archive
.kind(), ArchiveKind
::Bsd
);
344 __.SYMDEF SORTED0000";
345 let archive
= ArchiveFile
::parse(data
).unwrap();
346 assert_eq
!(archive
.kind(), ArchiveKind
::Bsd
);
356 let archive
= ArchiveFile
::parse(data
).unwrap();
357 assert_eq
!(archive
.kind(), ArchiveKind
::Coff
);
366 0123456789abcde/0 0 0 644 3 `\n\
370 let archive
= ArchiveFile
::parse(data
).unwrap();
371 assert_eq
!(archive
.kind(), ArchiveKind
::Gnu
);
372 let mut members
= archive
.members();
374 let member
= members
.next().unwrap().unwrap();
375 assert_eq
!(member
.name(), b
"0123456789abcde");
376 assert_eq
!(member
.data(), b
"odd");
378 let member
= members
.next().unwrap().unwrap();
379 assert_eq
!(member
.name(), b
"0123456789abcdef");
380 assert_eq
!(member
.data(), b
"even");
382 assert
!(members
.next().is_none());
389 0123456789abcde 0 0 0 644 3 `\n\
391 #1/16 0 0 0 644 20 `\n\
392 0123456789abcdefeven";
393 let archive
= ArchiveFile
::parse(data
).unwrap();
394 assert_eq
!(archive
.kind(), ArchiveKind
::Unknown
);
395 let mut members
= archive
.members();
397 let member
= members
.next().unwrap().unwrap();
398 assert_eq
!(member
.name(), b
"0123456789abcde");
399 assert_eq
!(member
.data(), b
"odd");
401 let member
= members
.next().unwrap().unwrap();
402 assert_eq
!(member
.name(), b
"0123456789abcdef");
403 assert_eq
!(member
.data(), b
"even");
405 assert
!(members
.next().is_none());