Skip to content

Commit b8a75a5

Browse files
bjorn3folkertdev
authored andcommitted
Add support for Windows
1 parent 1aaf5d8 commit b8a75a5

File tree

7 files changed

+386
-125
lines changed

7 files changed

+386
-125
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
# Files that should be left untouched (binary is macro for -text -diff)
1010
*.ref binary
11+
tests/*.txt eol=lf
1112

1213
#
1314
# Exclude files from exporting

.github/workflows/checks.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ jobs:
4444
os: macos-14
4545
features: ""
4646
target: "aarch64-apple-darwin"
47-
# - rust: stable-x86_64-gnu
48-
# os: windows-2022
49-
# features: ""
50-
# target: "x86_64-pc-windows-gnu"
47+
- rust: stable-x86_64-gnu
48+
os: windows-2022
49+
features: ""
50+
target: "x86_64-pc-windows-gnu"
5151
steps:
5252
- name: Checkout sources
5353
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

bzip2.rs

Lines changed: 129 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,59 @@ use std::mem::zeroed;
99
use std::path::{Path, PathBuf};
1010
use std::ptr;
1111
use std::sync::atomic::{AtomicUsize, Ordering};
12-
use std::time::SystemTime;
1312

1413
use libbzip2_rs_sys::{
1514
BZ2_bzRead, BZ2_bzReadClose, BZ2_bzReadGetUnused, BZ2_bzReadOpen, BZ2_bzWrite,
1615
BZ2_bzWriteClose64, BZ2_bzWriteOpen, BZ2_bzlibVersion, BZFILE,
1716
};
1817

1918
use libc::{
20-
_exit, close, exit, fclose, fdopen, ferror, fflush, fgetc, fileno, fopen, fread, fwrite, open,
21-
perror, remove, rewind, signal, stat, strlen, ungetc, utimbuf, write, FILE, O_CREAT, O_EXCL,
22-
O_WRONLY, SIGBUS, SIGHUP, SIGINT, SIGSEGV, SIGTERM, S_IRUSR, S_IWUSR,
19+
_exit, exit, fclose, ferror, fflush, fgetc, fileno, fopen, fread, fwrite, perror, remove,
20+
rewind, signal, stat, strlen, ungetc, write, FILE, SIGINT, SIGSEGV, SIGTERM,
2321
};
2422

2523
// FIXME remove this
24+
#[cfg(not(target_os = "windows"))]
2625
extern "C" {
2726
#[cfg_attr(target_os = "macos", link_name = "__stdinp")]
2827
static mut stdin: *mut FILE;
2928
#[cfg_attr(target_os = "macos", link_name = "__stdoutp")]
3029
static mut stdout: *mut FILE;
3130
}
3231

32+
#[cfg(all(target_os = "windows", target_env = "gnu"))]
33+
extern "C" {
34+
fn __acrt_iob_func(idx: libc::c_uint) -> *mut FILE;
35+
}
36+
37+
#[cfg(not(target_os = "windows"))]
38+
macro_rules! STDIN {
39+
() => {
40+
stdin
41+
};
42+
}
43+
44+
#[cfg(all(target_os = "windows", target_env = "gnu"))]
45+
macro_rules! STDIN {
46+
() => {
47+
__acrt_iob_func(0)
48+
};
49+
}
50+
51+
#[cfg(not(target_os = "windows"))]
52+
macro_rules! STDOUT {
53+
() => {
54+
stdout
55+
};
56+
}
57+
58+
#[cfg(all(target_os = "windows", target_env = "gnu"))]
59+
macro_rules! STDOUT {
60+
() => {
61+
__acrt_iob_func(1)
62+
};
63+
}
64+
3365
type Bool = libc::c_uchar;
3466

3567
type IntNative = libc::c_int;
@@ -126,7 +158,8 @@ unsafe fn compressStream(stream: *mut FILE, zStream: *mut FILE, metadata: Option
126158
let mut bzerr_dummy: i32 = 0;
127159
let mut ret: i32;
128160

129-
// TODO set files to binary mode?
161+
set_binary_mode(stream);
162+
set_binary_mode(zStream);
130163

131164
if ferror(stream) != 0 {
132165
// diverges
@@ -291,7 +324,8 @@ unsafe fn uncompressStream(
291324

292325
let mut state = State::Standard;
293326

294-
// TODO: set the file into binary mode?
327+
set_binary_mode(stream);
328+
set_binary_mode(zStream);
295329

296330
if ferror(stream) != 0 || ferror(zStream) != 0 {
297331
// diverges
@@ -395,7 +429,7 @@ unsafe fn uncompressStream(
395429
ioError()
396430
}
397431

398-
if stream != stdout {
432+
if stream != STDOUT!() {
399433
ret = fclose(stream);
400434
outputHandleJustInCase = core::ptr::null_mut();
401435
if ret == libc::EOF {
@@ -458,10 +492,10 @@ unsafe fn uncompressStream(
458492
libbzip2_rs_sys::BZ_MEM_ERROR => outOfMemory(),
459493
libbzip2_rs_sys::BZ_UNEXPECTED_EOF => compressedStreamEOF(),
460494
libbzip2_rs_sys::BZ_DATA_ERROR_MAGIC => {
461-
if zStream != stdin {
495+
if zStream != STDIN!() {
462496
fclose(zStream);
463497
}
464-
if stream != stdout {
498+
if stream != STDOUT!() {
465499
fclose(stream);
466500
}
467501
if streamNo == 1 {
@@ -587,7 +621,7 @@ unsafe fn testStream(zStream: *mut FILE) -> bool {
587621
false
588622
}
589623
libbzip2_rs_sys::BZ_DATA_ERROR_MAGIC => {
590-
if zStream != stdin {
624+
if zStream != STDIN!() {
591625
fclose(zStream);
592626
}
593627
if streamNo == 1 {
@@ -903,44 +937,65 @@ unsafe fn copy_filename(to: *mut c_char, from: &str) {
903937
}
904938

905939
fn fopen_output_safely_rust(name: impl AsRef<Path>) -> *mut FILE {
906-
use std::os::fd::IntoRawFd;
907-
use std::os::unix::fs::OpenOptionsExt;
940+
#[cfg(unix)]
941+
{
942+
use std::os::fd::IntoRawFd;
943+
use std::os::unix::fs::OpenOptionsExt;
908944

909-
let mut opts = std::fs::File::options();
945+
let mut opts = std::fs::File::options();
910946

911-
opts.write(true).create_new(true);
947+
opts.write(true).create_new(true);
912948

913-
#[allow(clippy::unnecessary_cast)]
914-
opts.mode((libc::S_IWUSR | libc::S_IRUSR) as u32);
949+
#[allow(clippy::unnecessary_cast)]
950+
opts.mode((libc::S_IWUSR | libc::S_IRUSR) as u32);
915951

916-
let Ok(file) = opts.open(name) else {
917-
return std::ptr::null_mut::<FILE>();
918-
};
952+
let Ok(file) = opts.open(name) else {
953+
return std::ptr::null_mut::<FILE>();
954+
};
919955

920-
let fd = file.into_raw_fd();
921-
let mode = b"wb\0".as_ptr().cast::<c_char>();
922-
let fp = unsafe { fdopen(fd, mode) };
923-
if fp.is_null() {
924-
unsafe { close(fd) };
956+
let fd = file.into_raw_fd();
957+
let mode = b"wb\0".as_ptr().cast::<c_char>();
958+
let fp = unsafe { libc::fdopen(fd, mode) };
959+
if fp.is_null() {
960+
unsafe { libc::close(fd) };
961+
}
962+
fp
925963
}
926964

927-
fp
965+
#[cfg(not(unix))]
966+
unsafe {
967+
use std::ffi::CString;
968+
969+
// The CString really only needs to live for the duration of the fopen
970+
#[allow(temporary_cstring_as_ptr)]
971+
libc::fopen(
972+
CString::new(name.as_ref().to_str().unwrap())
973+
.unwrap()
974+
.as_ptr(),
975+
b"wb\0".as_ptr().cast::<c_char>(),
976+
)
977+
}
928978
}
929979

930980
unsafe fn fopen_output_safely(name: *mut c_char, mode: *const libc::c_char) -> *mut FILE {
931-
let fh = open(
932-
name,
933-
O_WRONLY | O_CREAT | O_EXCL,
934-
S_IWUSR as libc::c_uint | S_IRUSR as libc::c_uint,
935-
);
936-
if fh == -1 as libc::c_int {
937-
return std::ptr::null_mut::<FILE>();
938-
}
939-
let fp = fdopen(fh, mode);
940-
if fp.is_null() {
941-
close(fh);
981+
#[cfg(unix)]
982+
{
983+
let fh = libc::open(
984+
name,
985+
libc::O_WRONLY | libc::O_CREAT | libc::O_EXCL,
986+
libc::S_IWUSR as libc::c_uint | libc::S_IRUSR as libc::c_uint,
987+
);
988+
if fh == -1 as libc::c_int {
989+
return std::ptr::null_mut::<FILE>();
990+
}
991+
let fp = libc::fdopen(fh, mode);
992+
if fp.is_null() {
993+
libc::close(fh);
994+
}
995+
fp
942996
}
943-
fp
997+
#[cfg(not(unix))]
998+
libc::fopen(name, mode)
944999
}
9451000

9461001
fn not_a_standard_file(path: &Path) -> bool {
@@ -963,21 +1018,23 @@ fn count_hardlinks(path: &Path) -> u64 {
9631018
}
9641019

9651020
#[cfg(not(unix))]
966-
unsafe fn count_hardlinks(path: &Path) -> u64 {
1021+
unsafe fn count_hardlinks(_path: &Path) -> u64 {
9671022
0 // FIXME
9681023
}
9691024

9701025
fn apply_saved_time_info_to_output_file(_dst_name: &CStr, _metadata: Metadata) {
9711026
#[cfg(unix)]
9721027
{
1028+
use std::time::SystemTime;
1029+
9731030
let convert = |x: SystemTime| {
9741031
x.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as libc::time_t
9751032
};
9761033

9771034
let actime = convert(_metadata.accessed().unwrap_or(SystemTime::UNIX_EPOCH));
9781035
let modtime = convert(_metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH));
9791036

980-
let buf = utimbuf { actime, modtime };
1037+
let buf = libc::utimbuf { actime, modtime };
9811038

9821039
match unsafe { libc::utime(_dst_name.as_ptr(), &buf) } {
9831040
0 => {}
@@ -986,24 +1043,24 @@ fn apply_saved_time_info_to_output_file(_dst_name: &CStr, _metadata: Metadata) {
9861043
}
9871044
}
9881045

989-
unsafe fn set_permissions(handle: *mut FILE, metadata: &Metadata) {
1046+
unsafe fn set_permissions(_handle: *mut FILE, _metadata: &Metadata) {
9901047
#[cfg(unix)]
9911048
{
9921049
use std::os::unix::fs::MetadataExt;
9931050

994-
let fd = fileno(handle);
1051+
let fd = fileno(_handle);
9951052
if fd < 0 {
9961053
// diverges
9971054
ioError()
9981055
}
9991056

1000-
let retVal = libc::fchmod(fd, metadata.mode() as libc::mode_t);
1057+
let retVal = libc::fchmod(fd, _metadata.mode() as libc::mode_t);
10011058
if retVal != 0 as libc::c_int {
10021059
ioError();
10031060
}
10041061

10051062
// chown() will in many cases return with EPERM, which can be safely ignored.
1006-
libc::fchown(fd, metadata.uid(), metadata.gid());
1063+
libc::fchown(fd, _metadata.uid(), _metadata.gid());
10071064
}
10081065
}
10091066

@@ -1031,6 +1088,24 @@ const BZ_N_SUFFIX_PAIRS: usize = 4;
10311088
const Z_SUFFIX: [&str; BZ_N_SUFFIX_PAIRS] = [".bz2", ".bz", ".tbz2", ".tbz"];
10321089
const UNZ_SUFFIX: [&str; BZ_N_SUFFIX_PAIRS] = ["", "", ".tar", ".tar"];
10331090

1091+
#[cfg(windows)]
1092+
/// Prevent Windows from mangling the read data.
1093+
unsafe fn set_binary_mode(file: *mut FILE) {
1094+
use std::ffi::c_int;
1095+
1096+
extern "C" {
1097+
fn _setmode(fd: c_int, mode: c_int) -> c_int;
1098+
}
1099+
1100+
if _setmode(fileno(file), libc::O_BINARY) == -1 {
1101+
ioError();
1102+
}
1103+
}
1104+
1105+
#[cfg(not(windows))]
1106+
/// Prevent Windows from mangling the read data.
1107+
unsafe fn set_binary_mode(_file: *mut FILE) {}
1108+
10341109
unsafe fn compress(name: Option<&str>) {
10351110
let in_name;
10361111
let out_name;
@@ -1165,8 +1240,8 @@ unsafe fn compress(name: Option<&str>) {
11651240

11661241
match srcMode {
11671242
SourceMode::I2O => {
1168-
inStr = stdin;
1169-
outStr = stdout;
1243+
inStr = STDIN!();
1244+
outStr = STDOUT!();
11701245
if std::io::stdout().is_terminal() {
11711246
eprintln!(
11721247
"{}: I won't write compressed data to a terminal.",
@@ -1186,7 +1261,7 @@ unsafe fn compress(name: Option<&str>) {
11861261
inName.as_mut_ptr(),
11871262
b"rb\0" as *const u8 as *const libc::c_char,
11881263
);
1189-
outStr = stdout;
1264+
outStr = STDOUT!();
11901265
if std::io::stdout().is_terminal() {
11911266
eprintln!(
11921267
"{}: I won't write compressed data to a terminal.",
@@ -1416,8 +1491,8 @@ unsafe fn uncompress(name: Option<&str>) {
14161491

14171492
match srcMode {
14181493
SourceMode::I2O => {
1419-
inStr = stdin;
1420-
outStr = stdout;
1494+
inStr = STDIN!();
1495+
outStr = STDOUT!();
14211496
if std::io::stdin().is_terminal() {
14221497
eprint!(
14231498
concat!(
@@ -1435,7 +1510,7 @@ unsafe fn uncompress(name: Option<&str>) {
14351510
inName.as_mut_ptr(),
14361511
b"rb\0" as *const u8 as *const libc::c_char,
14371512
);
1438-
outStr = stdout;
1513+
outStr = STDOUT!();
14391514
if inStr.is_null() {
14401515
eprintln!(
14411516
"{}: Can't open input file {}: {}.",
@@ -1616,7 +1691,7 @@ unsafe fn testf(name: Option<&str>) {
16161691
setExit(1);
16171692
return;
16181693
}
1619-
inStr = stdin;
1694+
inStr = STDIN!();
16201695
}
16211696
SourceMode::F2O | SourceMode::F2F => {
16221697
inStr = fopen(
@@ -1751,8 +1826,9 @@ unsafe fn main_0(program_path: &Path) -> IntNative {
17511826
SIGSEGV,
17521827
mySIGSEGVorSIGBUScatcher as unsafe extern "C" fn(libc::c_int) as usize,
17531828
);
1829+
#[cfg(not(target_os = "windows"))]
17541830
signal(
1755-
SIGBUS,
1831+
libc::SIGBUS,
17561832
mySIGSEGVorSIGBUScatcher as unsafe extern "C" fn(libc::c_int) as usize,
17571833
);
17581834

@@ -1922,8 +1998,9 @@ unsafe fn main_0(program_path: &Path) -> IntNative {
19221998
SIGTERM,
19231999
mySignalCatcher as unsafe extern "C" fn(IntNative) as usize,
19242000
);
2001+
#[cfg(not(target_os = "windows"))]
19252002
signal(
1926-
SIGHUP,
2003+
libc::SIGHUP,
19272004
mySignalCatcher as unsafe extern "C" fn(IntNative) as usize,
19282005
);
19292006
}

0 commit comments

Comments
 (0)