1use rescue_core::Param;
2use rescue_core;
3use sbx_specs::SBX_FILE_UID_LEN;
4use std::str::FromStr;
5
6use sbx_block::BlockType;
7use json_printer::BracketType;
8
9use file_utils;
10
11use clap::*;
12use cli_utils::*;
13
14pub fn sub_command<'a, 'b>() -> App<'a, 'b> {
15 SubCommand::with_name("rescue")
16 .about("Rescue SBX blocks from file/block device, essentially ddrescue but for SBX blocks
17
18===== IMPORTANT =====
19Please note that this is the last version of this software to be released under the name rsbx,
20future releases will be published under the name blkar. See project repo for details.
21=====================")
22 .arg(in_file_arg()
23 .help("File/block device to rescue sbx data from"))
24 .arg(out_dir_arg()
25 .required(true)
26 .help("Directory to store rescued data"))
27 .arg(Arg::with_name("log_file")
28 .value_name("LOGFILE")
29 .index(3)
30 .help("Log file to keep track of the progress to survive interruptions.
31Note that you should use the same log file for the same file and
32range specified in the initial run."))
33 .arg(Arg::with_name("block_type")
34 .value_name("TYPE")
35 .long("only-pick-block")
36 .takes_value(true)
37 .help("Only pick BLOCK-TYPE of blocks, one of :
38 any
39 meta
40 data"))
41 .arg(Arg::with_name("uid")
42 .value_name("UID-HEX")
43 .long("only-pick-uid")
44 .takes_value(true)
45 .help("Only pick blocks with UID-HEX as uid. Uid must be exactly 6
46bytes (12 hex digits) in length."))
47 .arg(force_misalign_arg())
48 .arg(pr_verbosity_level_arg())
49 .arg(from_byte_arg()
50 .help("Start from byte FROM-BYTE. The position is automatically rounded
51down to the closest multiple of 128 bytes, after adding the bytes
52processed field from the log file (if specified). If this option is
53not specified, defaults to the start of file. Negative values are
54rejected. If FROM-BYTE exceeds the largest possible
55position (file size - 1), then it will be treated as (file size - 1).
56The rounding procedure is applied after all auto-adjustments."))
57 .arg(to_byte_arg())
58 .arg(json_arg())
59}
60
61pub fn rescue<'a>(matches : &ArgMatches<'a>) -> i32 {
62 let json_printer = get_json_printer!(matches);
63
64 json_printer.print_open_bracket(None, BracketType::Curly);
65
66 let mut temp_uid = [0; SBX_FILE_UID_LEN];
67 let uid : Option<&[u8; SBX_FILE_UID_LEN]> = {
68 match matches.value_of("uid") {
69 None => None ,
70 Some(x) => { parse_uid!(temp_uid, x, json_printer);
71 Some(&temp_uid) }
72 }
73 };
74
75 let block_type = match matches.value_of("block_type") {
76 None => None,
77 Some(x) => {
78 match x {
79 "any" => None,
80 "meta" => Some(BlockType::Meta),
81 "data" => Some(BlockType::Data),
82 _ => exit_with_msg!(usr json_printer => "Invalid block type")
83 }
84 }
85 };
86
87 let from_pos = get_from_pos!(matches, json_printer);
88 let to_pos = get_to_pos!(matches, json_printer);
89
90 let pr_verbosity_level = get_pr_verbosity_level!(matches, json_printer);
91
92 let in_file = matches.value_of("in_file").unwrap();
93 exit_if_file!(not_exists in_file
94 => json_printer
95 => "File \"{}\" does not exist", in_file);
96 let out_dir = matches.value_of("out_dir").unwrap();
97
98 if !file_utils::check_if_file_exists(out_dir) {
99 exit_with_msg!(usr json_printer => "Directory \"{}\" does not exist", out_dir);
100 }
101 if !file_utils::check_if_file_is_dir(out_dir) {
102 exit_with_msg!(usr json_printer => "\"{}\" is not a directory", out_dir);
103 }
104
105 let log_file = matches.value_of("log_file");
106
107 let param = Param::new(in_file,
108 out_dir,
109 log_file,
110 from_pos,
111 to_pos,
112 matches.is_present("force_misalign"),
113 &json_printer,
114 block_type,
115 uid,
116 pr_verbosity_level);
117 match rescue_core::rescue_from_file(¶m) {
118 Ok(s) => exit_with_msg!(ok json_printer => "{}", s),
119 Err(e) => exit_with_msg!(op json_printer => "{}", e)
120 }
121}