[ostree] core: Add --union mode to checkout
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] core: Add --union mode to checkout
- Date: Tue, 6 Mar 2012 17:02:07 +0000 (UTC)
commit 76bc35186eb19b1c55c891f8e6e513f2c19eb99a
Author: Colin Walters <walters verbum org>
Date: Tue Mar 6 11:37:50 2012 -0500
core: Add --union mode to checkout
This is another step towards ostbuild using this instead of the
"compose" builtin.
src/libostree/ostree-core.c | 66 +++++++++++++++++++-
src/libostree/ostree-core.h | 8 ++
src/libostree/ostree-repo.c | 132 +++++++++++++++++++++++++++++++++-----
src/libostree/ostree-repo.h | 10 ++-
src/ostree/ot-builtin-checkout.c | 3 +
tests/t0000-basic.sh | 12 +++-
6 files changed, 210 insertions(+), 21 deletions(-)
---
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 8a4cb1f..5f938d1 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -915,6 +915,9 @@ ostree_create_temp_file_from_input (GFile *dir,
/* 128 attempts seems reasonable... */
for (i = 0; i < 128; i++)
{
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
g_free (possible_name);
possible_name = subst_xxxxxx (tmp_name->str);
g_clear_object (&possible_file);
@@ -941,7 +944,7 @@ ostree_create_temp_file_from_input (GFile *dir,
break;
}
}
- if (i == 128)
+ if (i >= 128)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Exhausted 128 attempts to create a temporary file");
@@ -990,3 +993,64 @@ ostree_create_temp_regular_file (GFile *dir,
g_clear_object (&ret_stream);
return ret;
}
+
+gboolean
+ostree_create_temp_hardlink (GFile *dir,
+ GFile *src,
+ const char *prefix,
+ const char *suffix,
+ GFile **out_file,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GString *tmp_name = NULL;
+ char *possible_name = NULL;
+ GFile *possible_file = NULL;
+ int i = 0;
+
+ tmp_name = create_tmp_string (ot_gfile_get_path_cached (dir),
+ prefix, suffix);
+
+ /* 128 attempts seems reasonable... */
+ for (i = 0; i < 128; i++)
+ {
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto out;
+
+ g_free (possible_name);
+ possible_name = subst_xxxxxx (tmp_name->str);
+ g_clear_object (&possible_file);
+ possible_file = g_file_get_child (dir, possible_name);
+
+ if (link (ot_gfile_get_path_cached (src), ot_gfile_get_path_cached (possible_file)) < 0)
+ {
+ if (errno == EEXIST)
+ continue;
+ else
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ if (i >= 128)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Exhausted 128 attempts to create a temporary file");
+ goto out;
+ }
+
+ ret = TRUE;
+ ot_transfer_out_value(out_file, &possible_file);
+ out:
+ if (tmp_name)
+ g_string_free (tmp_name, TRUE);
+ g_free (possible_name);
+ g_clear_object (&possible_file);
+ return ret;
+}
diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h
index 24489ce..e6893c9 100644
--- a/src/libostree/ostree-core.h
+++ b/src/libostree/ostree-core.h
@@ -182,6 +182,14 @@ gboolean ostree_create_temp_regular_file (GFile *dir,
GCancellable *cancellable,
GError **error);
+gboolean ostree_create_temp_hardlink (GFile *dir,
+ GFile *src,
+ const char *prefix,
+ const char *suffix,
+ GFile **out_file,
+ GCancellable *cancellable,
+ GError **error);
+
GVariant *ostree_create_archive_file_metadata (GFileInfo *file_info,
GVariant *xattrs);
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 8087f06..05ebbc4 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -2453,6 +2453,7 @@ ostree_repo_iter_objects (OstreeRepo *self,
static gboolean
checkout_file_from_input (GFile *file,
OstreeRepoCheckoutMode mode,
+ OstreeRepoCheckoutOverwriteMode overwrite_mode,
GFileInfo *finfo,
GVariant *xattrs,
GInputStream *input,
@@ -2460,6 +2461,9 @@ checkout_file_from_input (GFile *file,
GError **error)
{
gboolean ret = FALSE;
+ GError *temp_error = NULL;
+ GFile *dir = NULL;
+ GFile *temp_file = NULL;
GFileInfo *temp_info = NULL;
if (mode == OSTREE_REPO_CHECKOUT_MODE_USER)
@@ -2475,20 +2479,119 @@ checkout_file_from_input (GFile *file,
xattrs = NULL;
}
- if (!ostree_create_file_from_input (file, temp_info ? temp_info : finfo,
- xattrs, input, OSTREE_OBJECT_TYPE_RAW_FILE,
- NULL, cancellable, error))
- goto out;
+ if (overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
+ {
+ if (g_file_info_get_file_type (temp_info ? temp_info : finfo) == G_FILE_TYPE_DIRECTORY)
+ {
+ if (!ostree_create_file_from_input (file, temp_info ? temp_info : finfo,
+ xattrs, input, OSTREE_OBJECT_TYPE_RAW_FILE,
+ NULL, cancellable, &temp_error))
+ {
+ if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+ {
+ g_clear_error (&temp_error);
+ }
+ else
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ }
+ }
+ else
+ {
+ dir = g_file_get_parent (file);
+ if (!ostree_create_temp_file_from_input (dir, NULL, "checkout",
+ temp_info ? temp_info : finfo,
+ xattrs, input, OSTREE_OBJECT_TYPE_RAW_FILE,
+ &temp_file, NULL,
+ cancellable, error))
+ goto out;
+
+ if (rename (ot_gfile_get_path_cached (temp_file), ot_gfile_get_path_cached (file)) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ }
+ }
+ else
+ {
+ if (!ostree_create_file_from_input (file, temp_info ? temp_info : finfo,
+ xattrs, input, OSTREE_OBJECT_TYPE_RAW_FILE,
+ NULL, cancellable, error))
+ goto out;
+ }
ret = TRUE;
out:
g_clear_object (&temp_info);
+ g_clear_object (&temp_file);
+ g_clear_object (&dir);
+ return ret;
+}
+
+static gboolean
+checkout_file_hardlink (OstreeRepo *self,
+ OstreeRepoCheckoutMode mode,
+ OstreeRepoCheckoutOverwriteMode overwrite_mode,
+ GFile *source,
+ GFile *destination,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GFile *dir = NULL;
+ GFile *temp_file = NULL;
+
+ if (overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
+ {
+ dir = g_file_get_parent (destination);
+ if (!ostree_create_temp_hardlink (dir, (GFile*)source, NULL, "link",
+ &temp_file, cancellable, error))
+ goto out;
+
+ /* 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 (rename (ot_gfile_get_path_cached (temp_file),
+ ot_gfile_get_path_cached (destination)) < 0)
+ {
+ ot_util_set_error_from_errno (error, errno);
+ goto out;
+ }
+ g_clear_object (&temp_file);
+ }
+ else
+ {
+ 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;
+ }
+ }
+
+ ret = TRUE;
+ out:
+ g_clear_object (&dir);
+ if (temp_file)
+ (void) unlink (ot_gfile_get_path_cached (temp_file));
+ g_clear_object (&temp_file);
return ret;
}
gboolean
ostree_repo_checkout_tree (OstreeRepo *self,
OstreeRepoCheckoutMode mode,
+ OstreeRepoCheckoutOverwriteMode overwrite_mode,
GFile *destination,
OstreeRepoFile *source,
GFileInfo *source_info,
@@ -2511,7 +2614,7 @@ ostree_repo_checkout_tree (OstreeRepo *self,
if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
goto out;
- if (!checkout_file_from_input (destination, mode, source_info,
+ if (!checkout_file_from_input (destination, mode, overwrite_mode, source_info,
xattrs, NULL,
cancellable, error))
goto out;
@@ -2541,7 +2644,8 @@ ostree_repo_checkout_tree (OstreeRepo *self,
if (type == G_FILE_TYPE_DIRECTORY)
{
- if (!ostree_repo_checkout_tree (self, mode, dest_path, (OstreeRepoFile*)src_child, file_info,
+ if (!ostree_repo_checkout_tree (self, mode, overwrite_mode,
+ dest_path, (OstreeRepoFile*)src_child, file_info,
cancellable, error))
goto out;
}
@@ -2554,11 +2658,8 @@ ostree_repo_checkout_tree (OstreeRepo *self,
g_clear_object (&object_path);
object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_ARCHIVED_FILE_CONTENT);
- if (link (ot_gfile_get_path_cached (object_path), ot_gfile_get_path_cached (dest_path)) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
+ if (!checkout_file_hardlink (self, mode, overwrite_mode, object_path, dest_path, cancellable, error) < 0)
+ goto out;
}
else if (priv->mode == OSTREE_REPO_MODE_ARCHIVE)
{
@@ -2581,7 +2682,7 @@ ostree_repo_checkout_tree (OstreeRepo *self,
goto out;
}
- if (!checkout_file_from_input (dest_path, mode, file_info, xattrs,
+ if (!checkout_file_from_input (dest_path, mode, overwrite_mode, file_info, xattrs,
content_input, cancellable, error))
goto out;
}
@@ -2590,11 +2691,8 @@ ostree_repo_checkout_tree (OstreeRepo *self,
g_clear_object (&object_path);
object_path = ostree_repo_get_object_path (self, checksum, OSTREE_OBJECT_TYPE_RAW_FILE);
- if (link (ot_gfile_get_path_cached (object_path), ot_gfile_get_path_cached (dest_path)) < 0)
- {
- ot_util_set_error_from_errno (error, errno);
- goto out;
- }
+ if (!checkout_file_hardlink (self, mode, overwrite_mode, object_path, dest_path, cancellable, error) < 0)
+ goto out;
}
}
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 5206f37..25ef09e 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -201,13 +201,19 @@ gboolean ostree_repo_stage_commit (OstreeRepo *self,
GError **error);
typedef enum {
- OSTREE_REPO_CHECKOUT_MODE_NONE,
- OSTREE_REPO_CHECKOUT_MODE_USER
+ OSTREE_REPO_CHECKOUT_MODE_NONE = 0,
+ OSTREE_REPO_CHECKOUT_MODE_USER = 1
} OstreeRepoCheckoutMode;
+typedef enum {
+ OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0,
+ OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1
+} OstreeRepoCheckoutOverwriteMode;
+
gboolean
ostree_repo_checkout_tree (OstreeRepo *self,
OstreeRepoCheckoutMode mode,
+ OstreeRepoCheckoutOverwriteMode overwrite_mode,
GFile *destination,
OstreeRepoFile *source,
GFileInfo *source_info,
diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c
index f473072..fbdac13 100644
--- a/src/ostree/ot-builtin-checkout.c
+++ b/src/ostree/ot-builtin-checkout.c
@@ -29,10 +29,12 @@
static gboolean user_mode;
static char *subpath;
+static gboolean opt_union;
static GOptionEntry options[] = {
{ "user-mode", 'U', 0, G_OPTION_ARG_NONE, &user_mode, "Do not change file ownership or initialze extended attributes", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &subpath, "Checkout sub-directory PATH", "PATH" },
+ { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL },
{ NULL }
};
@@ -99,6 +101,7 @@ ostree_builtin_checkout (int argc, char **argv, GFile *repo_path, GError **error
goto out;
if (!ostree_repo_checkout_tree (repo, user_mode ? OSTREE_REPO_CHECKOUT_MODE_USER : 0,
+ opt_union ? OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES : 0,
destf, subtree, file_info, cancellable, error))
goto out;
diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh
index 606ef38..2d55e20 100755
--- a/tests/t0000-basic.sh
+++ b/tests/t0000-basic.sh
@@ -19,7 +19,7 @@
set -e
-echo "1..27"
+echo "1..28"
. libtest.sh
@@ -196,3 +196,13 @@ $OSTREE checkout --subpath /yet/another test2 checkout-test2-subpath
cd checkout-test2-subpath
assert_file_has_content tree/green "leaf"
echo "ok checkout subpath"
+
+cd ${test_tmpdir}
+$OSTREE checkout --union test2 checkout-test2-union
+find checkout-test2-union | wc -l > union-files-count
+$OSTREE checkout --union test2 checkout-test2-union
+find checkout-test2-union | wc -l > union-files-count.new
+cmp union-files-count{,.new}
+cd checkout-test2-union
+assert_file_has_content ./yet/another/tree/green "leaf"
+echo "ok checkout union 1"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]