From 9ba968a5f41e99e6a38d6ba1f1e177de39a3b447 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 3 Sep 2012 10:43:42 -0700 Subject: [PATCH] otutil: Add a few more helper functions To be used by wip/etc-writable branch. --- src/libotutil/ot-gio-utils.c | 180 ++++++++++++++++++++++++++++++----- src/libotutil/ot-gio-utils.h | 15 +++ 2 files changed, 171 insertions(+), 24 deletions(-) diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c index e31e47b3..71ab3836 100644 --- a/src/libotutil/ot-gio-utils.c +++ b/src/libotutil/ot-gio-utils.c @@ -131,6 +131,35 @@ ot_gfile_get_child_strconcat (GFile *parent, return ret; } +GFile * +ot_gfile_get_child_build_path (GFile *parent, + const char *first, ...) +{ + va_list args; + const char *arg; + ot_lfree char *path = NULL; + ot_lptrarray GPtrArray *components = NULL; + + va_start (args, first); + + components = g_ptr_array_new (); + + arg = first; + while (arg != NULL) + { + g_ptr_array_add (components, (char*)arg); + arg = va_arg (args, const char *); + } + + va_end (args); + + g_ptr_array_add (components, NULL); + + path = g_build_filenamev ((char**)components->pdata); + + return g_file_resolve_relative_path (parent, path); +} + /** * ot_gfile_unlink: * @path: Path to file @@ -394,25 +423,12 @@ ot_gio_checksum_stream_finish (GInputStream *in, return g_memdup (g_simple_async_result_get_op_res_gpointer (simple), 32); } -/** - * ot_gio_shutil_cp_al_or_fallback: - * @src: Source path - * @dest: Destination path - * @cancellable: - * @error: - * - * Recursively copy path @src (which must be a directory) to the - * target @dest. If possible, hardlinks are used; if a hardlink is - * not possible, a regular copy is created. Any existing files are - * overwritten. - * - * Returns: %TRUE on success - */ -gboolean -ot_gio_shutil_cp_al_or_fallback (GFile *src, - GFile *dest, - GCancellable *cancellable, - GError **error) +static gboolean +cp_internal (GFile *src, + GFile *dest, + gboolean use_hardlinks, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; ot_lobj GFileEnumerator *enumerator = NULL; @@ -453,19 +469,29 @@ ot_gio_shutil_cp_al_or_fallback (GFile *src, goto out; } - if (!ot_gio_shutil_cp_al_or_fallback (src_child, dest_child, cancellable, error)) + if (!cp_internal (src_child, dest_child, use_hardlinks, cancellable, error)) goto out; } else { + gboolean did_link = FALSE; (void) unlink (ot_gfile_get_path_cached (dest_child)); - if (link (ot_gfile_get_path_cached (src_child), ot_gfile_get_path_cached (dest_child)) == -1) + if (use_hardlinks) { - if (!(errno == EMLINK || errno == EXDEV)) + if (link (ot_gfile_get_path_cached (src_child), ot_gfile_get_path_cached (dest_child)) == -1) { - ot_util_set_error_from_errno (error, errno); - goto out; + if (!(errno == EMLINK || errno == EXDEV)) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + use_hardlinks = FALSE; } + else + did_link = TRUE; + } + if (!did_link) + { if (!g_file_copy (src_child, dest_child, G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA | G_FILE_COPY_NOFOLLOW_SYMLINKS, cancellable, NULL, NULL, error)) @@ -485,3 +511,109 @@ ot_gio_shutil_cp_al_or_fallback (GFile *src, return ret; } +/** + * ot_gio_shutil_cp_al_or_fallback: + * @src: Source path + * @dest: Destination path + * @cancellable: + * @error: + * + * Recursively copy path @src (which must be a directory) to the + * target @dest. If possible, hardlinks are used; if a hardlink is + * not possible, a regular copy is created. Any existing files are + * overwritten. + * + * Returns: %TRUE on success + */ +gboolean +ot_gio_shutil_cp_al_or_fallback (GFile *src, + GFile *dest, + GCancellable *cancellable, + GError **error) +{ + return cp_internal (src, dest, TRUE, cancellable, error); +} + +/** + * ot_gio_shutil_cp_a: + * @src: Source path + * @dest: Destination path + * @cancellable: + * @error: + * + * Recursively copy path @src (which must be a directory) to the + * target @dest. Any existing files are overwritten. + * + * Returns: %TRUE on success + */ +gboolean +ot_gio_shutil_cp_a (GFile *src, + GFile *dest, + GCancellable *cancellable, + GError **error) +{ + return cp_internal (src, dest, FALSE, cancellable, error); +} + +gboolean +ot_gio_shutil_rm_rf (GFile *path, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + ot_lobj GFileEnumerator *dir_enum = NULL; + ot_lobj GFileInfo *file_info = NULL; + GError *temp_error = NULL; + + dir_enum = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, &temp_error); + if (!dir_enum) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&temp_error); + ret = TRUE; + } + else + g_propagate_error (error, temp_error); + + goto out; + } + + while ((file_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL) + { + ot_lobj GFile *subpath = NULL; + GFileType type; + const char *name; + + type = g_file_info_get_attribute_uint32 (file_info, "standard::type"); + name = g_file_info_get_attribute_byte_string (file_info, "standard::name"); + + subpath = g_file_get_child (path, name); + + if (type == G_FILE_TYPE_DIRECTORY) + { + if (!ot_gio_shutil_rm_rf (subpath, cancellable, error)) + goto out; + } + else + { + if (!ot_gfile_unlink (subpath, cancellable, error)) + goto out; + } + g_clear_object (&file_info); + } + if (temp_error) + { + g_propagate_error (error, temp_error); + goto out; + } + + if (!g_file_delete (path, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h index 5855a974..32e80f15 100644 --- a/src/libotutil/ot-gio-utils.h +++ b/src/libotutil/ot-gio-utils.h @@ -40,6 +40,8 @@ GFile *ot_gfile_from_build_path (const char *first, ...) G_GNUC_NULL_TERMINATED; GFile *ot_gfile_get_child_strconcat (GFile *parent, const char *first, ...) G_GNUC_NULL_TERMINATED; +GFile *ot_gfile_get_child_build_path (GFile *parent, const char *first, ...) G_GNUC_NULL_TERMINATED; + const char *ot_gfile_get_path_cached (GFile *file); const char *ot_gfile_get_basename_cached (GFile *file); @@ -51,6 +53,11 @@ gboolean ot_gfile_rename (GFile *src, GCancellable *cancellable, GError **error); +gboolean ot_gfile_hardlink (GFile *src, + GFile *dest, + GCancellable *cancellable, + GError **error); + gboolean ot_gfile_unlink (GFile *path, GCancellable *cancellable, GError **error); @@ -96,11 +103,19 @@ guchar * ot_gio_checksum_stream_finish (GInputStream *in, GAsyncResult *result, GError **error); +gboolean ot_gio_shutil_cp_a (GFile *src, + GFile *dest, + GCancellable *cancellable, + GError **error); + gboolean ot_gio_shutil_cp_al_or_fallback (GFile *src, GFile *dest, GCancellable *cancellable, GError **error); +gboolean ot_gio_shutil_rm_rf (GFile *path, + GCancellable *cancellable, + GError **error); G_END_DECLS