diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index 8caff3f4..7e470460 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -41,6 +41,12 @@ ostree_validate_checksum_string (const char *sha256, return TRUE; } +GVariant * +ostree_wrap_metadata_variant (OstreeSerializedVariantType type, + GVariant *metadata) +{ + return g_variant_new ("(uv)", GUINT32_TO_BE ((guint32)type), metadata); +} void ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode) @@ -174,33 +180,59 @@ ostree_get_xattrs_for_file (GFile *f, return ret; } -gboolean -ostree_checksum_file (GFile *f, - OstreeObjectType objtype, - GChecksum **out_checksum, - GCancellable *cancellable, - GError **error) +static gboolean +checksum_directory (GFile *f, + GFileInfo *f_info, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error) { + gboolean ret = FALSE; + GVariant *dirmeta = NULL; + GVariant *packed = NULL; + GChecksum *ret_checksum = NULL; + + if (!ostree_get_directory_metadata (f, f_info, &dirmeta, cancellable, error)) + goto out; + packed = ostree_wrap_metadata_variant (OSTREE_SERIALIZED_DIRMETA_VARIANT, dirmeta); + ret_checksum = g_checksum_new (G_CHECKSUM_SHA256); + g_checksum_update (ret_checksum, g_variant_get_data (packed), + g_variant_get_size (packed)); + + ret = TRUE; + *out_checksum = ret_checksum; + ret_checksum = NULL; + out: + if (ret_checksum) + g_checksum_free (ret_checksum); + if (dirmeta) + g_variant_unref (dirmeta); + if (packed) + g_variant_unref (packed); + return ret; +} + +static gboolean +checksum_nondirectory (GFile *f, + GFileInfo *file_info, + OstreeObjectType objtype, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; const char *path = NULL; GChecksum *content_sha256 = NULL; GChecksum *content_and_meta_sha256 = NULL; ssize_t bytes_read; GVariant *xattrs = NULL; char *basename = NULL; - gboolean ret = FALSE; - GFileInfo *file_info = NULL; GInputStream *input = NULL; guint32 unix_mode; path = ot_gfile_get_path_cached (f); basename = g_path_get_basename (path); - file_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); - if (!file_info) - goto out; - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { input = (GInputStream*)g_file_read (f, cancellable, error); @@ -272,7 +304,6 @@ ostree_checksum_file (GFile *f, ret = TRUE; out: g_clear_object (&input); - g_clear_object (&file_info); g_free (basename); if (xattrs) g_variant_unref (xattrs); @@ -281,39 +312,62 @@ ostree_checksum_file (GFile *f, return ret; } +gboolean +ostree_checksum_file (GFile *f, + OstreeObjectType objtype, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GFileInfo *file_info = NULL; + GChecksum *ret_checksum = NULL; + + file_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); + if (!file_info) + goto out; + + if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + { + if (!checksum_directory (f, file_info, &ret_checksum, cancellable, error)) + goto out; + } + else + { + if (!checksum_nondirectory (f, file_info, objtype, &ret_checksum, cancellable, error)) + goto out; + } + + ret = TRUE; + *out_checksum = ret_checksum; + ret_checksum = NULL; + out: + g_clear_object (&file_info); + return ret; +} + gboolean ostree_get_directory_metadata (GFile *dir, + GFileInfo *dir_info, GVariant **out_metadata, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; - struct stat stbuf; GVariant *xattrs = NULL; GVariant *ret_metadata = NULL; - if (lstat (ot_gfile_get_path_cached (dir), &stbuf) < 0) - { - ot_util_set_error_from_errno (error, errno); - goto out; - } - - if (!S_ISDIR(stbuf.st_mode)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not a directory: '%s'", ot_gfile_get_path_cached (dir)); - goto out; - } - xattrs = ostree_get_xattrs_for_file (dir, error); if (!xattrs) goto out; ret_metadata = g_variant_new ("(uuuu@a(ayay))", OSTREE_DIR_META_VERSION, - GUINT32_TO_BE ((guint32)stbuf.st_uid), - GUINT32_TO_BE ((guint32)stbuf.st_gid), - GUINT32_TO_BE ((guint32)stbuf.st_mode), + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::uid")), + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::gid")), + GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::mode")), xattrs); g_variant_ref_sink (ret_metadata); diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index 38d08ed6..3e779e53 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -101,6 +101,9 @@ char *ostree_get_relative_object_path (const char *checksum, GVariant *ostree_get_xattrs_for_file (GFile *f, GError **error); +GVariant *ostree_wrap_metadata_variant (OstreeSerializedVariantType type, + GVariant *metadata); + gboolean ostree_set_xattrs (GFile *f, GVariant *xattrs, GCancellable *cancellable, GError **error); @@ -116,6 +119,7 @@ gboolean ostree_checksum_file (GFile *f, GError **error); gboolean ostree_get_directory_metadata (GFile *dir, + GFileInfo *dir_info, GVariant **out_metadata, GCancellable *cancellable, GError **error); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 60f38ba3..2b28fdc3 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -557,13 +557,6 @@ ostree_repo_is_archive (OstreeRepo *self) return priv->archive; } -static GVariant * -pack_metadata_variant (OstreeSerializedVariantType type, - GVariant *variant) -{ - return g_variant_new ("(uv)", GUINT32_TO_BE ((guint32)type), variant); -} - static gboolean write_gvariant_to_tmp (OstreeRepo *self, OstreeSerializedVariantType type, @@ -582,7 +575,7 @@ write_gvariant_to_tmp (OstreeRepo *self, GUnixOutputStream *stream = NULL; GChecksum *checksum = NULL; - serialized = pack_metadata_variant (type, variant); + serialized = ostree_wrap_metadata_variant (type, variant); tmp_name = g_build_filename (ot_gfile_get_path_cached (priv->tmp_dir), "variant-tmp-XXXXXX", NULL); fd = g_mkstemp (tmp_name); @@ -709,10 +702,17 @@ import_directory_meta (OstreeRepo *self, GChecksum *ret_checksum = NULL; GVariant *dirmeta = NULL; GFile *f = NULL; + GFileInfo *f_info = NULL; f = ot_util_new_file_for_path (path); - if (!ostree_get_directory_metadata (f, &dirmeta, NULL, error)) + f_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!f_info) + goto out; + + if (!ostree_get_directory_metadata (f, f_info, &dirmeta, NULL, error)) goto out; if (!import_gvariant_object (self, OSTREE_SERIALIZED_DIRMETA_VARIANT, @@ -726,6 +726,7 @@ import_directory_meta (OstreeRepo *self, ret_checksum = NULL; out: g_clear_object (&f); + g_clear_object (&f_info); if (ret_checksum) g_checksum_free (ret_checksum); if (dirmeta != NULL) @@ -1884,8 +1885,6 @@ get_file_checksum (GFile *f, { gboolean ret = FALSE; GChecksum *tmp_checksum = NULL; - GVariant *dirmeta = NULL; - GVariant *packed_dirmeta = NULL; char *ret_checksum = NULL; if (OSTREE_IS_REPO_FILE (f)) @@ -1894,36 +1893,18 @@ get_file_checksum (GFile *f, } else { - if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_DIRECTORY) - { - tmp_checksum = g_checksum_new (G_CHECKSUM_SHA256); - if (!ostree_get_directory_metadata (f, &dirmeta, cancellable, error)) - goto out; - packed_dirmeta = pack_metadata_variant (OSTREE_SERIALIZED_DIRMETA_VARIANT, dirmeta); - g_checksum_update (tmp_checksum, g_variant_get_data (packed_dirmeta), - g_variant_get_size (packed_dirmeta)); - ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum)); - } - else - { - if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE, - &tmp_checksum, cancellable, error)) - goto out; - ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum)); - } + if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE, + &tmp_checksum, cancellable, error)) + goto out; + ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum)); } ret = TRUE; *out_checksum = ret_checksum; ret_checksum = NULL; out: - g_free (ret_checksum); if (tmp_checksum) g_checksum_free (tmp_checksum); - if (dirmeta) - g_variant_unref (dirmeta); - if (packed_dirmeta) - g_variant_unref (packed_dirmeta); return ret; }