]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/pxar.rs
src/bin/proxmox-backup-client.rs: backup_image() - pass correct chunk size
[proxmox-backup.git] / src / bin / pxar.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
37940aa1 12use std::io::Write;
1ef46b81 13use std::path::{Path, PathBuf};
af309d4d
CE
14use std::fs::OpenOptions;
15use std::os::unix::fs::OpenOptionsExt;
c60d34bd 16
3dbfe5b1 17use proxmox_backup::pxar;
e86c4924 18
6049b71f 19fn print_filenames(
37940aa1 20 param: Value,
6049b71f
DM
21 _info: &ApiMethod,
22 _rpcenv: &mut RpcEnvironment,
23) -> Result<Value, Error> {
e86c4924 24
6049b71f 25 let archive = tools::required_string_param(&param, "archive")?;
e86c4924
DM
26 let file = std::fs::File::open(archive)?;
27
28 let mut reader = std::io::BufReader::new(file);
29
b344461b
CE
30 let mut feature_flags = pxar::CA_FORMAT_DEFAULT;
31 feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS;
32 feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS;
33 let mut decoder = pxar::SequentialDecoder::new(&mut reader, feature_flags);
e86c4924
DM
34
35 let stdout = std::io::stdout();
36 let mut out = stdout.lock();
37
37940aa1
DM
38 let mut path = PathBuf::from(".");
39 decoder.dump_entry(&mut path, false, &mut out)?;
e86c4924
DM
40
41 Ok(Value::Null)
42}
43
6049b71f
DM
44fn dump_archive(
45 param: Value,
46 _info: &ApiMethod,
47 _rpcenv: &mut RpcEnvironment,
48) -> Result<Value, Error> {
c60d34bd 49
6049b71f 50 let archive = tools::required_string_param(&param, "archive")?;
9b384433
CE
51 let with_xattrs = param["with-xattrs"].as_bool().unwrap_or(false);
52 let with_fcaps = param["with-fcaps"].as_bool().unwrap_or(false);
53 let with_acls = param["with-acls"].as_bool().unwrap_or(false);
40360fde 54 let file = std::fs::File::open(archive)?;
c60d34bd 55
40360fde 56 let mut reader = std::io::BufReader::new(file);
c60d34bd 57
b344461b 58 let mut feature_flags = pxar::CA_FORMAT_DEFAULT;
9b384433
CE
59 if !with_xattrs {
60 feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS;
61 }
62 if !with_fcaps {
63 feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS;
64 }
65 if !with_acls {
66 feature_flags ^= pxar::CA_FORMAT_WITH_ACL;
67 }
b344461b 68 let mut decoder = pxar::SequentialDecoder::new(&mut reader, feature_flags);
c60d34bd 69
40360fde
DM
70 let stdout = std::io::stdout();
71 let mut out = stdout.lock();
c60d34bd 72
40360fde 73 println!("PXAR dump: {}", archive);
c60d34bd 74
37940aa1
DM
75 let mut path = PathBuf::new();
76 decoder.dump_entry(&mut path, true, &mut out)?;
c60d34bd
DM
77
78 Ok(Value::Null)
79}
80
1ef46b81
DM
81fn extract_archive(
82 param: Value,
83 _info: &ApiMethod,
84 _rpcenv: &mut RpcEnvironment,
85) -> Result<Value, Error> {
86
87 let archive = tools::required_string_param(&param, "archive")?;
88 let target = tools::required_string_param(&param, "target")?;
89 let verbose = param["verbose"].as_bool().unwrap_or(false);
0d9bab05
CE
90 let no_xattrs = param["no-xattrs"].as_bool().unwrap_or(false);
91 let no_fcaps = param["no-fcaps"].as_bool().unwrap_or(false);
9b384433 92 let no_acls = param["no-acls"].as_bool().unwrap_or(false);
1ef46b81
DM
93
94 let file = std::fs::File::open(archive)?;
95
96 let mut reader = std::io::BufReader::new(file);
b344461b
CE
97 let mut feature_flags = pxar::CA_FORMAT_DEFAULT;
98 if no_xattrs {
99 feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS;
100 }
101 if no_fcaps {
102 feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS;
103 }
9b384433
CE
104 if no_acls {
105 feature_flags ^= pxar::CA_FORMAT_WITH_ACL;
106 }
1ef46b81 107
b344461b 108 let mut decoder = pxar::SequentialDecoder::new(&mut reader, feature_flags);
1ef46b81
DM
109
110 decoder.restore(Path::new(target), & |path| {
111 if verbose {
112 println!("{:?}", path);
113 }
114 Ok(())
115 })?;
116
117 Ok(Value::Null)
118}
119
6049b71f
DM
120fn create_archive(
121 param: Value,
122 _info: &ApiMethod,
123 _rpcenv: &mut RpcEnvironment,
124) -> Result<Value, Error> {
c60d34bd 125
6049b71f
DM
126 let archive = tools::required_string_param(&param, "archive")?;
127 let source = tools::required_string_param(&param, "source")?;
2689810c 128 let verbose = param["verbose"].as_bool().unwrap_or(false);
e3c30c50 129 let all_file_systems = param["all-file-systems"].as_bool().unwrap_or(false);
0d9bab05
CE
130 let no_xattrs = param["no-xattrs"].as_bool().unwrap_or(false);
131 let no_fcaps = param["no-fcaps"].as_bool().unwrap_or(false);
9b384433 132 let no_acls = param["no-acls"].as_bool().unwrap_or(false);
02c7d8e5 133
1ef46b81 134 let source = PathBuf::from(source);
02c7d8e5
DM
135
136 let mut dir = nix::dir::Dir::open(
137 &source, nix::fcntl::OFlag::O_NOFOLLOW, nix::sys::stat::Mode::empty())?;
138
af309d4d 139 let file = OpenOptions::new()
02c7d8e5
DM
140 .create_new(true)
141 .write(true)
af309d4d 142 .mode(0o640)
02c7d8e5
DM
143 .open(archive)?;
144
145 let mut writer = std::io::BufWriter::with_capacity(1024*1024, file);
b344461b
CE
146 let mut feature_flags = pxar::CA_FORMAT_DEFAULT;
147 if no_xattrs {
148 feature_flags ^= pxar::CA_FORMAT_WITH_XATTRS;
149 }
150 if no_fcaps {
151 feature_flags ^= pxar::CA_FORMAT_WITH_FCAPS;
152 }
9b384433
CE
153 if no_acls {
154 feature_flags ^= pxar::CA_FORMAT_WITH_ACL;
155 }
b344461b
CE
156
157 pxar::Encoder::encode(source, &mut dir, &mut writer, all_file_systems, verbose, feature_flags)?;
c60d34bd 158
02c7d8e5 159 writer.flush()?;
c60d34bd
DM
160
161 Ok(Value::Null)
162}
163
164fn main() {
165
166 let cmd_def = CliCommandMap::new()
167 .insert("create", CliCommand::new(
168 ApiMethod::new(
02c7d8e5 169 create_archive,
8968258b 170 ObjectSchema::new("Create new .pxar archive.")
c60d34bd
DM
171 .required("archive", StringSchema::new("Archive name"))
172 .required("source", StringSchema::new("Source directory."))
2689810c 173 .optional("verbose", BooleanSchema::new("Verbose output.").default(false))
0d9bab05
CE
174 .optional("no-xattrs", BooleanSchema::new("Ignore extended file attributes.").default(false))
175 .optional("no-fcaps", BooleanSchema::new("Ignore file capabilities.").default(false))
9b384433 176 .optional("no-acls", BooleanSchema::new("Ignore access control list entries.").default(false))
e3c30c50
DM
177 .optional("all-file-systems", BooleanSchema::new("Include mounted sudirs.").default(false))
178 ))
c60d34bd 179 .arg_param(vec!["archive", "source"])
ce7ba139
DM
180 .completion_cb("archive", tools::complete_file_name)
181 .completion_cb("source", tools::complete_file_name)
182 .into()
c60d34bd 183 )
1ef46b81
DM
184 .insert("extract", CliCommand::new(
185 ApiMethod::new(
186 extract_archive,
187 ObjectSchema::new("Extract an archive.")
188 .required("archive", StringSchema::new("Archive name."))
189 .required("target", StringSchema::new("Target directory."))
190 .optional("verbose", BooleanSchema::new("Verbose output.").default(false))
0d9bab05
CE
191 .optional("no-xattrs", BooleanSchema::new("Ignore extended file attributes.").default(false))
192 .optional("no-fcaps", BooleanSchema::new("Ignore file capabilities.").default(false))
9b384433 193 .optional("no-acls", BooleanSchema::new("Ignore access control list entries.").default(false))
1ef46b81
DM
194 ))
195 .arg_param(vec!["archive", "target"])
196 .completion_cb("archive", tools::complete_file_name)
197 .completion_cb("target", tools::complete_file_name)
198 .into()
199 )
e86c4924
DM
200 .insert("list", CliCommand::new(
201 ApiMethod::new(
202 print_filenames,
203 ObjectSchema::new("List the contents of an archive.")
204 .required("archive", StringSchema::new("Archive name."))
205 ))
206 .arg_param(vec!["archive"])
ce7ba139 207 .completion_cb("archive", tools::complete_file_name)
e86c4924
DM
208 .into()
209 )
c60d34bd
DM
210 .insert("dump", CliCommand::new(
211 ApiMethod::new(
212 dump_archive,
213 ObjectSchema::new("Textual dump of archive contents (debug toolkit).")
214 .required("archive", StringSchema::new("Archive name."))
9b384433
CE
215 .optional("with-xattrs", BooleanSchema::new("Dump extended file attributes.").default(false))
216 .optional("with-fcaps", BooleanSchema::new("Dump file capabilities.").default(false))
217 .optional("with-acls", BooleanSchema::new("Dump access control list entries.").default(false))
c60d34bd
DM
218 ))
219 .arg_param(vec!["archive"])
ce7ba139 220 .completion_cb("archive", tools::complete_file_name)
c60d34bd
DM
221 .into()
222 );
223
698d9d44 224 run_cli_command(cmd_def.into());
c60d34bd 225}