From dea910ac786e1c59d58be98abdb8301c3e002e0f Mon Sep 17 00:00:00 2001 From: Danyel Date: Fri, 6 Sep 2024 22:31:03 +0200 Subject: [PATCH] fix(linux): use non-wide functions for linux target --- Cargo.toml | 2 ++ src/lib.rs | 1 + src/open_archive.rs | 61 +++++++++++++++++++-------------------------- src/pathed/all.rs | 27 ++++++++++++++++++++ src/pathed/linux.rs | 27 ++++++++++++++++++++ src/pathed/mod.rs | 5 ++++ 6 files changed, 88 insertions(+), 35 deletions(-) create mode 100644 src/pathed/all.rs create mode 100644 src/pathed/linux.rs create mode 100644 src/pathed/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 6a7c2d2..787969e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,13 @@ repository = "https://github.com/muja/unrar.rs" [dependencies] regex = "1" bitflags = "1" +# [target.'cfg(not(target_os = "linux"))'.dependencies] widestring = "1" [dependencies.unrar_sys] path = "unrar_sys" version = "0.5" + [dev-dependencies] tempfile = "3.12.0" diff --git a/src/lib.rs b/src/lib.rs index 6a8a9f1..ef542af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub use archive::Archive; use unrar_sys as native; mod archive; pub mod error; +mod pathed; mod open_archive; pub use error::UnrarResult; pub use open_archive::{ diff --git a/src/open_archive.rs b/src/open_archive.rs index 3de1f2f..fd8f809 100644 --- a/src/open_archive.rs +++ b/src/open_archive.rs @@ -1,11 +1,9 @@ use super::error::*; use super::*; -use std::ffi::CString; use std::fmt; use std::os::raw::{c_int, c_uint}; use std::path::{Path, PathBuf}; use std::ptr::NonNull; -use widestring::WideCString; bitflags::bitflags! { #[derive(Default)] @@ -53,7 +51,7 @@ pub struct OpenArchive { extra: C, marker: std::marker::PhantomData, } -type Userdata = (T, Option); +type Userdata = (T, Option); mod private { use super::native; @@ -204,7 +202,7 @@ impl OpenArchive { /// /// ```no_run /// use unrar::{Archive, error::{When, Code}}; - /// + /// /// let mut archive = Archive::new("corrupt.rar").open_for_listing().expect("archive error"); /// loop { /// let mut error = None; @@ -233,12 +231,7 @@ impl OpenArchive { password: Option<&[u8]>, recover: Option<&mut Option>, ) -> UnrarResult { - #[cfg(target_os = "linux")] - // on Linux there is an issue with unicode filenames when using wide strings - // so we use non-wide strings. See https://github.com/muja/unrar.rs/issues/44 - let filename = CString::new(filename.as_os_str().as_encoded_bytes()).unwrap(); - #[cfg(not(target_os = "linux"))] - let filename = WideCString::from_os_str(&filename).unwrap(); + let filename = pathed::construct(filename); let mut data = native::OpenArchiveDataEx::new(filename.as_ptr() as *const _, Mode::VALUE as u32); @@ -247,7 +240,7 @@ impl OpenArchive { let arc = handle.and_then(|handle| { if let Some(pw) = password { - let cpw = CString::new(pw).unwrap(); + let cpw = std::ffi::CString::new(pw).unwrap(); unsafe { native::RARSetPassword(handle.as_ptr(), cpw.as_ptr() as *const _) } } Some(OpenArchive { @@ -360,16 +353,16 @@ impl OpenArchive { fn process_file( self, - path: Option<&WideCString>, - file: Option<&WideCString>, + path: Option<&pathed::RarPath>, + file: Option<&pathed::RarPath>, ) -> UnrarResult> { Ok(self.process_file_x::(path, file)?.1) } fn process_file_x( self, - path: Option<&WideCString>, - file: Option<&WideCString>, + path: Option<&pathed::RarPath>, + file: Option<&pathed::RarPath>, ) -> UnrarResult<(PM::Output, OpenArchive)> { let result = Ok(( Internal::::process_file_raw(&self.handle, path, file)?, @@ -413,8 +406,8 @@ impl OpenArchive { self, base: P, ) -> UnrarResult> { - let wdest = WideCString::from_os_str(base.as_ref()).expect("Unexpected nul in destination"); - self.process_file::(Some(&wdest), None) + let path = pathed::construct(&base); + self.process_file::(Some(&path), None) } /// Extracts the file into the specified file. @@ -425,10 +418,10 @@ impl OpenArchive { /// This function will panic if `dest` contains nul characters. pub fn extract_to>( self, - dest: P, + file: P, ) -> UnrarResult> { - let wdest = WideCString::from_os_str(dest.as_ref()).expect("Unexpected nul in destination"); - self.process_file::(None, Some(&wdest)) + let dest = pathed::construct(&file); + self.process_file::(None, Some(&dest)) } } @@ -513,7 +506,8 @@ impl Internal { native::UCM_CHANGEVOLUMEW => { // 2048 seems to be the buffer size in unrar, // also it's the maximum path length since 5.00. - let next = unsafe { WideCString::from_ptr_truncate(p1 as *const _, 2048) }; + let next = + unsafe { widestring::WideCString::from_ptr_truncate(p1 as *const _, 2048) }; user_data.1 = Some(next); match p2 { // Next volume not found. -1 means stop @@ -533,8 +527,8 @@ impl Internal { fn process_file_raw( handle: &Handle, - path: Option<&WideCString>, - file: Option<&WideCString>, + path: Option<&pathed::RarPath>, + file: Option<&pathed::RarPath>, ) -> UnrarResult { let mut user_data: Userdata = Default::default(); unsafe { @@ -544,16 +538,12 @@ impl Internal { &mut user_data as *mut _ as native::LPARAM, ); } - let process_result = Code::from(unsafe { - native::RARProcessFileW( - handle.0.as_ptr(), - M::OPERATION as i32, - path.map(|path| path.as_ptr() as *const _) - .unwrap_or(std::ptr::null()), - file.map(|file| file.as_ptr() as *const _) - .unwrap_or(std::ptr::null()), - ) - }) + let process_result = Code::from(pathed::process_file( + handle.0.as_ptr(), + M::OPERATION as i32, + path, + file, + )) .unwrap(); match process_result { Code::Success => Ok(user_data.0), @@ -646,8 +636,9 @@ impl fmt::Display for FileHeader { impl From for FileHeader { fn from(header: native::HeaderDataEx) -> Self { - let filename = - unsafe { WideCString::from_ptr_truncate(header.filename_w.as_ptr() as *const _, 1024) }; + let filename = unsafe { + widestring::WideCString::from_ptr_truncate(header.filename_w.as_ptr() as *const _, 1024) + }; FileHeader { filename: PathBuf::from(filename.to_os_string()), diff --git a/src/pathed/all.rs b/src/pathed/all.rs new file mode 100644 index 0000000..aa63dc1 --- /dev/null +++ b/src/pathed/all.rs @@ -0,0 +1,27 @@ +use widestring::WideCString; + +pub(crate) type RarPath = WideCString; + +pub(crate) fn construct>(path: P) -> RarPath { + WideCString::from_os_str(path.as_ref()).unwrap() +} + +pub(crate) fn process_file( + handle: *const unrar_sys::Handle, + operation: i32, + dest_path: Option<&RarPath>, + dest_name: Option<&RarPath>, +) -> i32 { + unsafe { + unrar_sys::RARProcessFileW( + handle, + operation, + dest_path + .map(|path| path.as_ptr() as *const _) + .unwrap_or(std::ptr::null()), + dest_name + .map(|file| file.as_ptr() as *const _) + .unwrap_or(std::ptr::null()), + ) + } +} diff --git a/src/pathed/linux.rs b/src/pathed/linux.rs new file mode 100644 index 0000000..e927724 --- /dev/null +++ b/src/pathed/linux.rs @@ -0,0 +1,27 @@ +use std::ffi::CString; + +pub(crate) type RarPath = CString; + +pub(crate) fn construct>(path: P) -> RarPath { + CString::new(path.as_ref().as_os_str().as_encoded_bytes()).unwrap() +} + +pub(crate) fn process_file( + handle: *const unrar_sys::Handle, + operation: i32, + dest_path: Option<&RarPath>, + dest_name: Option<&RarPath>, +) -> i32 { + unsafe { + unrar_sys::RARProcessFile( + handle, + operation, + dest_path + .map(|path| path.as_ptr() as *const _) + .unwrap_or(std::ptr::null()), + dest_name + .map(|file| file.as_ptr() as *const _) + .unwrap_or(std::ptr::null()), + ) + } +} diff --git a/src/pathed/mod.rs b/src/pathed/mod.rs new file mode 100644 index 0000000..f8da752 --- /dev/null +++ b/src/pathed/mod.rs @@ -0,0 +1,5 @@ +#[cfg_attr(target_os = "linux", path = "linux.rs")] +#[cfg_attr(not(target_os = "linux"), path = "all.rs")] +mod os; + +pub(crate) use os::*; \ No newline at end of file