diff --git a/programs/fileio.c b/programs/fileio.c index 650726dae..051f94c29 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -404,6 +404,13 @@ enum { FIO_RUST_ZSTD_FRAME_DECODING_ERROR = 1, FIO_RUST_ZSTD_FRAME_PREMATURE_END = 2, }; +enum { + FIO_RUST_ZSTD_FRAME_ACTION_OK = 0, + FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR = 1, + FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END = 2, + FIO_RUST_ZSTD_FRAME_ACTION_INVALID = 3, +}; +int FIO_rust_decompressZstdFrameAction(int status); typedef void (*FIO_rust_frame_progress_fn)(void* opaque, const char* srcFileName, U64 decodedSize); @@ -3786,23 +3793,24 @@ FIO_decompressZstdFrames(FIO_ctx_t* const fCtx, dRess_t* ress, fCtx, ress->dctx, ress->readCtx, ress->writeCtx, srcFileName, alreadyDecoded, &decodedSize, &zstdError, FIO_decompressZstdFrameProgress); + int const action = FIO_rust_decompressZstdFrameAction(status); - if (status == FIO_RUST_ZSTD_FRAME_OK) - return decodedSize; - if (status == FIO_RUST_ZSTD_FRAME_DECODING_ERROR) { - DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", - srcFileName, ZSTD_getErrorName(zstdError)); - FIO_zstdErrorHelp(prefs, ress, zstdError, srcFileName); - return FIO_ERROR_FRAME_DECODING; + switch (action) { + case FIO_RUST_ZSTD_FRAME_ACTION_OK: + return decodedSize; + case FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR: + DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n", + srcFileName, ZSTD_getErrorName(zstdError)); + FIO_zstdErrorHelp(prefs, ress, zstdError, srcFileName); + return FIO_ERROR_FRAME_DECODING; + case FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END: + DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", + srcFileName); + return FIO_ERROR_FRAME_DECODING; + default: + assert(0); + return FIO_ERROR_FRAME_DECODING; } - if (status == FIO_RUST_ZSTD_FRAME_PREMATURE_END) { - DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n", - srcFileName); - return FIO_ERROR_FRAME_DECODING; - } - - assert(0); - return FIO_ERROR_FRAME_DECODING; } diff --git a/rust/src/fileio_prefs.rs b/rust/src/fileio_prefs.rs index d95200b57..cee745c71 100644 --- a/rust/src/fileio_prefs.rs +++ b/rust/src/fileio_prefs.rs @@ -348,6 +348,42 @@ const FIO_RUST_ZSTD_ERROR_HELP_WINDOW_GUIDANCE: c_int = 1; #[cfg(feature = "decompression")] const FIO_RUST_ZSTD_ERROR_HELP_UNSUPPORTED_WINDOW_LOG: c_int = 2; +#[cfg(feature = "decompression")] +const FIO_RUST_ZSTD_FRAME_OK: c_int = 0; +#[cfg(feature = "decompression")] +const FIO_RUST_ZSTD_FRAME_DECODING_ERROR: c_int = 1; +#[cfg(feature = "decompression")] +const FIO_RUST_ZSTD_FRAME_PREMATURE_END: c_int = 2; + +#[cfg(feature = "decompression")] +pub const FIO_RUST_ZSTD_FRAME_ACTION_OK: c_int = 0; +#[cfg(feature = "decompression")] +pub const FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR: c_int = 1; +#[cfg(feature = "decompression")] +pub const FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END: c_int = 2; +#[cfg(feature = "decompression")] +pub const FIO_RUST_ZSTD_FRAME_ACTION_INVALID: c_int = 3; + +#[cfg(feature = "decompression")] +#[inline] +fn decompress_zstd_frame_action(status: c_int) -> c_int { + match status { + FIO_RUST_ZSTD_FRAME_OK => FIO_RUST_ZSTD_FRAME_ACTION_OK, + FIO_RUST_ZSTD_FRAME_DECODING_ERROR => FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR, + FIO_RUST_ZSTD_FRAME_PREMATURE_END => FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END, + _ => FIO_RUST_ZSTD_FRAME_ACTION_INVALID, + } +} + +/// Classify a zstd-frame status without owning the CLI's diagnostics or +/// private decompression resources. C keeps the exact messages, error-help +/// call, and return values for each resulting action. +#[cfg(feature = "decompression")] +#[no_mangle] +pub extern "C" fn FIO_rust_decompressZstdFrameAction(status: c_int) -> c_int { + decompress_zstd_frame_action(status) +} + #[cfg(feature = "decompression")] type FIO_rust_zstdErrorHelpDisplayFn = unsafe extern "C" fn(*mut c_void, c_int, *const c_char, u64, c_uint, c_uint, c_uint); @@ -2460,6 +2496,37 @@ mod tests { use std::fs; use std::mem::{align_of, offset_of, size_of}; + #[cfg(feature = "decompression")] + #[test] + fn decompress_zstd_frame_action_preserves_status_classes() { + let cases = [ + (FIO_RUST_ZSTD_FRAME_OK, FIO_RUST_ZSTD_FRAME_ACTION_OK), + ( + FIO_RUST_ZSTD_FRAME_DECODING_ERROR, + FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR, + ), + ( + FIO_RUST_ZSTD_FRAME_PREMATURE_END, + FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END, + ), + (-1, FIO_RUST_ZSTD_FRAME_ACTION_INVALID), + (3, FIO_RUST_ZSTD_FRAME_ACTION_INVALID), + ]; + + for (status, expected_action) in cases { + assert_eq!( + decompress_zstd_frame_action(status), + expected_action, + "unexpected action for zstd frame status {status}" + ); + assert_eq!( + FIO_rust_decompressZstdFrameAction(status), + expected_action, + "export disagrees for zstd frame status {status}" + ); + } + } + #[test] fn source_exclusion_preserves_case_sensitive_suffixes_and_null_policy() { let cases = [