]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/catar.rs
src/catar/encoder.rs: add verbose flags
[proxmox-backup.git] / src / bin / catar.rs
CommitLineData
c60d34bd
DM
1extern crate proxmox_backup;
2
3use failure::*;
4
ce7ba139 5use proxmox_backup::tools;
4de0e142 6use proxmox_backup::cli::*;
ef2f2efb 7use proxmox_backup::api_schema::*;
dc9a007b 8use proxmox_backup::api_schema::router::*;
c60d34bd
DM
9
10use serde_json::{Value};
11
02c7d8e5 12use std::io::{Read, Write};
e86c4924 13use std::path::PathBuf;
c60d34bd
DM
14
15use proxmox_backup::catar::format_definition::*;
02c7d8e5 16use proxmox_backup::catar::encoder::*;
e86c4924
DM
17use proxmox_backup::catar::decoder::*;
18
c60d34bd
DM
19use proxmox_backup::tools::*;
20
c60d34bd
DM
21fn print_goodby_entries(buffer: &[u8]) -> Result<(), Error> {
22 println!("GOODBY START: {}", buffer.len());
23
24 let entry_size = std::mem::size_of::<CaFormatGoodbyeItem>();
25 if (buffer.len() % entry_size) != 0 {
26 bail!("unexpected goodby item size ({})", entry_size);
27 }
28
29 let mut pos = 0;
30
bf205f94 31 while pos < buffer.len() {
c60d34bd
DM
32
33 let item = map_struct::<CaFormatGoodbyeItem>(&buffer[pos..pos+entry_size])?;
34
35 if item.hash == CA_FORMAT_GOODBYE_TAIL_MARKER {
36 println!(" Entry Offset: {}", item.offset);
37 if item.size != (buffer.len() + 16) as u64 {
38 bail!("gut unexpected goodby entry size (tail marker)");
39 }
40 } else {
41 println!(" Offset: {}", item.offset);
42 println!(" Size: {}", item.size);
43 println!(" Hash: {:016x}", item.hash);
44 }
45
46 pos += entry_size;
47 }
48
49 Ok(())
50}
51
6049b71f
DM
52fn print_filenames(
53 param: Value,
54 _info: &ApiMethod,
55 _rpcenv: &mut RpcEnvironment,
56) -> Result<Value, Error> {
e86c4924 57
6049b71f 58 let archive = tools::required_string_param(&param, "archive")?;
e86c4924
DM
59 let file = std::fs::File::open(archive)?;
60
61 let mut reader = std::io::BufReader::new(file);
62
63 let mut decoder = CaTarDecoder::new(&mut reader)?;
64
65 let root = decoder.root();
66
67 let stdout = std::io::stdout();
68 let mut out = stdout.lock();
69
70 decoder.print_filenames(&mut out, &mut PathBuf::from("."), &root)?;
71
72 Ok(Value::Null)
73}
74
6049b71f
DM
75fn dump_archive(
76 param: Value,
77 _info: &ApiMethod,
78 _rpcenv: &mut RpcEnvironment,
79) -> Result<Value, Error> {
c60d34bd 80
6049b71f 81 let archive = tools::required_string_param(&param, "archive")?;
c60d34bd
DM
82 let mut file = std::fs::File::open(archive)?;
83
84 println!("CATAR {}", archive);
85
86 let mut buffer = [0u8; 16];
87
88 let mut nesting = 0;
89
90 loop {
91 file.read_exact(&mut buffer)?;
92
93 let header = map_struct::<CaFormatHeader>(&mut buffer)?;
94
95 println!("Type: {:016x}", header.htype);
96 println!("Size: {}", header.size);
97
98 let mut rest = vec![0u8; (header.size as usize) - 16];
99 file.read_exact(&mut rest)?;
100
101 if header.htype == CA_FORMAT_FILENAME {
102 let name = read_os_string(&rest);
103 let hash = compute_goodbye_hash(&rest[..rest.len()-1]);
104 println!("Name: {:?} {:016x}", name, hash);
105 }
106
107 if header.htype == CA_FORMAT_ENTRY {
108 let entry = map_struct::<CaFormatEntry>(&mut rest)?;
109 println!("Mode: {:08x} {:08x}", entry.mode, (entry.mode as u32) & libc::S_IFDIR);
110 if ((entry.mode as u32) & libc::S_IFMT) == libc::S_IFDIR {
111 nesting += 1;
112 }
113 }
114 if header.htype == CA_FORMAT_GOODBYE {
115 nesting -= 1;
116 print_goodby_entries(&rest)?;
117 if nesting == 0 { break; }
118 }
119 }
120
121 Ok(Value::Null)
122}
123
6049b71f
DM
124fn create_archive(
125 param: Value,
126 _info: &ApiMethod,
127 _rpcenv: &mut RpcEnvironment,
128) -> Result<Value, Error> {
c60d34bd 129
6049b71f
DM
130 let archive = tools::required_string_param(&param, "archive")?;
131 let source = tools::required_string_param(&param, "source")?;
02c7d8e5
DM
132
133 let source = std::path::PathBuf::from(source);
134
135 let mut dir = nix::dir::Dir::open(
136 &source, nix::fcntl::OFlag::O_NOFOLLOW, nix::sys::stat::Mode::empty())?;
137
138 let file = std::fs::OpenOptions::new()
139 .create_new(true)
140 .write(true)
141 .open(archive)?;
142
143 let mut writer = std::io::BufWriter::with_capacity(1024*1024, file);
144
219ef0e6 145 CaTarEncoder::encode(source, &mut dir, None, &mut writer, false)?;
c60d34bd 146
02c7d8e5 147 writer.flush()?;
c60d34bd
DM
148
149 Ok(Value::Null)
150}
151
152fn main() {
153
154 let cmd_def = CliCommandMap::new()
155 .insert("create", CliCommand::new(
156 ApiMethod::new(
02c7d8e5 157 create_archive,
c60d34bd
DM
158 ObjectSchema::new("Create new catar archive.")
159 .required("archive", StringSchema::new("Archive name"))
160 .required("source", StringSchema::new("Source directory."))
161 ))
162 .arg_param(vec!["archive", "source"])
ce7ba139
DM
163 .completion_cb("archive", tools::complete_file_name)
164 .completion_cb("source", tools::complete_file_name)
165 .into()
c60d34bd 166 )
e86c4924
DM
167 .insert("list", CliCommand::new(
168 ApiMethod::new(
169 print_filenames,
170 ObjectSchema::new("List the contents of an archive.")
171 .required("archive", StringSchema::new("Archive name."))
172 ))
173 .arg_param(vec!["archive"])
ce7ba139 174 .completion_cb("archive", tools::complete_file_name)
e86c4924
DM
175 .into()
176 )
c60d34bd
DM
177 .insert("dump", CliCommand::new(
178 ApiMethod::new(
179 dump_archive,
180 ObjectSchema::new("Textual dump of archive contents (debug toolkit).")
181 .required("archive", StringSchema::new("Archive name."))
182 ))
183 .arg_param(vec!["archive"])
ce7ba139 184 .completion_cb("archive", tools::complete_file_name)
c60d34bd
DM
185 .into()
186 );
187
698d9d44 188 run_cli_command(cmd_def.into());
c60d34bd 189}