mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-24 19:22:11 +01:00
Merge branch '1454-gvdb-corruption' into 'master'
gvdb: Fix error handling in gvdb_table_new() Closes #1454 See merge request GNOME/glib!214
This commit is contained in:
commit
faa383936e
@ -2112,6 +2112,7 @@ set_overrides (GHashTable *schema_table,
|
|||||||
}
|
}
|
||||||
|
|
||||||
g_strfreev (groups);
|
g_strfreev (groups);
|
||||||
|
g_key_file_free (key_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -489,7 +489,7 @@ g_resource_unref (GResource *resource)
|
|||||||
{
|
{
|
||||||
if (g_atomic_int_dec_and_test (&resource->ref_count))
|
if (g_atomic_int_dec_and_test (&resource->ref_count))
|
||||||
{
|
{
|
||||||
gvdb_table_unref (resource->table);
|
gvdb_table_free (resource->table);
|
||||||
g_free (resource);
|
g_free (resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -512,6 +512,19 @@ g_resource_new_from_table (GvdbTable *table)
|
|||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_resource_error_from_gvdb_table_error (GError **g_resource_error,
|
||||||
|
GError *gvdb_table_error /* (transfer full) */)
|
||||||
|
{
|
||||||
|
if (g_error_matches (gvdb_table_error, G_FILE_ERROR, G_FILE_ERROR_INVAL))
|
||||||
|
g_set_error_literal (g_resource_error,
|
||||||
|
G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL,
|
||||||
|
gvdb_table_error->message);
|
||||||
|
else
|
||||||
|
g_propagate_error (g_resource_error, g_steal_pointer (&gvdb_table_error));
|
||||||
|
g_clear_error (&gvdb_table_error);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_resource_new_from_data:
|
* g_resource_new_from_data:
|
||||||
* @data: A #GBytes
|
* @data: A #GBytes
|
||||||
@ -528,6 +541,8 @@ g_resource_new_from_table (GvdbTable *table)
|
|||||||
* Otherwise this function will internally create a copy of the memory since
|
* Otherwise this function will internally create a copy of the memory since
|
||||||
* GLib 2.56, or in older versions fail and exit the process.
|
* GLib 2.56, or in older versions fail and exit the process.
|
||||||
*
|
*
|
||||||
|
* If @data is empty or corrupt, %G_RESOURCE_ERROR_INTERNAL will be returned.
|
||||||
|
*
|
||||||
* Returns: (transfer full): a new #GResource, or %NULL on error
|
* Returns: (transfer full): a new #GResource, or %NULL on error
|
||||||
*
|
*
|
||||||
* Since: 2.32
|
* Since: 2.32
|
||||||
@ -538,6 +553,7 @@ g_resource_new_from_data (GBytes *data,
|
|||||||
{
|
{
|
||||||
GvdbTable *table;
|
GvdbTable *table;
|
||||||
gboolean unref_data = FALSE;
|
gboolean unref_data = FALSE;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
|
||||||
if (((guintptr) g_bytes_get_data (data, NULL)) % sizeof (gpointer) != 0)
|
if (((guintptr) g_bytes_get_data (data, NULL)) % sizeof (gpointer) != 0)
|
||||||
{
|
{
|
||||||
@ -546,19 +562,16 @@ g_resource_new_from_data (GBytes *data,
|
|||||||
unref_data = TRUE;
|
unref_data = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
table = gvdb_table_new_from_data (g_bytes_get_data (data, NULL),
|
table = gvdb_table_new_from_bytes (data, TRUE, &local_error);
|
||||||
g_bytes_get_size (data),
|
|
||||||
TRUE,
|
|
||||||
g_bytes_ref (data),
|
|
||||||
(GvdbRefFunc)g_bytes_ref,
|
|
||||||
(GDestroyNotify)g_bytes_unref,
|
|
||||||
error);
|
|
||||||
|
|
||||||
if (unref_data)
|
if (unref_data)
|
||||||
g_bytes_unref (data);
|
g_bytes_unref (data);
|
||||||
|
|
||||||
if (table == NULL)
|
if (table == NULL)
|
||||||
return NULL;
|
{
|
||||||
|
g_resource_error_from_gvdb_table_error (error, g_steal_pointer (&local_error));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return g_resource_new_from_table (table);
|
return g_resource_new_from_table (table);
|
||||||
}
|
}
|
||||||
@ -574,6 +587,11 @@ g_resource_new_from_data (GBytes *data,
|
|||||||
* If you want to use this resource in the global resource namespace you need
|
* If you want to use this resource in the global resource namespace you need
|
||||||
* to register it with g_resources_register().
|
* to register it with g_resources_register().
|
||||||
*
|
*
|
||||||
|
* If @filename is empty or the data in it is corrupt,
|
||||||
|
* %G_RESOURCE_ERROR_INTERNAL will be returned. If @filename doesn’t exist, or
|
||||||
|
* there is an error in reading it, an error from g_mapped_file_new() will be
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
* Returns: (transfer full): a new #GResource, or %NULL on error
|
* Returns: (transfer full): a new #GResource, or %NULL on error
|
||||||
*
|
*
|
||||||
* Since: 2.32
|
* Since: 2.32
|
||||||
@ -583,10 +601,14 @@ g_resource_load (const gchar *filename,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GvdbTable *table;
|
GvdbTable *table;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
|
||||||
table = gvdb_table_new (filename, FALSE, error);
|
table = gvdb_table_new (filename, FALSE, &local_error);
|
||||||
if (table == NULL)
|
if (table == NULL)
|
||||||
return NULL;
|
{
|
||||||
|
g_resource_error_from_gvdb_table_error (error, g_steal_pointer (&local_error));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return g_resource_new_from_table (table);
|
return g_resource_new_from_table (table);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ g_settings_schema_source_unref (GSettingsSchemaSource *source)
|
|||||||
|
|
||||||
if (source->parent)
|
if (source->parent)
|
||||||
g_settings_schema_source_unref (source->parent);
|
g_settings_schema_source_unref (source->parent);
|
||||||
gvdb_table_unref (source->table);
|
gvdb_table_free (source->table);
|
||||||
g_free (source->directory);
|
g_free (source->directory);
|
||||||
|
|
||||||
if (source->text_tables)
|
if (source->text_tables)
|
||||||
@ -267,6 +267,9 @@ g_settings_schema_source_unref (GSettingsSchemaSource *source)
|
|||||||
* Generally, you should set @trusted to %TRUE for files installed by the
|
* Generally, you should set @trusted to %TRUE for files installed by the
|
||||||
* system and to %FALSE for files in the home directory.
|
* system and to %FALSE for files in the home directory.
|
||||||
*
|
*
|
||||||
|
* In either case, an empty file or some types of corruption in the file will
|
||||||
|
* result in %G_FILE_ERROR_INVAL being returned.
|
||||||
|
*
|
||||||
* If @parent is non-%NULL then there are two effects.
|
* If @parent is non-%NULL then there are two effects.
|
||||||
*
|
*
|
||||||
* First, if g_settings_schema_source_lookup() is called with the
|
* First, if g_settings_schema_source_lookup() is called with the
|
||||||
@ -802,7 +805,7 @@ g_settings_schema_source_list_schemas (GSettingsSchemaSource *source,
|
|||||||
else
|
else
|
||||||
g_hash_table_add (reloc, schema);
|
g_hash_table_add (reloc, schema);
|
||||||
|
|
||||||
gvdb_table_unref (table);
|
gvdb_table_free (table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,7 +931,7 @@ g_settings_schema_unref (GSettingsSchema *schema)
|
|||||||
g_settings_schema_unref (schema->extends);
|
g_settings_schema_unref (schema->extends);
|
||||||
|
|
||||||
g_settings_schema_source_unref (schema->source);
|
g_settings_schema_source_unref (schema->source);
|
||||||
gvdb_table_unref (schema->table);
|
gvdb_table_free (schema->table);
|
||||||
g_free (schema->items);
|
g_free (schema->items);
|
||||||
g_free (schema->id);
|
g_free (schema->id);
|
||||||
|
|
||||||
@ -1188,7 +1191,7 @@ g_settings_schema_list (GSettingsSchema *schema,
|
|||||||
g_hash_table_iter_remove (&iter);
|
g_hash_table_iter_remove (&iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
gvdb_table_unref (child_table);
|
gvdb_table_free (child_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now create the list */
|
/* Now create the list */
|
||||||
|
@ -339,6 +339,13 @@ file_builder_allocate_for_hash (FileBuilder *fb,
|
|||||||
#undef chunk
|
#undef chunk
|
||||||
|
|
||||||
memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le));
|
memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le));
|
||||||
|
|
||||||
|
/* NOTE - the code to actually fill in the bloom filter here is missing.
|
||||||
|
* Patches welcome!
|
||||||
|
*
|
||||||
|
* http://en.wikipedia.org/wiki/Bloom_filter
|
||||||
|
* http://0pointer.de/blog/projects/bloom.html
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -23,15 +23,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct _GvdbTable {
|
struct _GvdbTable {
|
||||||
gint ref_count;
|
GBytes *bytes;
|
||||||
|
|
||||||
const gchar *data;
|
const gchar *data;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
|
||||||
gpointer user_data;
|
|
||||||
GvdbRefFunc ref_user_data;
|
|
||||||
GDestroyNotify unref_user_data;
|
|
||||||
|
|
||||||
gboolean byteswapped;
|
gboolean byteswapped;
|
||||||
gboolean trusted;
|
gboolean trusted;
|
||||||
|
|
||||||
@ -124,80 +120,81 @@ gvdb_table_setup_root (GvdbTable *file,
|
|||||||
file->n_hash_items = size / sizeof (struct gvdb_hash_item);
|
file->n_hash_items = size / sizeof (struct gvdb_hash_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GvdbTable *
|
/**
|
||||||
new_from_data (const void *data,
|
* gvdb_table_new_from_bytes:
|
||||||
gsize data_len,
|
* @bytes: the #GBytes with the data
|
||||||
gboolean trusted,
|
* @trusted: if the contents of @bytes are trusted
|
||||||
gpointer user_data,
|
* @error: %NULL, or a pointer to a %NULL #GError
|
||||||
GvdbRefFunc ref,
|
*
|
||||||
GDestroyNotify unref,
|
* Creates a new #GvdbTable from the contents of @bytes.
|
||||||
const char *filename,
|
*
|
||||||
GError **error)
|
* This call can fail if the header contained in @bytes is invalid or if @bytes
|
||||||
|
* is empty; if so, %G_FILE_ERROR_INVAL will be returned.
|
||||||
|
*
|
||||||
|
* You should call gvdb_table_free() on the return result when you no
|
||||||
|
* longer require it.
|
||||||
|
*
|
||||||
|
* Returns: a new #GvdbTable
|
||||||
|
**/
|
||||||
|
GvdbTable *
|
||||||
|
gvdb_table_new_from_bytes (GBytes *bytes,
|
||||||
|
gboolean trusted,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
|
const struct gvdb_header *header;
|
||||||
GvdbTable *file;
|
GvdbTable *file;
|
||||||
|
|
||||||
file = g_slice_new0 (GvdbTable);
|
file = g_slice_new0 (GvdbTable);
|
||||||
file->data = data;
|
file->bytes = g_bytes_ref (bytes);
|
||||||
file->size = data_len;
|
file->data = g_bytes_get_data (bytes, &file->size);
|
||||||
file->trusted = trusted;
|
file->trusted = trusted;
|
||||||
file->ref_count = 1;
|
|
||||||
file->ref_user_data = ref;
|
|
||||||
file->unref_user_data = unref;
|
|
||||||
file->user_data = user_data;
|
|
||||||
|
|
||||||
if (sizeof (struct gvdb_header) <= file->size)
|
if (file->size < sizeof (struct gvdb_header))
|
||||||
{
|
goto invalid;
|
||||||
const struct gvdb_header *header = (gpointer) file->data;
|
|
||||||
|
|
||||||
if (header->signature[0] == GVDB_SIGNATURE0 &&
|
header = (gpointer) file->data;
|
||||||
header->signature[1] == GVDB_SIGNATURE1 &&
|
|
||||||
guint32_from_le (header->version) == 0)
|
|
||||||
file->byteswapped = FALSE;
|
|
||||||
|
|
||||||
else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 &&
|
if (header->signature[0] == GVDB_SIGNATURE0 &&
|
||||||
header->signature[1] == GVDB_SWAPPED_SIGNATURE1 &&
|
header->signature[1] == GVDB_SIGNATURE1 &&
|
||||||
guint32_from_le (header->version) == 0)
|
guint32_from_le (header->version) == 0)
|
||||||
file->byteswapped = TRUE;
|
file->byteswapped = FALSE;
|
||||||
|
|
||||||
else
|
else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 &&
|
||||||
{
|
header->signature[1] == GVDB_SWAPPED_SIGNATURE1 &&
|
||||||
if (filename)
|
guint32_from_le (header->version) == 0)
|
||||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
file->byteswapped = TRUE;
|
||||||
"%s: invalid header", filename);
|
|
||||||
else
|
|
||||||
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
|
|
||||||
"invalid gvdb header");
|
|
||||||
g_slice_free (GvdbTable, file);
|
|
||||||
if (unref)
|
|
||||||
unref (user_data);
|
|
||||||
|
|
||||||
return NULL;
|
else
|
||||||
}
|
goto invalid;
|
||||||
|
|
||||||
gvdb_table_setup_root (file, &header->root);
|
gvdb_table_setup_root (file, &header->root);
|
||||||
}
|
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
|
|
||||||
|
invalid:
|
||||||
|
g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "invalid gvdb header");
|
||||||
|
|
||||||
|
g_bytes_unref (file->bytes);
|
||||||
|
|
||||||
|
g_slice_free (GvdbTable, file);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gvdb_table_new:
|
* gvdb_table_new:
|
||||||
* @filename: the path to the hash file
|
* @filename: a filename
|
||||||
* @trusted: if the contents of @filename are trusted
|
* @trusted: if the contents of @bytes are trusted
|
||||||
* @error: %NULL, or a pointer to a %NULL #GError
|
* @error: %NULL, or a pointer to a %NULL #GError
|
||||||
*
|
*
|
||||||
* Creates a new #GvdbTable from the contents of the file found at
|
* Creates a new #GvdbTable using the #GMappedFile for @filename as the
|
||||||
* @filename.
|
* #GBytes.
|
||||||
*
|
*
|
||||||
* The only time this function fails is if the file cannot be opened.
|
* This function will fail if the file cannot be opened.
|
||||||
* In that case, the #GError that is returned will be an error from
|
* In that case, the #GError that is returned will be an error from
|
||||||
* g_mapped_file_new().
|
* g_mapped_file_new().
|
||||||
*
|
*
|
||||||
* An empty or otherwise corrupted file is considered to be a valid
|
* An empty or corrupt file will result in %G_FILE_ERROR_INVAL.
|
||||||
* #GvdbTable with no entries.
|
|
||||||
*
|
|
||||||
* You should call gvdb_table_unref() on the return result when you no
|
|
||||||
* longer require it.
|
|
||||||
*
|
*
|
||||||
* Returns: a new #GvdbTable
|
* Returns: a new #GvdbTable
|
||||||
**/
|
**/
|
||||||
@ -207,53 +204,21 @@ gvdb_table_new (const gchar *filename,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
GMappedFile *mapped;
|
GMappedFile *mapped;
|
||||||
|
GvdbTable *table;
|
||||||
|
GBytes *bytes;
|
||||||
|
|
||||||
if ((mapped = g_mapped_file_new (filename, FALSE, error)) == NULL)
|
mapped = g_mapped_file_new (filename, FALSE, error);
|
||||||
|
if (!mapped)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return new_from_data (g_mapped_file_get_contents (mapped),
|
bytes = g_mapped_file_get_bytes (mapped);
|
||||||
g_mapped_file_get_length (mapped),
|
table = gvdb_table_new_from_bytes (bytes, trusted, error);
|
||||||
trusted,
|
g_mapped_file_unref (mapped);
|
||||||
mapped,
|
g_bytes_unref (bytes);
|
||||||
(GvdbRefFunc)g_mapped_file_ref,
|
|
||||||
(GDestroyNotify)g_mapped_file_unref,
|
|
||||||
filename,
|
|
||||||
error);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
g_prefix_error (error, "%s: ", filename);
|
||||||
* gvdb_table_new_from_data:
|
|
||||||
* @data: the data
|
return table;
|
||||||
* @data_len: the length of @data in bytes
|
|
||||||
* @trusted: if the contents of @data are trusted
|
|
||||||
* @user_data: User supplied data that owns @data
|
|
||||||
* @ref: Ref function for @user_data
|
|
||||||
* @unref: Unref function for @user_data
|
|
||||||
*
|
|
||||||
* Creates a new #GvdbTable from the data in @data.
|
|
||||||
*
|
|
||||||
* An empty or otherwise corrupted data is considered to be a valid
|
|
||||||
* #GvdbTable with no entries.
|
|
||||||
*
|
|
||||||
* You should call gvdb_table_unref() on the return result when you no
|
|
||||||
* longer require it.
|
|
||||||
*
|
|
||||||
* Returns: a new #GvdbTable
|
|
||||||
**/
|
|
||||||
GvdbTable *
|
|
||||||
gvdb_table_new_from_data (const void *data,
|
|
||||||
gsize data_len,
|
|
||||||
gboolean trusted,
|
|
||||||
gpointer user_data,
|
|
||||||
GvdbRefFunc ref,
|
|
||||||
GDestroyNotify unref,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
return new_from_data (data, data_len,
|
|
||||||
trusted,
|
|
||||||
user_data, ref, unref,
|
|
||||||
NULL,
|
|
||||||
error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -346,18 +311,6 @@ gvdb_table_lookup (GvdbTable *file,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct gvdb_hash_item *
|
|
||||||
gvdb_table_get_item (GvdbTable *table,
|
|
||||||
guint32_le item_no)
|
|
||||||
{
|
|
||||||
guint32 item_no_native = guint32_from_le (item_no);
|
|
||||||
|
|
||||||
if G_LIKELY (item_no_native < table->n_hash_items)
|
|
||||||
return table->hash_items + item_no_native;
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gvdb_table_list_from_item (GvdbTable *table,
|
gvdb_table_list_from_item (GvdbTable *table,
|
||||||
const struct gvdb_hash_item *item,
|
const struct gvdb_hash_item *item,
|
||||||
@ -376,6 +329,155 @@ gvdb_table_list_from_item (GvdbTable *table,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gvdb_table_get_names:
|
||||||
|
* @table: a #GvdbTable
|
||||||
|
* @length: the number of items returned, or %NULL
|
||||||
|
*
|
||||||
|
* Gets a list of all names contained in @table.
|
||||||
|
*
|
||||||
|
* No call to gvdb_table_get_table(), gvdb_table_list() or
|
||||||
|
* gvdb_table_get_value() will succeed unless it is for one of the
|
||||||
|
* names returned by this function.
|
||||||
|
*
|
||||||
|
* Note that some names that are returned may still fail for all of the
|
||||||
|
* above calls in the case of the corrupted file. Note also that the
|
||||||
|
* returned strings may not be utf8.
|
||||||
|
*
|
||||||
|
* Returns: a %NULL-terminated list of strings, of length @length
|
||||||
|
**/
|
||||||
|
gchar **
|
||||||
|
gvdb_table_get_names (GvdbTable *table,
|
||||||
|
gint *length)
|
||||||
|
{
|
||||||
|
gchar **names;
|
||||||
|
gint n_names;
|
||||||
|
gint filled;
|
||||||
|
gint total;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
/* We generally proceed by iterating over the list of items in the
|
||||||
|
* hash table (in order of appearance) recording them into an array.
|
||||||
|
*
|
||||||
|
* Each item has a parent item (except root items). The parent item
|
||||||
|
* forms part of the name of the item. We could go fetching the
|
||||||
|
* parent item chain at the point that we encounter each item but then
|
||||||
|
* we would need to implement some sort of recursion along with checks
|
||||||
|
* for self-referential items.
|
||||||
|
*
|
||||||
|
* Instead, we do a number of passes. Each pass will build up one
|
||||||
|
* level of names (starting from the root). We continue to do passes
|
||||||
|
* until no more items are left. The first pass will only add root
|
||||||
|
* items and each further pass will only add items whose direct parent
|
||||||
|
* is an item added in the immediately previous pass. It's also
|
||||||
|
* possible that items get filled if they follow their parent within a
|
||||||
|
* particular pass.
|
||||||
|
*
|
||||||
|
* At most we will have a number of passes equal to the depth of the
|
||||||
|
* tree. Self-referential items will never be filled in (since their
|
||||||
|
* parent will have never been filled in). We continue until we have
|
||||||
|
* a pass that fills in no additional items.
|
||||||
|
*
|
||||||
|
* This takes an O(n) algorithm and turns it into O(n*m) where m is
|
||||||
|
* the depth of the tree, but in all sane cases the tree won't be very
|
||||||
|
* deep and the constant factor of this algorithm is lower (and the
|
||||||
|
* complexity of coding it, as well).
|
||||||
|
*/
|
||||||
|
|
||||||
|
n_names = table->n_hash_items;
|
||||||
|
names = g_new0 (gchar *, n_names + 1);
|
||||||
|
|
||||||
|
/* 'names' starts out all-NULL. On each pass we record the number
|
||||||
|
* of items changed from NULL to non-NULL in 'filled' so we know if we
|
||||||
|
* should repeat the loop. 'total' counts the total number of items
|
||||||
|
* filled. If 'total' ends up equal to 'n_names' then we know that
|
||||||
|
* 'names' has been completely filled.
|
||||||
|
*/
|
||||||
|
|
||||||
|
total = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Loop until we have filled no more entries */
|
||||||
|
filled = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < n_names; i++)
|
||||||
|
{
|
||||||
|
const struct gvdb_hash_item *item = &table->hash_items[i];
|
||||||
|
const gchar *name;
|
||||||
|
gsize name_length;
|
||||||
|
guint32 parent;
|
||||||
|
|
||||||
|
/* already got it on a previous pass */
|
||||||
|
if (names[i] != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
parent = guint32_from_le (item->parent);
|
||||||
|
|
||||||
|
if (parent == 0xffffffffu)
|
||||||
|
{
|
||||||
|
/* it's a root item */
|
||||||
|
name = gvdb_table_item_get_key (table, item, &name_length);
|
||||||
|
|
||||||
|
if (name != NULL)
|
||||||
|
{
|
||||||
|
names[i] = g_strndup (name, name_length);
|
||||||
|
filled++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (parent < n_names && names[parent] != NULL)
|
||||||
|
{
|
||||||
|
/* It's a non-root item whose parent was filled in already.
|
||||||
|
*
|
||||||
|
* Calculate the name of this item by combining it with
|
||||||
|
* its parent name.
|
||||||
|
*/
|
||||||
|
name = gvdb_table_item_get_key (table, item, &name_length);
|
||||||
|
|
||||||
|
if (name != NULL)
|
||||||
|
{
|
||||||
|
const gchar *parent_name = names[parent];
|
||||||
|
gsize parent_length;
|
||||||
|
gchar *fullname;
|
||||||
|
|
||||||
|
parent_length = strlen (parent_name);
|
||||||
|
fullname = g_malloc (parent_length + name_length + 1);
|
||||||
|
memcpy (fullname, parent_name, parent_length);
|
||||||
|
memcpy (fullname + parent_length, name, name_length);
|
||||||
|
fullname[parent_length + name_length] = '\0';
|
||||||
|
names[i] = fullname;
|
||||||
|
filled++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total += filled;
|
||||||
|
}
|
||||||
|
while (filled && total < n_names);
|
||||||
|
|
||||||
|
/* If the table was corrupted then 'names' may have holes in it.
|
||||||
|
* Collapse those.
|
||||||
|
*/
|
||||||
|
if G_UNLIKELY (total != n_names)
|
||||||
|
{
|
||||||
|
GPtrArray *fixed_names;
|
||||||
|
|
||||||
|
fixed_names = g_ptr_array_new ();
|
||||||
|
for (i = 0; i < n_names; i++)
|
||||||
|
if (names[i] != NULL)
|
||||||
|
g_ptr_array_add (fixed_names, names[i]);
|
||||||
|
|
||||||
|
g_free (names);
|
||||||
|
n_names = fixed_names->len;
|
||||||
|
g_ptr_array_add (fixed_names, NULL);
|
||||||
|
names = (gchar **) g_ptr_array_free (fixed_names, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length)
|
||||||
|
*length = n_names;
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gvdb_table_list:
|
* gvdb_table_list:
|
||||||
@ -457,7 +559,15 @@ gboolean
|
|||||||
gvdb_table_has_value (GvdbTable *file,
|
gvdb_table_has_value (GvdbTable *file,
|
||||||
const gchar *key)
|
const gchar *key)
|
||||||
{
|
{
|
||||||
return gvdb_table_lookup (file, key, 'v') != NULL;
|
static const struct gvdb_hash_item *item;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
item = gvdb_table_lookup (file, key, 'v');
|
||||||
|
|
||||||
|
if (item == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return gvdb_table_dereference (file, &item->value.pointer, 8, &size) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GVariant *
|
static GVariant *
|
||||||
@ -466,6 +576,7 @@ gvdb_table_value_from_item (GvdbTable *table,
|
|||||||
{
|
{
|
||||||
GVariant *variant, *value;
|
GVariant *variant, *value;
|
||||||
gconstpointer data;
|
gconstpointer data;
|
||||||
|
GBytes *bytes;
|
||||||
gsize size;
|
gsize size;
|
||||||
|
|
||||||
data = gvdb_table_dereference (table, &item->value.pointer, 8, &size);
|
data = gvdb_table_dereference (table, &item->value.pointer, 8, &size);
|
||||||
@ -473,12 +584,11 @@ gvdb_table_value_from_item (GvdbTable *table,
|
|||||||
if G_UNLIKELY (data == NULL)
|
if G_UNLIKELY (data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT,
|
bytes = g_bytes_new_from_bytes (table->bytes, ((gchar *) data) - table->data, size);
|
||||||
data, size, table->trusted,
|
variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, bytes, table->trusted);
|
||||||
table->unref_user_data,
|
|
||||||
table->ref_user_data ? table->ref_user_data (table->user_data) : table->user_data);
|
|
||||||
value = g_variant_get_variant (variant);
|
value = g_variant_get_variant (variant);
|
||||||
g_variant_unref (variant);
|
g_variant_unref (variant);
|
||||||
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -562,7 +672,7 @@ gvdb_table_get_raw_value (GvdbTable *table,
|
|||||||
* contained in the file. This newly-created #GvdbTable does not depend
|
* contained in the file. This newly-created #GvdbTable does not depend
|
||||||
* on the continued existence of @file.
|
* on the continued existence of @file.
|
||||||
*
|
*
|
||||||
* You should call gvdb_table_unref() on the return result when you no
|
* You should call gvdb_table_free() on the return result when you no
|
||||||
* longer require it.
|
* longer require it.
|
||||||
*
|
*
|
||||||
* Returns: a new #GvdbTable, or %NULL
|
* Returns: a new #GvdbTable, or %NULL
|
||||||
@ -580,14 +690,11 @@ gvdb_table_get_table (GvdbTable *file,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
new = g_slice_new0 (GvdbTable);
|
new = g_slice_new0 (GvdbTable);
|
||||||
new->user_data = file->ref_user_data ? file->ref_user_data (file->user_data) : file->user_data;
|
new->bytes = g_bytes_ref (file->bytes);
|
||||||
new->ref_user_data = file->ref_user_data;
|
|
||||||
new->unref_user_data = file->unref_user_data;
|
|
||||||
new->byteswapped = file->byteswapped;
|
new->byteswapped = file->byteswapped;
|
||||||
new->trusted = file->trusted;
|
new->trusted = file->trusted;
|
||||||
new->data = file->data;
|
new->data = file->data;
|
||||||
new->size = file->size;
|
new->size = file->size;
|
||||||
new->ref_count = 1;
|
|
||||||
|
|
||||||
gvdb_table_setup_root (new, &item->value.pointer);
|
gvdb_table_setup_root (new, &item->value.pointer);
|
||||||
|
|
||||||
@ -595,38 +702,16 @@ gvdb_table_get_table (GvdbTable *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gvdb_table_ref:
|
* gvdb_table_free:
|
||||||
* @file: a #GvdbTable
|
* @file: a #GvdbTable
|
||||||
*
|
*
|
||||||
* Increases the reference count on @file.
|
* Frees @file.
|
||||||
*
|
|
||||||
* Returns: a new reference on @file
|
|
||||||
**/
|
|
||||||
GvdbTable *
|
|
||||||
gvdb_table_ref (GvdbTable *file)
|
|
||||||
{
|
|
||||||
g_atomic_int_inc (&file->ref_count);
|
|
||||||
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gvdb_table_unref:
|
|
||||||
* @file: a #GvdbTable
|
|
||||||
*
|
|
||||||
* Decreases the reference count on @file, possibly freeing it.
|
|
||||||
*
|
|
||||||
* Since: 2.26
|
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
gvdb_table_unref (GvdbTable *file)
|
gvdb_table_free (GvdbTable *file)
|
||||||
{
|
{
|
||||||
if (g_atomic_int_dec_and_test (&file->ref_count))
|
g_bytes_unref (file->bytes);
|
||||||
{
|
g_slice_free (GvdbTable, file);
|
||||||
if (file->unref_user_data)
|
|
||||||
file->unref_user_data (file->user_data);
|
|
||||||
g_slice_free (GvdbTable, file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -646,105 +731,3 @@ gvdb_table_is_valid (GvdbTable *table)
|
|||||||
{
|
{
|
||||||
return !!*table->data;
|
return !!*table->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gvdb_table_walk:
|
|
||||||
* @table: a #GvdbTable
|
|
||||||
* @key: a key corresponding to a list
|
|
||||||
* @open_func: the #GvdbWalkOpenFunc
|
|
||||||
* @value_func: the #GvdbWalkValueFunc
|
|
||||||
* @close_func: the #GvdbWalkCloseFunc
|
|
||||||
* @user_data: data to pass to the callbacks
|
|
||||||
*
|
|
||||||
* Looks up the list at @key and iterate over the items in it.
|
|
||||||
*
|
|
||||||
* First, @open_func is called to signal that we are starting to iterate over
|
|
||||||
* the list. Then the list is iterated. When all items in the list have been
|
|
||||||
* iterated over, the @close_func is called.
|
|
||||||
*
|
|
||||||
* When iterating, if a given item in the list is a value then @value_func is
|
|
||||||
* called.
|
|
||||||
*
|
|
||||||
* If a given item in the list is itself a list then @open_func is called. If
|
|
||||||
* that function returns %TRUE then the walk begins iterating the items in the
|
|
||||||
* sublist, until there are no more items, at which point a matching
|
|
||||||
* @close_func call is made. If @open_func returns %FALSE then no iteration of
|
|
||||||
* the sublist occurs and no corresponding @close_func call is made.
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
gvdb_table_walk (GvdbTable *table,
|
|
||||||
const gchar *key,
|
|
||||||
GvdbWalkOpenFunc open_func,
|
|
||||||
GvdbWalkValueFunc value_func,
|
|
||||||
GvdbWalkCloseFunc close_func,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
const struct gvdb_hash_item *item;
|
|
||||||
const guint32_le *pointers[64];
|
|
||||||
const guint32_le *enders[64];
|
|
||||||
gsize name_lengths[64];
|
|
||||||
gint index = 0;
|
|
||||||
|
|
||||||
item = gvdb_table_lookup (table, key, 'L');
|
|
||||||
name_lengths[0] = 0;
|
|
||||||
pointers[0] = NULL;
|
|
||||||
enders[0] = NULL;
|
|
||||||
goto start_here;
|
|
||||||
|
|
||||||
while (index)
|
|
||||||
{
|
|
||||||
close_func (name_lengths[index], user_data);
|
|
||||||
index--;
|
|
||||||
|
|
||||||
while (pointers[index] < enders[index])
|
|
||||||
{
|
|
||||||
const gchar *name;
|
|
||||||
gsize name_len;
|
|
||||||
|
|
||||||
item = gvdb_table_get_item (table, *pointers[index]++);
|
|
||||||
start_here:
|
|
||||||
|
|
||||||
if (item != NULL &&
|
|
||||||
(name = gvdb_table_item_get_key (table, item, &name_len)))
|
|
||||||
{
|
|
||||||
if (item->type == 'L')
|
|
||||||
{
|
|
||||||
if (open_func (name, name_len, user_data))
|
|
||||||
{
|
|
||||||
guint length = 0;
|
|
||||||
|
|
||||||
index++;
|
|
||||||
g_assert (index < 64);
|
|
||||||
|
|
||||||
gvdb_table_list_from_item (table, item,
|
|
||||||
&pointers[index],
|
|
||||||
&length);
|
|
||||||
enders[index] = pointers[index] + length;
|
|
||||||
name_lengths[index] = name_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (item->type == 'v')
|
|
||||||
{
|
|
||||||
GVariant *value;
|
|
||||||
|
|
||||||
value = gvdb_table_value_from_item (table, item);
|
|
||||||
|
|
||||||
if (value != NULL)
|
|
||||||
{
|
|
||||||
if (table->byteswapped)
|
|
||||||
{
|
|
||||||
GVariant *tmp;
|
|
||||||
|
|
||||||
tmp = g_variant_byteswap (value);
|
|
||||||
g_variant_unref (value);
|
|
||||||
value = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_func (name, name_len, value, user_data);
|
|
||||||
g_variant_unref (value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -24,27 +24,21 @@
|
|||||||
|
|
||||||
typedef struct _GvdbTable GvdbTable;
|
typedef struct _GvdbTable GvdbTable;
|
||||||
|
|
||||||
typedef gpointer (*GvdbRefFunc) (gpointer data);
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
G_GNUC_INTERNAL
|
||||||
|
GvdbTable * gvdb_table_new_from_bytes (GBytes *bytes,
|
||||||
|
gboolean trusted,
|
||||||
|
GError **error);
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GvdbTable * gvdb_table_new (const gchar *filename,
|
GvdbTable * gvdb_table_new (const gchar *filename,
|
||||||
gboolean trusted,
|
gboolean trusted,
|
||||||
GError **error);
|
GError **error);
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GvdbTable * gvdb_table_new_from_data (const void *data,
|
void gvdb_table_free (GvdbTable *table);
|
||||||
gsize data_len,
|
|
||||||
gboolean trusted,
|
|
||||||
gpointer user_data,
|
|
||||||
GvdbRefFunc ref,
|
|
||||||
GDestroyNotify unref,
|
|
||||||
GError **error);
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
GvdbTable * gvdb_table_ref (GvdbTable *table);
|
gchar ** gvdb_table_get_names (GvdbTable *table,
|
||||||
G_GNUC_INTERNAL
|
gint *length);
|
||||||
void gvdb_table_unref (GvdbTable *table);
|
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gchar ** gvdb_table_list (GvdbTable *table,
|
gchar ** gvdb_table_list (GvdbTable *table,
|
||||||
const gchar *key);
|
const gchar *key);
|
||||||
@ -61,28 +55,9 @@ GVariant * gvdb_table_get_value (GvdbTab
|
|||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gboolean gvdb_table_has_value (GvdbTable *table,
|
gboolean gvdb_table_has_value (GvdbTable *table,
|
||||||
const gchar *key);
|
const gchar *key);
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
G_GNUC_INTERNAL
|
||||||
gboolean gvdb_table_is_valid (GvdbTable *table);
|
gboolean gvdb_table_is_valid (GvdbTable *table);
|
||||||
|
|
||||||
typedef void (*GvdbWalkValueFunc) (const gchar *name,
|
|
||||||
gsize name_len,
|
|
||||||
GVariant *value,
|
|
||||||
gpointer user_data);
|
|
||||||
typedef gboolean (*GvdbWalkOpenFunc) (const gchar *name,
|
|
||||||
gsize name_len,
|
|
||||||
gpointer user_data);
|
|
||||||
typedef void (*GvdbWalkCloseFunc) (gsize name_len,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
G_GNUC_INTERNAL
|
|
||||||
void gvdb_table_walk (GvdbTable *table,
|
|
||||||
const gchar *key,
|
|
||||||
GvdbWalkOpenFunc open_func,
|
|
||||||
GvdbWalkValueFunc value_func,
|
|
||||||
GvdbWalkCloseFunc close_func,
|
|
||||||
gpointer user_data);
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __gvdb_reader_h__ */
|
#endif /* __gvdb_reader_h__ */
|
||||||
|
@ -23,9 +23,34 @@
|
|||||||
|
|
||||||
<maintainer>
|
<maintainer>
|
||||||
<foaf:Person>
|
<foaf:Person>
|
||||||
<foaf:name>Ryan Lortie</foaf:name>
|
<foaf:name>Matthias Clasen</foaf:name>
|
||||||
<foaf:mbox rdf:resource='mailto:desrt@desrt.ca'/>
|
<foaf:mbox rdf:resource="mailto:mclasen@redhat.com"/>
|
||||||
<gnome:userid>ryanl</gnome:userid>
|
<gnome:userid>matthiasc</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Allison Ryan Lortie</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:desrt@desrt.ca"/>
|
||||||
|
<gnome:userid>desrt</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Philip Withnall</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:philip@tecnocode.co.uk"/>
|
||||||
|
<foaf:mbox rdf:resource="mailto:withnall@endlessm.com"/>
|
||||||
|
<gnome:userid>pwithnall</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Emmanuele Bassi</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:ebassi@gnome.org"/>
|
||||||
|
<gnome:userid>ebassi</gnome:userid>
|
||||||
</foaf:Person>
|
</foaf:Person>
|
||||||
</maintainer>
|
</maintainer>
|
||||||
|
|
||||||
|
@ -2353,6 +2353,18 @@ test_schema_source (void)
|
|||||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
|
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
|
|
||||||
|
/* Test error handling of corrupt compiled files. */
|
||||||
|
source = g_settings_schema_source_new_from_directory ("schema-source-corrupt", parent, TRUE, &error);
|
||||||
|
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL);
|
||||||
|
g_assert_null (source);
|
||||||
|
g_clear_error (&error);
|
||||||
|
|
||||||
|
/* Test error handling of empty compiled files. */
|
||||||
|
source = g_settings_schema_source_new_from_directory ("schema-source-empty", parent, TRUE, &error);
|
||||||
|
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL);
|
||||||
|
g_assert_null (source);
|
||||||
|
g_clear_error (&error);
|
||||||
|
|
||||||
/* create a source with the parent */
|
/* create a source with the parent */
|
||||||
source = g_settings_schema_source_new_from_directory ("schema-source", parent, TRUE, &error);
|
source = g_settings_schema_source_new_from_directory ("schema-source", parent, TRUE, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
@ -2770,6 +2782,12 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
if (!g_test_subprocess ())
|
if (!g_test_subprocess ())
|
||||||
{
|
{
|
||||||
|
GError *local_error = NULL;
|
||||||
|
/* A GVDB header is 6 guint32s, and requires a magic number in the first
|
||||||
|
* two guint32s. A set of zero bytes of a greater length is considered
|
||||||
|
* corrupt. */
|
||||||
|
const guint8 gschemas_compiled_corrupt[sizeof (guint32) * 7] = { 0, };
|
||||||
|
|
||||||
backend_set = g_getenv ("GSETTINGS_BACKEND") != NULL;
|
backend_set = g_getenv ("GSETTINGS_BACKEND") != NULL;
|
||||||
|
|
||||||
g_setenv ("XDG_DATA_DIRS", ".", TRUE);
|
g_setenv ("XDG_DATA_DIRS", ".", TRUE);
|
||||||
@ -2821,6 +2839,21 @@ main (int argc, char *argv[])
|
|||||||
"--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml",
|
"--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml",
|
||||||
NULL, NULL, &result, NULL));
|
NULL, NULL, &result, NULL));
|
||||||
g_assert (result == 0);
|
g_assert (result == 0);
|
||||||
|
|
||||||
|
g_remove ("schema-source-corrupt/gschemas.compiled");
|
||||||
|
g_mkdir ("schema-source-corrupt", 0777);
|
||||||
|
g_file_set_contents ("schema-source-corrupt/gschemas.compiled",
|
||||||
|
(const gchar *) gschemas_compiled_corrupt,
|
||||||
|
sizeof (gschemas_compiled_corrupt),
|
||||||
|
&local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
|
|
||||||
|
g_remove ("schema-source-empty/gschemas.compiled");
|
||||||
|
g_mkdir ("schema-source-empty", 0777);
|
||||||
|
g_file_set_contents ("schema-source-empty/gschemas.compiled",
|
||||||
|
"", 0,
|
||||||
|
&local_error);
|
||||||
|
g_assert_no_error (local_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_test_add_func ("/gsettings/basic", test_basic);
|
g_test_add_func ("/gsettings/basic", test_basic);
|
||||||
|
@ -317,6 +317,45 @@ test_resource_data_unaligned (void)
|
|||||||
g_resource_unref (resource);
|
g_resource_unref (resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test error handling for corrupt GResource files (specifically, a corrupt
|
||||||
|
* GVDB header). */
|
||||||
|
static void
|
||||||
|
test_resource_data_corrupt (void)
|
||||||
|
{
|
||||||
|
/* A GVDB header is 6 guint32s, and requires a magic number in the first two
|
||||||
|
* guint32s. A set of zero bytes of a greater length is considered corrupt. */
|
||||||
|
static const guint8 data[sizeof (guint32) * 7] = { 0, };
|
||||||
|
GBytes *bytes = NULL;
|
||||||
|
GResource *resource = NULL;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
|
||||||
|
bytes = g_bytes_new_static (data, sizeof (data));
|
||||||
|
resource = g_resource_new_from_data (bytes, &local_error);
|
||||||
|
g_bytes_unref (bytes);
|
||||||
|
g_assert_error (local_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL);
|
||||||
|
g_assert_null (resource);
|
||||||
|
|
||||||
|
g_clear_error (&local_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test handling for empty GResource files. They should also be treated as
|
||||||
|
* corrupt. */
|
||||||
|
static void
|
||||||
|
test_resource_data_empty (void)
|
||||||
|
{
|
||||||
|
GBytes *bytes = NULL;
|
||||||
|
GResource *resource = NULL;
|
||||||
|
GError *local_error = NULL;
|
||||||
|
|
||||||
|
bytes = g_bytes_new_static (NULL, 0);
|
||||||
|
resource = g_resource_new_from_data (bytes, &local_error);
|
||||||
|
g_bytes_unref (bytes);
|
||||||
|
g_assert_error (local_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL);
|
||||||
|
g_assert_null (resource);
|
||||||
|
|
||||||
|
g_clear_error (&local_error);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_resource_registered (void)
|
test_resource_registered (void)
|
||||||
{
|
{
|
||||||
@ -785,6 +824,8 @@ main (int argc,
|
|||||||
g_test_add_func ("/resource/file-path", test_resource_file_path);
|
g_test_add_func ("/resource/file-path", test_resource_file_path);
|
||||||
g_test_add_func ("/resource/data", test_resource_data);
|
g_test_add_func ("/resource/data", test_resource_data);
|
||||||
g_test_add_func ("/resource/data_unaligned", test_resource_data_unaligned);
|
g_test_add_func ("/resource/data_unaligned", test_resource_data_unaligned);
|
||||||
|
g_test_add_func ("/resource/data-corrupt", test_resource_data_corrupt);
|
||||||
|
g_test_add_func ("/resource/data-empty", test_resource_data_empty);
|
||||||
g_test_add_func ("/resource/registered", test_resource_registered);
|
g_test_add_func ("/resource/registered", test_resource_registered);
|
||||||
g_test_add_func ("/resource/manual", test_resource_manual);
|
g_test_add_func ("/resource/manual", test_resource_manual);
|
||||||
g_test_add_func ("/resource/manual2", test_resource_manual2);
|
g_test_add_func ("/resource/manual2", test_resource_manual2);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user