From 0a2912b7d681c1480368c18953b3e8e0502716fb Mon Sep 17 00:00:00 2001 From: Darkrael <42981119+Darkrael@users.noreply.github.com> Date: Thu, 27 Mar 2025 13:40:39 +0100 Subject: [PATCH 1/5] Fixes #138. Important note: Due to bindgen now generating "unsafe extern" blocks instead of "extern" blocks, the MSRV is now 1.82, where support for this was added. --- scripts/generate-ffi | 77 ++++++++++++++++++++++---------------------- src/ffi/generated.rs | 61 ++++++++++++++++++----------------- src/iterator.rs | 11 +++++-- src/lib.rs | 19 +++++++++++ 4 files changed, 97 insertions(+), 71 deletions(-) diff --git a/scripts/generate-ffi b/scripts/generate-ffi index 365dccd..f484f0f 100755 --- a/scripts/generate-ffi +++ b/scripts/generate-ffi @@ -21,52 +21,53 @@ cat < $basedir/wrapper.h EOF bindgen \ - \ - --size_t-is-usize \ \ --raw-line "#![allow(non_camel_case_types)]" \ + --raw-line "#[cfg(not(target_os = \"windows\"))]" \ --raw-line "use libc::stat;" \ + --raw-line "#[cfg(target_os = \"windows\")]" \ + --raw-line "use crate::stat;" \ --raw-line "pub const ARCHIVE_EOF: i32 = 1;" \ --raw-line "pub const ARCHIVE_OK: i32 = 0;" \ \ - --whitelist-var "ARCHIVE_WARN" \ + --allowlist-var "ARCHIVE_WARN" \ \ - --whitelist-var "ARCHIVE_EXTRACT_TIME" \ - --whitelist-var "ARCHIVE_EXTRACT_PERM" \ - --whitelist-var "ARCHIVE_EXTRACT_ACL" \ - --whitelist-var "ARCHIVE_EXTRACT_FFLAGS" \ - --whitelist-var "ARCHIVE_EXTRACT_OWNER" \ - --whitelist-var "ARCHIVE_EXTRACT_FFLAGS" \ - --whitelist-var "ARCHIVE_EXTRACT_XATTR" \ - --whitelist-function "archive_read_new" \ - --whitelist-function "archive_read_set_seek_callback" \ - --whitelist-function "archive_read_support_filter_all" \ - --whitelist-function "archive_read_support_format_all" \ - --whitelist-function "archive_read_support_format_raw" \ - --whitelist-function "archive_read_close" \ - --whitelist-function "archive_read_free" \ - --whitelist-function "archive_read_data_block" \ - --whitelist-function "archive_read_next_header" \ - --whitelist-function "archive_read_open" \ - --whitelist-function "archive_write_disk_new" \ - --whitelist-function "archive_write_disk_set_options" \ - --whitelist-function "archive_write_disk_set_standard_lookup" \ - --whitelist-function "archive_write_header" \ - --whitelist-function "archive_write_finish_entry" \ - --whitelist-function "archive_write_data_block" \ - --whitelist-function "archive_write_close" \ - --whitelist-function "archive_write_free" \ - --whitelist-function "archive_entry_pathname" \ - --whitelist-function "archive_entry_free" \ - --whitelist-function "archive_entry_set_pathname" \ - --whitelist-function "archive_entry_set_hardlink" \ - --whitelist-function "archive_entry_hardlink" \ + --allowlist-var "ARCHIVE_EXTRACT_TIME" \ + --allowlist-var "ARCHIVE_EXTRACT_PERM" \ + --allowlist-var "ARCHIVE_EXTRACT_ACL" \ + --allowlist-var "ARCHIVE_EXTRACT_FFLAGS" \ + --allowlist-var "ARCHIVE_EXTRACT_OWNER" \ + --allowlist-var "ARCHIVE_EXTRACT_FFLAGS" \ + --allowlist-var "ARCHIVE_EXTRACT_XATTR" \ + --allowlist-function "archive_read_new" \ + --allowlist-function "archive_read_set_seek_callback" \ + --allowlist-function "archive_read_support_filter_all" \ + --allowlist-function "archive_read_support_format_all" \ + --allowlist-function "archive_read_support_format_raw" \ + --allowlist-function "archive_read_close" \ + --allowlist-function "archive_read_free" \ + --allowlist-function "archive_read_data_block" \ + --allowlist-function "archive_read_next_header" \ + --allowlist-function "archive_read_open" \ + --allowlist-function "archive_write_disk_new" \ + --allowlist-function "archive_write_disk_set_options" \ + --allowlist-function "archive_write_disk_set_standard_lookup" \ + --allowlist-function "archive_write_header" \ + --allowlist-function "archive_write_finish_entry" \ + --allowlist-function "archive_write_data_block" \ + --allowlist-function "archive_write_close" \ + --allowlist-function "archive_write_free" \ + --allowlist-function "archive_entry_pathname" \ + --allowlist-function "archive_entry_free" \ + --allowlist-function "archive_entry_set_pathname" \ + --allowlist-function "archive_entry_set_hardlink" \ + --allowlist-function "archive_entry_hardlink" \ --blocklist-type "stat" \ - --blacklist-type "timespec" \ - --whitelist-function "archive_entry_stat" \ - --whitelist-function "archive_set_error" \ - --whitelist-function "archive_error_string" \ - --whitelist-function "archive_errno" \ + --blocklist-type "timespec" \ + --allowlist-function "archive_entry_stat" \ + --allowlist-function "archive_set_error" \ + --allowlist-function "archive_error_string" \ + --allowlist-function "archive_errno" \ \ --output $basedir/src/ffi/generated.rs \ \ diff --git a/src/ffi/generated.rs b/src/ffi/generated.rs index 50f04c4..c2e9de8 100644 --- a/src/ffi/generated.rs +++ b/src/ffi/generated.rs @@ -1,6 +1,9 @@ -/* automatically generated by rust-bindgen 0.59.1 */ +/* automatically generated by rust-bindgen 0.71.1 */ #![allow(non_camel_case_types)] +#[cfg(target_os = "windows")] +use crate::stat; +#[cfg(not(target_os = "windows"))] use libc::stat; pub(crate) const ARCHIVE_EOF: i32 = 1; pub(crate) const ARCHIVE_OK: i32 = 0; @@ -12,7 +15,6 @@ pub(crate) const ARCHIVE_EXTRACT_TIME: u32 = 4; pub(crate) const ARCHIVE_EXTRACT_ACL: u32 = 32; pub(crate) const ARCHIVE_EXTRACT_FFLAGS: u32 = 64; pub(crate) const ARCHIVE_EXTRACT_XATTR: u32 = 128; -pub(crate) type __int64_t = ::std::os::raw::c_long; pub(crate) type __dev_t = ::std::os::raw::c_ulong; pub(crate) type __uid_t = ::std::os::raw::c_uint; pub(crate) type __gid_t = ::std::os::raw::c_uint; @@ -23,7 +25,6 @@ pub(crate) type __off_t = ::std::os::raw::c_long; pub(crate) type __time_t = ::std::os::raw::c_long; pub(crate) type __blksize_t = ::std::os::raw::c_long; pub(crate) type __blkcnt_t = ::std::os::raw::c_long; -pub(crate) type __ssize_t = ::std::os::raw::c_long; pub(crate) type __syscall_slong_t = ::std::os::raw::c_long; pub(crate) type la_int64_t = i64; pub(crate) type la_ssize_t = isize; @@ -64,25 +65,25 @@ pub(crate) type archive_close_callback = ::std::option::Option< _client_data: *mut ::std::os::raw::c_void, ) -> ::std::os::raw::c_int, >; -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_new() -> *mut archive; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_support_filter_all(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_support_format_all(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_support_format_raw(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_set_seek_callback( arg1: *mut archive, arg2: archive_seek_callback, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_open( arg1: *mut archive, _client_data: *mut ::std::os::raw::c_void, @@ -91,13 +92,13 @@ extern "C" { arg4: archive_close_callback, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_next_header( arg1: *mut archive, arg2: *mut *mut archive_entry, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_data_block( a: *mut archive, buff: *mut *const ::std::os::raw::c_void, @@ -105,19 +106,19 @@ extern "C" { offset: *mut la_int64_t, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_close(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_read_free(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_header( arg1: *mut archive, arg2: *mut archive_entry, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_data_block( arg1: *mut archive, arg2: *const ::std::os::raw::c_void, @@ -125,36 +126,36 @@ extern "C" { arg4: la_int64_t, ) -> la_ssize_t; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_finish_entry(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_close(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_free(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_disk_new() -> *mut archive; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_disk_set_options( arg1: *mut archive, flags: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_write_disk_set_standard_lookup( arg1: *mut archive, ) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_errno(arg1: *mut archive) -> ::std::os::raw::c_int; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_error_string(arg1: *mut archive) -> *const ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_set_error( arg1: *mut archive, _err: ::std::os::raw::c_int, @@ -162,29 +163,29 @@ extern "C" { ... ); } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_free(arg1: *mut archive_entry); } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_hardlink(arg1: *mut archive_entry) -> *const ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_pathname(arg1: *mut archive_entry) -> *const ::std::os::raw::c_char; } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_set_hardlink( arg1: *mut archive_entry, arg2: *const ::std::os::raw::c_char, ); } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_set_pathname( arg1: *mut archive_entry, arg2: *const ::std::os::raw::c_char, ); } -extern "C" { +unsafe extern "C" { pub(crate) fn archive_entry_stat(arg1: *mut archive_entry) -> *const stat; } diff --git a/src/iterator.rs b/src/iterator.rs index 16e1d11..868e5dd 100644 --- a/src/iterator.rs +++ b/src/iterator.rs @@ -6,6 +6,11 @@ use std::{ use libc::{c_int, c_void}; +#[cfg(target_os = "windows")] +use crate::stat; +#[cfg(not(target_os = "windows"))] +use libc::stat; + use crate::{ error::archive_result, ffi, ffi::UTF8LocaleGuard, DecodeCallback, Error, Result, READER_BUFFER_SIZE, @@ -26,7 +31,7 @@ struct HeapReadSeekerPipe { /// completion. pub enum ArchiveContents { /// Marks the start of an entry, either a file or a directory. - StartOfEntry(String, libc::stat), + StartOfEntry(String, stat), /// A chunk of uncompressed data from the entry. Entries may have zero or /// more chunks. DataChunk(Vec), @@ -42,7 +47,7 @@ pub enum ArchiveContents { /// Gets called on an encounter of a new archive entry with the filename and /// file status information of that entry. /// The entry is processed on a return value of `true` and ignored on `false`. -pub type EntryFilterCallbackFn = dyn Fn(&str, &libc::stat) -> bool; +pub type EntryFilterCallbackFn = dyn Fn(&str, &stat) -> bool; /// An iterator over the contents of an archive. #[allow(clippy::module_name_repetitions)] @@ -481,7 +486,7 @@ where /// By default all entries are iterated. pub fn filter(mut self, filter: F) -> ArchiveIteratorBuilder where - F: Fn(&str, &libc::stat) -> bool + 'static, + F: Fn(&str, &stat) -> bool + 'static, { self.filter = Some(Box::new(filter)); self diff --git a/src/lib.rs b/src/lib.rs index 12a3fe9..8ba9c8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,25 @@ use std::{ const READER_BUFFER_SIZE: usize = 16384; +/// A data type that represents the libc stat type on windows, not stat64 +#[cfg(target_os = "windows")] +#[derive(Copy, Clone)] +#[repr(C)] +#[allow(non_camel_case_types)] +pub struct stat { + pub st_dev: libc::dev_t, + pub st_ino: libc::ino_t, + pub st_mode: u16, + pub st_nlink: libc::c_short, + pub st_uid: libc::c_short, + pub st_gid: libc::c_short, + pub st_rdev: libc::dev_t, + pub st_size: i32, + pub st_atime: libc::time_t, + pub st_mtime: libc::time_t, + pub st_ctime: libc::time_t, +} + /// Determine the ownership behavior when unpacking the archive. #[derive(Clone, Copy, Debug)] pub enum Ownership { From 6d7f1bee8cf7ed948e67ef306318dae985386dce Mon Sep 17 00:00:00 2001 From: Darkrael <42981119+Darkrael@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:13:41 +0200 Subject: [PATCH 2/5] Downgraded tokio to 1.38 to downgrade mio to pre 1.0 to maintain compatibility with rust 1.65 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3a39617..7168ea4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ futures-io = { version = "0.3.5", optional = true } futures-util = { version = "0.3.5", features = ["sink", "io"], optional = true } futures-executor = { version = "0.3.5", optional = true } blocking = { version = "1.0.0", optional = true } -tokio = { version = "1.0.0", features = ["rt-multi-thread", "macros", "fs", "net"], optional = true } +tokio = { version = "=1.38", features = ["rt-multi-thread", "macros", "fs", "net"], optional = true } tokio-util = { version = "0.7.0", features = ["compat"], optional = true } libc = "0.2.86" From f783ac91d050cb9381c7ea4fc0a20e0cf75e08f2 Mon Sep 17 00:00:00 2001 From: Darkrael <42981119+Darkrael@users.noreply.github.com> Date: Mon, 31 Mar 2025 10:27:19 +0200 Subject: [PATCH 3/5] Update generate-ffi to target rust version 1.65 to avoid incompatible syntax when generating and update generated.rs. --- scripts/generate-ffi | 2 ++ src/ffi/generated.rs | 54 ++++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/scripts/generate-ffi b/scripts/generate-ffi index f484f0f..c23cae3 100755 --- a/scripts/generate-ffi +++ b/scripts/generate-ffi @@ -21,6 +21,8 @@ cat < $basedir/wrapper.h EOF bindgen \ + \ + --rust-target "1.65.0" \ \ --raw-line "#![allow(non_camel_case_types)]" \ --raw-line "#[cfg(not(target_os = \"windows\"))]" \ diff --git a/src/ffi/generated.rs b/src/ffi/generated.rs index c2e9de8..12dceef 100644 --- a/src/ffi/generated.rs +++ b/src/ffi/generated.rs @@ -65,25 +65,25 @@ pub(crate) type archive_close_callback = ::std::option::Option< _client_data: *mut ::std::os::raw::c_void, ) -> ::std::os::raw::c_int, >; -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_new() -> *mut archive; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_support_filter_all(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_support_format_all(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_support_format_raw(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_set_seek_callback( arg1: *mut archive, arg2: archive_seek_callback, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_open( arg1: *mut archive, _client_data: *mut ::std::os::raw::c_void, @@ -92,13 +92,13 @@ unsafe extern "C" { arg4: archive_close_callback, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_next_header( arg1: *mut archive, arg2: *mut *mut archive_entry, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_data_block( a: *mut archive, buff: *mut *const ::std::os::raw::c_void, @@ -106,19 +106,19 @@ unsafe extern "C" { offset: *mut la_int64_t, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_close(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_read_free(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_header( arg1: *mut archive, arg2: *mut archive_entry, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_data_block( arg1: *mut archive, arg2: *const ::std::os::raw::c_void, @@ -126,36 +126,36 @@ unsafe extern "C" { arg4: la_int64_t, ) -> la_ssize_t; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_finish_entry(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_close(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_free(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_disk_new() -> *mut archive; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_disk_set_options( arg1: *mut archive, flags: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_write_disk_set_standard_lookup( arg1: *mut archive, ) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_errno(arg1: *mut archive) -> ::std::os::raw::c_int; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_error_string(arg1: *mut archive) -> *const ::std::os::raw::c_char; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_set_error( arg1: *mut archive, _err: ::std::os::raw::c_int, @@ -163,29 +163,29 @@ unsafe extern "C" { ... ); } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_free(arg1: *mut archive_entry); } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_hardlink(arg1: *mut archive_entry) -> *const ::std::os::raw::c_char; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_pathname(arg1: *mut archive_entry) -> *const ::std::os::raw::c_char; } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_set_hardlink( arg1: *mut archive_entry, arg2: *const ::std::os::raw::c_char, ); } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_set_pathname( arg1: *mut archive_entry, arg2: *const ::std::os::raw::c_char, ); } -unsafe extern "C" { +extern "C" { pub(crate) fn archive_entry_stat(arg1: *mut archive_entry) -> *const stat; } From b335e91105c94565e7d6fbbebb1cd52a679ea876 Mon Sep 17 00:00:00 2001 From: Darkrael <42981119+Darkrael@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:57:54 +0200 Subject: [PATCH 4/5] Update Cargo.toml to lock tokio-utils to 0.7.22 to be compatible with rust 1.65 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7168ea4..8b73f5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ futures-util = { version = "0.3.5", features = ["sink", "io"], optional = true } futures-executor = { version = "0.3.5", optional = true } blocking = { version = "1.0.0", optional = true } tokio = { version = "=1.38", features = ["rt-multi-thread", "macros", "fs", "net"], optional = true } -tokio-util = { version = "0.7.0", features = ["compat"], optional = true } +tokio-util = { version = "=0.7.11", features = ["compat"], optional = true } libc = "0.2.86" [features] From 82f510120ce66fcc021c47598873a8a9220bd05f Mon Sep 17 00:00:00 2001 From: Darkrael <42981119+Darkrael@users.noreply.github.com> Date: Fri, 11 Apr 2025 16:59:24 +0200 Subject: [PATCH 5/5] Update integration_test.rs to test the stat object given by the ArchiveIterator --- tests/integration_test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 6d18ad8..61478be 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -541,9 +541,9 @@ fn collect_iterate_results_with_encoding( for content in &mut iter { match content { - ArchiveContents::StartOfEntry(file_name, _) => { + ArchiveContents::StartOfEntry(file_name, stat) => { assert!(name.is_empty()); - assert_eq!(size, 0); + assert_eq!(stat.st_size == 0, file_name.ends_with('/')); name = file_name; } ArchiveContents::DataChunk(data) => {