redhook icon indicating copy to clipboard operation
redhook copied to clipboard

string conversion between C (char*) and Rust (&str, String)

Open milahu opened this issue 4 years ago • 0 comments

can we add this somehow? im new to rust, so i hope there is a shorter way ...

convert string from C to Rust

unsafe fn str_of_chars(cstr: *const libc::c_char) -> &'static str {
    return std::str::from_utf8(std::ffi::CStr::from_ptr(cstr).to_bytes()).unwrap();
}

// https://users.rust-lang.org/t/how-to-convert-a-non-zero-terminated-c-string-to-rust-str-or-string/2177
unsafe fn str_of_chars_size(cstr: *const libc::c_char, size: isize) -> &'static str {
    return std::str::from_utf8(std::slice::from_raw_parts(cstr as *const u8, size as usize)).unwrap()
}
sample use
hook! {
    unsafe fn statx(
        dirfd: libc::c_int,
        pathname: *const libc::c_char,
        flags: libc::c_int,
        mask: libc::c_uint,
        statxbuf: *mut libc::statx // https://docs.rs/libc/0.2.103/libc/struct.statx.html
    ) -> libc::c_int => my_statx {

        let retval = real!(statx)(dirfd, pathname, flags, mask, statxbuf);
        let pathname_str = str_of_chars(pathname);
        println!("statx({}) -> retval {}, stx_mode {:#o}", pathname_str, retval, (*statxbuf).stx_mode);
        return retval;
    }
}

hook! {
    unsafe fn readlink(
        path: *const libc::c_char,
        buf: *mut libc::c_char,
        bufsiz: libc::size_t
    ) -> libc::ssize_t => my_readlink {

        let buf_len = real!(readlink)(path, buf, bufsiz);
        let path_str = str_of_chars(path);
        let buf_str = str_of_chars_size(buf, buf_len);
        println!("readlink({}) -> target {}, bufsiz {} of {}", path_str, buf_str, buf_len, bufsiz);
        return buf_len;
    }
}

convert string from Rust to C

    path_resolved_str = "some string ...";

    // TODO move to function/macro
    let r_string_2 = path_resolved_str.to_owned();
    let c_string_2 = CString::new(r_string_2).unwrap();
    let path_resolved: *const libc::c_char = c_string_2.as_ptr() as *const libc::c_char;

    let r_string = "open: path_resolved = \"%s\"\n";
    let c_string = CString::new(r_string).unwrap();
    let c_chars: *const libc::c_char = c_string.as_ptr() as *const libc::c_char;

    libc::printf(c_chars, path_resolved);

write Rust string to C buffer

unsafe fn str_to_c_char_buf(
    src_str: &str,
    buf: *mut libc::c_char,
    bufsz: libc::size_t
) -> libc::size_t {
    // write string to buffer
    // https://stackoverflow.com/questions/51320714
    let src_string = String::from(src_str);
    let src_cstring = CString::new(src_string).unwrap();
    //let src_bytes = src_cstring.as_bytes_with_nul();
    let src_bytes = src_cstring.as_bytes();
    let buf_bytes = slice::from_raw_parts_mut(buf as *mut u8, bufsz as usize);
    buf_bytes[..src_bytes.len()].copy_from_slice(src_bytes);
    return src_bytes.len() as libc::size_t;
}

// example use
hook! {
    // https://docs.rs/libc/latest/libc/fn.readlink.html
    unsafe fn readlink(
        path: *const libc::c_char,
        buf: *mut libc::c_char,
        bufsz: libc::size_t
    ) -> libc::ssize_t => readlink_hooked {
        let mut retval = real!(readlink)(path, buf, bufsz);
        if true {
            // modify result
            retval = str_to_c_char_buf("/asdf", buf, bufsz) as libc::ssize_t;
        }
        return retval;
    }
}

milahu avatar Sep 29 '21 08:09 milahu