diff --git a/programs/fileio.c b/programs/fileio.c index cf4ae6dbd..650726dae 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -471,6 +471,9 @@ int FIO_rust_finishDecompressFrames(int status, U64 decodedSize, const FIO_rust_decompress_callbacks_t* callbacks); int FIO_rust_decompressStatusDiagnostic(int status); +int FIO_rust_decompressPassThroughPolicy(int passThrough, + int overwrite, + int destinationIsStdout); typedef void (*FIO_rust_decompress_read_fill_fn)( void* opaque, size_t requested, const unsigned char** buffer, size_t* loaded); @@ -4216,18 +4219,14 @@ static int FIO_decompressFrames(FIO_ctx_t* const fCtx, const char* dstFileName, const char* srcFileName) { U64 filesize = 0; - int passThrough = prefs->passThrough; + int const passThrough = FIO_rust_decompressPassThroughPolicy( + prefs->passThrough, + prefs->overwrite, + prefs->passThrough == -1 ? !strcmp(dstFileName, stdoutmark) : 0); FIO_rust_decompression_projection_t projection; FIO_rust_decompress_callbacks_t callbacks; int status; - if (passThrough == -1) { - /* If pass-through mode is not explicitly enabled or disabled, - * default to the legacy behavior of enabling it if we are writing - * to stdout with the overwrite flag enabled. - */ - passThrough = prefs->overwrite && !strcmp(dstFileName, stdoutmark); - } assert(passThrough == 0 || passThrough == 1); projection.fCtx = fCtx; diff --git a/rust/src/fileio_asyncio.rs b/rust/src/fileio_asyncio.rs index fc2cc65ad..77408dda4 100644 --- a/rust/src/fileio_asyncio.rs +++ b/rust/src/fileio_asyncio.rs @@ -64,6 +64,31 @@ pub const FIO_RUST_DECOMPRESS_DIAGNOSTIC_LZMA_UNSUPPORTED: c_int = 4; pub const FIO_RUST_DECOMPRESS_DIAGNOSTIC_LZ4_UNSUPPORTED: c_int = 5; pub const FIO_RUST_DECOMPRESS_DIAGNOSTIC_UNSUPPORTED_FORMAT: c_int = 6; +/// Resolves the legacy automatic pass-through mode without touching the +/// destination name or any C-owned file state. Explicit values are returned +/// unchanged so the C assertion keeps its original validation behavior. +#[inline] +fn decompress_pass_through_policy( + pass_through: c_int, + overwrite: c_int, + destination_is_stdout: c_int, +) -> c_int { + if pass_through == -1 { + (overwrite != 0 && destination_is_stdout != 0) as c_int + } else { + pass_through + } +} + +#[no_mangle] +pub extern "C" fn FIO_rust_decompressPassThroughPolicy( + pass_through: c_int, + overwrite: c_int, + destination_is_stdout: c_int, +) -> c_int { + decompress_pass_through_policy(pass_through, overwrite, destination_is_stdout) +} + /// Maps decompression results to the diagnostics that the C CLI displays. /// Statuses without a legacy diagnostic deliberately map to `NONE`, retaining /// the previous C callback's silent default case. @@ -5299,6 +5324,25 @@ impl PoolInner { mod tests { use super::*; + #[test] + fn decompression_pass_through_policy_preserves_explicit_and_default_modes() { + for pass_through in [0, 1] { + assert_eq!( + decompress_pass_through_policy(pass_through, 0, 0), + pass_through + ); + assert_eq!( + decompress_pass_through_policy(pass_through, 1, 1), + pass_through + ); + } + + assert_eq!(decompress_pass_through_policy(-1, 0, 0), 0); + assert_eq!(decompress_pass_through_policy(-1, 0, 1), 0); + assert_eq!(decompress_pass_through_policy(-1, 1, 0), 0); + assert_eq!(decompress_pass_through_policy(-1, 1, 1), 1); + } + #[test] fn decompression_status_diagnostic_preserves_cli_mapping() { for (status, diagnostic) in [