-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add tools to unpack and pack a CFB file
- Loading branch information
Showing
5 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "cfb_utils" | ||
version = "0.0.1" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
cfb = "0.10.0" | ||
walkdir = "2" | ||
pathdiff = "0.1.0" | ||
path-slash = "0.2.1" | ||
byteorder = "1.5.0" | ||
|
||
[[bin]] | ||
name = "cfb_pack" | ||
path = "src/bin/cfb_pack.rs" | ||
|
||
[[bin]] | ||
name = "cfb_unpack" | ||
path = "src/bin/cfb_unpack.rs" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# CFB Utils | ||
|
||
Rust based CLI tools to extract CFB containers and rebuild them. Streams become files and storages become directories while unpacking, packing behaves vice versa. | ||
|
||
## Usage | ||
|
||
```bash | ||
cargo build | ||
|
||
# Unpack your CFB file | ||
cargo run --bin cfb_unpack YOUR_CFB.DSN ./output_dir | ||
|
||
# Modify streams | ||
|
||
# Pack the folder to a CFB file again | ||
cargo run --bin cfb_pack ./output_dir YOUR_CFB2.DSN | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
use cfb; | ||
use std::env; | ||
use std::path::{Path, PathBuf}; | ||
extern crate pathdiff; | ||
|
||
use std::fs; | ||
use std::io::Write; | ||
use std::process::exit; | ||
|
||
use walkdir::WalkDir; | ||
|
||
fn help() { | ||
println!( | ||
"usage: cfb_pack <unpacked_cfb_root_dir> <output_cfb_file> | ||
Generates 'output_cfb_file' from 'unpacked_cfb_root_dir', where all all | ||
directories become 'storage's and all files become 'stream's." | ||
); | ||
} | ||
|
||
fn cfb_pack(output_cfb: &Path, unpacked_cfb_dir: &Path) { | ||
println!("Packing: {:#?}", unpacked_cfb_dir); | ||
println!("Into: {:#?}", output_cfb); | ||
|
||
let mut cfb = cfb::create(output_cfb).unwrap(); | ||
|
||
for entry in WalkDir::new(unpacked_cfb_dir) { | ||
let entry = entry.unwrap(); | ||
|
||
let a = pathdiff::diff_paths(entry.path(), unpacked_cfb_dir).unwrap(); | ||
let rel_path = a.as_path(); | ||
|
||
let tmp_str = rel_path.to_str().unwrap().replace(r"\", "/"); | ||
let mut internal_path = String::from("/"); | ||
internal_path.push_str(&tmp_str); | ||
|
||
// Skip root storage | ||
if internal_path == "/" { | ||
continue; | ||
} | ||
|
||
if entry.metadata().unwrap().is_file() { | ||
println!(" Creating stream: {:#?}", internal_path); | ||
let data: Vec<u8> = fs::read(entry.path()).unwrap(); | ||
// @TODO: Need to create parent storages first. Otherwise create_stream fails | ||
let mut stream = cfb.create_stream(&internal_path).unwrap(); | ||
stream.write_all(&data).unwrap(); | ||
} | ||
|
||
if entry.metadata().unwrap().is_dir() { | ||
println!(" Creating storage: {:#?}", internal_path); | ||
cfb.create_storage_all(&internal_path).unwrap(); | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let args: Vec<String> = env::args().collect(); | ||
|
||
let mut output_cfb = Path::new(""); | ||
let mut unpacked_cfb_dir = Path::new(""); | ||
|
||
match args.len() { | ||
3 => { | ||
unpacked_cfb_dir = Path::new(&args[1]); | ||
output_cfb = Path::new(&args[2]); | ||
} | ||
_ => { | ||
help(); | ||
exit(1); | ||
} | ||
} | ||
|
||
let tmp: PathBuf = unpacked_cfb_dir.canonicalize().unwrap(); | ||
let unpacked_cfb_dir = Path::new(&tmp); | ||
|
||
cfb_pack(output_cfb, unpacked_cfb_dir); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use cfb; | ||
use std::path::{Path, PathBuf}; | ||
extern crate pathdiff; | ||
use std::env; | ||
use std::fs; | ||
use std::fs::File; | ||
use std::io::{Read, Write}; | ||
use std::process::exit; | ||
|
||
fn help() { | ||
println!( | ||
"usage: cfb_unpack <input_cfb_file> <unpacked_cfb_root_dir> | ||
Unpacks 'input_cfb_file' to 'unpacked_cfb_root_dir', where all all | ||
'storages's become directories and all 'stream's become files." | ||
); | ||
} | ||
|
||
fn construct_external_path(cfb_path: &Path, fs_root_dir: &Path) -> PathBuf { | ||
// Strip `cfb_path` from leading `/` | ||
let rel_internal_path = Path::new(&cfb_path.to_str().unwrap()[1..]); | ||
let tmp_str_path = fs_root_dir.join(rel_internal_path); | ||
tmp_str_path | ||
} | ||
|
||
fn cfb_unpack(input_cfb: &Path, unpacked_cfb_dir: &Path) { | ||
println!("Unpacking: {:#?}", input_cfb); | ||
println!("Into: {:#?}", unpacked_cfb_dir); | ||
|
||
let mut cfb = cfb::open(input_cfb).unwrap(); | ||
|
||
fs::create_dir_all(&unpacked_cfb_dir).unwrap(); | ||
|
||
let entries = cfb.walk().collect::<Vec<_>>(); | ||
|
||
for entry in entries { | ||
let external_path = construct_external_path(entry.path(), unpacked_cfb_dir); | ||
|
||
if entry.is_storage() { | ||
println!(" Creating storage: {:#?}", external_path); | ||
fs::create_dir_all(&external_path).unwrap(); | ||
} | ||
|
||
if entry.is_stream() { | ||
println!(" Creating stream: {:#?}", external_path); | ||
|
||
let data = { | ||
let mut stream = cfb.open_stream(&entry.path()).unwrap(); | ||
let mut buffer = Vec::new(); | ||
stream.read_to_end(&mut buffer).unwrap(); | ||
buffer | ||
}; | ||
|
||
fs::create_dir_all(&external_path.parent().unwrap()).unwrap(); | ||
let mut file = File::create(external_path).unwrap(); | ||
// Write a slice of bytes to the file | ||
file.write_all(&data).unwrap(); | ||
} | ||
} | ||
} | ||
|
||
fn main() { | ||
let args: Vec<String> = env::args().collect(); | ||
|
||
let mut input_cfb = Path::new(""); | ||
let mut unpacked_cfb_dir = Path::new(""); | ||
|
||
match args.len() { | ||
3 => { | ||
input_cfb = Path::new(&args[1]); | ||
unpacked_cfb_dir = Path::new(&args[2]); | ||
} | ||
_ => { | ||
help(); | ||
exit(1); | ||
} | ||
} | ||
|
||
let tmp: PathBuf = input_cfb.canonicalize().unwrap(); | ||
let input_cfb = Path::new(&tmp); | ||
|
||
cfb_unpack(input_cfb, unpacked_cfb_dir); | ||
} |