]> git.proxmox.com Git - proxmox-backup.git/blame - src/bin/backup-client.rs
src/backup/archive_index.rs: first try
[proxmox-backup.git] / src / bin / backup-client.rs
CommitLineData
fe0e04c6 1extern crate proxmox_backup;
ff5d3707 2
3use failure::*;
606ce64b 4use std::os::unix::io::AsRawFd;
ff5d3707 5
fe0e04c6
DM
6use proxmox_backup::tools;
7use proxmox_backup::cli::command::*;
8use proxmox_backup::api::schema::*;
9use proxmox_backup::api::router::*;
10//use proxmox_backup::backup::chunk_store::*;
11//use proxmox_backup::backup::image_index::*;
12//use proxmox_backup::config::datastore;
fb8365b7 13use proxmox_backup::catar::encoder::*;
cb4412b1 14use proxmox_backup::backup::chunker::*;
fe0e04c6 15use proxmox_backup::backup::datastore::*;
43eeef28 16use serde_json::{Value};
ff5d3707 17
a914a774 18fn required_string_param<'a>(param: &'a Value, name: &str) -> &'a str {
19 param[name].as_str().expect(&format!("missing parameter '{}'", name))
20}
21
fb8365b7
DM
22fn backup_dir(
23 datastore: &DataStore,
24 path: &str,
25 dir: &mut nix::dir::Dir,
26 target: &str,
27 chunk_size: usize,
28) -> Result<(), Error> {
bcd879cf
DM
29
30 let mut target = std::path::PathBuf::from(target);
31
32 if let Some(ext) = target.extension() {
33 if ext != "aidx" {
34 bail!("got wrong file extension - expected '.aidx'");
35 }
36 } else {
37 target.set_extension("aidx");
38 }
39
fb8365b7 40 // fixme: implement chunked writer
1c287cb1
DM
41 // let writer = std::fs::OpenOptions::new()
42 // .create(true)
43 // .write(true)
44 // .truncate(true)
45 // .open("mytest.catar")?;
46
0433db19 47 let mut index = datastore.create_archive_writer(&target, chunk_size)?;
fb8365b7
DM
48
49 let path = std::path::PathBuf::from(path);
50
0433db19 51 CaTarEncoder::encode(path, dir, index)?;
bcd879cf
DM
52
53 Ok(())
54}
55
56fn backup_image(datastore: &DataStore, file: &std::fs::File, size: usize, target: &str, chunk_size: usize) -> Result<(), Error> {
57
58 let mut target = std::path::PathBuf::from(target);
59
60 if let Some(ext) = target.extension() {
61 if ext != "iidx" {
62 bail!("got wrong file extension - expected '.iidx'");
63 }
64 } else {
65 target.set_extension("iidx");
66 }
67
68 let mut index = datastore.create_image_writer(&target, size, chunk_size)?;
69
70 tools::file_chunker(file, chunk_size, |pos, chunk| {
71 index.add_chunk(pos, chunk)?;
72 Ok(true)
73 })?;
74
75 index.close()?; // commit changes
76
77 Ok(())
78}
79
80fn create_backup(param: Value, _info: &ApiMethod) -> Result<Value, Error> {
ff5d3707 81
a914a774 82 let filename = required_string_param(&param, "filename");
83 let store = required_string_param(&param, "store");
c34eb166 84 let target = required_string_param(&param, "target");
a914a774 85
2d9d143a
DM
86 let mut chunk_size = 4*1024*1024;
87
88 if let Some(size) = param["chunk-size"].as_u64() {
89 static SIZES: [u64; 7] = [64, 128, 256, 512, 1024, 2048, 4096];
90
91 if SIZES.contains(&size) {
92 chunk_size = (size as usize) * 1024;
93 } else {
94 bail!("Got unsupported chunk size '{}'", size);
95 }
96 }
97
bcd879cf 98 let datastore = DataStore::open(store)?;
a914a774 99
bcd879cf 100 let file = std::fs::File::open(filename)?;
fb8365b7
DM
101 let rawfd = file.as_raw_fd();
102 let stat = nix::sys::stat::fstat(rawfd)?;
a914a774 103
bcd879cf
DM
104 if (stat.st_mode & libc::S_IFDIR) != 0 {
105 println!("Backup directory '{}' to '{}'", filename, store);
106
fb8365b7
DM
107 let mut dir = nix::dir::Dir::from_fd(rawfd)?;
108
109 backup_dir(&datastore, &filename, &mut dir, &target, chunk_size)?;
bcd879cf
DM
110
111 } else if (stat.st_mode & (libc::S_IFREG|libc::S_IFBLK)) != 0 {
112 println!("Backup file '{}' to '{}'", filename, store);
606ce64b 113
4818c8b6
DM
114 if stat.st_size <= 0 { bail!("got strange file size '{}'", stat.st_size); }
115 let size = stat.st_size as usize;
a914a774 116
bcd879cf 117 backup_image(&datastore, &file, size, &target, chunk_size)?;
d62e6e22 118
bcd879cf
DM
119 let idx = datastore.open_image_reader(target)?;
120 idx.print_info();
4818c8b6 121
bcd879cf
DM
122 } else {
123 bail!("unsupported file type (expected a directory, file or block device)");
4818c8b6
DM
124 }
125
f0819fe5 126 //datastore.garbage_collection()?;
3d5c11e5 127
ff5d3707 128 Ok(Value::Null)
129}
130
131
132fn main() {
133
134 let cmd_def = CliCommand::new(
135 ApiMethod::new(
bcd879cf
DM
136 create_backup,
137 ObjectSchema::new("Create backup.")
138 .required("filename", StringSchema::new("Source name (file or directory name)"))
ff5d3707 139 .required("store", StringSchema::new("Datastore name."))
c34eb166 140 .required("target", StringSchema::new("Target name."))
2d9d143a
DM
141 .optional(
142 "chunk-size",
143 IntegerSchema::new("Chunk size in KB. Must be a power of 2.")
144 .minimum(64)
145 .maximum(4096)
146 .default(4096)
147 )
ff5d3707 148 ))
c34eb166 149 .arg_param(vec!["filename", "target"])
fe0e04c6 150 .completion_cb("store", proxmox_backup::config::datastore::complete_datastore_name);
f8838fe9 151
a914a774 152
ff5d3707 153 if let Err(err) = run_cli_command(&cmd_def.into()) {
154 eprintln!("Error: {}", err);
155 print_cli_usage();
156 std::process::exit(-1);
157 }
158
159}