geofft/redhook

share state between hooks

Opened this issue · 0 comments

could be useful. add to examples?

// we need Arc and Mutex to make this thread-safe
use std::sync::Arc;
use std::sync::Mutex;

use std::collections::HashMap;

struct State {
    map: HashMap<String, String>,
    init_done: bool,
    cwd: String
}

/* add to Cargo.toml:
lazy_static = "*"
*/
lazy_static::lazy_static! {
    static ref STATE_ARC: Arc<Mutex<State>> = {
        // init state. this is called on the first "lock state for this scope"
        let cwd_str = std::env::current_dir().unwrap().into_os_string().into_string().unwrap(); // pathbuf to string
        let state = State {
            map: HashMap::new(),
            init_done: false,
            cwd: cwd_str
        };
        let state_arc = Arc::new(Mutex::new(state));
        return state_arc;
    };
}


hook! {
    unsafe fn some_hooked_function(
        dir: *const libc::c_char
    ) -> libc::c_int => my_some_hooked_function {

        // lock state for this scope
        let mut state = STATE_ARC.lock().unwrap();

        // use state ...

        if !state.init_done {
            println!("preload init. cwd = {}", state.cwd);
            state.init_done = true;
        }

        let map_from = "foo";
        let map_to = "bar";
        state.map.insert(map_from.to_owned(), map_to.to_owned()); // must copy values

        for map_from in state.map.keys() {
            let map_to = state.map.get(map_from);
            println!("preload map {} -> {}", map_from, map_to);
        }
    }
}

hook! {
    unsafe fn chdir(
        dir: *const libc::c_char
    ) -> libc::c_int => my_chdir {
        let retval = real!(chdir)(dir);
        let dir_str = str_of_chars(dir);
        if retval == 0 {
            // success
            // lock state for this scope
            let mut state = STATE_ARC.lock().unwrap();
            if dir_str.starts_with("/") {
                state.cwd = dir_str.to_owned();
            }
            else {
                // get absolute path
                // TODO better: resolve ../
                let mut dir_abs = state.cwd.to_owned();
                dir_abs.push_str("/");
                dir_abs.push_str(dir_str);
                state.cwd = dir_abs;
            }
            println!("preload chdir {}", state.cwd);
        }
        return retval;
    }
}