Skip to content

Commit

Permalink
fix(linux): use non-wide functions for linux target
Browse files Browse the repository at this point in the history
  • Loading branch information
muja committed Sep 6, 2024
1 parent 5bebae3 commit dea910a
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 35 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
61 changes: 26 additions & 35 deletions src/open_archive.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -53,7 +51,7 @@ pub struct OpenArchive<M: OpenMode, C: Cursor> {
extra: C,
marker: std::marker::PhantomData<M>,
}
type Userdata<T> = (T, Option<WideCString>);
type Userdata<T> = (T, Option<widestring::WideCString>);

mod private {
use super::native;
Expand Down Expand Up @@ -204,7 +202,7 @@ impl<Mode: OpenMode, C: Cursor> OpenArchive<Mode, C> {
///
/// ```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;
Expand Down Expand Up @@ -233,12 +231,7 @@ impl<Mode: OpenMode> OpenArchive<Mode, CursorBeforeHeader> {
password: Option<&[u8]>,
recover: Option<&mut Option<Self>>,
) -> UnrarResult<Self> {
#[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);
Expand All @@ -247,7 +240,7 @@ impl<Mode: OpenMode> OpenArchive<Mode, CursorBeforeHeader> {

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 {
Expand Down Expand Up @@ -360,16 +353,16 @@ impl<M: OpenMode> OpenArchive<M, CursorBeforeFile> {

fn process_file<PM: ProcessMode>(
self,
path: Option<&WideCString>,
file: Option<&WideCString>,
path: Option<&pathed::RarPath>,
file: Option<&pathed::RarPath>,
) -> UnrarResult<OpenArchive<M, CursorBeforeHeader>> {
Ok(self.process_file_x::<PM>(path, file)?.1)
}

fn process_file_x<PM: ProcessMode>(
self,
path: Option<&WideCString>,
file: Option<&WideCString>,
path: Option<&pathed::RarPath>,
file: Option<&pathed::RarPath>,
) -> UnrarResult<(PM::Output, OpenArchive<M, CursorBeforeHeader>)> {
let result = Ok((
Internal::<PM>::process_file_raw(&self.handle, path, file)?,
Expand Down Expand Up @@ -413,8 +406,8 @@ impl OpenArchive<Process, CursorBeforeFile> {
self,
base: P,
) -> UnrarResult<OpenArchive<Process, CursorBeforeHeader>> {
let wdest = WideCString::from_os_str(base.as_ref()).expect("Unexpected nul in destination");
self.process_file::<Extract>(Some(&wdest), None)
let path = pathed::construct(&base);
self.process_file::<Extract>(Some(&path), None)
}

/// Extracts the file into the specified file.
Expand All @@ -425,10 +418,10 @@ impl OpenArchive<Process, CursorBeforeFile> {
/// This function will panic if `dest` contains nul characters.
pub fn extract_to<P: AsRef<Path>>(
self,
dest: P,
file: P,
) -> UnrarResult<OpenArchive<Process, CursorBeforeHeader>> {
let wdest = WideCString::from_os_str(dest.as_ref()).expect("Unexpected nul in destination");
self.process_file::<Extract>(None, Some(&wdest))
let dest = pathed::construct(&file);
self.process_file::<Extract>(None, Some(&dest))
}
}

Expand Down Expand Up @@ -513,7 +506,8 @@ impl<M: ProcessMode> Internal<M> {
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
Expand All @@ -533,8 +527,8 @@ impl<M: ProcessMode> Internal<M> {

fn process_file_raw(
handle: &Handle,
path: Option<&WideCString>,
file: Option<&WideCString>,
path: Option<&pathed::RarPath>,
file: Option<&pathed::RarPath>,
) -> UnrarResult<M::Output> {
let mut user_data: Userdata<M::Output> = Default::default();
unsafe {
Expand All @@ -544,16 +538,12 @@ impl<M: ProcessMode> Internal<M> {
&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),
Expand Down Expand Up @@ -646,8 +636,9 @@ impl fmt::Display for FileHeader {

impl From<native::HeaderDataEx> 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()),
Expand Down
27 changes: 27 additions & 0 deletions src/pathed/all.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use widestring::WideCString;

pub(crate) type RarPath = WideCString;

pub(crate) fn construct<P: AsRef<std::path::Path>>(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()),
)
}
}
27 changes: 27 additions & 0 deletions src/pathed/linux.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use std::ffi::CString;

pub(crate) type RarPath = CString;

pub(crate) fn construct<P: AsRef<std::path::Path>>(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()),
)
}
}
5 changes: 5 additions & 0 deletions src/pathed/mod.rs
Original file line number Diff line number Diff line change
@@ -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::*;

0 comments on commit dea910a

Please sign in to comment.