core: When using hardlinks, always use linkat() for destination

This avoids repeatedly traversing the target pathname, and is just
more efficient.

Part of a prelude to using fd-relative API for the source object path
too.
This commit is contained in:
Colin Walters 2013-09-06 18:28:20 -04:00
parent 2b61caa2fe
commit 4dcf1a4282
1 changed files with 17 additions and 9 deletions

View File

@ -327,8 +327,8 @@ checkout_file_hardlink (OstreeRepo *self,
OstreeRepoCheckoutMode mode, OstreeRepoCheckoutMode mode,
OstreeRepoCheckoutOverwriteMode overwrite_mode, OstreeRepoCheckoutOverwriteMode overwrite_mode,
GFile *source, GFile *source,
GFile *destination,
int dirfd, int dirfd,
const char *name,
gboolean *out_was_supported, gboolean *out_was_supported,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
@ -337,11 +337,7 @@ checkout_file_hardlink (OstreeRepo *self,
gboolean ret_was_supported = FALSE; gboolean ret_was_supported = FALSE;
again: again:
if (dirfd != -1 && if (linkat (-1, gs_file_get_path_cached (source), dirfd, name, 0) != -1)
linkat (-1, gs_file_get_path_cached (source),
dirfd, gs_file_get_basename_cached (destination), 0) != -1)
ret_was_supported = TRUE;
else if (link (gs_file_get_path_cached (source), gs_file_get_path_cached (destination)) != -1)
ret_was_supported = TRUE; ret_was_supported = TRUE;
else if (errno == EMLINK || errno == EXDEV || errno == EPERM) else if (errno == EMLINK || errno == EXDEV || errno == EPERM)
{ {
@ -360,7 +356,7 @@ checkout_file_hardlink (OstreeRepo *self,
* *
* So we can't make this atomic. * So we can't make this atomic.
*/ */
(void) unlink (gs_file_get_path_cached (destination)); (void) unlinkat (dirfd, name, 0);
goto again; goto again;
ret_was_supported = TRUE; ret_was_supported = TRUE;
} }
@ -447,6 +443,8 @@ static gboolean
checkout_one_file (OstreeRepo *repo, checkout_one_file (OstreeRepo *repo,
GFile *source, GFile *source,
GFileInfo *source_info, GFileInfo *source_info,
int destination_dfd,
const char *destination_name,
GFile *destination, GFile *destination,
OstreeRepoCheckoutMode mode, OstreeRepoCheckoutMode mode,
OstreeRepoCheckoutOverwriteMode overwrite_mode, OstreeRepoCheckoutOverwriteMode overwrite_mode,
@ -547,7 +545,7 @@ checkout_one_file (OstreeRepo *repo,
/* If we found one, try hardlinking */ /* If we found one, try hardlinking */
if (!checkout_file_hardlink (repo, mode, if (!checkout_file_hardlink (repo, mode,
overwrite_mode, loose_path, overwrite_mode, loose_path,
destination, -1, destination_dfd, destination_name,
&hardlink_supported, cancellable, error)) &hardlink_supported, cancellable, error))
{ {
g_prefix_error (error, "Hardlinking loose object %s to %s: ", checksum, g_prefix_error (error, "Hardlinking loose object %s to %s: ", checksum,
@ -607,6 +605,7 @@ ostree_repo_checkout_tree (OstreeRepo *self,
gboolean ret = FALSE; gboolean ret = FALSE;
gs_unref_variant GVariant *xattrs = NULL; gs_unref_variant GVariant *xattrs = NULL;
gs_unref_object GFileEnumerator *dir_enum = NULL; gs_unref_object GFileEnumerator *dir_enum = NULL;
int destination_dfd = -1;
if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error)) if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
goto out; goto out;
@ -629,6 +628,10 @@ ostree_repo_checkout_tree (OstreeRepo *self,
if (!dir_enum) if (!dir_enum)
goto out; goto out;
if (!gs_file_open_dir_fd (destination, &destination_dfd,
cancellable, error))
goto out;
while (TRUE) while (TRUE)
{ {
GFileInfo *file_info; GFileInfo *file_info;
@ -654,7 +657,10 @@ ostree_repo_checkout_tree (OstreeRepo *self,
} }
else else
{ {
if (!checkout_one_file (self, src_child, file_info, dest_path, if (!checkout_one_file (self, src_child, file_info,
destination_dfd,
name,
dest_path,
mode, overwrite_mode, mode, overwrite_mode,
cancellable, error)) cancellable, error))
goto out; goto out;
@ -663,6 +669,8 @@ ostree_repo_checkout_tree (OstreeRepo *self,
ret = TRUE; ret = TRUE;
out: out:
if (destination_dfd != -1)
(void) close (destination_dfd);
return ret; return ret;
} }