Search code examples
rustiso-image

read ISO image from Rust (FFI bindings)


I am trying to read the contents from the ISO image using Rust. I have installed libiso9660-dev and libcdio-dev on my Linux machine to get access to the header files. Libiso9660 is a library to work with ISO9660 filesystems (development files). I used bindgen to generate bindings to the library. Until this point, everything was pretty straightforward.

Here is the part of the bindings relevant to my code:

    extern "C" {
        pub fn iso9660_open(psz_path: *const ::std::os::raw::c_char) -> *mut iso9660_t;
    }

    extern "C" {
        pub fn iso9660_ifs_get_application_id(
            p_iso: *mut iso9660_t,
            p_psz_app_id: *mut *mut cdio_utf8_t,
        ) -> ::std::os::raw::c_uchar;
    }

The next step is to use generated bindings. Here is the relevant code:

    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

    use std::os::raw::{c_char};
    use std::ffi::{CString};
    use std::ptr;

    pub fn open_image(path: &str) {
        let c_str = CString::new(path).unwrap();
        let psz_path = c_str.as_ptr() as *const c_char;
        let image = unsafe { iso9660_open(psz_path) };
        get_image_info(image);
    }

    fn get_image_info(image: *mut iso9660_t) {
        println!("Getting image info...");
        let ptr_null = ptr::null_mut();
        let app_info = unsafe { iso9660_ifs_get_application_id(image, ptr_null) };
        // here is the "segmentation fault (core dumped)"
    }

Here is the example that I want to replicate in Rust (line 89 is where I am at this point).

open_image seems to be working, but I get the segmentation fault when I call iso9660_ifs_get_application_id. I assume that I am not calling the method as I should because of the types, but other than that, I have nothing. Any hint or help would be highly appreciated. Thank you!


Solution

  • Notice the type of the p_psz_app_id parameter: *mut *mut cdio_utf8_t. It is a double pointer. Here is what the C example code is doing:

    char *psz_str = NULL;
    if (iso9660_ifs_get_application_id(p_iso, &psz_str)) {
      printf(title ": %s\n", psz_str);
    }
    free(psz_str);
    psz_str = NULL;
    

    It's passing &psz_str to the iso9660_ifs_get_application_id() function. Here, &psz_str is a valid pointer pointing to the null pointer psz_str; it is not itself a null pointer. The Rust code is passing in a null pointer for this parameter, which is the issue.