[ostree] core: Fall back to copying checkouts on EMLINK/EXDEV



commit 35a80c8e39a69d6fe31f5f76b2cb8eacbd3dc529
Author: Colin Walters <walters verbum org>
Date:   Tue Jun 12 14:50:38 2012 -0400

    core: Fall back to copying checkouts on EMLINK/EXDEV
    
    The previous fix to just ignore symbolic links for hard linking isn't
    really good enough, since it can happen for empty files too.
    
    Since this is an optimization, when we get EMLINK, let's instead just
    fall back to copying.  This also applies to EXDEV.

 src/libostree/ostree-repo.c |   57 ++++++++++++++++++++++++++----------------
 1 files changed, 35 insertions(+), 22 deletions(-)
---
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index a3ff556..e71a35b 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -4115,39 +4115,49 @@ checkout_file_hardlink (OstreeRepo                  *self,
                         OstreeRepoCheckoutOverwriteMode    overwrite_mode,
                         GFile                    *source,
                         GFile                    *destination,
+                        gboolean                 *out_was_supported,
                         GCancellable             *cancellable,
                         GError                  **error)
 {
   gboolean ret = FALSE;
+  gboolean ret_was_supported = FALSE;
   ot_lobj GFile *dir = NULL;
 
-  if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
+  if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) != -1)
+    ret_was_supported = TRUE;
+  else if (errno == EMLINK || errno == EXDEV)
     {
-      if (errno == EEXIST && overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
-        { 
-          /* Idiocy, from man rename(2)
-           *
-           * "If oldpath and newpath are existing hard links referring to
-           * the same file, then rename() does nothing, and returns a
-           * success status."
-           *
-           * So we can't make this atomic.  
-           */
-          (void) unlink (ot_gfile_get_path_cached (destination));
-          if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
-            {
-              ot_util_set_error_from_errno (error, errno);
-              goto out;
-            }
-        }
-      else
+      /* EMLINK and EXDEV shouldn't be fatal; we just can't do the
+       * optimization of hardlinking instead of copying.
+       */
+      ret_was_supported = FALSE;
+    }
+  else if (errno == EEXIST && overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
+    { 
+      /* Idiocy, from man rename(2)
+       *
+       * "If oldpath and newpath are existing hard links referring to
+       * the same file, then rename() does nothing, and returns a
+       * success status."
+       *
+       * So we can't make this atomic.  
+       */
+      (void) unlink (ot_gfile_get_path_cached (destination));
+      if (link (ot_gfile_get_path_cached (source), ot_gfile_get_path_cached (destination)) < 0)
         {
           ot_util_set_error_from_errno (error, errno);
           goto out;
         }
     }
+  else
+    {
+      ot_util_set_error_from_errno (error, errno);
+      goto out;
+    }
 
   ret = TRUE;
+  if (out_was_supported)
+    *out_was_supported = ret_was_supported;
  out:
   return ret;
 }
@@ -4214,6 +4224,7 @@ checkout_one_file (OstreeRepo                  *self,
 {
   gboolean ret = FALSE;
   const char *checksum;
+  gboolean hardlink_supported;
   ot_lobj GFile *loose_path = NULL;
   ot_lobj GInputStream *input = NULL;
   ot_lvariant GVariant *xattrs = NULL;
@@ -4235,12 +4246,14 @@ checkout_one_file (OstreeRepo                  *self,
 
   if (loose_path)
     {
-      /* If we found one, we can just hardlink */
+      /* If we found one, try hardlinking */
       if (!checkout_file_hardlink (self, mode, overwrite_mode, loose_path, destination,
-                                   cancellable, error))
+                                   &hardlink_supported, cancellable, error))
         goto out;
     }
-  else
+
+  /* Fall back to copy if there's no loose object, or we couldn't hardlink */
+  if (loose_path == NULL || !hardlink_supported)
     {
       if (!ostree_repo_load_file (self, checksum, &input, NULL, &xattrs, cancellable, error))
         goto out;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]