pxar: deal with files changing size during archiving
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
		| @ -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( | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user