feat(cli): port file I/O preferences to Rust
Move fileio preference and context allocation, defaults, setters, and small query helpers into Rust while keeping the actual file operations in C. Keep the C structs and ABI declarations as anchors, and make the CLI build track the new Rust source. Test Plan: - rustfmt +nightly --check --edition 2021 rust/src/fileio_prefs.rs rust/cli/src/lib.rs - RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo test --manifest-path rust/cli/Cargo.toml - RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - git diff --cached --check
This commit is contained in:
@@ -0,0 +1,681 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(clippy::missing_safety_doc)]
|
||||
|
||||
//! Rust implementation of the small preference/context part of `fileio.c`.
|
||||
//!
|
||||
//! The file-I/O operations themselves remain in C. These layouts are passed
|
||||
//! directly to that code, so allocation deliberately uses the C allocator and
|
||||
//! preference creation initializes exactly the fields initialized by the C
|
||||
//! implementation. In particular, the four legacy fields which C leaves
|
||||
//! unspecified are not zero-filled here either.
|
||||
|
||||
use std::ffi::c_void;
|
||||
use std::mem::size_of;
|
||||
use std::os::raw::{c_char, c_int, c_uint};
|
||||
use std::ptr;
|
||||
|
||||
const FIO_ZSTD_COMPRESSION: c_int = 0;
|
||||
const FIO_OVERLAP_LOG_NOTSET: c_int = 9999;
|
||||
const FIO_LDM_PARAM_NOTSET: c_int = 9999;
|
||||
|
||||
#[cfg(target_vendor = "apple")]
|
||||
const ZSTD_SPARSE_DEFAULT: c_int = 0;
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
const ZSTD_SPARSE_DEFAULT: c_int = 1;
|
||||
|
||||
#[repr(C)]
|
||||
struct FIO_display_prefs_t {
|
||||
displayLevel: c_int,
|
||||
progressSetting: c_int,
|
||||
}
|
||||
|
||||
/// C's `FIO_prefs_t` from `programs/fileio_types.h`.
|
||||
#[repr(C)]
|
||||
pub struct FIO_prefs_t {
|
||||
compressionType: c_int,
|
||||
sparseFileSupport: c_int,
|
||||
dictIDFlag: c_int,
|
||||
checksumFlag: c_int,
|
||||
blockSize: c_int,
|
||||
overlapLog: c_int,
|
||||
adaptiveMode: c_int,
|
||||
useRowMatchFinder: c_int,
|
||||
rsyncable: c_int,
|
||||
minAdaptLevel: c_int,
|
||||
maxAdaptLevel: c_int,
|
||||
ldmFlag: c_int,
|
||||
ldmHashLog: c_int,
|
||||
ldmMinMatch: c_int,
|
||||
ldmBucketSizeLog: c_int,
|
||||
ldmHashRateLog: c_int,
|
||||
streamSrcSize: usize,
|
||||
targetCBlockSize: usize,
|
||||
srcSizeHint: c_int,
|
||||
testMode: c_int,
|
||||
literalCompressionMode: c_int,
|
||||
removeSrcFile: c_int,
|
||||
overwrite: c_int,
|
||||
asyncIO: c_int,
|
||||
memLimit: c_uint,
|
||||
nbWorkers: c_int,
|
||||
excludeCompressedFiles: c_int,
|
||||
patchFromMode: c_int,
|
||||
contentSize: c_int,
|
||||
allowBlockDevices: c_int,
|
||||
passThrough: c_int,
|
||||
mmapDict: c_int,
|
||||
}
|
||||
|
||||
/// C's private `FIO_ctx_s` from `programs/fileio.c`.
|
||||
#[repr(C)]
|
||||
pub struct FIO_ctx_t {
|
||||
nbFilesTotal: c_int,
|
||||
hasStdinInput: c_int,
|
||||
hasStdoutOutput: c_int,
|
||||
currFileIdx: c_int,
|
||||
nbFilesProcessed: c_int,
|
||||
totalBytesInput: usize,
|
||||
totalBytesOutput: usize,
|
||||
}
|
||||
|
||||
/// Mirror of the `FileNamesTable` used by `FIO_determineHasStdinInput`.
|
||||
#[repr(C)]
|
||||
pub struct FileNamesTable {
|
||||
fileNames: *mut *const c_char,
|
||||
buf: *mut c_char,
|
||||
tableSize: usize,
|
||||
tableCapacity: usize,
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
unsafe extern "C" {
|
||||
static mut g_display_prefs: FIO_display_prefs_t;
|
||||
fn AIO_supported() -> c_int;
|
||||
#[cfg(feature = "compression")]
|
||||
fn ZSTD_minCLevel() -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
static mut TEST_DISPLAY_PREFS: FIO_display_prefs_t = FIO_display_prefs_t {
|
||||
displayLevel: 2,
|
||||
progressSetting: 0,
|
||||
};
|
||||
|
||||
#[inline]
|
||||
unsafe fn display_prefs() -> *mut FIO_display_prefs_t {
|
||||
#[cfg(test)]
|
||||
{
|
||||
ptr::addr_of_mut!(TEST_DISPLAY_PREFS)
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
ptr::addr_of_mut!(g_display_prefs)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn aio_supported() -> bool {
|
||||
#[cfg(test)]
|
||||
{
|
||||
false
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
unsafe { AIO_supported() != 0 }
|
||||
}
|
||||
}
|
||||
|
||||
fn display(level: c_int, message: &str) {
|
||||
let enabled = unsafe { (*display_prefs()).displayLevel >= level };
|
||||
if enabled {
|
||||
eprint!("{message}");
|
||||
}
|
||||
}
|
||||
|
||||
fn throw(error: c_int, message: &str) -> ! {
|
||||
let enabled = unsafe { (*display_prefs()).displayLevel >= 1 };
|
||||
if enabled {
|
||||
eprintln!("zstd: error {error} : {message} ");
|
||||
}
|
||||
std::process::exit(error);
|
||||
}
|
||||
|
||||
unsafe fn allocate<T>() -> *mut T {
|
||||
let allocation = unsafe { libc::malloc(size_of::<T>()) }.cast::<T>();
|
||||
if allocation.is_null() {
|
||||
throw(21, "Allocation error : not enough memory");
|
||||
}
|
||||
allocation
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_createPreferences() -> *mut FIO_prefs_t {
|
||||
let ret = unsafe { allocate::<FIO_prefs_t>() };
|
||||
|
||||
/* Keep this list in lock-step with the original C initialization. The
|
||||
* useRowMatchFinder, patchFromMode, contentSize, and mmapDict fields are
|
||||
* intentionally left unspecified until their CLI setters are called. */
|
||||
unsafe {
|
||||
ptr::addr_of_mut!((*ret).compressionType).write(FIO_ZSTD_COMPRESSION);
|
||||
ptr::addr_of_mut!((*ret).overwrite).write(0);
|
||||
ptr::addr_of_mut!((*ret).sparseFileSupport).write(ZSTD_SPARSE_DEFAULT);
|
||||
ptr::addr_of_mut!((*ret).dictIDFlag).write(1);
|
||||
ptr::addr_of_mut!((*ret).checksumFlag).write(1);
|
||||
ptr::addr_of_mut!((*ret).removeSrcFile).write(0);
|
||||
ptr::addr_of_mut!((*ret).memLimit).write(0);
|
||||
ptr::addr_of_mut!((*ret).nbWorkers).write(1);
|
||||
ptr::addr_of_mut!((*ret).blockSize).write(0);
|
||||
ptr::addr_of_mut!((*ret).overlapLog).write(FIO_OVERLAP_LOG_NOTSET);
|
||||
ptr::addr_of_mut!((*ret).adaptiveMode).write(0);
|
||||
ptr::addr_of_mut!((*ret).rsyncable).write(0);
|
||||
ptr::addr_of_mut!((*ret).minAdaptLevel).write(-50);
|
||||
ptr::addr_of_mut!((*ret).maxAdaptLevel).write(22);
|
||||
ptr::addr_of_mut!((*ret).ldmFlag).write(0);
|
||||
ptr::addr_of_mut!((*ret).ldmHashLog).write(0);
|
||||
ptr::addr_of_mut!((*ret).ldmMinMatch).write(0);
|
||||
ptr::addr_of_mut!((*ret).ldmBucketSizeLog).write(FIO_LDM_PARAM_NOTSET);
|
||||
ptr::addr_of_mut!((*ret).ldmHashRateLog).write(FIO_LDM_PARAM_NOTSET);
|
||||
ptr::addr_of_mut!((*ret).streamSrcSize).write(0);
|
||||
ptr::addr_of_mut!((*ret).targetCBlockSize).write(0);
|
||||
ptr::addr_of_mut!((*ret).srcSizeHint).write(0);
|
||||
ptr::addr_of_mut!((*ret).testMode).write(0);
|
||||
ptr::addr_of_mut!((*ret).literalCompressionMode).write(0);
|
||||
ptr::addr_of_mut!((*ret).excludeCompressedFiles).write(0);
|
||||
ptr::addr_of_mut!((*ret).allowBlockDevices).write(0);
|
||||
ptr::addr_of_mut!((*ret).asyncIO).write(c_int::from(aio_supported()));
|
||||
ptr::addr_of_mut!((*ret).passThrough).write(-1);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_createContext() -> *mut FIO_ctx_t {
|
||||
let ret = unsafe { allocate::<FIO_ctx_t>() };
|
||||
unsafe {
|
||||
ptr::addr_of_mut!((*ret).currFileIdx).write(0);
|
||||
ptr::addr_of_mut!((*ret).hasStdinInput).write(0);
|
||||
ptr::addr_of_mut!((*ret).hasStdoutOutput).write(0);
|
||||
ptr::addr_of_mut!((*ret).nbFilesTotal).write(1);
|
||||
ptr::addr_of_mut!((*ret).nbFilesProcessed).write(0);
|
||||
ptr::addr_of_mut!((*ret).totalBytesInput).write(0);
|
||||
ptr::addr_of_mut!((*ret).totalBytesOutput).write(0);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_freePreferences(prefs: *mut FIO_prefs_t) {
|
||||
unsafe { libc::free(prefs.cast::<c_void>()) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_freeContext(ctx: *mut FIO_ctx_t) {
|
||||
unsafe { libc::free(ctx.cast::<c_void>()) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn FIO_setNotificationLevel(level: c_int) {
|
||||
unsafe { (*display_prefs()).displayLevel = level };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn FIO_setProgressSetting(setting: c_int) {
|
||||
unsafe { (*display_prefs()).progressSetting = setting };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setCompressionType(prefs: *mut FIO_prefs_t, compression_type: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).compressionType).write(compression_type) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_overwriteMode(prefs: *mut FIO_prefs_t) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).overwrite).write(1) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setSparseWrite(prefs: *mut FIO_prefs_t, sparse: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).sparseFileSupport).write(sparse) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setDictIDFlag(prefs: *mut FIO_prefs_t, dict_id_flag: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).dictIDFlag).write(dict_id_flag) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setChecksumFlag(prefs: *mut FIO_prefs_t, checksum_flag: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).checksumFlag).write(checksum_flag) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setRemoveSrcFile(prefs: *mut FIO_prefs_t, flag: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).removeSrcFile).write(c_int::from(flag != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setMemLimit(prefs: *mut FIO_prefs_t, mem_limit: c_uint) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).memLimit).write(mem_limit) };
|
||||
}
|
||||
|
||||
#[cfg(feature = "compression")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setNbWorkers(prefs: *mut FIO_prefs_t, nb_workers: c_int) {
|
||||
if unsafe { !aio_supported() } && nb_workers > 0 {
|
||||
display(2, "Note : multi-threading is disabled \n");
|
||||
}
|
||||
unsafe { ptr::addr_of_mut!((*prefs).nbWorkers).write(nb_workers) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setExcludeCompressedFile(
|
||||
prefs: *mut FIO_prefs_t,
|
||||
exclude_compressed_files: c_int,
|
||||
) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).excludeCompressedFiles).write(exclude_compressed_files) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setAllowBlockDevices(
|
||||
prefs: *mut FIO_prefs_t,
|
||||
allow_block_devices: c_int,
|
||||
) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).allowBlockDevices).write(allow_block_devices) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setBlockSize(prefs: *mut FIO_prefs_t, block_size: c_int) {
|
||||
if block_size != 0 && unsafe { (*prefs).nbWorkers == 0 } {
|
||||
display(2, "Setting block size is useless in single-thread mode \n");
|
||||
}
|
||||
unsafe { ptr::addr_of_mut!((*prefs).blockSize).write(block_size) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setOverlapLog(prefs: *mut FIO_prefs_t, overlap_log: c_int) {
|
||||
if overlap_log != 0 && unsafe { (*prefs).nbWorkers == 0 } {
|
||||
display(2, "Setting overlapLog is useless in single-thread mode \n");
|
||||
}
|
||||
unsafe { ptr::addr_of_mut!((*prefs).overlapLog).write(overlap_log) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setAdaptiveMode(prefs: *mut FIO_prefs_t, adapt: c_int) {
|
||||
if adapt > 0 && unsafe { (*prefs).nbWorkers == 0 } {
|
||||
throw(
|
||||
1,
|
||||
"Adaptive mode is not compatible with single thread mode \n",
|
||||
);
|
||||
}
|
||||
unsafe { ptr::addr_of_mut!((*prefs).adaptiveMode).write(adapt) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setUseRowMatchFinder(
|
||||
prefs: *mut FIO_prefs_t,
|
||||
use_row_match_finder: c_int,
|
||||
) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).useRowMatchFinder).write(use_row_match_finder) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setRsyncable(prefs: *mut FIO_prefs_t, rsyncable: c_int) {
|
||||
if rsyncable > 0 && unsafe { (*prefs).nbWorkers == 0 } {
|
||||
throw(
|
||||
1,
|
||||
"Rsyncable mode is not compatible with single thread mode \n",
|
||||
);
|
||||
}
|
||||
unsafe { ptr::addr_of_mut!((*prefs).rsyncable).write(rsyncable) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setStreamSrcSize(prefs: *mut FIO_prefs_t, stream_src_size: usize) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).streamSrcSize).write(stream_src_size) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setTargetCBlockSize(
|
||||
prefs: *mut FIO_prefs_t,
|
||||
target_c_block_size: usize,
|
||||
) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).targetCBlockSize).write(target_c_block_size) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setSrcSizeHint(prefs: *mut FIO_prefs_t, src_size_hint: usize) {
|
||||
let capped = src_size_hint.min(c_int::MAX as usize) as c_int;
|
||||
unsafe { ptr::addr_of_mut!((*prefs).srcSizeHint).write(capped) };
|
||||
}
|
||||
|
||||
#[cfg(feature = "decompression")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setTestMode(prefs: *mut FIO_prefs_t, test_mode: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).testMode).write(c_int::from(test_mode != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLiteralCompressionMode(prefs: *mut FIO_prefs_t, mode: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).literalCompressionMode).write(mode) };
|
||||
}
|
||||
|
||||
#[cfg(feature = "compression")]
|
||||
#[inline]
|
||||
fn min_compression_level() -> c_int {
|
||||
#[cfg(test)]
|
||||
{
|
||||
-50
|
||||
}
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
unsafe { ZSTD_minCLevel() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compression")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setAdaptMin(prefs: *mut FIO_prefs_t, min_c_level: c_int) {
|
||||
assert!(min_c_level >= min_compression_level());
|
||||
unsafe { ptr::addr_of_mut!((*prefs).minAdaptLevel).write(min_c_level) };
|
||||
}
|
||||
|
||||
#[cfg(feature = "compression")]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setAdaptMax(prefs: *mut FIO_prefs_t, max_c_level: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).maxAdaptLevel).write(max_c_level) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLdmFlag(prefs: *mut FIO_prefs_t, ldm_flag: c_uint) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).ldmFlag).write(c_int::from(ldm_flag > 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLdmHashLog(prefs: *mut FIO_prefs_t, ldm_hash_log: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).ldmHashLog).write(ldm_hash_log) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLdmMinMatch(prefs: *mut FIO_prefs_t, ldm_min_match: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).ldmMinMatch).write(ldm_min_match) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLdmBucketSizeLog(
|
||||
prefs: *mut FIO_prefs_t,
|
||||
ldm_bucket_size_log: c_int,
|
||||
) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).ldmBucketSizeLog).write(ldm_bucket_size_log) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setLdmHashRateLog(prefs: *mut FIO_prefs_t, ldm_hash_rate_log: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).ldmHashRateLog).write(ldm_hash_rate_log) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setPatchFromMode(prefs: *mut FIO_prefs_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).patchFromMode).write(c_int::from(value != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setContentSize(prefs: *mut FIO_prefs_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).contentSize).write(c_int::from(value != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setAsyncIOFlag(prefs: *mut FIO_prefs_t, value: c_int) {
|
||||
if unsafe { aio_supported() } {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).asyncIO).write(value) };
|
||||
} else {
|
||||
display(
|
||||
2,
|
||||
"Note : asyncio is disabled (lack of multithreading support) \n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setPassThroughFlag(prefs: *mut FIO_prefs_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).passThrough).write(c_int::from(value != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setMMapDict(prefs: *mut FIO_prefs_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*prefs).mmapDict).write(value) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setHasStdoutOutput(ctx: *mut FIO_ctx_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*ctx).hasStdoutOutput).write(value) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setNbFilesTotal(ctx: *mut FIO_ctx_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*ctx).nbFilesTotal).write(value) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_setHasStdinInput(ctx: *mut FIO_ctx_t, value: c_int) {
|
||||
unsafe { ptr::addr_of_mut!((*ctx).hasStdinInput).write(c_int::from(value != 0)) };
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn FIO_determineHasStdinInput(
|
||||
ctx: *mut FIO_ctx_t,
|
||||
filenames: *const FileNamesTable,
|
||||
) {
|
||||
for index in 0..unsafe { (*filenames).tableSize } {
|
||||
let file_name = unsafe { *(*filenames).fileNames.add(index) };
|
||||
if unsafe { libc::strcmp(c"/*stdin*\\".as_ptr(), file_name) == 0 } {
|
||||
unsafe { ptr::addr_of_mut!((*ctx).hasStdinInput).write(1) };
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::mem::{align_of, offset_of, size_of};
|
||||
|
||||
#[test]
|
||||
fn c_layouts_match_the_headers() {
|
||||
let word = size_of::<usize>();
|
||||
let int = size_of::<c_int>();
|
||||
|
||||
assert_eq!(align_of::<FIO_display_prefs_t>(), align_of::<c_int>());
|
||||
assert_eq!(size_of::<FIO_display_prefs_t>(), 2 * int);
|
||||
|
||||
assert_eq!(align_of::<FIO_prefs_t>(), align_of::<usize>());
|
||||
assert_eq!(offset_of!(FIO_prefs_t, compressionType), 0);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, sparseFileSupport), int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, ldmHashRateLog), 15 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, streamSrcSize), 16 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, targetCBlockSize), 16 * int + word);
|
||||
let tail = 16 * int + 2 * word;
|
||||
assert_eq!(offset_of!(FIO_prefs_t, srcSizeHint), tail);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, testMode), tail + int);
|
||||
assert_eq!(
|
||||
offset_of!(FIO_prefs_t, literalCompressionMode),
|
||||
tail + 2 * int
|
||||
);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, removeSrcFile), tail + 3 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, overwrite), tail + 4 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, asyncIO), tail + 5 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, memLimit), tail + 6 * int);
|
||||
assert_eq!(offset_of!(FIO_prefs_t, mmapDict), tail + 13 * int);
|
||||
assert_eq!(size_of::<FIO_prefs_t>(), tail + 14 * int);
|
||||
|
||||
assert_eq!(align_of::<FIO_ctx_t>(), align_of::<usize>());
|
||||
assert_eq!(offset_of!(FIO_ctx_t, currFileIdx), 3 * int);
|
||||
let total_bytes = (5 * int).next_multiple_of(word);
|
||||
assert_eq!(offset_of!(FIO_ctx_t, totalBytesInput), total_bytes);
|
||||
assert_eq!(offset_of!(FIO_ctx_t, totalBytesOutput), total_bytes + word);
|
||||
assert_eq!(size_of::<FIO_ctx_t>(), total_bytes + 2 * word);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preference_defaults_match_fileio_c() {
|
||||
let prefs = unsafe { FIO_createPreferences() };
|
||||
assert!(!prefs.is_null());
|
||||
let prefs = unsafe { &*prefs };
|
||||
|
||||
assert_eq!(prefs.compressionType, 0);
|
||||
assert_eq!(prefs.overwrite, 0);
|
||||
assert_eq!(prefs.sparseFileSupport, ZSTD_SPARSE_DEFAULT);
|
||||
assert_eq!(prefs.dictIDFlag, 1);
|
||||
assert_eq!(prefs.checksumFlag, 1);
|
||||
assert_eq!(prefs.removeSrcFile, 0);
|
||||
assert_eq!(prefs.memLimit, 0);
|
||||
assert_eq!(prefs.nbWorkers, 1);
|
||||
assert_eq!(prefs.blockSize, 0);
|
||||
assert_eq!(prefs.overlapLog, FIO_OVERLAP_LOG_NOTSET);
|
||||
assert_eq!(prefs.adaptiveMode, 0);
|
||||
assert_eq!(prefs.rsyncable, 0);
|
||||
assert_eq!(prefs.minAdaptLevel, -50);
|
||||
assert_eq!(prefs.maxAdaptLevel, 22);
|
||||
assert_eq!(prefs.ldmFlag, 0);
|
||||
assert_eq!(prefs.ldmHashLog, 0);
|
||||
assert_eq!(prefs.ldmMinMatch, 0);
|
||||
assert_eq!(prefs.ldmBucketSizeLog, FIO_LDM_PARAM_NOTSET);
|
||||
assert_eq!(prefs.ldmHashRateLog, FIO_LDM_PARAM_NOTSET);
|
||||
assert_eq!(prefs.streamSrcSize, 0);
|
||||
assert_eq!(prefs.targetCBlockSize, 0);
|
||||
assert_eq!(prefs.srcSizeHint, 0);
|
||||
assert_eq!(prefs.testMode, 0);
|
||||
assert_eq!(prefs.literalCompressionMode, 0);
|
||||
assert_eq!(prefs.excludeCompressedFiles, 0);
|
||||
assert_eq!(prefs.allowBlockDevices, 0);
|
||||
assert_eq!(prefs.asyncIO, 0);
|
||||
assert_eq!(prefs.passThrough, -1);
|
||||
|
||||
unsafe { FIO_freePreferences(prefs as *const FIO_prefs_t as *mut FIO_prefs_t) };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn context_defaults_and_setters_match_fileio_c() {
|
||||
let ctx = unsafe { FIO_createContext() };
|
||||
assert!(!ctx.is_null());
|
||||
unsafe {
|
||||
assert_eq!((*ctx).currFileIdx, 0);
|
||||
assert_eq!((*ctx).hasStdinInput, 0);
|
||||
assert_eq!((*ctx).hasStdoutOutput, 0);
|
||||
assert_eq!((*ctx).nbFilesTotal, 1);
|
||||
assert_eq!((*ctx).nbFilesProcessed, 0);
|
||||
assert_eq!((*ctx).totalBytesInput, 0);
|
||||
assert_eq!((*ctx).totalBytesOutput, 0);
|
||||
|
||||
FIO_setNbFilesTotal(ctx, 7);
|
||||
FIO_setHasStdinInput(ctx, -1);
|
||||
FIO_setHasStdoutOutput(ctx, -2);
|
||||
assert_eq!((*ctx).nbFilesTotal, 7);
|
||||
assert_eq!((*ctx).hasStdinInput, 1);
|
||||
assert_eq!((*ctx).hasStdoutOutput, -2);
|
||||
}
|
||||
|
||||
let names = [c"input".as_ptr(), c"/*stdin*\\".as_ptr()];
|
||||
let table = FileNamesTable {
|
||||
fileNames: names.as_ptr().cast_mut(),
|
||||
buf: ptr::null_mut(),
|
||||
tableSize: names.len(),
|
||||
tableCapacity: names.len(),
|
||||
};
|
||||
unsafe { FIO_determineHasStdinInput(ctx, &table) };
|
||||
assert_eq!(unsafe { (*ctx).hasStdinInput }, 1);
|
||||
unsafe { FIO_freeContext(ctx) };
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preference_setters_update_the_c_layout() {
|
||||
let prefs = unsafe { FIO_createPreferences() };
|
||||
unsafe {
|
||||
FIO_setCompressionType(prefs, 3);
|
||||
FIO_overwriteMode(prefs);
|
||||
FIO_setSparseWrite(prefs, 2);
|
||||
FIO_setDictIDFlag(prefs, 0);
|
||||
FIO_setChecksumFlag(prefs, 2);
|
||||
FIO_setRemoveSrcFile(prefs, -1);
|
||||
FIO_setMemLimit(prefs, 123);
|
||||
#[cfg(feature = "compression")]
|
||||
FIO_setNbWorkers(prefs, 2);
|
||||
FIO_setExcludeCompressedFile(prefs, 1);
|
||||
FIO_setAllowBlockDevices(prefs, 1);
|
||||
FIO_setUseRowMatchFinder(prefs, 2);
|
||||
FIO_setBlockSize(prefs, 4096);
|
||||
FIO_setOverlapLog(prefs, 5);
|
||||
FIO_setAdaptiveMode(prefs, 1);
|
||||
FIO_setRsyncable(prefs, 1);
|
||||
FIO_setStreamSrcSize(prefs, 100);
|
||||
FIO_setTargetCBlockSize(prefs, 200);
|
||||
FIO_setSrcSizeHint(prefs, usize::MAX);
|
||||
FIO_setLiteralCompressionMode(prefs, 2);
|
||||
FIO_setLdmFlag(prefs, 1);
|
||||
FIO_setLdmHashLog(prefs, 6);
|
||||
FIO_setLdmMinMatch(prefs, 7);
|
||||
FIO_setLdmBucketSizeLog(prefs, 8);
|
||||
FIO_setLdmHashRateLog(prefs, 9);
|
||||
FIO_setPatchFromMode(prefs, -1);
|
||||
FIO_setContentSize(prefs, -1);
|
||||
FIO_setPassThroughFlag(prefs, -1);
|
||||
FIO_setMMapDict(prefs, 2);
|
||||
FIO_setAsyncIOFlag(prefs, 1);
|
||||
|
||||
#[cfg(feature = "compression")]
|
||||
{
|
||||
FIO_setAdaptMin(prefs, -40);
|
||||
FIO_setAdaptMax(prefs, 18);
|
||||
}
|
||||
#[cfg(feature = "decompression")]
|
||||
FIO_setTestMode(prefs, -1);
|
||||
|
||||
assert_eq!((*prefs).compressionType, 3);
|
||||
assert_eq!((*prefs).overwrite, 1);
|
||||
assert_eq!((*prefs).sparseFileSupport, 2);
|
||||
assert_eq!((*prefs).dictIDFlag, 0);
|
||||
assert_eq!((*prefs).checksumFlag, 2);
|
||||
assert_eq!((*prefs).removeSrcFile, 1);
|
||||
assert_eq!((*prefs).memLimit, 123);
|
||||
#[cfg(feature = "compression")]
|
||||
assert_eq!((*prefs).nbWorkers, 2);
|
||||
assert_eq!((*prefs).excludeCompressedFiles, 1);
|
||||
assert_eq!((*prefs).allowBlockDevices, 1);
|
||||
assert_eq!((*prefs).useRowMatchFinder, 2);
|
||||
assert_eq!((*prefs).blockSize, 4096);
|
||||
assert_eq!((*prefs).overlapLog, 5);
|
||||
assert_eq!((*prefs).adaptiveMode, 1);
|
||||
assert_eq!((*prefs).rsyncable, 1);
|
||||
assert_eq!((*prefs).streamSrcSize, 100);
|
||||
assert_eq!((*prefs).targetCBlockSize, 200);
|
||||
assert_eq!((*prefs).srcSizeHint, c_int::MAX);
|
||||
assert_eq!((*prefs).literalCompressionMode, 2);
|
||||
assert_eq!((*prefs).ldmFlag, 1);
|
||||
assert_eq!((*prefs).ldmHashLog, 6);
|
||||
assert_eq!((*prefs).ldmMinMatch, 7);
|
||||
assert_eq!((*prefs).ldmBucketSizeLog, 8);
|
||||
assert_eq!((*prefs).ldmHashRateLog, 9);
|
||||
assert_eq!((*prefs).patchFromMode, 1);
|
||||
assert_eq!((*prefs).contentSize, 1);
|
||||
assert_eq!((*prefs).passThrough, 1);
|
||||
assert_eq!((*prefs).mmapDict, 2);
|
||||
#[cfg(test)]
|
||||
assert_eq!((*prefs).asyncIO, 0);
|
||||
#[cfg(feature = "compression")]
|
||||
{
|
||||
assert_eq!((*prefs).minAdaptLevel, -40);
|
||||
assert_eq!((*prefs).maxAdaptLevel, 18);
|
||||
}
|
||||
#[cfg(feature = "decompression")]
|
||||
assert_eq!((*prefs).testMode, 1);
|
||||
}
|
||||
|
||||
FIO_setNotificationLevel(0);
|
||||
FIO_setProgressSetting(2);
|
||||
unsafe {
|
||||
assert_eq!((*display_prefs()).displayLevel, 0);
|
||||
assert_eq!((*display_prefs()).progressSetting, 2);
|
||||
FIO_freePreferences(prefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user