[pbs-devel] [PATCH v2 proxmox-backup 1/2] fix: #4761: unlink existing entries for hard/symlinks when overwrite

Christian Ebner c.ebner at proxmox.com
Tue Aug 1 12:34:11 CEST 2023


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 at proxmox.com>
---
changes since v1:
* rebased to current master

 pbs-client/src/pxar/extract.rs | 39 +++++++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

diff --git a/pbs-client/src/pxar/extract.rs b/pbs-client/src/pxar/extract.rs
index 4dbaf52d..c1e7b417 100644
--- a/pbs-client/src/pxar/extract.rs
+++ b/pbs-client/src/pxar/extract.rs
@@ -547,7 +547,21 @@ impl Extractor {
         link: &OsStr,
     ) -> Result<(), Error> {
         let parent = self.parent_fd()?;
-        nix::unistd::symlinkat(link, Some(parent), file_name)?;
+
+        match nix::unistd::symlinkat(link, Some(parent), file_name) {
+            Ok(()) => {}
+            Err(nix::errno::Errno::EEXIST) => {
+                if !self.overwrite {
+                    return Err(nix::errno::Errno::EEXIST.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,32 @@ impl Extractor {
         let parent = self.parent_fd()?;
         let root = self.dir_stack.root_dir_fd()?;
         let target = CString::new(link.as_bytes())?;
-        nix::unistd::linkat(
+
+        match nix::unistd::linkat(
             Some(root.as_raw_fd()),
             target.as_c_str(),
             Some(parent),
             file_name,
             nix::unistd::LinkatFlags::NoSymlinkFollow,
-        )?;
+        ) {
+            Ok(()) => {}
+            Err(nix::errno::Errno::EEXIST) => {
+                if !self.overwrite {
+                    return Err(nix::errno::Errno::EEXIST.into());
+                }
+                // Never unlink directories
+                let flag = nix::unistd::UnlinkatFlags::NoRemoveDir;
+                nix::unistd::unlinkat(Some(parent), file_name, flag)?;
+                nix::unistd::linkat(
+                    Some(root.as_raw_fd()),
+                    target.as_c_str(),
+                    Some(parent),
+                    file_name,
+                    nix::unistd::LinkatFlags::NoSymlinkFollow,
+                )?;
+            }
+            Err(err) => return Err(err.into())
+        }
 
         Ok(())
     }
-- 
2.39.2






More information about the pbs-devel mailing list