mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-11 03:46:17 +01:00
gvdb-reader: drop gvdb_table_walk()
The attempt at the simple method for preventing unbounded recursion proved to be insufficient due to the existence of dconf databases in the wild that violated the rule (leading to the entire content of the database being scrapped). It also still had the ugly assert for less than 64 levels of recursion that could have been hit by a determined advisary. gvdb_table_get_names() allows the dconf-service to do everything it needs without the troubles associated with the walk approach.
This commit is contained in:
parent
d9577f100b
commit
fc37611a97
127
gvdb-reader.c
127
gvdb-reader.c
@ -348,18 +348,6 @@ gvdb_table_lookup (GvdbTable *file,
|
||||
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
|
||||
gvdb_table_list_from_item (GvdbTable *table,
|
||||
const struct gvdb_hash_item *item,
|
||||
@ -798,118 +786,3 @@ gvdb_table_is_valid (GvdbTable *table)
|
||||
{
|
||||
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')
|
||||
{
|
||||
const guint32_le *dir;
|
||||
guint length;
|
||||
|
||||
if (gvdb_table_list_from_item (table, item, &dir, &length))
|
||||
{
|
||||
/* In order to avoid files with recursive contents
|
||||
* we impose the rule that a directory's data must
|
||||
* follow the data of any directory pointing to
|
||||
* it.
|
||||
*
|
||||
* If we discover that our newly-discovered
|
||||
* directory follows the one we're traversing now
|
||||
* then bail out.
|
||||
*/
|
||||
if (dir <= pointers[index])
|
||||
continue;
|
||||
|
||||
if (open_func (name, name_len, user_data))
|
||||
{
|
||||
index++;
|
||||
g_assert (index < 64);
|
||||
|
||||
name_lengths[index] = name_len;
|
||||
pointers[index] = dir;
|
||||
enders[index] = pointers[index] + length;
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,28 +65,9 @@ GVariant * gvdb_table_get_value (GvdbTab
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gvdb_table_has_value (GvdbTable *table,
|
||||
const gchar *key);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
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
|
||||
|
||||
#endif /* __gvdb_reader_h__ */
|
||||
|
Loading…
Reference in New Issue
Block a user