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:
+34
-9
@@ -435,6 +435,31 @@ void FIO_rust_freeDict(int dictBufferType,
|
|||||||
size_t* bufferSize,
|
size_t* bufferSize,
|
||||||
void** dictHandle);
|
void** dictHandle);
|
||||||
int FIO_rust_removeFile(const char* path);
|
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);
|
int FIO_rust_passThrough(ReadPoolCtx_t* readCtx, WritePoolCtx_t* writeCtx);
|
||||||
enum {
|
enum {
|
||||||
FIO_RUST_ZSTD_FRAME_OK = 0,
|
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 */
|
* @result : Unlink `fileName`, even if it's read-only */
|
||||||
static int FIO_removeFile(const char* path)
|
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);
|
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);
|
DISPLAYLEVEL(2, "zstd: Failed to stat %s while trying to remove it\n", path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
case FIO_RUST_REMOVE_FILE_ACTION_NON_REGULAR:
|
||||||
if (status == FIO_REMOVE_NON_REGULAR) {
|
|
||||||
DISPLAYLEVEL(2, "zstd: Refusing to remove non-regular file %s\n", path);
|
DISPLAYLEVEL(2, "zstd: Refusing to remove non-regular file %s\n", path);
|
||||||
return 0;
|
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() :
|
/** FIO_openSrcFile() :
|
||||||
|
|||||||
@@ -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_SUCCESS: c_int = 0;
|
||||||
const FIO_PATCH_MEM_LIMIT_UNKNOWN_SIZE: c_int = 1;
|
const FIO_PATCH_MEM_LIMIT_UNKNOWN_SIZE: c_int = 1;
|
||||||
const FIO_PATCH_MEM_LIMIT_TOO_LARGE: c_int = 2;
|
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_PROCEED: c_int = 0;
|
||||||
const FIO_MULTI_FILES_ACTION_FATAL_STDOUT_REMOVE: c_int = 1;
|
const FIO_MULTI_FILES_ACTION_FATAL_STDOUT_REMOVE: c_int = 1;
|
||||||
const FIO_MULTI_FILES_ACTION_FATAL_TEST_REMOVE: c_int = 2;
|
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_FILE_ERROR: c_int = 3;
|
||||||
pub const FIO_RUST_LIST_FILE_ACTION_TRUNCATED_INPUT: c_int = 4;
|
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_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 UTIL_FILESIZE_UNKNOWN: u64 = u64::MAX;
|
||||||
const COMPRESSED_FILE_EXTENSIONS: &[&[u8]] = &[
|
const COMPRESSED_FILE_EXTENSIONS: &[&[u8]] = &[
|
||||||
b".zst",
|
b".zst",
|
||||||
@@ -734,6 +743,27 @@ pub extern "C" fn FIO_rust_listFileStatusAction(status: c_int) -> c_int {
|
|||||||
list_file_status_action(status)
|
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.
|
/// Callback projection for the C-owned `--list` file operations.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FIO_listMultipleFilesCallbacks_t {
|
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]
|
#[test]
|
||||||
fn source_exclusion_preserves_case_sensitive_suffixes_and_null_policy() {
|
fn source_exclusion_preserves_case_sensitive_suffixes_and_null_policy() {
|
||||||
let cases = [
|
let cases = [
|
||||||
|
|||||||
Reference in New Issue
Block a user