1use crate::cli_utils::*;
2use crate::file_utils;
3use crate::json_printer::BracketType;
4use crate::rescue_core;
5use crate::rescue_core::Param;
6use crate::sbx_block::BlockType;
7use crate::sbx_specs::SBX_FILE_UID_LEN;
8use clap::*;
9
10pub fn sub_command<'a, 'b>() -> App<'a, 'b> {
11 SubCommand::with_name("rescue")
12 .about("Rescue SBX blocks from file/block device, essentially ddrescue but for SBX blocks")
13 .arg(in_file_arg().help("File/block device to rescue sbx data from"))
14 .arg(
15 out_dir_arg()
16 .required(true)
17 .help("Directory to store rescued data"),
18 )
19 .arg(
20 Arg::with_name("log_file")
21 .value_name("LOGFILE")
22 .index(3)
23 .help(
24 "Log file to keep track of the progress to survive interruptions.
25Note that you should use the same log file for the same file and
26range specified in the initial run.",
27 ),
28 )
29 .arg(
30 Arg::with_name("block_type")
31 .value_name("TYPE")
32 .long("only-pick-block")
33 .takes_value(true)
34 .help(
35 "Only pick TYPE of blocks, one of :
36 any
37 meta
38 data",
39 ),
40 )
41 .arg(only_pick_uid_arg())
42 .arg(force_misalign_arg())
43 .arg(pr_verbosity_level_arg())
44 .arg(from_byte_arg().help(FROM_BYTE_ARG_HELP_MSG_SCAN))
45 .arg(to_byte_inc_arg())
46 .arg(to_byte_exc_arg())
47 .arg(json_arg())
48}
49
50pub fn rescue<'a>(matches: &ArgMatches<'a>) -> i32 {
51 let json_printer = get_json_printer!(matches);
52
53 json_printer.print_open_bracket(None, BracketType::Curly);
54
55 let mut temp_uid = [0; SBX_FILE_UID_LEN];
56 let uid: Option<&[u8; SBX_FILE_UID_LEN]> = get_uid!(matches, temp_uid, json_printer);
57
58 let block_type = match matches.value_of("block_type") {
59 None => None,
60 Some(x) => match x {
61 "any" => None,
62 "meta" => Some(BlockType::Meta),
63 "data" => Some(BlockType::Data),
64 _ => exit_with_msg!(usr json_printer => "Invalid block type"),
65 },
66 };
67
68 let from_pos = get_from_pos!(matches, json_printer);
69 let to_pos = get_to_pos!(matches, json_printer);
70
71 let pr_verbosity_level = get_pr_verbosity_level!(matches, json_printer);
72
73 let in_file = matches.value_of("in_file").unwrap();
74 exit_if_file!(does_not_exist in_file
75 => json_printer
76 => "File \"{}\" does not exist", in_file);
77 let out_dir = matches.value_of("out_dir").unwrap();
78
79 if !file_utils::check_if_file_exists(out_dir) {
80 exit_with_msg!(usr json_printer => "Directory \"{}\" does not exist", out_dir);
81 }
82 if !file_utils::check_if_file_is_dir(out_dir) {
83 exit_with_msg!(usr json_printer => "\"{}\" is not a directory", out_dir);
84 }
85
86 let log_file = matches.value_of("log_file");
87
88 let param = Param::new(
89 in_file,
90 out_dir,
91 log_file,
92 from_pos,
93 to_pos,
94 matches.is_present("force_misalign"),
95 &json_printer,
96 block_type,
97 uid,
98 pr_verbosity_level,
99 );
100 match rescue_core::rescue_from_file(¶m) {
101 Ok(s) => exit_with_msg!(ok json_printer => "{}", s),
102 Err(e) => exit_with_msg!(op json_printer => "{}", e),
103 }
104}