]>
Commit | Line | Data |
---|---|---|
c60d34bd DM |
1 | extern crate proxmox_backup; |
2 | ||
3 | use failure::*; | |
4 | ||
ce7ba139 | 5 | use proxmox_backup::tools; |
4de0e142 | 6 | use proxmox_backup::cli::*; |
ef2f2efb | 7 | use proxmox_backup::api_schema::*; |
dc9a007b | 8 | use proxmox_backup::api_schema::router::*; |
c60d34bd DM |
9 | |
10 | use serde_json::{Value}; | |
11 | ||
37940aa1 | 12 | use std::io::Write; |
1ef46b81 | 13 | use std::path::{Path, PathBuf}; |
af309d4d CE |
14 | use std::fs::OpenOptions; |
15 | use std::os::unix::fs::OpenOptionsExt; | |
c60d34bd | 16 | |
3dbfe5b1 | 17 | use proxmox_backup::pxar; |
e86c4924 | 18 | |
6049b71f | 19 | fn 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(¶m, "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 |
44 | fn 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(¶m, "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 |
81 | fn extract_archive( |
82 | param: Value, | |
83 | _info: &ApiMethod, | |
84 | _rpcenv: &mut RpcEnvironment, | |
85 | ) -> Result<Value, Error> { | |
86 | ||
87 | let archive = tools::required_string_param(¶m, "archive")?; | |
88 | let target = tools::required_string_param(¶m, "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 |
120 | fn 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(¶m, "archive")?; |
127 | let source = tools::required_string_param(¶m, "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 | ||
164 | fn 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 | } |