feat(fileio): move output path construction to Rust
Move the basename-preserving output-directory helper behind the existing Rust utility ABI. Keep the libc allocation contract and platform separator behavior intact while leaving the C file-I/O engines and higher-level naming policy unchanged. Test Plan: - cargo test --manifest-path rust/cli/Cargo.toml (93 passed) - cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets - make -B -C tests -j2 test-cli-tests (41 passed)
This commit is contained in:
+3
-36
@@ -709,13 +709,8 @@ int FIO_checkFilenameCollisions(const char** filenameTable, unsigned nbFiles) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char*
|
char* UTIL_createFilenameFromOutDir(const char* path, const char* outDirName,
|
||||||
extractFilename(const char* path, char separator)
|
size_t suffixLen);
|
||||||
{
|
|
||||||
const char* search = strrchr(path, separator);
|
|
||||||
if (search == NULL) return path;
|
|
||||||
return search+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIO_createFilename_fromOutDir() :
|
/* FIO_createFilename_fromOutDir() :
|
||||||
* Takes a source file name and specified output directory, and
|
* Takes a source file name and specified output directory, and
|
||||||
@@ -725,35 +720,7 @@ extractFilename(const char* path, char separator)
|
|||||||
static char*
|
static char*
|
||||||
FIO_createFilename_fromOutDir(const char* path, const char* outDirName, const size_t suffixLen)
|
FIO_createFilename_fromOutDir(const char* path, const char* outDirName, const size_t suffixLen)
|
||||||
{
|
{
|
||||||
const char* filenameStart;
|
return UTIL_createFilenameFromOutDir(path, outDirName, suffixLen);
|
||||||
char separator;
|
|
||||||
char* result;
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__) /* windows support */
|
|
||||||
separator = '\\';
|
|
||||||
#else
|
|
||||||
separator = '/';
|
|
||||||
#endif
|
|
||||||
|
|
||||||
filenameStart = extractFilename(path, separator);
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__) || defined (__MSVCRT__) /* windows support */
|
|
||||||
filenameStart = extractFilename(filenameStart, '/'); /* sometimes, '/' separator is also used on Windows (mingw+msys2) */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
result = (char*) calloc(1, strlen(outDirName) + 1 + strlen(filenameStart) + suffixLen + 1);
|
|
||||||
if (!result) {
|
|
||||||
EXM_THROW(30, "zstd: FIO_createFilename_fromOutDir: %s", strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(result, outDirName, strlen(outDirName));
|
|
||||||
if (outDirName[strlen(outDirName)-1] == separator) {
|
|
||||||
memcpy(result + strlen(outDirName), filenameStart, strlen(filenameStart));
|
|
||||||
} else {
|
|
||||||
memcpy(result + strlen(outDirName), &separator, 1);
|
|
||||||
memcpy(result + strlen(outDirName) + 1, filenameStart, strlen(filenameStart));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIO_highbit64() :
|
/* FIO_highbit64() :
|
||||||
|
|||||||
@@ -161,6 +161,59 @@ fn path_separator() -> u8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build the basename-preserving output path used by the file-I/O backend.
|
||||||
|
///
|
||||||
|
/// The caller owns the returned libc allocation. `suffix_len` is retained in
|
||||||
|
/// the ABI because the original C helper reserved that extra capacity for its
|
||||||
|
/// callers, even though it only wrote the directory and basename.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn UTIL_createFilenameFromOutDir(
|
||||||
|
path: *const c_char,
|
||||||
|
out_dir: *const c_char,
|
||||||
|
_suffix_len: usize,
|
||||||
|
) -> *mut c_char {
|
||||||
|
if path.is_null() || out_dir.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
let path = unsafe { c_bytes(path) };
|
||||||
|
let out_dir = unsafe { c_bytes(out_dir) };
|
||||||
|
if out_dir.is_empty() {
|
||||||
|
std::process::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
let separator = path_separator();
|
||||||
|
let mut filename = path;
|
||||||
|
if let Some(index) = path.iter().rposition(|&byte| byte == separator) {
|
||||||
|
filename = &path[index + 1..];
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
if let Some(index) = filename.iter().rposition(|&byte| byte == b'/') {
|
||||||
|
filename = &filename[index + 1..];
|
||||||
|
}
|
||||||
|
|
||||||
|
let separator_len = usize::from(out_dir.last().copied() != Some(separator));
|
||||||
|
let Some(size) = out_dir
|
||||||
|
.len()
|
||||||
|
.checked_add(separator_len)
|
||||||
|
.and_then(|size| size.checked_add(filename.len()))
|
||||||
|
.and_then(|size| size.checked_add(1))
|
||||||
|
else {
|
||||||
|
std::process::abort();
|
||||||
|
};
|
||||||
|
let result = unsafe { malloc_bytes(size).cast::<c_char>() };
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(out_dir.as_ptr(), result.cast(), out_dir.len());
|
||||||
|
let mut offset = out_dir.len();
|
||||||
|
if separator_len != 0 {
|
||||||
|
*result.add(offset) = separator as c_char;
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
ptr::copy_nonoverlapping(filename.as_ptr(), result.add(offset).cast(), filename.len());
|
||||||
|
*result.add(offset + filename.len()) = 0;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
fn path_from_bytes(bytes: &[u8]) -> PathBuf {
|
fn path_from_bytes(bytes: &[u8]) -> PathBuf {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
@@ -1558,6 +1611,24 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn output_path_preserves_basename_and_trailing_separator() {
|
||||||
|
let path = CString::new("input/nested/file.txt").unwrap();
|
||||||
|
let out_dir = CString::new("out").unwrap();
|
||||||
|
unsafe {
|
||||||
|
let name = UTIL_createFilenameFromOutDir(path.as_ptr(), out_dir.as_ptr(), 4);
|
||||||
|
assert_eq!(CStr::from_ptr(name).to_bytes(), b"out/file.txt");
|
||||||
|
free_ptr(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
let out_dir = CString::new(if cfg!(windows) { "out\\" } else { "out/" }).unwrap();
|
||||||
|
unsafe {
|
||||||
|
let name = UTIL_createFilenameFromOutDir(path.as_ptr(), out_dir.as_ptr(), 0);
|
||||||
|
assert_eq!(CStr::from_ptr(name).to_bytes(), b"out/file.txt");
|
||||||
|
free_ptr(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn human_readable_size_uses_the_c_scaling_policy() {
|
fn human_readable_size_uses_the_c_scaling_policy() {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
Reference in New Issue
Block a user