5
0
mirror of git://git.proxmox.com/git/proxmox-backup.git synced 2025-01-08 21:18:07 +03:00

fix: #4761: unlink existing entries for hard/symlinks when overwrite

Creating symlinks or hardlinks might fail if a directory entry with the
same name is already present on the filesystem during restore.

When the overwrite flag is given, on failure unlink the existing entry
(except directories) and retry hard/symlink creation.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
This commit is contained in:
Christian Ebner 2023-08-16 11:57:45 +02:00 committed by Wolfgang Bumiller
parent 03a9f822b3
commit e22da2f40a

View File

@ -547,7 +547,21 @@ impl Extractor {
link: &OsStr,
) -> Result<(), Error> {
let parent = self.parent_fd()?;
match nix::unistd::symlinkat(link, Some(parent), file_name) {
Ok(()) => {}
Err(err @ nix::errno::Errno::EEXIST) => {
if !self.overwrite {
return Err(err.into());
}
// Never unlink directories
let flag = nix::unistd::UnlinkatFlags::NoRemoveDir;
nix::unistd::unlinkat(Some(parent), file_name, flag)?;
nix::unistd::symlinkat(link, Some(parent), file_name)?;
}
Err(err) => return Err(err.into())
}
metadata::apply_at(
self.feature_flags,
metadata,
@ -564,13 +578,29 @@ impl Extractor {
let parent = self.parent_fd()?;
let root = self.dir_stack.root_dir_fd()?;
let target = CString::new(link.as_bytes())?;
let dolink = || {
nix::unistd::linkat(
Some(root.as_raw_fd()),
target.as_c_str(),
Some(parent),
file_name,
nix::unistd::LinkatFlags::NoSymlinkFollow,
)?;
)
};
match dolink() {
Ok(()) => {}
Err(err @ nix::errno::Errno::EEXIST) => {
if !self.overwrite {
return Err(err.into());
}
// Never unlink directories
let flag = nix::unistd::UnlinkatFlags::NoRemoveDir;
nix::unistd::unlinkat(Some(parent), file_name, flag)?;
dolink()?;
}
Err(err) => return Err(err.into())
}
Ok(())
}