core: Make checksum API also operate on directories

This commit is contained in:
Colin Walters 2011-11-18 06:34:54 -05:00
parent b8cef545d1
commit 7f64d5cec7
3 changed files with 104 additions and 65 deletions

View File

@ -41,6 +41,12 @@ ostree_validate_checksum_string (const char *sha256,
return TRUE; return TRUE;
} }
GVariant *
ostree_wrap_metadata_variant (OstreeSerializedVariantType type,
GVariant *metadata)
{
return g_variant_new ("(uv)", GUINT32_TO_BE ((guint32)type), metadata);
}
void void
ostree_checksum_update_stat (GChecksum *checksum, guint32 uid, guint32 gid, guint32 mode) 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; return ret;
} }
gboolean static gboolean
ostree_checksum_file (GFile *f, checksum_directory (GFile *f,
OstreeObjectType objtype, GFileInfo *f_info,
GChecksum **out_checksum, GChecksum **out_checksum,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) 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; const char *path = NULL;
GChecksum *content_sha256 = NULL; GChecksum *content_sha256 = NULL;
GChecksum *content_and_meta_sha256 = NULL; GChecksum *content_and_meta_sha256 = NULL;
ssize_t bytes_read; ssize_t bytes_read;
GVariant *xattrs = NULL; GVariant *xattrs = NULL;
char *basename = NULL; char *basename = NULL;
gboolean ret = FALSE;
GFileInfo *file_info = NULL;
GInputStream *input = NULL; GInputStream *input = NULL;
guint32 unix_mode; guint32 unix_mode;
path = ot_gfile_get_path_cached (f); path = ot_gfile_get_path_cached (f);
basename = g_path_get_basename (path); 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) if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
{ {
input = (GInputStream*)g_file_read (f, cancellable, error); input = (GInputStream*)g_file_read (f, cancellable, error);
@ -272,7 +304,6 @@ ostree_checksum_file (GFile *f,
ret = TRUE; ret = TRUE;
out: out:
g_clear_object (&input); g_clear_object (&input);
g_clear_object (&file_info);
g_free (basename); g_free (basename);
if (xattrs) if (xattrs)
g_variant_unref (xattrs); g_variant_unref (xattrs);
@ -281,39 +312,62 @@ ostree_checksum_file (GFile *f,
return ret; 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 gboolean
ostree_get_directory_metadata (GFile *dir, ostree_get_directory_metadata (GFile *dir,
GFileInfo *dir_info,
GVariant **out_metadata, GVariant **out_metadata,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
struct stat stbuf;
GVariant *xattrs = NULL; GVariant *xattrs = NULL;
GVariant *ret_metadata = 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); xattrs = ostree_get_xattrs_for_file (dir, error);
if (!xattrs) if (!xattrs)
goto out; goto out;
ret_metadata = g_variant_new ("(uuuu@a(ayay))", ret_metadata = g_variant_new ("(uuuu@a(ayay))",
OSTREE_DIR_META_VERSION, OSTREE_DIR_META_VERSION,
GUINT32_TO_BE ((guint32)stbuf.st_uid), GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::uid")),
GUINT32_TO_BE ((guint32)stbuf.st_gid), GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::gid")),
GUINT32_TO_BE ((guint32)stbuf.st_mode), GUINT32_TO_BE (g_file_info_get_attribute_uint32 (dir_info, "unix::mode")),
xattrs); xattrs);
g_variant_ref_sink (ret_metadata); g_variant_ref_sink (ret_metadata);

View File

@ -101,6 +101,9 @@ char *ostree_get_relative_object_path (const char *checksum,
GVariant *ostree_get_xattrs_for_file (GFile *f, GVariant *ostree_get_xattrs_for_file (GFile *f,
GError **error); GError **error);
GVariant *ostree_wrap_metadata_variant (OstreeSerializedVariantType type,
GVariant *metadata);
gboolean ostree_set_xattrs (GFile *f, GVariant *xattrs, gboolean ostree_set_xattrs (GFile *f, GVariant *xattrs,
GCancellable *cancellable, GError **error); GCancellable *cancellable, GError **error);
@ -116,6 +119,7 @@ gboolean ostree_checksum_file (GFile *f,
GError **error); GError **error);
gboolean ostree_get_directory_metadata (GFile *dir, gboolean ostree_get_directory_metadata (GFile *dir,
GFileInfo *dir_info,
GVariant **out_metadata, GVariant **out_metadata,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);

View File

@ -557,13 +557,6 @@ ostree_repo_is_archive (OstreeRepo *self)
return priv->archive; 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 static gboolean
write_gvariant_to_tmp (OstreeRepo *self, write_gvariant_to_tmp (OstreeRepo *self,
OstreeSerializedVariantType type, OstreeSerializedVariantType type,
@ -582,7 +575,7 @@ write_gvariant_to_tmp (OstreeRepo *self,
GUnixOutputStream *stream = NULL; GUnixOutputStream *stream = NULL;
GChecksum *checksum = 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); tmp_name = g_build_filename (ot_gfile_get_path_cached (priv->tmp_dir), "variant-tmp-XXXXXX", NULL);
fd = g_mkstemp (tmp_name); fd = g_mkstemp (tmp_name);
@ -709,10 +702,17 @@ import_directory_meta (OstreeRepo *self,
GChecksum *ret_checksum = NULL; GChecksum *ret_checksum = NULL;
GVariant *dirmeta = NULL; GVariant *dirmeta = NULL;
GFile *f = NULL; GFile *f = NULL;
GFileInfo *f_info = NULL;
f = ot_util_new_file_for_path (path); 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; goto out;
if (!import_gvariant_object (self, OSTREE_SERIALIZED_DIRMETA_VARIANT, if (!import_gvariant_object (self, OSTREE_SERIALIZED_DIRMETA_VARIANT,
@ -726,6 +726,7 @@ import_directory_meta (OstreeRepo *self,
ret_checksum = NULL; ret_checksum = NULL;
out: out:
g_clear_object (&f); g_clear_object (&f);
g_clear_object (&f_info);
if (ret_checksum) if (ret_checksum)
g_checksum_free (ret_checksum); g_checksum_free (ret_checksum);
if (dirmeta != NULL) if (dirmeta != NULL)
@ -1884,8 +1885,6 @@ get_file_checksum (GFile *f,
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
GChecksum *tmp_checksum = NULL; GChecksum *tmp_checksum = NULL;
GVariant *dirmeta = NULL;
GVariant *packed_dirmeta = NULL;
char *ret_checksum = NULL; char *ret_checksum = NULL;
if (OSTREE_IS_REPO_FILE (f)) if (OSTREE_IS_REPO_FILE (f))
@ -1894,36 +1893,18 @@ get_file_checksum (GFile *f,
} }
else else
{ {
if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_DIRECTORY) if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE,
{ &tmp_checksum, cancellable, error))
tmp_checksum = g_checksum_new (G_CHECKSUM_SHA256); goto out;
if (!ostree_get_directory_metadata (f, &dirmeta, cancellable, error)) ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
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));
}
} }
ret = TRUE; ret = TRUE;
*out_checksum = ret_checksum; *out_checksum = ret_checksum;
ret_checksum = NULL; ret_checksum = NULL;
out: out:
g_free (ret_checksum);
if (tmp_checksum) if (tmp_checksum)
g_checksum_free (tmp_checksum); g_checksum_free (tmp_checksum);
if (dirmeta)
g_variant_unref (dirmeta);
if (packed_dirmeta)
g_variant_unref (packed_dirmeta);
return ret; return ret;
} }