refactor(cli): move file-removal policy to Rust

Keep FIO_removeFile responsible for the filesystem operation, exact diagnostics, and C return wrapper, but route its status classification through a Rust policy bridge. Unknown statuses are explicitly treated as failed removal. ABI value assertions and focused mapping tests preserve the C contract.

Test Plan: Not run in this atomic commit; the capped serial Rust, native, smoke, and original test-suite verification follows.
This commit is contained in:
2026-07-21 07:55:18 +02:00
parent b89acb1fb5
commit 78c4118a67
2 changed files with 99 additions and 9 deletions
+65
View File
@@ -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 = [