diff --git a/programs/fileio.c b/programs/fileio.c index 2337cdc1a..61a512e82 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -435,6 +435,31 @@ void FIO_rust_freeDict(int dictBufferType, size_t* bufferSize, void** dictHandle); int FIO_rust_removeFile(const char* path); +enum { + FIO_REMOVE_SUCCESS = 0, + FIO_REMOVE_STAT_FAILED = 1, + FIO_REMOVE_NON_REGULAR = 2, + FIO_REMOVE_FAILED = 3 +}; +enum { + FIO_RUST_REMOVE_FILE_ACTION_SUCCESS = 0, + FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED = 1, + FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR = 2, + FIO_RUST_REMOVE_FILE_ACTION_FAILED = 3, + FIO_RUST_REMOVE_FILE_ACTION_INVALID = 4 +}; +typedef char FIO_rust_remove_file_status_values[ + (FIO_REMOVE_SUCCESS == 0 + && FIO_REMOVE_STAT_FAILED == 1 + && FIO_REMOVE_NON_REGULAR == 2 + && FIO_REMOVE_FAILED == 3) ? 1 : -1]; +typedef char FIO_rust_remove_file_action_values[ + (FIO_RUST_REMOVE_FILE_ACTION_SUCCESS == 0 + && FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED == 1 + && FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR == 2 + && FIO_RUST_REMOVE_FILE_ACTION_FAILED == 3 + && FIO_RUST_REMOVE_FILE_ACTION_INVALID == 4) ? 1 : -1]; +int FIO_rust_removeFileAction(int status); int FIO_rust_passThrough(ReadPoolCtx_t* readCtx, WritePoolCtx_t* writeCtx); enum { FIO_RUST_ZSTD_FRAME_OK = 0, @@ -647,21 +672,21 @@ int FIO_LZ4_GetBlockSize_FromBlockId(int id); * @result : Unlink `fileName`, even if it's read-only */ static int FIO_removeFile(const char* path) { - enum { - FIO_REMOVE_SUCCESS = 0, - FIO_REMOVE_STAT_FAILED = 1, - FIO_REMOVE_NON_REGULAR = 2, - }; int const status = FIO_rust_removeFile(path); - if (status == FIO_REMOVE_STAT_FAILED) { + switch (FIO_rust_removeFileAction(status)) { + case FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED: DISPLAYLEVEL(2, "zstd: Failed to stat %s while trying to remove it\n", path); return 0; - } - if (status == FIO_REMOVE_NON_REGULAR) { + case FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR: DISPLAYLEVEL(2, "zstd: Refusing to remove non-regular file %s\n", path); return 0; + case FIO_RUST_REMOVE_FILE_ACTION_SUCCESS: + return 0; + case FIO_RUST_REMOVE_FILE_ACTION_FAILED: + case FIO_RUST_REMOVE_FILE_ACTION_INVALID: + default: + return 1; } - return status == FIO_REMOVE_SUCCESS ? 0 : 1; } /** FIO_openSrcFile() : diff --git a/rust/src/fileio_prefs.rs b/rust/src/fileio_prefs.rs index 48ab2ec8a..ea49abe80 100644 --- a/rust/src/fileio_prefs.rs +++ b/rust/src/fileio_prefs.rs @@ -22,6 +22,10 @@ const FIO_LDM_PARAM_NOTSET: c_int = 9999; const FIO_PATCH_MEM_LIMIT_SUCCESS: c_int = 0; const FIO_PATCH_MEM_LIMIT_UNKNOWN_SIZE: c_int = 1; const FIO_PATCH_MEM_LIMIT_TOO_LARGE: c_int = 2; +const FIO_REMOVE_SUCCESS: c_int = 0; +const FIO_REMOVE_STAT_FAILED: c_int = 1; +const FIO_REMOVE_NON_REGULAR: c_int = 2; +const FIO_REMOVE_FAILED: c_int = 3; const FIO_MULTI_FILES_ACTION_PROCEED: c_int = 0; const FIO_MULTI_FILES_ACTION_FATAL_STDOUT_REMOVE: c_int = 1; const FIO_MULTI_FILES_ACTION_FATAL_TEST_REMOVE: c_int = 2; @@ -39,6 +43,11 @@ pub const FIO_RUST_LIST_FILE_ACTION_NOT_ZSTD: c_int = 2; pub const FIO_RUST_LIST_FILE_ACTION_FILE_ERROR: c_int = 3; pub const FIO_RUST_LIST_FILE_ACTION_TRUNCATED_INPUT: c_int = 4; pub const FIO_RUST_LIST_FILE_ACTION_INVALID: c_int = 5; +pub const FIO_RUST_REMOVE_FILE_ACTION_SUCCESS: c_int = 0; +pub const FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED: c_int = 1; +pub const FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR: c_int = 2; +pub const FIO_RUST_REMOVE_FILE_ACTION_FAILED: c_int = 3; +pub const FIO_RUST_REMOVE_FILE_ACTION_INVALID: c_int = 4; const UTIL_FILESIZE_UNKNOWN: u64 = u64::MAX; const COMPRESSED_FILE_EXTENSIONS: &[&[u8]] = &[ b".zst", @@ -734,6 +743,27 @@ pub extern "C" fn FIO_rust_listFileStatusAction(status: c_int) -> c_int { list_file_status_action(status) } +#[inline] +fn remove_file_action(status: c_int) -> c_int { + match status { + FIO_REMOVE_SUCCESS => FIO_RUST_REMOVE_FILE_ACTION_SUCCESS, + FIO_REMOVE_STAT_FAILED => FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED, + FIO_REMOVE_NON_REGULAR => FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR, + FIO_REMOVE_FAILED => FIO_RUST_REMOVE_FILE_ACTION_FAILED, + _ => FIO_RUST_REMOVE_FILE_ACTION_INVALID, + } +} + +/// Map the C-owned file-removal result to its policy action. +/// +/// C retains the filesystem operation, exact diagnostics, and return-value +/// wrapper. Rust owns only the status classification, with unknown statuses +/// remaining a failed removal for the C caller. +#[no_mangle] +pub extern "C" fn FIO_rust_removeFileAction(status: c_int) -> c_int { + remove_file_action(status) +} + /// Callback projection for the C-owned `--list` file operations. #[repr(C)] pub struct FIO_listMultipleFilesCallbacks_t { @@ -2612,6 +2642,41 @@ mod tests { } } + #[test] + fn remove_file_action_preserves_status_mapping_and_unknown_failure_policy() { + for (status, action) in [ + ( + FIO_REMOVE_SUCCESS, + FIO_RUST_REMOVE_FILE_ACTION_SUCCESS, + ), + ( + FIO_REMOVE_STAT_FAILED, + FIO_RUST_REMOVE_FILE_ACTION_STAT_FAILED, + ), + ( + FIO_REMOVE_NON_REGULAR, + FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR, + ), + ( + FIO_REMOVE_FAILED, + FIO_RUST_REMOVE_FILE_ACTION_FAILED, + ), + (-1, FIO_RUST_REMOVE_FILE_ACTION_INVALID), + (c_int::MAX, FIO_RUST_REMOVE_FILE_ACTION_INVALID), + ] { + assert_eq!( + remove_file_action(status), + action, + "unexpected action for remove status {status}" + ); + assert_eq!( + FIO_rust_removeFileAction(status), + action, + "C ABI disagrees for remove status {status}" + ); + } + } + #[test] fn source_exclusion_preserves_case_sensitive_suffixes_and_null_policy() { let cases = [