|
52 | 52 | //! Archive-listing and archive-extraction entry points (`list_archive_files`, |
53 | 53 | //! `list_archive_entries`, `uncompress_archive`, `uncompress_archive_file`, |
54 | 54 | //! `ArchiveIterator`, and their async/`_with_encoding` siblings) no longer |
55 | | -//! register libarchive's "raw" format handler. They return an error for |
56 | | -//! input that isn't a real archive instead of yielding a single entry |
57 | | -//! called `data`, so callers can reliably distinguish archives from other |
58 | | -//! files. |
| 55 | +//! accept libarchive's two promiscuous format handlers: "raw" (which |
| 56 | +//! matches arbitrary bytes) and "mtree" (which matches free-form text). |
| 57 | +//! They return an error for input that isn't a real archive, so callers |
| 58 | +//! can reliably distinguish archives from other files. |
59 | 59 | //! |
60 | 60 | //! Use [`uncompress_data`] for decompressing a single stream (gzip, xz, …) |
61 | 61 | //! — it continues to support raw input because that is its purpose. For |
@@ -241,6 +241,7 @@ where |
241 | 241 | ffi::ARCHIVE_EOF => return Ok(entries), |
242 | 242 | value => archive_result(value, archive_reader)?, |
243 | 243 | } |
| 244 | + reject_mtree_format(archive_reader)?; |
244 | 245 |
|
245 | 246 | let _utf8_guard = ffi::WindowsUTF8LocaleGuard::new(); |
246 | 247 | let cstr = libarchive_entry_pathname(entry)?; |
@@ -363,6 +364,7 @@ where |
363 | 364 | ffi::ARCHIVE_EOF => return Ok(()), |
364 | 365 | value => archive_result(value, archive_reader)?, |
365 | 366 | } |
| 367 | + reject_mtree_format(archive_reader)?; |
366 | 368 |
|
367 | 369 | let _utf8_guard = ffi::WindowsUTF8LocaleGuard::new(); |
368 | 370 | let cstr = libarchive_entry_pathname(entry)?; |
@@ -478,6 +480,7 @@ where |
478 | 480 | } |
479 | 481 | value => archive_result(value, archive_reader)?, |
480 | 482 | } |
| 483 | + reject_mtree_format(archive_reader)?; |
481 | 484 |
|
482 | 485 | let _utf8_guard = ffi::WindowsUTF8LocaleGuard::new(); |
483 | 486 | let cstr = libarchive_entry_pathname(entry)?; |
@@ -681,6 +684,23 @@ fn sanitize_destination_path(dest: &Path) -> Result<&Path> { |
681 | 684 | }) |
682 | 685 | } |
683 | 686 |
|
| 687 | +// libarchive's mtree format handler parses free-form text specifications and |
| 688 | +// willingly matches innocuous content (a plain gunzip'd text file, for |
| 689 | +// instance). Treat an mtree match the same way we treat raw: not an archive. |
| 690 | +// Must be called after a successful `archive_read_next_header`, which is |
| 691 | +// when libarchive populates the format code. |
| 692 | +pub(crate) unsafe fn reject_mtree_format(archive_reader: *mut ffi::archive) -> Result<()> { |
| 693 | + if ffi::archive_format(archive_reader) & ffi::ARCHIVE_FORMAT_BASE_MASK |
| 694 | + == ffi::ARCHIVE_FORMAT_MTREE |
| 695 | + { |
| 696 | + return Err(Error::Extraction { |
| 697 | + code: None, |
| 698 | + details: "mtree specifications are not treated as archives".to_string(), |
| 699 | + }); |
| 700 | + } |
| 701 | + Ok(()) |
| 702 | +} |
| 703 | + |
684 | 704 | fn libarchive_copy_data( |
685 | 705 | archive_reader: *mut ffi::archive, |
686 | 706 | archive_writer: *mut ffi::archive, |
|
0 commit comments