refactor(cli): move source-open policy to Rust

Move stdin-sentinel classification and source stat/open result policy into the Rust fileio backend while keeping C responsible for diagnostics, binary-mode setup, and FILE ownership. The bridge leaves stat layout and native file utilities behind the existing C ABI and adds a focused no-stat stdin test.

Test Plan: git diff --cached --check; focused Rust test added but full capped verification will run after the remaining workers are integrated.
This commit is contained in:
2026-07-21 07:14:54 +02:00
parent 14e3f7c140
commit 8ae0dfa49d
2 changed files with 35 additions and 8 deletions
+7 -6
View File
@@ -351,6 +351,7 @@ enum {
FIO_RUST_OPEN_SRC_STAT_FAILED = 1,
FIO_RUST_OPEN_SRC_NON_REGULAR = 2,
FIO_RUST_OPEN_SRC_FOPEN_FAILED = 3,
FIO_RUST_OPEN_SRC_STDIN = 4,
};
int FIO_rust_openSrcFile(int allowBlockDevices,
const char* srcFileName,
@@ -671,17 +672,17 @@ static FILE* FIO_openSrcFile(const FIO_prefs_t* const prefs, const char* srcFile
int allowBlockDevices = prefs != NULL ? prefs->allowBlockDevices : 0;
assert(srcFileName != NULL);
assert(statbuf != NULL);
if (!strcmp (srcFileName, stdinmark)) {
DISPLAYLEVEL(4,"Using stdin for input \n");
SET_BINARY_MODE(stdin);
return stdin;
}
{ FILE* f = NULL;
int const status = FIO_rust_openSrcFile(allowBlockDevices,
srcFileName,
statbuf,
&f);
if (status == FIO_RUST_OPEN_SRC_STDIN) {
DISPLAYLEVEL(4,"Using stdin for input \n");
SET_BINARY_MODE(stdin);
return stdin;
}
if (status == FIO_RUST_OPEN_SRC_STAT_FAILED) {
DISPLAYLEVEL(1, "zstd: can't stat %s : %s -- ignored \n",
srcFileName, strerror(errno));
+28 -2
View File
@@ -55,6 +55,7 @@ const FIO_OPEN_SRC_SUCCESS: c_int = 0;
const FIO_OPEN_SRC_STAT_FAILED: c_int = 1;
const FIO_OPEN_SRC_NON_REGULAR: c_int = 2;
const FIO_OPEN_SRC_FOPEN_FAILED: c_int = 3;
const FIO_OPEN_SRC_STDIN: c_int = 4;
const FIO_OPEN_DST_SUCCESS: c_int = 0;
const FIO_OPEN_DST_SETBUF_FAILED: c_int = 1;
@@ -84,6 +85,7 @@ const FIO_OPEN_DST_ACTION_SUCCESS: c_int = 11;
const FIO_OPEN_DST_ACTION_INVALID: c_int = 12;
static STDOUT_MARK: &[u8] = b"/*stdout*\\\0";
static STDIN_MARK: &[u8] = b"/*stdin*\\\0";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum DestinationDecision {
@@ -475,7 +477,8 @@ pub unsafe extern "C" fn FIO_rust_getDictFileStat(
FIO_DICT_STAT_SUCCESS
}
/// Opens a non-stdin source path and returns a status for the C policy adapter.
/// Classifies stdin before opening or statting, then opens a non-stdin source
/// path and returns a status for the C policy adapter.
///
/// `stat_buf` and `out_file` deliberately cross this boundary as opaque
/// pointers. The existing utility ABI owns the target-specific `stat_t` layout
@@ -488,7 +491,17 @@ pub unsafe extern "C" fn FIO_rust_openSrcFile(
stat_buf: *mut c_void,
out_file: *mut *mut c_void,
) -> c_int {
if file_name.is_null() || stat_buf.is_null() || out_file.is_null() {
if file_name.is_null() || out_file.is_null() {
return FIO_OPEN_SRC_STAT_FAILED;
}
// The stdin sentinel is a dispatch decision, not a filesystem path. It
// must be recognized before the stat buffer is touched; C retains the
// stream selection, binary-mode setup, and exact diagnostic.
if c_string_equals(file_name, STDIN_MARK) {
return FIO_OPEN_SRC_STDIN;
}
if stat_buf.is_null() {
return FIO_OPEN_SRC_STAT_FAILED;
}
@@ -1698,6 +1711,19 @@ mod tests {
assert!(file.is_null());
}
#[test]
fn classifies_stdin_before_stat_and_leaves_output_untouched() {
let stdin = CString::new("/*stdin*\\").expect("stdin sentinel contains no NUL");
let sentinel = ptr::dangling_mut::<c_void>();
let mut out_file = sentinel;
let status = unsafe {
FIO_rust_openSrcFile(0, stdin.as_ptr(), ptr::null_mut(), &mut out_file)
};
assert_eq!(status, FIO_OPEN_SRC_STDIN);
assert_eq!(out_file, sentinel);
}
#[test]
fn rejects_directory_source_path() {
let path = temp_path("open-directory");