pxar: deal with files changing size during archiving

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2020-06-26 11:49:51 +02:00
parent d5d5f2174e
commit a8e2940ff3

View File

@ -2,7 +2,7 @@ use std::collections::{HashSet, HashMap};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ffi::{CStr, CString, OsStr}; use std::ffi::{CStr, CString, OsStr};
use std::fmt; use std::fmt;
use std::io::{self, Write}; use std::io::{self, Read, Write};
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -20,6 +20,7 @@ use pxar::encoder::LinkOffset;
use proxmox::c_str; use proxmox::c_str;
use proxmox::sys::error::SysError; use proxmox::sys::error::SysError;
use proxmox::tools::fd::RawFdNum; use proxmox::tools::fd::RawFdNum;
use proxmox::tools::vec;
use crate::pxar::catalog::BackupCatalogWriter; use crate::pxar::catalog::BackupCatalogWriter;
use crate::pxar::Flags; use crate::pxar::Flags;
@ -35,6 +36,7 @@ fn detect_fs_type(fd: RawFd) -> Result<i64, Error> {
Ok(fs_stat.f_type) Ok(fs_stat.f_type)
} }
#[rustfmt::skip]
pub fn is_virtual_file_system(magic: i64) -> bool { pub fn is_virtual_file_system(magic: i64) -> bool {
use proxmox::sys::linux::magic::*; use proxmox::sys::linux::magic::*;
@ -114,6 +116,7 @@ struct Archiver<'a, 'b> {
device_set: Option<HashSet<u64>>, device_set: Option<HashSet<u64>>,
hardlinks: HashMap<HardLinkInfo, (PathBuf, LinkOffset)>, hardlinks: HashMap<HardLinkInfo, (PathBuf, LinkOffset)>,
errors: ErrorReporter, errors: ErrorReporter,
file_copy_buffer: Vec<u8>,
} }
type Encoder<'a, 'b> = pxar::encoder::Encoder<'a, &'b mut dyn pxar::encoder::SeqWrite>; type Encoder<'a, 'b> = pxar::encoder::Encoder<'a, &'b mut dyn pxar::encoder::SeqWrite>;
@ -178,6 +181,7 @@ where
device_set, device_set,
hardlinks: HashMap::new(), hardlinks: HashMap::new(),
errors: ErrorReporter, errors: ErrorReporter,
file_copy_buffer: vec::undefined(4 * 1024 * 1024),
}; };
archiver.archive_dir_contents(&mut encoder, source_dir, true)?; archiver.archive_dir_contents(&mut encoder, source_dir, true)?;
@ -410,6 +414,24 @@ impl<'a, 'b> Archiver<'a, 'b> {
Ok(()) 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( fn add_entry(
&mut self, &mut self,
encoder: &mut Encoder, encoder: &mut Encoder,
@ -591,8 +613,29 @@ impl<'a, 'b> Archiver<'a, 'b> {
file_size: u64, file_size: u64,
) -> Result<LinkOffset, Error> { ) -> Result<LinkOffset, Error> {
let mut file = unsafe { std::fs::File::from_raw_fd(fd.into_raw_fd()) }; 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)?; let mut remaining = file_size;
Ok(offset) 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( fn add_symlink(