diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index b869e33a..72d921a4 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -29,8 +29,6 @@ G_BEGIN_DECLS #define OSTREE_MAX_METADATA_SIZE (1 << 26) -#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,standard::is-hidden,unix::*" - #define OSTREE_EMPTY_STRING_SHA256 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; typedef enum { diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c index 867a0323..2d55f985 100644 --- a/src/libotutil/ot-gio-utils.c +++ b/src/libotutil/ot-gio-utils.c @@ -132,3 +132,93 @@ ot_gfile_get_basename_cached (GFile *file) } return name; } + +gboolean +ot_gfile_merge_dirs (GFile *destination, + GFile *src, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + const char *dest_path = NULL; + const char *src_path = NULL; + GError *temp_error = NULL; + GFileInfo *src_fileinfo = NULL; + GFileInfo *dest_fileinfo = NULL; + GFileEnumerator *src_enum = NULL; + GFile *dest_subfile = NULL; + GFile *src_subfile = NULL; + const char *name; + guint32 type; + const int move_flags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA; + + dest_path = ot_gfile_get_path_cached (destination); + src_path = ot_gfile_get_path_cached (src); + + dest_fileinfo = g_file_query_info (destination, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, &temp_error); + if (dest_fileinfo) + { + type = g_file_info_get_attribute_uint32 (dest_fileinfo, "standard::type"); + if (type != G_FILE_TYPE_DIRECTORY) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Attempting to replace non-directory %s with directory %s", + dest_path, src_path); + goto out; + } + + src_enum = g_file_enumerate_children (src, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!src_enum) + goto out; + + while ((src_fileinfo = g_file_enumerator_next_file (src_enum, cancellable, &temp_error)) != NULL) + { + type = g_file_info_get_attribute_uint32 (src_fileinfo, "standard::type"); + name = g_file_info_get_attribute_byte_string (src_fileinfo, "standard::name"); + + dest_subfile = g_file_get_child (destination, name); + src_subfile = g_file_get_child (src, name); + + if (type == G_FILE_TYPE_DIRECTORY) + { + if (!ot_gfile_merge_dirs (dest_subfile, src_subfile, cancellable, error)) + goto out; + } + else + { + if (!g_file_move (src_subfile, dest_subfile, + move_flags, NULL, NULL, cancellable, error)) + goto out; + } + + g_clear_object (&dest_subfile); + g_clear_object (&src_subfile); + } + if (temp_error) + { + g_propagate_error (error, temp_error); + goto out; + } + } + else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + if (!g_file_move (src, destination, move_flags, NULL, NULL, cancellable, error)) + goto out; + } + else + goto out; + + ret = TRUE; + out: + g_clear_object (&src_fileinfo); + g_clear_object (&dest_fileinfo); + g_clear_object (&src_enum); + g_clear_object (&dest_subfile); + g_clear_object (&src_subfile); + return ret; +} diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h index 4f6952dc..819a8738 100644 --- a/src/libotutil/ot-gio-utils.h +++ b/src/libotutil/ot-gio-utils.h @@ -27,6 +27,8 @@ G_BEGIN_DECLS +#define OSTREE_GIO_FAST_QUERYINFO "standard::name,standard::type,standard::is-symlink,standard::symlink-target,standard::is-hidden,unix::*" + GFile *ot_gfile_new_for_path (const char *path); const char *ot_gfile_get_path_cached (GFile *file); @@ -41,6 +43,12 @@ gboolean ot_gfile_load_contents_utf8 (GFile *file, GCancellable *cancellable, GError **error); + +gboolean ot_gfile_merge_dirs (GFile *destination, + GFile *src, + GCancellable *cancellable, + GError **error); + G_END_DECLS #endif diff --git a/src/ostree/ot-builtin-compose.c b/src/ostree/ot-builtin-compose.c index c5f7e31b..f22662da 100644 --- a/src/ostree/ot-builtin-compose.c +++ b/src/ostree/ot-builtin-compose.c @@ -74,103 +74,6 @@ rm_rf (GFile *path) g_clear_object (&path_enum); } -static gboolean -merge_dir (GFile *destination, - GFile *src, - GError **error) -{ - gboolean ret = FALSE; - const char *dest_path = NULL; - const char *src_path = NULL; - GError *temp_error = NULL; - GFileInfo *src_fileinfo = NULL; - GFileInfo *dest_fileinfo = NULL; - GFileEnumerator *src_enum = NULL; - GFile *dest_subfile = NULL; - GFile *src_subfile = NULL; - const char *name; - guint32 type; - - dest_path = ot_gfile_get_path_cached (destination); - src_path = ot_gfile_get_path_cached (src); - - dest_fileinfo = g_file_query_info (destination, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, &temp_error); - if (dest_fileinfo) - { - type = g_file_info_get_attribute_uint32 (dest_fileinfo, "standard::type"); - if (type != G_FILE_TYPE_DIRECTORY) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Attempting to replace non-directory %s with directory %s", - dest_path, src_path); - goto out; - } - - src_enum = g_file_enumerate_children (src, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, error); - if (!src_enum) - goto out; - - while ((src_fileinfo = g_file_enumerator_next_file (src_enum, NULL, &temp_error)) != NULL) - { - type = g_file_info_get_attribute_uint32 (src_fileinfo, "standard::type"); - name = g_file_info_get_attribute_byte_string (src_fileinfo, "standard::name"); - - dest_subfile = g_file_get_child (destination, name); - src_subfile = g_file_get_child (src, name); - - if (type == G_FILE_TYPE_DIRECTORY) - { - if (!merge_dir (dest_subfile, src_subfile, error)) - goto out; - } - else - { - if (!g_file_delete (dest_subfile, NULL, &temp_error)) - { - if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - g_clear_error (&temp_error); - else - { - g_propagate_error (error, temp_error); - goto out; - } - } - if (!g_file_move (src_subfile, dest_subfile, 0, NULL, NULL, NULL, error)) - goto out; - } - - g_clear_object (&dest_subfile); - g_clear_object (&src_subfile); - } - if (temp_error) - { - g_propagate_error (error, temp_error); - goto out; - } - } - else if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - { - g_clear_error (&temp_error); - if (!g_file_move (src, destination, 0, NULL, NULL, NULL, error)) - goto out; - } - else - goto out; - - ret = TRUE; - out: - g_clear_object (&src_fileinfo); - g_clear_object (&dest_fileinfo); - g_clear_object (&src_enum); - g_clear_object (&dest_subfile); - g_clear_object (&src_subfile); - return ret; -} - static gboolean compose_branch_on_dir (OstreeRepo *repo, GFile *destination, @@ -199,7 +102,7 @@ compose_branch_on_dir (OstreeRepo *repo, goto out; g_print ("...done\n"); g_print ("Merging over destination...\n"); - if (!merge_dir (destination, branchf, error)) + if (!ot_gfile_merge_dirs (destination, branchf, NULL, error)) goto out; if (metadata_builder)