summary refs log tree commit diff
path: root/ripple/fossil/src/bin/extract.rs
blob: b21a0634ba58a4b7ffd0eb80053d7895ccbde9a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// SPDX-FileCopyrightText: edef <edef@unfathomable.blue>
// SPDX-License-Identifier: OSL-3.0

use {
	fossil::{store, Directory},
	prost::Message,
	std::{
		fs,
		io::{self, Read, Write},
		os::unix::{fs::symlink, prelude::OpenOptionsExt},
		path::Path,
	},
};

fn main() {
	let store = fossil::Store::open("fossil.db").unwrap();
	let root = {
		let mut stdin = io::stdin();

		let mut bytes = Vec::new();
		stdin.read_to_end(&mut bytes).unwrap();

		let pb = store::Directory::decode(&*bytes).unwrap();
		Directory::from_pb(pb)
	};

	let root_path = Path::new(".");
	extract(&store, root_path, &root);
}

fn extract(store: &fossil::Store, path: &Path, dir: &Directory) {
	for (name, node) in &dir.children {
		let path = path.join(name);
		match node.clone() {
			fossil::Node::Directory(fossil::DirectoryRef { ident, size: _ }) => {
				let blob = store.read_blob(ident);
				let pb = store::Directory::decode(&*blob).unwrap();
				fs::create_dir(&path).unwrap();
				extract(store, &path, &Directory::from_pb(pb));
			}
			fossil::Node::File(fossil::FileRef {
				ident,
				executable,
				size: _,
			}) => {
				let mode = if executable { 0o755 } else { 0o644 };
				let mut f = fs::OpenOptions::new()
					.write(true)
					.create_new(true)
					.mode(mode)
					.open(path)
					.unwrap();
				let blob = store.read_blob(ident);
				f.write_all(&blob).unwrap();
			}
			fossil::Node::Link { target } => {
				symlink(target, path).unwrap();
			}
		}
	}
}