Skip to content

Commit

Permalink
hook NtCreateFile instead of CreateFile{A,W}
Browse files Browse the repository at this point in the history
this also attempts to keep track of handles so we can purge the files when all handles are closed, but bnlc mysteriously leaks a handle every time a game is loaded/unloaded...

this also fixes the paths to all temp files so we don't have to deal with goofy temporary file names
  • Loading branch information
bigfarts committed Apr 26, 2023
1 parent 92a35c6 commit 17090b7
Show file tree
Hide file tree
Showing 5 changed files with 444 additions and 184 deletions.
53 changes: 11 additions & 42 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions chaudloader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@ crate-type = ["cdylib"]
[dependencies]
retour = "0.1"
anyhow = "1"
winapi = { version = "0.3.9", features = ["dxgi"] }
winapi = "0.3.9"
log = "0.4"
env_logger = "0.9.0"
thiserror = "1"
zip = "0.6"
tempfile = "3"
clean-path = "0.2"
windows-libloader = { path = "../windows-libloader" }
const_format = "0.2"
Expand All @@ -26,3 +25,4 @@ indexmap = "1"
semver = { version = "1", features = ["serde"] }
serde_plain = "1"
crc32fast = "1"
ntapi = "0.4"
74 changes: 41 additions & 33 deletions chaudloader/src/assets.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::hooks;

pub mod exedat;
pub mod mpak;
pub mod msg;
Expand Down Expand Up @@ -55,42 +53,52 @@ impl Replacer {
self.replacers.insert(path.to_path_buf(), Box::new(pack_cb));
}

pub fn purge(
&mut self,
path: &std::path::Path,
) -> Result<Option<std::path::PathBuf>, std::io::Error> {
let replacement_path = if let Some(path) = self.replacement_paths.remove(path) {
path
} else {
return Ok(None);
};
std::fs::remove_file(&replacement_path)?;
Ok(Some(replacement_path))
}

pub fn get<'a>(
&'a mut self,
path: &'a std::path::Path,
) -> Result<(&'a std::path::Path, bool), std::io::Error> {
Ok((
match self.replacement_paths.entry(path.to_path_buf()) {
std::collections::hash_map::Entry::Occupied(entry) => entry.into_mut().as_path(),
std::collections::hash_map::Entry::Vacant(entry) => {
let replacer = if let Some(replacer) = self.replacers.get(path) {
replacer
} else {
return Ok((path, false));
};

// Unwrap these hook guards because there's not much we can do if they fail.
let _create_file_a_hook_guard =
unsafe { hooks::HookDisableGuard::new(&hooks::stage1::CreateFileAHook) }
.unwrap();
let _create_file_w_hook_guard =
unsafe { hooks::HookDisableGuard::new(&hooks::stage1::CreateFileWHook) }
.unwrap();
path: &std::path::Path,
) -> Result<Option<&'a std::path::Path>, std::io::Error> {
Ok(match self.replacement_paths.entry(path.to_path_buf()) {
std::collections::hash_map::Entry::Occupied(entry) => Some(entry.into_mut().as_path()),
std::collections::hash_map::Entry::Vacant(entry) => {
let replacer = if let Some(replacer) = self.replacers.get(path) {
replacer
} else {
return Ok(None);
};

let dest_f = tempfile::NamedTempFile::new_in(&self.temp_dir)?;
log::info!(
"replacing {} -> {}",
path.display(),
dest_f.path().display()
);
let (mut dest_f, dest_path) = dest_f.keep()?;
let dest_path = self.temp_dir.join(std::path::Path::new(
&path
.as_os_str()
.to_string_lossy()
.replace("_", "__")
.replace("../", "_DOTDOTSLASH_")
.replace("./", "_DOTSLASH_")
.replace("/", "_SLASH_")
.replace("..\\", "_DOTDOTSLASH_")
.replace(".\\", "_DOTSLASH_")
.replace("\\", "_SLASH_"),
));
{
let mut dest_f = std::fs::File::create(&dest_path)?;
log::info!("replacing {} -> {}", path.display(), dest_path.display());
replacer(&mut dest_f)?;

entry.insert(dest_path).as_path()
}
},
true,
))
Some(entry.insert(dest_path).as_path())
}
})
}
}

Expand Down
7 changes: 3 additions & 4 deletions chaudloader/src/hooks/stage0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,15 +230,14 @@ unsafe fn init(game_volume: crate::GameVolume) -> Result<(), anyhow::Error> {
.unwrap()
.into_inner();

// TODO: This path is a little wobbly, since it relies on BNLC specifying this weird relative path.
// We should canonicalize this path instead.
let dat_path = std::path::Path::new("..\\exe\\data").join(&dat_filename);

if !overlay.has_overlaid_files() {
continue;
}

let overlay = std::cell::RefCell::new(overlay);

// TODO: This path is a little wobbly, since it relies on BNLC specifying this exact path.
let dat_path = std::path::Path::new(&format!("data\\{}", &dat_filename)).to_path_buf();
assets_replacer.add(&dat_path, move |writer| {
let mut overlay = overlay.borrow_mut();
Ok(overlay.pack_into(writer)?)
Expand Down
Loading

0 comments on commit 17090b7

Please sign in to comment.