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

Christian Ebner c.ebner at proxmox.com
Wed Jun 7 15:30:26 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>
---
 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 f6c1991f..14f9b43d 100644
--- a/pbs-client/src/pxar/extract.rs
+++ b/pbs-client/src/pxar/extract.rs
@@ -326,7 +326,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,
@@ -343,13 +357,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