Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d5ab04a90 | |||
4059285649 | |||
2e079b8bf2 | |||
4ff2c9b832 | |||
a8e2940ff3 |
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "proxmox-backup"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
authors = ["Dietmar Maurer <dietmar@proxmox.com>"]
|
||||
edition = "2018"
|
||||
license = "AGPL-3"
|
||||
|
10
debian/changelog
vendored
10
debian/changelog
vendored
@ -1,3 +1,13 @@
|
||||
rust-proxmox-backup (0.5.0-1) unstable; urgency=medium
|
||||
|
||||
* partially revert commit 1f82f9b7b5d231da22a541432d5617cb303c0000
|
||||
|
||||
* ui: allow to Forget (delete) backup snapshots
|
||||
|
||||
* pxar: deal with files changing size during archiving
|
||||
|
||||
-- Proxmox Support Team <support@proxmox.com> Mon, 29 Jun 2020 13:00:54 +0200
|
||||
|
||||
rust-proxmox-backup (0.4.0-1) unstable; urgency=medium
|
||||
|
||||
* change api for incremental backups mode
|
||||
|
@ -189,6 +189,19 @@ impl IndexFile for DynamicIndexReader {
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_csum(&self) -> ([u8; 32], u64) {
|
||||
let mut csum = openssl::sha::Sha256::new();
|
||||
let mut chunk_end = 0;
|
||||
for pos in 0..self.index_count() {
|
||||
let info = self.chunk_info(pos).unwrap();
|
||||
chunk_end = info.range.end;
|
||||
csum.update(&chunk_end.to_le_bytes());
|
||||
csum.update(&info.digest);
|
||||
}
|
||||
let csum = csum.finish();
|
||||
(csum, chunk_end)
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
fn chunk_info(&self, pos: usize) -> Option<ChunkReadInfo> {
|
||||
if pos >= self.index.len() {
|
||||
|
@ -206,6 +206,19 @@ impl IndexFile for FixedIndexReader {
|
||||
digest: *digest,
|
||||
})
|
||||
}
|
||||
|
||||
fn compute_csum(&self) -> ([u8; 32], u64) {
|
||||
let mut csum = openssl::sha::Sha256::new();
|
||||
let mut chunk_end = 0;
|
||||
for pos in 0..self.index_count() {
|
||||
let info = self.chunk_info(pos).unwrap();
|
||||
chunk_end = info.range.end;
|
||||
csum.update(&info.digest);
|
||||
}
|
||||
let csum = csum.finish();
|
||||
|
||||
(csum, chunk_end)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FixedIndexWriter {
|
||||
|
@ -23,19 +23,7 @@ pub trait IndexFile {
|
||||
fn chunk_info(&self, pos: usize) -> Option<ChunkReadInfo>;
|
||||
|
||||
/// Compute index checksum and size
|
||||
fn compute_csum(&self) -> ([u8; 32], u64) {
|
||||
let mut csum = openssl::sha::Sha256::new();
|
||||
let mut chunk_end = 0;
|
||||
for pos in 0..self.index_count() {
|
||||
let info = self.chunk_info(pos).unwrap();
|
||||
chunk_end = info.range.end;
|
||||
csum.update(&chunk_end.to_le_bytes());
|
||||
csum.update(&info.digest);
|
||||
}
|
||||
let csum = csum.finish();
|
||||
|
||||
(csum, chunk_end)
|
||||
}
|
||||
fn compute_csum(&self) -> ([u8; 32], u64);
|
||||
|
||||
/// Returns most often used chunks
|
||||
fn find_most_used_chunks(&self, max: usize) -> HashMap<[u8; 32], usize> {
|
||||
|
@ -434,7 +434,7 @@ impl BackupWriter {
|
||||
self.h2.download("previous", Some(param), &mut tmpfile).await?;
|
||||
|
||||
let index = DynamicIndexReader::new(tmpfile)
|
||||
.map_err(|err| format_err!("unable to read fixed index '{}' - {}", archive_name, err))?;
|
||||
.map_err(|err| format_err!("unable to read dynmamic index '{}' - {}", archive_name, err))?;
|
||||
// Note: do not use values stored in index (not trusted) - instead, computed them again
|
||||
let (csum, size) = index.compute_csum();
|
||||
manifest.verify_file(archive_name, &csum, size)?;
|
||||
|
@ -2,7 +2,7 @@ use std::collections::{HashSet, HashMap};
|
||||
use std::convert::TryFrom;
|
||||
use std::ffi::{CStr, CString, OsStr};
|
||||
use std::fmt;
|
||||
use std::io::{self, Write};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -20,6 +20,7 @@ use pxar::encoder::LinkOffset;
|
||||
use proxmox::c_str;
|
||||
use proxmox::sys::error::SysError;
|
||||
use proxmox::tools::fd::RawFdNum;
|
||||
use proxmox::tools::vec;
|
||||
|
||||
use crate::pxar::catalog::BackupCatalogWriter;
|
||||
use crate::pxar::Flags;
|
||||
@ -35,6 +36,7 @@ fn detect_fs_type(fd: RawFd) -> Result<i64, Error> {
|
||||
Ok(fs_stat.f_type)
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub fn is_virtual_file_system(magic: i64) -> bool {
|
||||
use proxmox::sys::linux::magic::*;
|
||||
|
||||
@ -114,6 +116,7 @@ struct Archiver<'a, 'b> {
|
||||
device_set: Option<HashSet<u64>>,
|
||||
hardlinks: HashMap<HardLinkInfo, (PathBuf, LinkOffset)>,
|
||||
errors: ErrorReporter,
|
||||
file_copy_buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
type Encoder<'a, 'b> = pxar::encoder::Encoder<'a, &'b mut dyn pxar::encoder::SeqWrite>;
|
||||
@ -178,6 +181,7 @@ where
|
||||
device_set,
|
||||
hardlinks: HashMap::new(),
|
||||
errors: ErrorReporter,
|
||||
file_copy_buffer: vec::undefined(4 * 1024 * 1024),
|
||||
};
|
||||
|
||||
archiver.archive_dir_contents(&mut encoder, source_dir, true)?;
|
||||
@ -410,6 +414,24 @@ impl<'a, 'b> Archiver<'a, 'b> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn report_file_shrunk_while_reading(&mut self) -> Result<(), Error> {
|
||||
write!(
|
||||
self.errors,
|
||||
"warning: file size shrunk while reading: {:?}, file will be padded with zeros!",
|
||||
self.path,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn report_file_grew_while_reading(&mut self) -> Result<(), Error> {
|
||||
write!(
|
||||
self.errors,
|
||||
"warning: file size increased while reading: {:?}, file will be truncated!",
|
||||
self.path,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_entry(
|
||||
&mut self,
|
||||
encoder: &mut Encoder,
|
||||
@ -591,8 +613,29 @@ impl<'a, 'b> Archiver<'a, 'b> {
|
||||
file_size: u64,
|
||||
) -> Result<LinkOffset, Error> {
|
||||
let mut file = unsafe { std::fs::File::from_raw_fd(fd.into_raw_fd()) };
|
||||
let offset = encoder.add_file(metadata, file_name, file_size, &mut file)?;
|
||||
Ok(offset)
|
||||
let mut remaining = file_size;
|
||||
let mut out = encoder.create_file(metadata, file_name, file_size)?;
|
||||
while remaining != 0 {
|
||||
let mut got = file.read(&mut self.file_copy_buffer[..])?;
|
||||
if got as u64 > remaining {
|
||||
self.report_file_grew_while_reading()?;
|
||||
got = remaining as usize;
|
||||
}
|
||||
out.write_all(&self.file_copy_buffer[..got])?;
|
||||
remaining -= got as u64;
|
||||
}
|
||||
if remaining > 0 {
|
||||
self.report_file_shrunk_while_reading()?;
|
||||
let to_zero = remaining.min(self.file_copy_buffer.len() as u64) as usize;
|
||||
vec::clear(&mut self.file_copy_buffer[..to_zero]);
|
||||
while remaining != 0 {
|
||||
let fill = remaining.min(self.file_copy_buffer.len() as u64) as usize;
|
||||
out.write_all(&self.file_copy_buffer[..fill])?;
|
||||
remaining -= fill as u64;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(out.file_offset())
|
||||
}
|
||||
|
||||
fn add_symlink(
|
||||
|
@ -199,6 +199,34 @@ Ext.define('PBS.DataStoreContent', {
|
||||
win.show();
|
||||
},
|
||||
|
||||
onForget: function() {
|
||||
var view = this.getView();
|
||||
|
||||
let rec = view.selModel.getSelection()[0];
|
||||
if (!(rec && rec.data)) return;
|
||||
let data = rec.data;
|
||||
if (!data.leaf) return;
|
||||
|
||||
if (!view.datastore) return;
|
||||
|
||||
console.log(data);
|
||||
|
||||
Proxmox.Utils.API2Request({
|
||||
params: {
|
||||
"backup-type": data["backup-type"],
|
||||
"backup-id": data["backup-id"],
|
||||
"backup-time": (data['backup-time'].getTime()/1000).toFixed(0),
|
||||
},
|
||||
url: `/admin/datastore/${view.datastore}/snapshots`,
|
||||
method: 'DELETE',
|
||||
waitMsgTarget: view,
|
||||
failure: function(response, opts) {
|
||||
Ext.Msg.alert(gettext('Error'), response.htmlStatus);
|
||||
},
|
||||
callback: this.reload.bind(this),
|
||||
});
|
||||
},
|
||||
|
||||
openBackupFileDownloader: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
@ -336,6 +364,21 @@ Ext.define('PBS.DataStoreContent', {
|
||||
enableFn: function(record) { return !record.data.leaf; },
|
||||
handler: 'onPrune',
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxButton',
|
||||
text: gettext('Forget'),
|
||||
disabled: true,
|
||||
parentXType: 'pbsDataStoreContent',
|
||||
handler: 'onForget',
|
||||
confirmMsg: function(record) {
|
||||
console.log(record);
|
||||
let name = record.data.text;
|
||||
return Ext.String.format(gettext('Are you sure you want to remove snapshot {0}'), `'${name}'`);
|
||||
},
|
||||
enableFn: function(record) {
|
||||
return !!record.data.leaf;
|
||||
},
|
||||
},
|
||||
{
|
||||
xtype: 'proxmoxButton',
|
||||
text: gettext('Download Files'),
|
||||
|
Reference in New Issue
Block a user