mirror of
https://github.com/flatpak/flatpak.git
synced 2026-02-19 23:25:42 -05:00
Remove document portal
This is now in xdg-desktop-portal. We keep a version of the document portal dbus XML so that we avoid weird build dependencies. Flatpak itself is technically not dependent on the document portal, but it is very much recommended that you use it. Closes: #1398 Approved by: alexlarsson
This commit is contained in:
committed by
Atomic Bot
parent
0c3c42d8db
commit
f2a6c1db8d
6
.gitignore
vendored
6
.gitignore
vendored
@@ -36,7 +36,6 @@ flatpak-session-helper
|
||||
xdg-document-portal
|
||||
xdg-permission-store
|
||||
flatpak-builder
|
||||
testdb
|
||||
*~
|
||||
profile/flatpak.sh
|
||||
flatpak-dbus.[ch]
|
||||
@@ -68,9 +67,6 @@ Flatpak-1.0.*
|
||||
/doc/flatpak-docs.xml
|
||||
/doc/*.1
|
||||
/doc/*.5
|
||||
/test-doc-portal
|
||||
/test-doc-portal.log
|
||||
/test-doc-portal.trs
|
||||
/test-libglnx-errors
|
||||
/test-libglnx-errors.log
|
||||
/test-libglnx-errors.trs
|
||||
@@ -89,8 +85,6 @@ Flatpak-1.0.*
|
||||
/testlibrary
|
||||
/testlibrary.log
|
||||
/testlibrary.trs
|
||||
/testdb.log
|
||||
/testdb.trs
|
||||
/tests/test-keyring/.gpg-v21-migrated
|
||||
/tests/test-keyring/private-keys-v1.d/
|
||||
/tests/test-keyring/trustdb.gpg
|
||||
|
||||
@@ -94,8 +94,6 @@ include lib/Makefile.am.inc
|
||||
include session-helper/Makefile.am.inc
|
||||
include system-helper/Makefile.am.inc
|
||||
include dbus-proxy/Makefile.am.inc
|
||||
include permission-store/Makefile.am.inc
|
||||
include document-portal/Makefile.am.inc
|
||||
include tests/Makefile.am.inc
|
||||
|
||||
if !WITH_SYSTEM_BWRAP
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
|
||||
#include "flatpak-builtins.h"
|
||||
#include "flatpak-utils.h"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
noinst_LTLIBRARIES += libflatpak-common.la
|
||||
|
||||
dbus_built_sources = common/flatpak-dbus.c common/flatpak-dbus.h
|
||||
dbus_built_sources = common/flatpak-dbus.c common/flatpak-dbus.h common/flatpak-document-dbus.c common/flatpak-document-dbus.h
|
||||
systemd_dbus_built_sources = common/flatpak-systemd-dbus.c common/flatpak-systemd-dbus.h
|
||||
|
||||
common/flatpak-dbus.c: data/org.freedesktop.Flatpak.xml Makefile
|
||||
@@ -9,7 +9,16 @@ common/flatpak-dbus.c: data/org.freedesktop.Flatpak.xml Makefile
|
||||
--interface-prefix org.freedesktop.Flatpak. \
|
||||
--c-namespace Flatpak \
|
||||
--generate-c-code $(builddir)/common/flatpak-dbus \
|
||||
$(srcdir)/data/org.freedesktop.Flatpak.xml \
|
||||
$(srcdir)/data/org.freedesktop.Flatpak.xml \
|
||||
$(NULL)
|
||||
|
||||
common/flatpak-document-dbus.c: data/org.freedesktop.portal.Documents.xml Makefile
|
||||
mkdir -p $(builddir)/common
|
||||
$(AM_V_GEN) $(GDBUS_CODEGEN) \
|
||||
--interface-prefix org.freedesktop.portal. \
|
||||
--c-namespace XdpDbus \
|
||||
--generate-c-code $(builddir)/common/flatpak-document-dbus \
|
||||
$(srcdir)/data/org.freedesktop.portal.Documents.xml \
|
||||
$(NULL)
|
||||
|
||||
common/flatpak-systemd-dbus.c: data/org.freedesktop.systemd1.xml Makefile
|
||||
@@ -53,13 +62,6 @@ libflatpak_common_la_SOURCES = \
|
||||
common/flatpak-table-printer.h \
|
||||
common/flatpak-chain-input-stream.c \
|
||||
common/flatpak-chain-input-stream.h \
|
||||
common/gvdb/gvdb-reader.h \
|
||||
common/gvdb/gvdb-format.h \
|
||||
common/gvdb/gvdb-reader.c \
|
||||
common/gvdb/gvdb-builder.h \
|
||||
common/gvdb/gvdb-builder.c \
|
||||
common/flatpak-db.c \
|
||||
common/flatpak-db.h \
|
||||
common/flatpak-json.c \
|
||||
common/flatpak-json.h \
|
||||
common/flatpak-json-oci.c \
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include "flatpak-utils.h"
|
||||
#include "flatpak-dir.h"
|
||||
#include "flatpak-systemd-dbus.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "lib/flatpak-error.h"
|
||||
|
||||
/* Same order as enum */
|
||||
|
||||
1224
common/flatpak-db.c
1224
common/flatpak-db.c
File diff suppressed because it is too large
Load Diff
@@ -1,103 +0,0 @@
|
||||
/* flatpak-db.h
|
||||
*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef FLATPAK_DB_H
|
||||
#define FLATPAK_DB_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct FlatpakDb FlatpakDb;
|
||||
typedef struct _FlatpakDbEntry FlatpakDbEntry;
|
||||
|
||||
#define FLATPAK_TYPE_DB (flatpak_db_get_type ())
|
||||
#define FLATPAK_DB(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), FLATPAK_TYPE_DB, FlatpakDb))
|
||||
#define FLATPAK_IS_DB(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FLATPAK_TYPE_DB))
|
||||
|
||||
GType flatpak_db_get_type (void);
|
||||
|
||||
FlatpakDb * flatpak_db_new (const char *path,
|
||||
gboolean fail_if_not_found,
|
||||
GError **error);
|
||||
char ** flatpak_db_list_ids (FlatpakDb *self);
|
||||
char ** flatpak_db_list_apps (FlatpakDb *self);
|
||||
char ** flatpak_db_list_ids_by_app (FlatpakDb *self,
|
||||
const char *app);
|
||||
char ** flatpak_db_list_ids_by_value (FlatpakDb *self,
|
||||
GVariant *data);
|
||||
FlatpakDbEntry *flatpak_db_lookup (FlatpakDb *self,
|
||||
const char *id);
|
||||
GString * flatpak_db_print_string (FlatpakDb *self,
|
||||
GString *string);
|
||||
char * flatpak_db_print (FlatpakDb *self);
|
||||
|
||||
gboolean flatpak_db_is_dirty (FlatpakDb *self);
|
||||
void flatpak_db_set_entry (FlatpakDb *self,
|
||||
const char *id,
|
||||
FlatpakDbEntry *entry);
|
||||
void flatpak_db_update (FlatpakDb *self);
|
||||
GBytes * flatpak_db_get_content (FlatpakDb *self);
|
||||
const char * flatpak_db_get_path (FlatpakDb *self);
|
||||
gboolean flatpak_db_save_content (FlatpakDb *self,
|
||||
GError **error);
|
||||
void flatpak_db_save_content_async (FlatpakDb *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean flatpak_db_save_content_finish (FlatpakDb *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
void flatpak_db_set_path (FlatpakDb *self,
|
||||
const char *path);
|
||||
|
||||
|
||||
FlatpakDbEntry *flatpak_db_entry_ref (FlatpakDbEntry *entry);
|
||||
void flatpak_db_entry_unref (FlatpakDbEntry *entry);
|
||||
GVariant * flatpak_db_entry_get_data (FlatpakDbEntry *entry);
|
||||
const char ** flatpak_db_entry_list_apps (FlatpakDbEntry *entry);
|
||||
const char ** flatpak_db_entry_list_permissions (FlatpakDbEntry *entry,
|
||||
const char *app);
|
||||
gboolean flatpak_db_entry_has_permission (FlatpakDbEntry *entry,
|
||||
const char *app,
|
||||
const char *permission);
|
||||
gboolean flatpak_db_entry_has_permissions (FlatpakDbEntry *entry,
|
||||
const char *app,
|
||||
const char **permissions);
|
||||
GString * flatpak_db_entry_print_string (FlatpakDbEntry *entry,
|
||||
GString *string);
|
||||
|
||||
FlatpakDbEntry *flatpak_db_entry_new (GVariant *data);
|
||||
FlatpakDbEntry *flatpak_db_entry_modify_data (FlatpakDbEntry *entry,
|
||||
GVariant *data);
|
||||
FlatpakDbEntry *flatpak_db_entry_set_app_permissions (FlatpakDbEntry *entry,
|
||||
const char *app,
|
||||
const char **permissions);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDb, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDbEntry, flatpak_db_entry_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* FLATPAK_DB_H */
|
||||
@@ -43,7 +43,6 @@
|
||||
#include "flatpak-utils.h"
|
||||
#include "flatpak-dir.h"
|
||||
#include "flatpak-systemd-dbus.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "lib/flatpak-error.h"
|
||||
|
||||
/* We don't want to export paths pointing into these, because they are readonly
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#include "flatpak-utils.h"
|
||||
#include "flatpak-dir.h"
|
||||
#include "flatpak-systemd-dbus.h"
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
#include "lib/flatpak-error.h"
|
||||
|
||||
#define DEFAULT_SHELL "/bin/sh"
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include <libsoup/soup.h>
|
||||
#include "flatpak-dbus.h"
|
||||
#include "flatpak-document-dbus.h"
|
||||
#include <ostree.h>
|
||||
#include <json-glib/json-glib.h>
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
|
||||
typedef enum {
|
||||
FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV = 1 << 0,
|
||||
|
||||
2
common/gvdb/.gitignore
vendored
2
common/gvdb/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
libgvdb.a
|
||||
libgvdb-shared.a
|
||||
@@ -1,7 +0,0 @@
|
||||
DO NOT MODIFY ANY FILE IN THIS DIRECTORY
|
||||
|
||||
(except maybe the Makefile.am)
|
||||
|
||||
This directory is the result of a git subtree merge with the 'gvdb'
|
||||
module on git.gnome.org. Please apply fixes to the 'gvdb' module and
|
||||
perform a git merge.
|
||||
@@ -1,537 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "gvdb-builder.h"
|
||||
#include "gvdb-format.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <fcntl.h>
|
||||
#if !defined(G_OS_WIN32) || !defined(_MSC_VER)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct _GvdbItem
|
||||
{
|
||||
gchar *key;
|
||||
guint32 hash_value;
|
||||
guint32_le assigned_index;
|
||||
GvdbItem *parent;
|
||||
GvdbItem *sibling;
|
||||
GvdbItem *next;
|
||||
|
||||
/* one of:
|
||||
* this:
|
||||
*/
|
||||
GVariant *value;
|
||||
|
||||
/* this: */
|
||||
GHashTable *table;
|
||||
|
||||
/* or this: */
|
||||
GvdbItem *child;
|
||||
};
|
||||
|
||||
static void
|
||||
gvdb_item_free (gpointer data)
|
||||
{
|
||||
GvdbItem *item = data;
|
||||
|
||||
g_free (item->key);
|
||||
|
||||
if (item->value)
|
||||
g_variant_unref (item->value);
|
||||
|
||||
if (item->table)
|
||||
g_hash_table_unref (item->table);
|
||||
|
||||
g_slice_free (GvdbItem, item);
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
gvdb_hash_table_new (GHashTable *parent,
|
||||
const gchar *name_in_parent)
|
||||
{
|
||||
GHashTable *table;
|
||||
|
||||
table = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, gvdb_item_free);
|
||||
|
||||
if (parent)
|
||||
{
|
||||
GvdbItem *item;
|
||||
|
||||
item = gvdb_hash_table_insert (parent, name_in_parent);
|
||||
gvdb_item_set_hash_table (item, table);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static guint32
|
||||
djb_hash (const gchar *key)
|
||||
{
|
||||
guint32 hash_value = 5381;
|
||||
|
||||
while (*key)
|
||||
hash_value = hash_value * 33 + *(signed char *)key++;
|
||||
|
||||
return hash_value;
|
||||
}
|
||||
|
||||
GvdbItem *
|
||||
gvdb_hash_table_insert (GHashTable *table,
|
||||
const gchar *key)
|
||||
{
|
||||
GvdbItem *item;
|
||||
|
||||
item = g_slice_new0 (GvdbItem);
|
||||
item->key = g_strdup (key);
|
||||
item->hash_value = djb_hash (key);
|
||||
|
||||
g_hash_table_insert (table, g_strdup (key), item);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void
|
||||
gvdb_hash_table_insert_string (GHashTable *table,
|
||||
const gchar *key,
|
||||
const gchar *value)
|
||||
{
|
||||
GvdbItem *item;
|
||||
|
||||
item = gvdb_hash_table_insert (table, key);
|
||||
gvdb_item_set_value (item, g_variant_new_string (value));
|
||||
}
|
||||
|
||||
void
|
||||
gvdb_item_set_value (GvdbItem *item,
|
||||
GVariant *value)
|
||||
{
|
||||
g_return_if_fail (!item->value && !item->table && !item->child);
|
||||
|
||||
item->value = g_variant_ref_sink (value);
|
||||
}
|
||||
|
||||
void
|
||||
gvdb_item_set_hash_table (GvdbItem *item,
|
||||
GHashTable *table)
|
||||
{
|
||||
g_return_if_fail (!item->value && !item->table && !item->child);
|
||||
|
||||
item->table = g_hash_table_ref (table);
|
||||
}
|
||||
|
||||
void
|
||||
gvdb_item_set_parent (GvdbItem *item,
|
||||
GvdbItem *parent)
|
||||
{
|
||||
GvdbItem **node;
|
||||
|
||||
g_return_if_fail (g_str_has_prefix (item->key, parent->key));
|
||||
g_return_if_fail (!parent->value && !parent->table);
|
||||
g_return_if_fail (!item->parent && !item->sibling);
|
||||
|
||||
for (node = &parent->child; *node; node = &(*node)->sibling)
|
||||
if (strcmp ((*node)->key, item->key) > 0)
|
||||
break;
|
||||
|
||||
item->parent = parent;
|
||||
item->sibling = *node;
|
||||
*node = item;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GvdbItem **buckets;
|
||||
gint n_buckets;
|
||||
} HashTable;
|
||||
|
||||
static HashTable *
|
||||
hash_table_new (gint n_buckets)
|
||||
{
|
||||
HashTable *table;
|
||||
|
||||
table = g_slice_new (HashTable);
|
||||
table->buckets = g_new0 (GvdbItem *, n_buckets);
|
||||
table->n_buckets = n_buckets;
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void
|
||||
hash_table_free (HashTable *table)
|
||||
{
|
||||
g_free (table->buckets);
|
||||
|
||||
g_slice_free (HashTable, table);
|
||||
}
|
||||
|
||||
static void
|
||||
hash_table_insert (gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
guint32 hash_value, bucket;
|
||||
HashTable *table = data;
|
||||
GvdbItem *item = value;
|
||||
|
||||
hash_value = djb_hash (key);
|
||||
bucket = hash_value % table->n_buckets;
|
||||
item->next = table->buckets[bucket];
|
||||
table->buckets[bucket] = item;
|
||||
}
|
||||
|
||||
static guint32_le
|
||||
item_to_index (GvdbItem *item)
|
||||
{
|
||||
if (item != NULL)
|
||||
return item->assigned_index;
|
||||
|
||||
return guint32_to_le (-1u);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GQueue *chunks;
|
||||
guint64 offset;
|
||||
gboolean byteswap;
|
||||
} FileBuilder;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gsize offset;
|
||||
gsize size;
|
||||
gpointer data;
|
||||
} FileChunk;
|
||||
|
||||
static gpointer
|
||||
file_builder_allocate (FileBuilder *fb,
|
||||
guint alignment,
|
||||
gsize size,
|
||||
struct gvdb_pointer *pointer)
|
||||
{
|
||||
FileChunk *chunk;
|
||||
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
fb->offset += (-fb->offset) & (alignment - 1);
|
||||
chunk = g_slice_new (FileChunk);
|
||||
chunk->offset = fb->offset;
|
||||
chunk->size = size;
|
||||
chunk->data = g_malloc (size);
|
||||
|
||||
pointer->start = guint32_to_le (fb->offset);
|
||||
fb->offset += size;
|
||||
pointer->end = guint32_to_le (fb->offset);
|
||||
|
||||
g_queue_push_tail (fb->chunks, chunk);
|
||||
|
||||
return chunk->data;
|
||||
}
|
||||
|
||||
static void
|
||||
file_builder_add_value (FileBuilder *fb,
|
||||
GVariant *value,
|
||||
struct gvdb_pointer *pointer)
|
||||
{
|
||||
GVariant *variant, *normal;
|
||||
gpointer data;
|
||||
gsize size;
|
||||
|
||||
if (fb->byteswap)
|
||||
{
|
||||
value = g_variant_byteswap (value);
|
||||
variant = g_variant_new_variant (value);
|
||||
g_variant_unref (value);
|
||||
}
|
||||
else
|
||||
variant = g_variant_new_variant (value);
|
||||
|
||||
normal = g_variant_get_normal_form (variant);
|
||||
g_variant_unref (variant);
|
||||
|
||||
size = g_variant_get_size (normal);
|
||||
data = file_builder_allocate (fb, 8, size, pointer);
|
||||
g_variant_store (normal, data);
|
||||
g_variant_unref (normal);
|
||||
}
|
||||
|
||||
static void
|
||||
file_builder_add_string (FileBuilder *fb,
|
||||
const gchar *string,
|
||||
guint32_le *start,
|
||||
guint16_le *size)
|
||||
{
|
||||
FileChunk *chunk;
|
||||
gsize length;
|
||||
|
||||
length = strlen (string);
|
||||
|
||||
chunk = g_slice_new (FileChunk);
|
||||
chunk->offset = fb->offset;
|
||||
chunk->size = length;
|
||||
chunk->data = g_malloc (length);
|
||||
memcpy (chunk->data, string, length);
|
||||
|
||||
*start = guint32_to_le (fb->offset);
|
||||
*size = guint16_to_le (length);
|
||||
fb->offset += length;
|
||||
|
||||
g_queue_push_tail (fb->chunks, chunk);
|
||||
}
|
||||
|
||||
static void
|
||||
file_builder_allocate_for_hash (FileBuilder *fb,
|
||||
gsize n_buckets,
|
||||
gsize n_items,
|
||||
guint bloom_shift,
|
||||
gsize n_bloom_words,
|
||||
guint32_le **bloom_filter,
|
||||
guint32_le **hash_buckets,
|
||||
struct gvdb_hash_item **hash_items,
|
||||
struct gvdb_pointer *pointer)
|
||||
{
|
||||
guint32_le bloom_hdr, table_hdr;
|
||||
guchar *data;
|
||||
gsize size;
|
||||
|
||||
g_assert (n_bloom_words < (1u << 27));
|
||||
|
||||
bloom_hdr = guint32_to_le (bloom_shift << 27 | n_bloom_words);
|
||||
table_hdr = guint32_to_le (n_buckets);
|
||||
|
||||
size = sizeof bloom_hdr + sizeof table_hdr +
|
||||
n_bloom_words * sizeof (guint32_le) +
|
||||
n_buckets * sizeof (guint32_le) +
|
||||
n_items * sizeof (struct gvdb_hash_item);
|
||||
|
||||
data = file_builder_allocate (fb, 4, size, pointer);
|
||||
|
||||
#define chunk(s) (size -= (s), data += (s), data - (s))
|
||||
memcpy (chunk (sizeof bloom_hdr), &bloom_hdr, sizeof bloom_hdr);
|
||||
memcpy (chunk (sizeof table_hdr), &table_hdr, sizeof table_hdr);
|
||||
*bloom_filter = (guint32_le *) chunk (n_bloom_words * sizeof (guint32_le));
|
||||
*hash_buckets = (guint32_le *) chunk (n_buckets * sizeof (guint32_le));
|
||||
*hash_items = (struct gvdb_hash_item *) chunk (n_items *
|
||||
sizeof (struct gvdb_hash_item));
|
||||
g_assert (size == 0);
|
||||
#undef chunk
|
||||
|
||||
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
|
||||
file_builder_add_hash (FileBuilder *fb,
|
||||
GHashTable *table,
|
||||
struct gvdb_pointer *pointer)
|
||||
{
|
||||
guint32_le *buckets, *bloom_filter;
|
||||
struct gvdb_hash_item *items;
|
||||
HashTable *mytable;
|
||||
GvdbItem *item;
|
||||
guint32 index;
|
||||
gint bucket;
|
||||
|
||||
mytable = hash_table_new (g_hash_table_size (table));
|
||||
g_hash_table_foreach (table, hash_table_insert, mytable);
|
||||
index = 0;
|
||||
|
||||
for (bucket = 0; bucket < mytable->n_buckets; bucket++)
|
||||
for (item = mytable->buckets[bucket]; item; item = item->next)
|
||||
item->assigned_index = guint32_to_le (index++);
|
||||
|
||||
file_builder_allocate_for_hash (fb, mytable->n_buckets, index, 5, 0,
|
||||
&bloom_filter, &buckets, &items, pointer);
|
||||
|
||||
index = 0;
|
||||
for (bucket = 0; bucket < mytable->n_buckets; bucket++)
|
||||
{
|
||||
buckets[bucket] = guint32_to_le (index);
|
||||
|
||||
for (item = mytable->buckets[bucket]; item; item = item->next)
|
||||
{
|
||||
struct gvdb_hash_item *entry = items++;
|
||||
const gchar *basename;
|
||||
|
||||
g_assert (index == guint32_from_le (item->assigned_index));
|
||||
entry->hash_value = guint32_to_le (item->hash_value);
|
||||
entry->parent = item_to_index (item->parent);
|
||||
entry->unused = 0;
|
||||
|
||||
if (item->parent != NULL)
|
||||
basename = item->key + strlen (item->parent->key);
|
||||
else
|
||||
basename = item->key;
|
||||
|
||||
file_builder_add_string (fb, basename,
|
||||
&entry->key_start,
|
||||
&entry->key_size);
|
||||
|
||||
if (item->value != NULL)
|
||||
{
|
||||
g_assert (item->child == NULL && item->table == NULL);
|
||||
|
||||
file_builder_add_value (fb, item->value, &entry->value.pointer);
|
||||
entry->type = 'v';
|
||||
}
|
||||
|
||||
if (item->child != NULL)
|
||||
{
|
||||
guint32 children = 0, i = 0;
|
||||
guint32_le *offsets;
|
||||
GvdbItem *child;
|
||||
|
||||
g_assert (item->table == NULL);
|
||||
|
||||
for (child = item->child; child; child = child->sibling)
|
||||
children++;
|
||||
|
||||
offsets = file_builder_allocate (fb, 4, 4 * children,
|
||||
&entry->value.pointer);
|
||||
entry->type = 'L';
|
||||
|
||||
for (child = item->child; child; child = child->sibling)
|
||||
offsets[i++] = child->assigned_index;
|
||||
|
||||
g_assert (children == i);
|
||||
}
|
||||
|
||||
if (item->table != NULL)
|
||||
{
|
||||
entry->type = 'H';
|
||||
file_builder_add_hash (fb, item->table, &entry->value.pointer);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
hash_table_free (mytable);
|
||||
}
|
||||
|
||||
static FileBuilder *
|
||||
file_builder_new (gboolean byteswap)
|
||||
{
|
||||
FileBuilder *builder;
|
||||
|
||||
builder = g_slice_new (FileBuilder);
|
||||
builder->chunks = g_queue_new ();
|
||||
builder->offset = sizeof (struct gvdb_header);
|
||||
builder->byteswap = byteswap;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static GString *
|
||||
file_builder_serialise (FileBuilder *fb,
|
||||
struct gvdb_pointer root)
|
||||
{
|
||||
struct gvdb_header header = { { 0, }, };
|
||||
GString *result;
|
||||
|
||||
if (fb->byteswap)
|
||||
{
|
||||
header.signature[0] = GVDB_SWAPPED_SIGNATURE0;
|
||||
header.signature[1] = GVDB_SWAPPED_SIGNATURE1;
|
||||
}
|
||||
else
|
||||
{
|
||||
header.signature[0] = GVDB_SIGNATURE0;
|
||||
header.signature[1] = GVDB_SIGNATURE1;
|
||||
}
|
||||
|
||||
result = g_string_new (NULL);
|
||||
|
||||
header.root = root;
|
||||
g_string_append_len (result, (gpointer) &header, sizeof header);
|
||||
|
||||
while (!g_queue_is_empty (fb->chunks))
|
||||
{
|
||||
FileChunk *chunk = g_queue_pop_head (fb->chunks);
|
||||
|
||||
if (result->len != chunk->offset)
|
||||
{
|
||||
gchar zero[8] = { 0, };
|
||||
|
||||
g_assert (chunk->offset > result->len);
|
||||
g_assert (chunk->offset - result->len < 8);
|
||||
|
||||
g_string_append_len (result, zero, chunk->offset - result->len);
|
||||
g_assert (result->len == chunk->offset);
|
||||
}
|
||||
|
||||
g_string_append_len (result, chunk->data, chunk->size);
|
||||
g_free (chunk->data);
|
||||
|
||||
g_slice_free (FileChunk, chunk);
|
||||
}
|
||||
|
||||
g_queue_free (fb->chunks);
|
||||
g_slice_free (FileBuilder, fb);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
gvdb_table_get_content (GHashTable *table,
|
||||
gboolean byteswap)
|
||||
{
|
||||
struct gvdb_pointer root;
|
||||
FileBuilder *fb;
|
||||
GString *str;
|
||||
GBytes *res;
|
||||
|
||||
fb = file_builder_new (byteswap);
|
||||
file_builder_add_hash (fb, table, &root);
|
||||
str = file_builder_serialise (fb, root);
|
||||
|
||||
res = g_bytes_new_take (str->str, str->len);
|
||||
g_string_free (str, FALSE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gvdb_table_write_contents (GHashTable *table,
|
||||
const gchar *filename,
|
||||
gboolean byteswap,
|
||||
GError **error)
|
||||
{
|
||||
GBytes *content;
|
||||
gboolean status;
|
||||
|
||||
content = gvdb_table_get_content (table, byteswap);
|
||||
|
||||
status = g_file_set_contents (filename, g_bytes_get_data (content, NULL), g_bytes_get_size (content), error);
|
||||
|
||||
g_bytes_unref (content);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __gvdb_builder_h__
|
||||
#define __gvdb_builder_h__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
typedef struct _GvdbItem GvdbItem;
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GHashTable * gvdb_hash_table_new (GHashTable *parent,
|
||||
const gchar *key);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GvdbItem * gvdb_hash_table_insert (GHashTable *table,
|
||||
const gchar *key);
|
||||
G_GNUC_INTERNAL
|
||||
void gvdb_hash_table_insert_string (GHashTable *table,
|
||||
const gchar *key,
|
||||
const gchar *value);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void gvdb_item_set_value (GvdbItem *item,
|
||||
GVariant *value);
|
||||
G_GNUC_INTERNAL
|
||||
void gvdb_item_set_hash_table (GvdbItem *item,
|
||||
GHashTable *table);
|
||||
G_GNUC_INTERNAL
|
||||
void gvdb_item_set_parent (GvdbItem *item,
|
||||
GvdbItem *parent);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gvdb_table_write_contents (GHashTable *table,
|
||||
const gchar *filename,
|
||||
gboolean byteswap,
|
||||
GError **error);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GBytes * gvdb_table_get_content (GHashTable *table,
|
||||
gboolean byteswap);
|
||||
|
||||
|
||||
#endif /* __gvdb_builder_h__ */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __gvdb_format_h__
|
||||
#define __gvdb_format_h__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct { guint16 value; } guint16_le;
|
||||
typedef struct { guint32 value; } guint32_le;
|
||||
|
||||
struct gvdb_pointer {
|
||||
guint32_le start;
|
||||
guint32_le end;
|
||||
};
|
||||
|
||||
struct gvdb_hash_header {
|
||||
guint32_le n_bloom_words;
|
||||
guint32_le n_buckets;
|
||||
};
|
||||
|
||||
struct gvdb_hash_item {
|
||||
guint32_le hash_value;
|
||||
guint32_le parent;
|
||||
|
||||
guint32_le key_start;
|
||||
guint16_le key_size;
|
||||
gchar type;
|
||||
gchar unused;
|
||||
|
||||
union
|
||||
{
|
||||
struct gvdb_pointer pointer;
|
||||
gchar direct[8];
|
||||
} value;
|
||||
};
|
||||
|
||||
struct gvdb_header {
|
||||
guint32 signature[2];
|
||||
guint32_le version;
|
||||
guint32_le options;
|
||||
|
||||
struct gvdb_pointer root;
|
||||
};
|
||||
|
||||
static inline guint32_le guint32_to_le (guint32 value) {
|
||||
guint32_le result = { GUINT32_TO_LE (value) };
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline guint32 guint32_from_le (guint32_le value) {
|
||||
return GUINT32_FROM_LE (value.value);
|
||||
}
|
||||
|
||||
static inline guint16_le guint16_to_le (guint16 value) {
|
||||
guint16_le result = { GUINT16_TO_LE (value) };
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline guint16 guint16_from_le (guint16_le value) {
|
||||
return GUINT16_FROM_LE (value.value);
|
||||
}
|
||||
|
||||
#define GVDB_SIGNATURE0 1918981703
|
||||
#define GVDB_SIGNATURE1 1953390953
|
||||
#define GVDB_SWAPPED_SIGNATURE0 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE0)
|
||||
#define GVDB_SWAPPED_SIGNATURE1 GUINT32_SWAP_LE_BE (GVDB_SIGNATURE1)
|
||||
|
||||
#endif /* __gvdb_format_h__ */
|
||||
@@ -1,718 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "gvdb-reader.h"
|
||||
#include "gvdb-format.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct _GvdbTable {
|
||||
GBytes *bytes;
|
||||
|
||||
const gchar *data;
|
||||
gsize size;
|
||||
|
||||
gboolean byteswapped;
|
||||
gboolean trusted;
|
||||
|
||||
const guint32_le *bloom_words;
|
||||
guint32 n_bloom_words;
|
||||
guint bloom_shift;
|
||||
|
||||
const guint32_le *hash_buckets;
|
||||
guint32 n_buckets;
|
||||
|
||||
struct gvdb_hash_item *hash_items;
|
||||
guint32 n_hash_items;
|
||||
};
|
||||
|
||||
static const gchar *
|
||||
gvdb_table_item_get_key (GvdbTable *file,
|
||||
const struct gvdb_hash_item *item,
|
||||
gsize *size)
|
||||
{
|
||||
guint32 start, end;
|
||||
|
||||
start = guint32_from_le (item->key_start);
|
||||
*size = guint16_from_le (item->key_size);
|
||||
end = start + *size;
|
||||
|
||||
if G_UNLIKELY (start > end || end > file->size)
|
||||
return NULL;
|
||||
|
||||
return file->data + start;
|
||||
}
|
||||
|
||||
static gconstpointer
|
||||
gvdb_table_dereference (GvdbTable *file,
|
||||
const struct gvdb_pointer *pointer,
|
||||
gint alignment,
|
||||
gsize *size)
|
||||
{
|
||||
guint32 start, end;
|
||||
|
||||
start = guint32_from_le (pointer->start);
|
||||
end = guint32_from_le (pointer->end);
|
||||
|
||||
if G_UNLIKELY (start > end || end > file->size || start & (alignment - 1))
|
||||
return NULL;
|
||||
|
||||
*size = end - start;
|
||||
|
||||
return file->data + start;
|
||||
}
|
||||
|
||||
static void
|
||||
gvdb_table_setup_root (GvdbTable *file,
|
||||
const struct gvdb_pointer *pointer)
|
||||
{
|
||||
const struct gvdb_hash_header *header;
|
||||
guint32 n_bloom_words;
|
||||
guint32 n_buckets;
|
||||
gsize size;
|
||||
|
||||
header = gvdb_table_dereference (file, pointer, 4, &size);
|
||||
|
||||
if G_UNLIKELY (header == NULL || size < sizeof *header)
|
||||
return;
|
||||
|
||||
size -= sizeof *header;
|
||||
|
||||
n_bloom_words = guint32_from_le (header->n_bloom_words);
|
||||
n_buckets = guint32_from_le (header->n_buckets);
|
||||
n_bloom_words &= (1u << 27) - 1;
|
||||
|
||||
if G_UNLIKELY (n_bloom_words * sizeof (guint32_le) > size)
|
||||
return;
|
||||
|
||||
file->bloom_words = (gpointer) (header + 1);
|
||||
size -= n_bloom_words * sizeof (guint32_le);
|
||||
file->n_bloom_words = n_bloom_words;
|
||||
|
||||
if G_UNLIKELY (n_buckets > G_MAXUINT / sizeof (guint32_le) ||
|
||||
n_buckets * sizeof (guint32_le) > size)
|
||||
return;
|
||||
|
||||
file->hash_buckets = file->bloom_words + file->n_bloom_words;
|
||||
size -= n_buckets * sizeof (guint32_le);
|
||||
file->n_buckets = n_buckets;
|
||||
|
||||
if G_UNLIKELY (size % sizeof (struct gvdb_hash_item))
|
||||
return;
|
||||
|
||||
file->hash_items = (gpointer) (file->hash_buckets + n_buckets);
|
||||
file->n_hash_items = size / sizeof (struct gvdb_hash_item);
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_new_from_bytes:
|
||||
* @bytes: the #GBytes with the data
|
||||
* @trusted: if the contents of @bytes are trusted
|
||||
* @error: %NULL, or a pointer to a %NULL #GError
|
||||
* @returns: a new #GvdbTable
|
||||
*
|
||||
* Creates a new #GvdbTable from the contents of @bytes.
|
||||
*
|
||||
* This call can fail if the header contained in @bytes is invalid.
|
||||
*
|
||||
* You should call gvdb_table_free() on the return result when you no
|
||||
* longer require it.
|
||||
**/
|
||||
GvdbTable *
|
||||
gvdb_table_new_from_bytes (GBytes *bytes,
|
||||
gboolean trusted,
|
||||
GError **error)
|
||||
{
|
||||
const struct gvdb_header *header;
|
||||
GvdbTable *file;
|
||||
|
||||
file = g_slice_new0 (GvdbTable);
|
||||
file->bytes = g_bytes_ref (bytes);
|
||||
file->data = g_bytes_get_data (bytes, &file->size);
|
||||
file->trusted = trusted;
|
||||
|
||||
if (file->size < sizeof (struct gvdb_header))
|
||||
goto invalid;
|
||||
|
||||
header = (gpointer) file->data;
|
||||
|
||||
if (header->signature[0] == GVDB_SIGNATURE0 &&
|
||||
header->signature[1] == GVDB_SIGNATURE1 &&
|
||||
guint32_from_le (header->version) == 0)
|
||||
file->byteswapped = FALSE;
|
||||
|
||||
else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 &&
|
||||
header->signature[1] == GVDB_SWAPPED_SIGNATURE1 &&
|
||||
guint32_from_le (header->version) == 0)
|
||||
file->byteswapped = TRUE;
|
||||
|
||||
else
|
||||
goto invalid;
|
||||
|
||||
gvdb_table_setup_root (file, &header->root);
|
||||
|
||||
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:
|
||||
* @filename: a filename
|
||||
* @trusted: if the contents of @bytes are trusted
|
||||
* @error: %NULL, or a pointer to a %NULL #GError
|
||||
* @returns: a new #GvdbTable
|
||||
*
|
||||
* Creates a new #GvdbTable using the #GMappedFile for @filename as the
|
||||
* #GBytes.
|
||||
**/
|
||||
GvdbTable *
|
||||
gvdb_table_new (const gchar *filename,
|
||||
gboolean trusted,
|
||||
GError **error)
|
||||
{
|
||||
GMappedFile *mapped;
|
||||
GvdbTable *table;
|
||||
GBytes *bytes;
|
||||
|
||||
mapped = g_mapped_file_new (filename, FALSE, error);
|
||||
if (!mapped)
|
||||
return NULL;
|
||||
|
||||
bytes = g_mapped_file_get_bytes (mapped);
|
||||
table = gvdb_table_new_from_bytes (bytes, trusted, error);
|
||||
g_mapped_file_unref (mapped);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
g_prefix_error (error, "%s: ", filename);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gvdb_table_bloom_filter (GvdbTable *file,
|
||||
guint32 hash_value)
|
||||
{
|
||||
guint32 word, mask;
|
||||
|
||||
if (file->n_bloom_words == 0)
|
||||
return TRUE;
|
||||
|
||||
word = (hash_value / 32) % file->n_bloom_words;
|
||||
mask = 1 << (hash_value & 31);
|
||||
mask |= 1 << ((hash_value >> file->bloom_shift) & 31);
|
||||
|
||||
return (guint32_from_le (file->bloom_words[word]) & mask) == mask;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gvdb_table_check_name (GvdbTable *file,
|
||||
struct gvdb_hash_item *item,
|
||||
const gchar *key,
|
||||
guint key_length)
|
||||
{
|
||||
const gchar *this_key;
|
||||
gsize this_size;
|
||||
guint32 parent;
|
||||
|
||||
this_key = gvdb_table_item_get_key (file, item, &this_size);
|
||||
|
||||
if G_UNLIKELY (this_key == NULL || this_size > key_length)
|
||||
return FALSE;
|
||||
|
||||
key_length -= this_size;
|
||||
|
||||
if G_UNLIKELY (memcmp (this_key, key + key_length, this_size) != 0)
|
||||
return FALSE;
|
||||
|
||||
parent = guint32_from_le (item->parent);
|
||||
if (key_length == 0 && parent == 0xffffffffu)
|
||||
return TRUE;
|
||||
|
||||
if G_LIKELY (parent < file->n_hash_items && this_size > 0)
|
||||
return gvdb_table_check_name (file,
|
||||
&file->hash_items[parent],
|
||||
key, key_length);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static const struct gvdb_hash_item *
|
||||
gvdb_table_lookup (GvdbTable *file,
|
||||
const gchar *key,
|
||||
gchar type)
|
||||
{
|
||||
guint32 hash_value = 5381;
|
||||
guint key_length;
|
||||
guint32 bucket;
|
||||
guint32 lastno;
|
||||
guint32 itemno;
|
||||
|
||||
if G_UNLIKELY (file->n_buckets == 0 || file->n_hash_items == 0)
|
||||
return NULL;
|
||||
|
||||
for (key_length = 0; key[key_length]; key_length++)
|
||||
hash_value = (hash_value * 33) + ((signed char *) key)[key_length];
|
||||
|
||||
if (!gvdb_table_bloom_filter (file, hash_value))
|
||||
return NULL;
|
||||
|
||||
bucket = hash_value % file->n_buckets;
|
||||
itemno = guint32_from_le (file->hash_buckets[bucket]);
|
||||
|
||||
if (bucket == file->n_buckets - 1 ||
|
||||
(lastno = guint32_from_le(file->hash_buckets[bucket + 1])) > file->n_hash_items)
|
||||
lastno = file->n_hash_items;
|
||||
|
||||
while G_LIKELY (itemno < lastno)
|
||||
{
|
||||
struct gvdb_hash_item *item = &file->hash_items[itemno];
|
||||
|
||||
if (hash_value == guint32_from_le (item->hash_value))
|
||||
if G_LIKELY (gvdb_table_check_name (file, item, key, key_length))
|
||||
if G_LIKELY (item->type == type)
|
||||
return item;
|
||||
|
||||
itemno++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gvdb_table_list_from_item (GvdbTable *table,
|
||||
const struct gvdb_hash_item *item,
|
||||
const guint32_le **list,
|
||||
guint *length)
|
||||
{
|
||||
gsize size;
|
||||
|
||||
*list = gvdb_table_dereference (table, &item->value.pointer, 4, &size);
|
||||
|
||||
if G_LIKELY (*list == NULL || size % 4)
|
||||
return FALSE;
|
||||
|
||||
*length = size / 4;
|
||||
|
||||
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:
|
||||
* @file: a #GvdbTable
|
||||
* @key: a string
|
||||
* @returns: a %NULL-terminated string array
|
||||
*
|
||||
* List all of the keys that appear below @key. The nesting of keys
|
||||
* within the hash file is defined by the program that created the hash
|
||||
* file. One thing is constant: each item in the returned array can be
|
||||
* concatenated to @key to obtain the full name of that key.
|
||||
*
|
||||
* It is not possible to tell from this function if a given key is
|
||||
* itself a path, a value, or another hash table; you are expected to
|
||||
* know this for yourself.
|
||||
*
|
||||
* You should call g_strfreev() on the return result when you no longer
|
||||
* require it.
|
||||
**/
|
||||
gchar **
|
||||
gvdb_table_list (GvdbTable *file,
|
||||
const gchar *key)
|
||||
{
|
||||
const struct gvdb_hash_item *item;
|
||||
const guint32_le *list;
|
||||
gchar **strv;
|
||||
guint length;
|
||||
guint i;
|
||||
|
||||
if ((item = gvdb_table_lookup (file, key, 'L')) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!gvdb_table_list_from_item (file, item, &list, &length))
|
||||
return NULL;
|
||||
|
||||
strv = g_new (gchar *, length + 1);
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
guint32 itemno = guint32_from_le (list[i]);
|
||||
|
||||
if (itemno < file->n_hash_items)
|
||||
{
|
||||
const struct gvdb_hash_item *item;
|
||||
const gchar *string;
|
||||
gsize strsize;
|
||||
|
||||
item = file->hash_items + itemno;
|
||||
|
||||
string = gvdb_table_item_get_key (file, item, &strsize);
|
||||
|
||||
if (string != NULL)
|
||||
strv[i] = g_strndup (string, strsize);
|
||||
else
|
||||
strv[i] = g_malloc0 (1);
|
||||
}
|
||||
else
|
||||
strv[i] = g_malloc0 (1);
|
||||
}
|
||||
|
||||
strv[i] = NULL;
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_has_value:
|
||||
* @file: a #GvdbTable
|
||||
* @key: a string
|
||||
* @returns: %TRUE if @key is in the table
|
||||
*
|
||||
* Checks for a value named @key in @file.
|
||||
*
|
||||
* Note: this function does not consider non-value nodes (other hash
|
||||
* tables, for example).
|
||||
**/
|
||||
gboolean
|
||||
gvdb_table_has_value (GvdbTable *file,
|
||||
const gchar *key)
|
||||
{
|
||||
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 *
|
||||
gvdb_table_value_from_item (GvdbTable *table,
|
||||
const struct gvdb_hash_item *item)
|
||||
{
|
||||
GVariant *variant, *value;
|
||||
gconstpointer data;
|
||||
GBytes *bytes;
|
||||
gsize size;
|
||||
|
||||
data = gvdb_table_dereference (table, &item->value.pointer, 8, &size);
|
||||
|
||||
if G_UNLIKELY (data == NULL)
|
||||
return NULL;
|
||||
|
||||
bytes = g_bytes_new_from_bytes (table->bytes, ((gchar *) data) - table->data, size);
|
||||
variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, bytes, table->trusted);
|
||||
value = g_variant_get_variant (variant);
|
||||
g_variant_unref (variant);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_get_value:
|
||||
* @file: a #GvdbTable
|
||||
* @key: a string
|
||||
* @returns: a #GVariant, or %NULL
|
||||
*
|
||||
* Looks up a value named @key in @file.
|
||||
*
|
||||
* If the value is not found then %NULL is returned. Otherwise, a new
|
||||
* #GVariant instance is returned. The #GVariant does not depend on the
|
||||
* continued existence of @file.
|
||||
*
|
||||
* You should call g_variant_unref() on the return result when you no
|
||||
* longer require it.
|
||||
**/
|
||||
GVariant *
|
||||
gvdb_table_get_value (GvdbTable *file,
|
||||
const gchar *key)
|
||||
{
|
||||
const struct gvdb_hash_item *item;
|
||||
GVariant *value;
|
||||
|
||||
if ((item = gvdb_table_lookup (file, key, 'v')) == NULL)
|
||||
return NULL;
|
||||
|
||||
value = gvdb_table_value_from_item (file, item);
|
||||
|
||||
if (value && file->byteswapped)
|
||||
{
|
||||
GVariant *tmp;
|
||||
|
||||
tmp = g_variant_byteswap (value);
|
||||
g_variant_unref (value);
|
||||
value = tmp;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_get_raw_value:
|
||||
* @table: a #GvdbTable
|
||||
* @key: a string
|
||||
* @returns: a #GVariant, or %NULL
|
||||
*
|
||||
* Looks up a value named @key in @file.
|
||||
*
|
||||
* This call is equivalent to gvdb_table_get_value() except that it
|
||||
* never byteswaps the value.
|
||||
**/
|
||||
GVariant *
|
||||
gvdb_table_get_raw_value (GvdbTable *table,
|
||||
const gchar *key)
|
||||
{
|
||||
const struct gvdb_hash_item *item;
|
||||
|
||||
if ((item = gvdb_table_lookup (table, key, 'v')) == NULL)
|
||||
return NULL;
|
||||
|
||||
return gvdb_table_value_from_item (table, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_get_table:
|
||||
* @file: a #GvdbTable
|
||||
* @key: a string
|
||||
* @returns: a new #GvdbTable, or %NULL
|
||||
*
|
||||
* Looks up the hash table named @key in @file.
|
||||
*
|
||||
* The toplevel hash table in a #GvdbTable can contain reference to
|
||||
* child hash tables (and those can contain further references...).
|
||||
*
|
||||
* If @key is not found in @file then %NULL is returned. Otherwise, a
|
||||
* new #GvdbTable is returned, referring to the child hashtable as
|
||||
* contained in the file. This newly-created #GvdbTable does not depend
|
||||
* on the continued existence of @file.
|
||||
*
|
||||
* You should call gvdb_table_free() on the return result when you no
|
||||
* longer require it.
|
||||
**/
|
||||
GvdbTable *
|
||||
gvdb_table_get_table (GvdbTable *file,
|
||||
const gchar *key)
|
||||
{
|
||||
const struct gvdb_hash_item *item;
|
||||
GvdbTable *new;
|
||||
|
||||
item = gvdb_table_lookup (file, key, 'H');
|
||||
|
||||
if (item == NULL)
|
||||
return NULL;
|
||||
|
||||
new = g_slice_new0 (GvdbTable);
|
||||
new->bytes = g_bytes_ref (file->bytes);
|
||||
new->byteswapped = file->byteswapped;
|
||||
new->trusted = file->trusted;
|
||||
new->data = file->data;
|
||||
new->size = file->size;
|
||||
|
||||
gvdb_table_setup_root (new, &item->value.pointer);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_free:
|
||||
* @file: a #GvdbTable
|
||||
*
|
||||
* Frees @file.
|
||||
**/
|
||||
void
|
||||
gvdb_table_free (GvdbTable *file)
|
||||
{
|
||||
g_bytes_unref (file->bytes);
|
||||
g_slice_free (GvdbTable, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* gvdb_table_is_valid:
|
||||
* @table: a #GvdbTable
|
||||
* @returns: %TRUE if @table is still valid
|
||||
*
|
||||
* Checks if the table is still valid.
|
||||
*
|
||||
* An on-disk GVDB can be marked as invalid. This happens when the file
|
||||
* has been replaced. The appropriate action is typically to reopen the
|
||||
* file.
|
||||
**/
|
||||
gboolean
|
||||
gvdb_table_is_valid (GvdbTable *table)
|
||||
{
|
||||
return !!*table->data;
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2010 Codethink Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the licence, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#ifndef __gvdb_reader_h__
|
||||
#define __gvdb_reader_h__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct _GvdbTable GvdbTable;
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GvdbTable * gvdb_table_new_from_bytes (GBytes *bytes,
|
||||
gboolean trusted,
|
||||
GError **error);
|
||||
G_GNUC_INTERNAL
|
||||
GvdbTable * gvdb_table_new (const gchar *filename,
|
||||
gboolean trusted,
|
||||
GError **error);
|
||||
G_GNUC_INTERNAL
|
||||
void gvdb_table_free (GvdbTable *table);
|
||||
G_GNUC_INTERNAL
|
||||
gchar ** gvdb_table_get_names (GvdbTable *table,
|
||||
gint *length);
|
||||
G_GNUC_INTERNAL
|
||||
gchar ** gvdb_table_list (GvdbTable *table,
|
||||
const gchar *key);
|
||||
G_GNUC_INTERNAL
|
||||
GvdbTable * gvdb_table_get_table (GvdbTable *table,
|
||||
const gchar *key);
|
||||
G_GNUC_INTERNAL
|
||||
GVariant * gvdb_table_get_raw_value (GvdbTable *table,
|
||||
const gchar *key);
|
||||
G_GNUC_INTERNAL
|
||||
GVariant * gvdb_table_get_value (GvdbTable *table,
|
||||
const gchar *key);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gvdb_table_has_value (GvdbTable *table,
|
||||
const gchar *key);
|
||||
G_GNUC_INTERNAL
|
||||
gboolean gvdb_table_is_valid (GvdbTable *table);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __gvdb_reader_h__ */
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
|
||||
<Project xmlns='http://usefulinc.com/ns/doap#'
|
||||
xmlns:foaf='http://xmlns.com/foaf/0.1/'
|
||||
xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
|
||||
xmlns:gnome='http://api.gnome.org/doap-extensions#'>
|
||||
|
||||
<name xml:lang='en'>gvdb</name>
|
||||
<shortdesc xml:lang='en'>GVariant Database file</shortdesc>
|
||||
<description xml:lang='en'>
|
||||
A simple database file format that stores a mapping from strings to
|
||||
GVariant values in a way that is extremely efficient for lookups.
|
||||
|
||||
The database is written once and can not be modified.
|
||||
|
||||
Included here is reader code and a first-pass implementation of a
|
||||
writer (that does not currently produce particularly optimised
|
||||
output).
|
||||
|
||||
It is intended that this code be used by copy-pasting into your
|
||||
project or by making use of git-merge(1).
|
||||
</description>
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Ryan Lortie</foaf:name>
|
||||
<foaf:mbox rdf:resource='mailto:desrt@desrt.ca'/>
|
||||
<gnome:userid>ryanl</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
|
||||
</Project>
|
||||
@@ -1,13 +1,10 @@
|
||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||
introspection_DATA = \
|
||||
data/org.freedesktop.impl.portal.PermissionStore.xml \
|
||||
data/org.freedesktop.portal.Documents.xml \
|
||||
data/org.freedesktop.Flatpak.xml \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST += \
|
||||
data/org.freedesktop.portal.Documents.xml \
|
||||
data/org.freedesktop.impl.portal.PermissionStore.xml \
|
||||
data/org.freedesktop.systemd1.xml \
|
||||
data/org.freedesktop.Flatpak.xml \
|
||||
$(NULL)
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
|
||||
<!--
|
||||
Copyright (C) 2015 Red Hat, Inc.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General
|
||||
Public License along with this library; if not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
Boston, MA 02110-1301, USA.
|
||||
|
||||
Author: Alexander Larsson <alexl@redhat.com>
|
||||
-->
|
||||
|
||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<!--
|
||||
org.freedesktop.impl.portal.PermissionStore:
|
||||
@short_description: Database to store permissions
|
||||
|
||||
The permission store can be used by portals to store permissions
|
||||
that sandboxed applications have to various resources, such as
|
||||
files outside the sandbox.
|
||||
|
||||
Since the resources managed by portals can be varied, the permission
|
||||
store is fairly free-form: there can be multiple tables; resources are
|
||||
identified by an ID, as are applications, and permissions are stored as
|
||||
string arrays. None of these strings are interpreted by the permission
|
||||
store in any way.
|
||||
|
||||
In addition, the permission store allows to associate extra data
|
||||
(in the form of a GVariant) with each resource.
|
||||
-->
|
||||
<interface name='org.freedesktop.impl.portal.PermissionStore'>
|
||||
<property name="version" type="u" access="read"/>
|
||||
|
||||
<!--
|
||||
Lookup:
|
||||
@table: the name of the table to use
|
||||
@id: the resource ID to look up
|
||||
@permissions: map from application ID to permissions
|
||||
@data: data that is associated with the resource
|
||||
|
||||
Looks up the entry for a resource in one of the tables and returns
|
||||
all associated application permissions and data.
|
||||
-->
|
||||
<method name="Lookup">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='id' type='s' direction='in'/>
|
||||
<arg name='permissions' type='a{sas}' direction='out'/>
|
||||
<arg name='data' type='v' direction='out'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Set:
|
||||
@table: the name of the table to use
|
||||
@create: whether to create the table if it does not exist
|
||||
@id: the resource ID to modify
|
||||
@app_permissions: map from application ID to permissions
|
||||
@data: data to associate with the resource
|
||||
|
||||
Writes the entry for a resource in the given table.
|
||||
-->
|
||||
<method name="Set">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='create' type='b' direction='in'/>
|
||||
<arg name='id' type='s' direction='in'/>
|
||||
<arg name='app_permissions' type='a{sas}' direction='in'/>
|
||||
<arg name='data' type='v' direction='in'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Delete:
|
||||
@table: the name of the table to use
|
||||
@id: the resource ID to delete
|
||||
|
||||
Removes the entry for a resource in the given table.
|
||||
-->
|
||||
<method name="Delete">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='id' type='s' direction='in'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
SetValue:
|
||||
@table: the name of the table to use
|
||||
@create: whether to create the table if it does not exist
|
||||
@id: the resource ID to modify
|
||||
@data: data to associate with the resource
|
||||
|
||||
Sets just the data for a resource in the given table.
|
||||
-->
|
||||
<method name="SetValue">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='create' type='b' direction='in'/>
|
||||
<arg name='id' type='s' direction='in'/>
|
||||
<arg name='data' type='v' direction='in'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
SetPermission:
|
||||
@table: the name of the table to use
|
||||
@create: whether to create the table if it does not exist
|
||||
@id: the resource ID to modify
|
||||
@app: the application ID to modify
|
||||
@permissions: permissions to set
|
||||
|
||||
Sets the permissions for an application and a resource
|
||||
in the given table.
|
||||
-->
|
||||
<method name="SetPermission">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='create' type='b' direction='in'/>
|
||||
<arg name='id' type='s' direction='in'/>
|
||||
<arg name='app' type='s' direction='in'/>
|
||||
<arg name='permissions' type='as' direction='in'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
List:
|
||||
@table: the name of the table to use
|
||||
@ids: IDs of all resources that are present in the table
|
||||
|
||||
Returns all the resources that are present in the table.
|
||||
-->
|
||||
<method name="List">
|
||||
<arg name='table' type='s' direction='in'/>
|
||||
<arg name='ids' type='as' direction='out'/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Changed:
|
||||
@table: the name of the table
|
||||
@ids: IDs of the changed resource
|
||||
@deleted: whether the resource was deleted
|
||||
@data: the data that is associated the resource
|
||||
@permissions: the permissions that are associated with the resource
|
||||
|
||||
The Changed signal is emitted when the entry for a resource
|
||||
is modified or deleted. If the entry was deleted, then @data
|
||||
and @permissions contain the last values that were found in the
|
||||
database. If the entry was modified, they contain the new values.
|
||||
-->
|
||||
<signal name="Changed">
|
||||
<arg name='table' type='s' direction='out'/>
|
||||
<arg name='id' type='s' direction='out'/>
|
||||
<arg name='deleted' type='b' direction='out'/>
|
||||
<arg name='data' type='v' direction='out'/>
|
||||
<arg name='permissions' type='a{sas}' direction='out'/>
|
||||
</signal>
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
@@ -1,43 +0,0 @@
|
||||
libexec_PROGRAMS += \
|
||||
xdg-document-portal \
|
||||
$(NULL)
|
||||
|
||||
xdp_dbus_built_sources = document-portal/xdp-dbus.c document-portal/xdp-dbus.h
|
||||
BUILT_SOURCES += $(xdp_dbus_built_sources)
|
||||
|
||||
document-portal/xdp-dbus.c: data/org.freedesktop.portal.Documents.xml Makefile
|
||||
mkdir -p $(builddir)/document-portal
|
||||
$(AM_V_GEN) $(GDBUS_CODEGEN) \
|
||||
--interface-prefix org.freedesktop.portal. \
|
||||
--c-namespace XdpDbus \
|
||||
--generate-c-code $(builddir)/document-portal/xdp-dbus \
|
||||
--annotate "org.freedesktop.portal.Documents.Add()" org.gtk.GDBus.C.UnixFD "yes" \
|
||||
--annotate "org.freedesktop.portal.Documents.AddFull()" org.gtk.GDBus.C.UnixFD "yes" \
|
||||
$(srcdir)/data/org.freedesktop.portal.Documents.xml \
|
||||
$(NULL)
|
||||
|
||||
document-portal/%-dbus.h: document-portal/%-dbus.c
|
||||
@true # Built as a side-effect of the rules for the .c
|
||||
|
||||
service_in_files += document-portal/xdg-document-portal.service.in
|
||||
systemduserunit_DATA += document-portal/xdg-document-portal.service
|
||||
|
||||
service_in_files += document-portal/org.freedesktop.portal.Documents.service.in
|
||||
dbus_service_DATA += document-portal/org.freedesktop.portal.Documents.service
|
||||
|
||||
nodist_xdg_document_portal_SOURCES = \
|
||||
$(xdp_dbus_built_sources) \
|
||||
$(ps_dbus_built_sources) \
|
||||
$(NULL)
|
||||
|
||||
xdg_document_portal_SOURCES = \
|
||||
document-portal/xdp-main.c \
|
||||
document-portal/xdp-enums.h \
|
||||
document-portal/xdp-util.h \
|
||||
document-portal/xdp-util.c \
|
||||
document-portal/xdp-fuse.h \
|
||||
document-portal/xdp-fuse.c \
|
||||
$(NULL)
|
||||
|
||||
xdg_document_portal_LDADD = $(AM_LDADD) $(BASE_LIBS) $(FUSE_LIBS) libflatpak-common.la
|
||||
xdg_document_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(FUSE_CFLAGS) -I$(srcdir)/document-portal -I$(builddir)/document-portal -I$(srcdir)/permission-store -I$(builddir)/permission-store -DFLATPAK_COMPILATION
|
||||
@@ -1,4 +0,0 @@
|
||||
[D-BUS Service]
|
||||
Name=org.freedesktop.portal.Documents
|
||||
Exec=@libexecdir@/xdg-document-portal
|
||||
SystemdService=xdg-document-portal.service
|
||||
@@ -1,7 +0,0 @@
|
||||
[Unit]
|
||||
Description=flatpak document portal service
|
||||
|
||||
[Service]
|
||||
BusName=org.freedesktop.portal.Documents
|
||||
ExecStart=@libexecdir@/xdg-document-portal
|
||||
Type=dbus
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef XDP_ENUMS_H
|
||||
#define XDP_ENUMS_H
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
XDP_PERMISSION_FLAGS_READ = (1 << 0),
|
||||
XDP_PERMISSION_FLAGS_WRITE = (1 << 1),
|
||||
XDP_PERMISSION_FLAGS_GRANT_PERMISSIONS = (1 << 2),
|
||||
XDP_PERMISSION_FLAGS_DELETE = (1 << 3),
|
||||
|
||||
XDP_PERMISSION_FLAGS_ALL = ((1 << 4) - 1)
|
||||
} XdpPermissionFlags;
|
||||
|
||||
typedef enum {
|
||||
XDP_ADD_FLAGS_REUSE_EXISTING = (1 << 0),
|
||||
XDP_ADD_FLAGS_PERSISTENT = (1 << 1),
|
||||
XDP_ADD_FLAGS_AS_NEEDED_BY_APP = (1 << 2),
|
||||
|
||||
XDP_ADD_FLAGS_FLAGS_ALL = ((1 << 3) - 1)
|
||||
} XdpAddFullFlags;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XDP_ENUMS_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
#ifndef XDP_FUSE_H
|
||||
#define XDP_FUSE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "flatpak-db.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
char ** xdp_list_apps (void);
|
||||
char ** xdp_list_docs (void);
|
||||
FlatpakDbEntry *xdp_lookup_doc (const char *doc_id);
|
||||
|
||||
gboolean xdp_fuse_init (GError **error);
|
||||
void xdp_fuse_exit (void);
|
||||
const char *xdp_fuse_get_mountpoint (void);
|
||||
void xdp_fuse_invalidate_doc_app (const char *doc_id,
|
||||
const char *opt_app_id);
|
||||
char *xdp_fuse_lookup_id_for_inode (ino_t inode);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XDP_FUSE_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <gio/gio.h>
|
||||
#include "flatpak-portal-error.h"
|
||||
#include "xdp-util.h"
|
||||
|
||||
const char **
|
||||
xdg_unparse_permissions (XdpPermissionFlags permissions)
|
||||
{
|
||||
GPtrArray *array;
|
||||
|
||||
array = g_ptr_array_new ();
|
||||
|
||||
if (permissions & XDP_PERMISSION_FLAGS_READ)
|
||||
g_ptr_array_add (array, "read");
|
||||
if (permissions & XDP_PERMISSION_FLAGS_WRITE)
|
||||
g_ptr_array_add (array, "write");
|
||||
if (permissions & XDP_PERMISSION_FLAGS_GRANT_PERMISSIONS)
|
||||
g_ptr_array_add (array, "grant-permissions");
|
||||
if (permissions & XDP_PERMISSION_FLAGS_DELETE)
|
||||
g_ptr_array_add (array, "delete");
|
||||
|
||||
g_ptr_array_add (array, NULL);
|
||||
return (const char **) g_ptr_array_free (array, FALSE);
|
||||
}
|
||||
|
||||
XdpPermissionFlags
|
||||
xdp_parse_permissions (const char **permissions)
|
||||
{
|
||||
XdpPermissionFlags perms;
|
||||
int i;
|
||||
|
||||
perms = 0;
|
||||
for (i = 0; permissions[i]; i++)
|
||||
{
|
||||
if (strcmp (permissions[i], "read") == 0)
|
||||
perms |= XDP_PERMISSION_FLAGS_READ;
|
||||
else if (strcmp (permissions[i], "write") == 0)
|
||||
perms |= XDP_PERMISSION_FLAGS_WRITE;
|
||||
else if (strcmp (permissions[i], "grant-permissions") == 0)
|
||||
perms |= XDP_PERMISSION_FLAGS_GRANT_PERMISSIONS;
|
||||
else if (strcmp (permissions[i], "delete") == 0)
|
||||
perms |= XDP_PERMISSION_FLAGS_DELETE;
|
||||
else
|
||||
g_warning ("No such permission: %s", permissions[i]);
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
XdpPermissionFlags
|
||||
xdp_entry_get_permissions (FlatpakDbEntry *entry,
|
||||
const char *app_id)
|
||||
{
|
||||
g_autofree const char **permissions = NULL;
|
||||
|
||||
if (strcmp (app_id, "") == 0)
|
||||
return XDP_PERMISSION_FLAGS_ALL;
|
||||
|
||||
permissions = flatpak_db_entry_list_permissions (entry, app_id);
|
||||
return xdp_parse_permissions (permissions);
|
||||
}
|
||||
|
||||
gboolean
|
||||
xdp_entry_has_permissions (FlatpakDbEntry *entry,
|
||||
const char *app_id,
|
||||
XdpPermissionFlags perms)
|
||||
{
|
||||
XdpPermissionFlags current_perms;
|
||||
|
||||
current_perms = xdp_entry_get_permissions (entry, app_id);
|
||||
|
||||
return (current_perms & perms) == perms;
|
||||
}
|
||||
|
||||
char *
|
||||
xdp_name_from_id (guint32 doc_id)
|
||||
{
|
||||
return g_strdup_printf ("%x", doc_id);
|
||||
}
|
||||
|
||||
const char *
|
||||
xdp_entry_get_path (FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) v = flatpak_db_entry_get_data (entry);
|
||||
g_autoptr(GVariant) c = g_variant_get_child_value (v, 0);
|
||||
return g_variant_get_bytestring (c);
|
||||
}
|
||||
|
||||
char *
|
||||
xdp_entry_dup_basename (FlatpakDbEntry *entry)
|
||||
{
|
||||
const char *path = xdp_entry_get_path (entry);
|
||||
|
||||
return g_path_get_basename (path);
|
||||
}
|
||||
|
||||
char *
|
||||
xdp_entry_dup_dirname (FlatpakDbEntry *entry)
|
||||
{
|
||||
const char *path = xdp_entry_get_path (entry);
|
||||
|
||||
return g_path_get_dirname (path);
|
||||
}
|
||||
|
||||
guint64
|
||||
xdp_entry_get_device (FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) v = flatpak_db_entry_get_data (entry);
|
||||
g_autoptr(GVariant) c = g_variant_get_child_value (v, 1);
|
||||
return g_variant_get_uint64 (c);
|
||||
}
|
||||
|
||||
guint64
|
||||
xdp_entry_get_inode (FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) v = flatpak_db_entry_get_data (entry);
|
||||
g_autoptr(GVariant) c = g_variant_get_child_value (v, 2);
|
||||
return g_variant_get_uint64 (c);
|
||||
}
|
||||
|
||||
guint32
|
||||
xdp_entry_get_flags (FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) v = flatpak_db_entry_get_data (entry);
|
||||
g_autoptr(GVariant) c = g_variant_get_child_value (v, 3);
|
||||
return g_variant_get_uint32 (c);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef XDP_UTIL_H
|
||||
#define XDP_UTIL_H
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "flatpak-db.h"
|
||||
#include "xdp-enums.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define XDP_ENTRY_FLAG_UNIQUE (1 << 0)
|
||||
#define XDP_ENTRY_FLAG_TRANSIENT (1 << 1)
|
||||
|
||||
const char ** xdg_unparse_permissions (XdpPermissionFlags permissions);
|
||||
XdpPermissionFlags xdp_parse_permissions (const char **permissions);
|
||||
|
||||
XdpPermissionFlags xdp_entry_get_permissions (FlatpakDbEntry *entry,
|
||||
const char *app_id);
|
||||
gboolean xdp_entry_has_permissions (FlatpakDbEntry *entry,
|
||||
const char *app_id,
|
||||
XdpPermissionFlags perms);
|
||||
const char * xdp_entry_get_path (FlatpakDbEntry *entry);
|
||||
char * xdp_entry_dup_basename (FlatpakDbEntry *entry);
|
||||
char * xdp_entry_dup_dirname (FlatpakDbEntry *entry);
|
||||
guint64 xdp_entry_get_device (FlatpakDbEntry *entry);
|
||||
guint64 xdp_entry_get_inode (FlatpakDbEntry *entry);
|
||||
guint32 xdp_entry_get_flags (FlatpakDbEntry *entry);
|
||||
|
||||
char * xdp_name_from_id (guint32 doc_id);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* XDP_UTIL_H */
|
||||
@@ -1,37 +0,0 @@
|
||||
libexec_PROGRAMS += \
|
||||
xdg-permission-store \
|
||||
$(NULL)
|
||||
|
||||
service_in_files += permission-store/xdg-permission-store.service.in
|
||||
systemduserunit_DATA += permission-store/xdg-permission-store.service
|
||||
|
||||
service_in_files += permission-store/org.freedesktop.impl.portal.PermissionStore.service.in
|
||||
dbus_service_DATA += permission-store/org.freedesktop.impl.portal.PermissionStore.service
|
||||
|
||||
nodist_xdg_permission_store_SOURCES = permission-store/permission-store-dbus.c permission-store/permission-store-dbus.h
|
||||
BUILT_SOURCES += $(nodist_xdg_permission_store_SOURCES)
|
||||
CLEANFILES += $(nodist_xdg_permission_store_SOURCES)
|
||||
|
||||
permission-store/permission-store-dbus.c: data/org.freedesktop.impl.portal.PermissionStore.xml Makefile
|
||||
mkdir -p $(builddir)/permission-store
|
||||
$(AM_V_GEN) $(GDBUS_CODEGEN) \
|
||||
--interface-prefix org.freedesktop.impl.portal. \
|
||||
--c-namespace Xdg \
|
||||
--generate-c-code $(builddir)/permission-store/permission-store-dbus \
|
||||
$(srcdir)/data/org.freedesktop.impl.portal.PermissionStore.xml \
|
||||
$(NULL)
|
||||
|
||||
permission-store/%-dbus.h: permission-store/%-dbus.c
|
||||
@true # Built as a side-effect of the rules for the .c
|
||||
|
||||
# also used by the document portal
|
||||
ps_dbus_built_sources = $(nodist_xdg_permission_store_SOURCES)
|
||||
|
||||
xdg_permission_store_SOURCES = \
|
||||
permission-store/permission-store.c \
|
||||
permission-store/xdg-permission-store.c \
|
||||
permission-store/xdg-permission-store.h \
|
||||
$(NULL)
|
||||
|
||||
xdg_permission_store_LDADD = $(AM_LDADD) $(BASE_LIBS) libflatpak-common.la
|
||||
xdg_permission_store_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS) $(SOUP_CFLAGS) $(JSON_CFLAGS) $(OSTREE_CFLAGS) $(GSYSTEM_CFLAGS) -I$(srcdir)/permission-store -I$(builddir)/permission-store
|
||||
@@ -1,4 +0,0 @@
|
||||
[D-BUS Service]
|
||||
Name=org.freedesktop.impl.portal.PermissionStore
|
||||
Exec=@libexecdir@/xdg-permission-store
|
||||
SystemdService=xdg-permission-store.service
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2014 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
#include "permission-store-dbus.h"
|
||||
#include "xdg-permission-store.h"
|
||||
#include "flatpak-utils.h"
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
xdg_permission_store_start (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static gboolean opt_verbose;
|
||||
static gboolean opt_replace;
|
||||
static gboolean opt_version;
|
||||
|
||||
static GOptionEntry entries[] = {
|
||||
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &opt_verbose, "Print debug information", NULL },
|
||||
{ "replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace", NULL },
|
||||
{ "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Print version and exit", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
message_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Make this look like normal console output */
|
||||
if (log_level & G_LOG_LEVEL_DEBUG)
|
||||
printf ("XDP: %s\n", message);
|
||||
else
|
||||
printf ("%s: %s\n", g_get_prgname (), message);
|
||||
}
|
||||
|
||||
static void
|
||||
printerr_handler (const gchar *string)
|
||||
{
|
||||
const char *prefix = "";
|
||||
const char *suffix = "";
|
||||
if (flatpak_fancy_output ())
|
||||
{
|
||||
prefix = FLATPAK_ANSI_RED FLATPAK_ANSI_BOLD_ON;
|
||||
suffix = FLATPAK_ANSI_BOLD_OFF FLATPAK_ANSI_COLOR_RESET;
|
||||
}
|
||||
fprintf (stderr, "%serror: %s%s\n", prefix, suffix, string);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
guint owner_id;
|
||||
GMainLoop *loop;
|
||||
GOptionContext *context;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_setenv ("GIO_USE_VFS", "local", TRUE);
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
flatpak_migrate_from_xdg_app ();
|
||||
|
||||
g_set_printerr_handler (printerr_handler);
|
||||
|
||||
context = g_option_context_new ("- permission store");
|
||||
g_option_context_add_main_entries (context, entries, NULL);
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_printerr ("Option parsing failed: %s", error->message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opt_version)
|
||||
{
|
||||
g_print ("%s\n", PACKAGE_STRING);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (opt_verbose)
|
||||
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, message_handler, NULL);
|
||||
|
||||
g_set_prgname (argv[0]);
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.freedesktop.impl.portal.PermissionStore",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | (opt_replace ? G_BUS_NAME_OWNER_FLAGS_REPLACE : 0),
|
||||
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,468 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
#include "permission-store/permission-store-dbus.h"
|
||||
#include "xdg-permission-store.h"
|
||||
#include "flatpak-db.h"
|
||||
#include "flatpak-portal-error.h"
|
||||
|
||||
GHashTable *tables = NULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
FlatpakDb *db;
|
||||
GList *outstanding_writes;
|
||||
GList *current_writes;
|
||||
gboolean writing;
|
||||
} Table;
|
||||
|
||||
static void start_writeout (Table *table);
|
||||
|
||||
static void
|
||||
table_free (Table *table)
|
||||
{
|
||||
g_free (table->name);
|
||||
g_object_unref (table->db);
|
||||
g_free (table);
|
||||
}
|
||||
|
||||
static Table *
|
||||
lookup_table (const char *name,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
Table *table;
|
||||
FlatpakDb *db;
|
||||
g_autofree char *dir = NULL;
|
||||
g_autofree char *path = NULL;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
table = g_hash_table_lookup (tables, name);
|
||||
if (table != NULL)
|
||||
return table;
|
||||
|
||||
dir = g_build_filename (g_get_user_data_dir (), "flatpak/db", NULL);
|
||||
g_mkdir_with_parents (dir, 0755);
|
||||
|
||||
path = g_build_filename (dir, name, NULL);
|
||||
db = flatpak_db_new (path, FALSE, &error);
|
||||
if (db == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_FAILED,
|
||||
"Unable to load db file: %s", error->message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
table = g_new0 (Table, 1);
|
||||
table->name = g_strdup (name);
|
||||
table->db = db;
|
||||
|
||||
g_hash_table_insert (tables, table->name, table);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
static void
|
||||
writeout_done (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
Table *table = user_data;
|
||||
GList *l;
|
||||
|
||||
g_autoptr(GError) error = NULL;
|
||||
gboolean ok;
|
||||
|
||||
ok = flatpak_db_save_content_finish (table->db, res, &error);
|
||||
|
||||
for (l = table->current_writes; l != NULL; l = l->next)
|
||||
{
|
||||
GDBusMethodInvocation *invocation = l->data;
|
||||
|
||||
if (ok)
|
||||
g_dbus_method_invocation_return_value (invocation,
|
||||
g_variant_new ("()"));
|
||||
else
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_FAILED,
|
||||
"Unable to write db: %s", error->message);
|
||||
}
|
||||
|
||||
g_list_free (table->current_writes);
|
||||
table->current_writes = NULL;
|
||||
table->writing = FALSE;
|
||||
|
||||
if (table->outstanding_writes != NULL)
|
||||
start_writeout (table);
|
||||
}
|
||||
|
||||
static void
|
||||
start_writeout (Table *table)
|
||||
{
|
||||
g_assert (table->current_writes == NULL);
|
||||
table->current_writes = table->outstanding_writes;
|
||||
table->outstanding_writes = NULL;
|
||||
table->writing = TRUE;
|
||||
|
||||
flatpak_db_update (table->db);
|
||||
|
||||
flatpak_db_save_content_async (table->db, NULL, writeout_done, table);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_writeout (Table *table,
|
||||
GDBusMethodInvocation *invocation)
|
||||
{
|
||||
table->outstanding_writes = g_list_prepend (table->outstanding_writes, invocation);
|
||||
|
||||
if (!table->writing)
|
||||
start_writeout (table);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_list (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name)
|
||||
{
|
||||
Table *table;
|
||||
|
||||
g_auto(GStrv) ids = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
ids = flatpak_db_list_ids (table->db);
|
||||
|
||||
xdg_permission_store_complete_list (object, invocation, (const char * const *) ids);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
get_app_permissions (FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autofree const char **apps = NULL;
|
||||
GVariantBuilder builder;
|
||||
int i;
|
||||
|
||||
apps = flatpak_db_entry_list_apps (entry);
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sas}"));
|
||||
|
||||
for (i = 0; apps[i] != NULL; i++)
|
||||
{
|
||||
g_autofree const char **permissions = flatpak_db_entry_list_permissions (entry, apps[i]);
|
||||
g_variant_builder_add_value (&builder,
|
||||
g_variant_new ("{s@as}",
|
||||
apps[i],
|
||||
g_variant_new_strv (permissions, -1)));
|
||||
}
|
||||
|
||||
return g_variant_ref_sink (g_variant_builder_end (&builder));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_lookup (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name,
|
||||
const gchar *id)
|
||||
{
|
||||
Table *table;
|
||||
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
g_autoptr(GVariant) permissions = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
entry = flatpak_db_lookup (table->db, id);
|
||||
if (entry == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_NOT_FOUND,
|
||||
"No entry for %s", id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
data = flatpak_db_entry_get_data (entry);
|
||||
permissions = get_app_permissions (entry);
|
||||
|
||||
xdg_permission_store_complete_lookup (object, invocation,
|
||||
permissions,
|
||||
g_variant_new_variant (data));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_deleted (XdgPermissionStore *object,
|
||||
const gchar *table_name,
|
||||
const gchar *id,
|
||||
FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
g_autoptr(GVariant) permissions = NULL;
|
||||
|
||||
data = flatpak_db_entry_get_data (entry);
|
||||
permissions = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sas}"), NULL, 0));
|
||||
|
||||
xdg_permission_store_emit_changed (object,
|
||||
table_name, id,
|
||||
TRUE,
|
||||
g_variant_new_variant (data),
|
||||
permissions);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
emit_changed (XdgPermissionStore *object,
|
||||
const gchar *table_name,
|
||||
const gchar *id,
|
||||
FlatpakDbEntry *entry)
|
||||
{
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
g_autoptr(GVariant) permissions = NULL;
|
||||
|
||||
data = flatpak_db_entry_get_data (entry);
|
||||
permissions = get_app_permissions (entry);
|
||||
|
||||
xdg_permission_store_emit_changed (object,
|
||||
table_name, id,
|
||||
FALSE,
|
||||
g_variant_new_variant (data),
|
||||
permissions);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_delete (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name,
|
||||
const gchar *id)
|
||||
{
|
||||
Table *table;
|
||||
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
entry = flatpak_db_lookup (table->db, id);
|
||||
if (entry == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_NOT_FOUND,
|
||||
"No entry for %s", id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
flatpak_db_set_entry (table->db, id, NULL);
|
||||
emit_deleted (object, table_name, id, entry);
|
||||
|
||||
ensure_writeout (table, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name,
|
||||
gboolean create,
|
||||
const gchar *id,
|
||||
GVariant *app_permissions,
|
||||
GVariant *data)
|
||||
{
|
||||
Table *table;
|
||||
GVariantIter iter;
|
||||
GVariant *child;
|
||||
|
||||
g_autoptr(GVariant) data_child = NULL;
|
||||
g_autoptr(FlatpakDbEntry) old_entry = NULL;
|
||||
g_autoptr(FlatpakDbEntry) new_entry = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
old_entry = flatpak_db_lookup (table->db, id);
|
||||
if (old_entry == NULL && !create)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_NOT_FOUND,
|
||||
"Id %s not found", id);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
data_child = g_variant_get_child_value (data, 0);
|
||||
new_entry = flatpak_db_entry_new (data_child);
|
||||
|
||||
/* Add all the given app permissions */
|
||||
|
||||
g_variant_iter_init (&iter, app_permissions);
|
||||
while ((child = g_variant_iter_next_value (&iter)))
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) old_entry = NULL;
|
||||
const char *child_app_id;
|
||||
g_autofree const char **permissions;
|
||||
|
||||
g_variant_get (child, "{&s^a&s}", &child_app_id, &permissions);
|
||||
|
||||
old_entry = new_entry;
|
||||
new_entry = flatpak_db_entry_set_app_permissions (new_entry, child_app_id, (const char **) permissions);
|
||||
|
||||
g_variant_unref (child);
|
||||
}
|
||||
|
||||
flatpak_db_set_entry (table->db, id, new_entry);
|
||||
emit_changed (object, table_name, id, new_entry);
|
||||
|
||||
ensure_writeout (table, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_permission (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name,
|
||||
gboolean create,
|
||||
const gchar *id,
|
||||
const gchar *app,
|
||||
const gchar *const *permissions)
|
||||
{
|
||||
Table *table;
|
||||
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
g_autoptr(FlatpakDbEntry) new_entry = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
entry = flatpak_db_lookup (table->db, id);
|
||||
if (entry == NULL)
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
entry = flatpak_db_entry_new (NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_NOT_FOUND,
|
||||
"Id %s not found", id);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
new_entry = flatpak_db_entry_set_app_permissions (entry, app, (const char **) permissions);
|
||||
flatpak_db_set_entry (table->db, id, new_entry);
|
||||
emit_changed (object, table_name, id, new_entry);
|
||||
|
||||
ensure_writeout (table, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_set_value (XdgPermissionStore *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *table_name,
|
||||
gboolean create,
|
||||
const gchar *id,
|
||||
GVariant *data)
|
||||
{
|
||||
Table *table;
|
||||
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
g_autoptr(FlatpakDbEntry) new_entry = NULL;
|
||||
|
||||
table = lookup_table (table_name, invocation);
|
||||
if (table == NULL)
|
||||
return TRUE;
|
||||
|
||||
entry = flatpak_db_lookup (table->db, id);
|
||||
if (entry == NULL)
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
new_entry = flatpak_db_entry_new (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation,
|
||||
FLATPAK_PORTAL_ERROR, FLATPAK_PORTAL_ERROR_NOT_FOUND,
|
||||
"Id %s not found", id);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_entry = flatpak_db_entry_modify_data (entry, data);
|
||||
}
|
||||
|
||||
flatpak_db_set_entry (table->db, id, new_entry);
|
||||
emit_changed (object, table_name, id, new_entry);
|
||||
|
||||
ensure_writeout (table, invocation);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
xdg_permission_store_start (GDBusConnection *connection)
|
||||
{
|
||||
XdgPermissionStore *store;
|
||||
GError *error = NULL;
|
||||
|
||||
tables = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, (GDestroyNotify) table_free);
|
||||
|
||||
store = xdg_permission_store_skeleton_new ();
|
||||
|
||||
xdg_permission_store_set_version (XDG_PERMISSION_STORE (store), 1);
|
||||
|
||||
g_signal_connect (store, "handle-list", G_CALLBACK (handle_list), NULL);
|
||||
g_signal_connect (store, "handle-lookup", G_CALLBACK (handle_lookup), NULL);
|
||||
g_signal_connect (store, "handle-set", G_CALLBACK (handle_set), NULL);
|
||||
g_signal_connect (store, "handle-set-permission", G_CALLBACK (handle_set_permission), NULL);
|
||||
g_signal_connect (store, "handle-set-value", G_CALLBACK (handle_set_value), NULL);
|
||||
g_signal_connect (store, "handle-delete", G_CALLBACK (handle_delete), NULL);
|
||||
|
||||
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (store),
|
||||
connection,
|
||||
"/org/freedesktop/impl/portal/PermissionStore",
|
||||
&error))
|
||||
{
|
||||
g_warning ("error: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2015 Red Hat, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Alexander Larsson <alexl@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __FLATPAK_PERMISSION_STORE_H__
|
||||
#define __FLATPAK_PERMISSION_STORE_H__
|
||||
|
||||
#include "flatpak-dbus.h"
|
||||
|
||||
void xdg_permission_store_start (GDBusConnection *connection);
|
||||
|
||||
#endif /* __FLATPAK_PERMISSION_STORE_H__ */
|
||||
@@ -1,7 +0,0 @@
|
||||
[Unit]
|
||||
Description=sandboxed app permission store
|
||||
|
||||
[Service]
|
||||
BusName=org.freedesktop.impl.portal.PermissionStore
|
||||
ExecStart=@libexecdir@/xdg-permission-store
|
||||
Type=dbus
|
||||
@@ -12,27 +12,6 @@ else
|
||||
AM_TESTS_ENVIRONMENT += FLATPAK_BWRAP=$$(cd $(top_builddir) && pwd)/flatpak-bwrap
|
||||
endif
|
||||
|
||||
testdb_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS)
|
||||
testdb_LDADD = \
|
||||
$(AM_LDADD) \
|
||||
$(BASE_LIBS) \
|
||||
$(OSTREE_LIBS) \
|
||||
libglnx.la \
|
||||
libflatpak-common.la \
|
||||
$(NULL)
|
||||
testdb_SOURCES = tests/testdb.c
|
||||
|
||||
test_doc_portal_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS)
|
||||
test_doc_portal_LDADD = \
|
||||
$(AM_LDADD) \
|
||||
$(BASE_LIBS) \
|
||||
$(OSTREE_LIBS) \
|
||||
libglnx.la \
|
||||
libflatpak-common.la \
|
||||
$(NULL)
|
||||
test_doc_portal_SOURCES = tests/test-doc-portal.c
|
||||
nodist_test_doc_portal_SOURCES = $(xdp_dbus_built_sources)
|
||||
|
||||
testlibrary_CFLAGS = $(AM_CFLAGS) $(BASE_CFLAGS)
|
||||
testlibrary_LDADD = \
|
||||
$(AM_LDADD) \
|
||||
@@ -42,16 +21,6 @@ testlibrary_LDADD = \
|
||||
$(NULL)
|
||||
testlibrary_SOURCES = tests/testlibrary.c
|
||||
|
||||
EXTRA_test_doc_portal_DEPENDENCIES = tests/services/org.freedesktop.impl.portal.PermissionStore.service tests/services/org.freedesktop.portal.Documents.service tests/services/org.freedesktop.Flatpak.service tests/services/org.freedesktop.Flatpak.SystemHelper.service
|
||||
|
||||
tests/services/org.freedesktop.portal.Documents.service: document-portal/org.freedesktop.portal.Documents.service.in
|
||||
mkdir -p tests/services
|
||||
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" $< > $@
|
||||
|
||||
tests/services/org.freedesktop.impl.portal.PermissionStore.service: permission-store/org.freedesktop.impl.portal.PermissionStore.service.in
|
||||
mkdir -p tests/services
|
||||
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" $< > $@
|
||||
|
||||
tests/services/org.freedesktop.Flatpak.service: session-helper/org.freedesktop.Flatpak.service.in
|
||||
mkdir -p tests/services
|
||||
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" $< > $@
|
||||
@@ -60,14 +29,12 @@ tests/services/org.freedesktop.Flatpak.SystemHelper.service: system-helper/org.f
|
||||
mkdir -p tests/services
|
||||
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(abs_top_builddir)|" -e "s|\@extraargs\@| --session --no-idle-exit|" $< > $@
|
||||
|
||||
tests/libtest.sh: tests/services/org.freedesktop.impl.portal.PermissionStore.service tests/services/org.freedesktop.portal.Documents.service tests/services/org.freedesktop.Flatpak.service
|
||||
tests/libtest.sh: tests/services/org.freedesktop.Flatpak.service tests/services/org.freedesktop.Flatpak.SystemHelper.service
|
||||
|
||||
install-test-data-hook:
|
||||
if ENABLE_INSTALLED_TESTS
|
||||
mkdir -p $(DESTDIR)$(installed_testdir)/services
|
||||
ln -sf $(dbus_servicedir)/org.freedesktop.Flatpak.service $(DESTDIR)$(installed_testdir)/services/
|
||||
ln -sf $(dbus_servicedir)/org.freedesktop.portal.Documents.service $(DESTDIR)$(installed_testdir)/services/
|
||||
ln -sf $(dbus_servicedir)/org.freedesktop.impl.portal.PermissionStore.service $(DESTDIR)$(installed_testdir)/services/
|
||||
$(AM_V_GEN) $(SED) -e "s|\@libexecdir\@|$(libexecdir)|" -e "s|\@extraargs\@| --session --no-idle-exit|" $(top_srcdir)/system-helper/org.freedesktop.Flatpak.SystemHelper.service.in > $(DESTDIR)$(installed_testdir)/services/org.freedesktop.Flatpak.SystemHelper.service
|
||||
endif
|
||||
|
||||
@@ -93,7 +60,6 @@ dist_installed_test_data = \
|
||||
|
||||
installed_test_keyringdir = $(installed_testdir)/test-keyring
|
||||
installed_test_keyring2dir = $(installed_testdir)/test-keyring2
|
||||
installed_test_dbsdir = $(installed_testdir)/dbs
|
||||
|
||||
if ENABLE_INSTALLED_TESTS
|
||||
dist_installed_test_keyring_DATA = \
|
||||
@@ -106,7 +72,6 @@ dist_installed_test_keyring2_DATA = \
|
||||
tests/test-keyring2/pubring.gpg \
|
||||
tests/test-keyring2/secring.gpg \
|
||||
$(NULL)
|
||||
dist_installed_test_dbs_DATA = tests/dbs/no_tables
|
||||
endif
|
||||
|
||||
dist_test_scripts = \
|
||||
@@ -127,15 +92,13 @@ dist_test_scripts = \
|
||||
tests/test-update-remote-configuration.sh \
|
||||
$(NULL)
|
||||
|
||||
test_programs = testdb test-doc-portal testlibrary
|
||||
test_programs = testlibrary
|
||||
|
||||
@VALGRIND_CHECK_RULES@
|
||||
VALGRIND_SUPPRESSIONS_FILES=tests/flatpak.supp tests/glib.supp
|
||||
EXTRA_DIST += tests/flatpak.supp tests/glib.supp
|
||||
DISTCLEANFILES += \
|
||||
tests/services/org.freedesktop.Flatpak.service \
|
||||
tests/services/org.freedesktop.portal.Documents.service \
|
||||
tests/services/org.freedesktop.impl.portal.PermissionStore.service \
|
||||
tests/services/org.freedesktop.Flatpak.SystemHelper.service \
|
||||
tests/package_version.txt \
|
||||
$(NULL)
|
||||
|
||||
Binary file not shown.
@@ -1,505 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libglnx/libglnx.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#include "document-portal/xdp-dbus.h"
|
||||
|
||||
#include "flatpak-dbus.h"
|
||||
|
||||
char outdir[] = "/tmp/xdp-test-XXXXXX";
|
||||
|
||||
GTestDBus *dbus;
|
||||
GDBusConnection *session_bus;
|
||||
XdpDbusDocuments *documents;
|
||||
char *mountpoint;
|
||||
static gboolean have_fuse;
|
||||
|
||||
static char *
|
||||
make_doc_dir (const char *id, const char *app)
|
||||
{
|
||||
if (app)
|
||||
return g_build_filename (mountpoint, "by-app", app, id, NULL);
|
||||
else
|
||||
return g_build_filename (mountpoint, id, NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
make_doc_path (const char *id, const char *basename, const char *app)
|
||||
{
|
||||
g_autofree char *dir = make_doc_dir (id, app);
|
||||
|
||||
return g_build_filename (dir, basename, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
assert_host_has_contents (const char *basename, const char *expected_contents)
|
||||
{
|
||||
g_autofree char *path = g_build_filename (outdir, basename, NULL);
|
||||
g_autofree char *real_contents = NULL;
|
||||
gsize real_contents_length;
|
||||
GError *error = NULL;
|
||||
|
||||
g_file_get_contents (path, &real_contents, &real_contents_length, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpstr (real_contents, ==, expected_contents);
|
||||
g_assert_cmpuint (real_contents_length, ==, strlen (expected_contents));
|
||||
}
|
||||
|
||||
static void
|
||||
assert_doc_has_contents (const char *id, const char *basename, const char *app, const char *expected_contents)
|
||||
{
|
||||
g_autofree char *path = make_doc_path (id, basename, app);
|
||||
g_autofree char *real_contents = NULL;
|
||||
gsize real_contents_length;
|
||||
GError *error = NULL;
|
||||
|
||||
g_file_get_contents (path, &real_contents, &real_contents_length, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpstr (real_contents, ==, expected_contents);
|
||||
g_assert_cmpuint (real_contents_length, ==, strlen (expected_contents));
|
||||
}
|
||||
|
||||
static void
|
||||
assert_doc_not_exist (const char *id, const char *basename, const char *app)
|
||||
{
|
||||
g_autofree char *path = make_doc_path (id, basename, app);
|
||||
struct stat buf;
|
||||
int res, fd;
|
||||
|
||||
res = stat (path, &buf);
|
||||
g_assert_cmpint (res, ==, -1);
|
||||
g_assert_cmpint (errno, ==, ENOENT);
|
||||
|
||||
fd = open (path, O_RDONLY);
|
||||
g_assert_cmpint (fd, ==, -1);
|
||||
g_assert_cmpint (errno, ==, ENOENT);
|
||||
}
|
||||
|
||||
static char *
|
||||
export_file (const char *path, gboolean unique)
|
||||
{
|
||||
int fd, fd_id;
|
||||
GUnixFDList *fd_list = NULL;
|
||||
|
||||
g_autoptr(GVariant) reply = NULL;
|
||||
GError *error = NULL;
|
||||
char *doc_id;
|
||||
|
||||
fd = open (path, O_PATH | O_CLOEXEC);
|
||||
g_assert (fd >= 0);
|
||||
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
fd_id = g_unix_fd_list_append (fd_list, fd, &error);
|
||||
g_assert_no_error (error);
|
||||
close (fd);
|
||||
|
||||
reply = g_dbus_connection_call_with_unix_fd_list_sync (session_bus,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
"org.freedesktop.portal.Documents",
|
||||
"Add",
|
||||
g_variant_new ("(hbb)", fd_id, !unique, FALSE),
|
||||
G_VARIANT_TYPE ("(s)"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
30000,
|
||||
fd_list, NULL,
|
||||
NULL,
|
||||
&error);
|
||||
g_object_unref (fd_list);
|
||||
g_assert_no_error (error);
|
||||
g_assert (reply != NULL);
|
||||
|
||||
g_variant_get (reply, "(s)", &doc_id);
|
||||
g_assert (doc_id != NULL);
|
||||
return doc_id;
|
||||
}
|
||||
|
||||
static char *
|
||||
export_new_file (const char *basename, const char *contents, gboolean unique)
|
||||
{
|
||||
g_autofree char *path = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
path = g_build_filename (outdir, basename, NULL);
|
||||
|
||||
g_file_set_contents (path, contents, -1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
return export_file (path, unique);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_doc (const char *id, const char *basename, const char *app, const char *contents, GError **error)
|
||||
{
|
||||
g_autofree char *path = make_doc_path (id, basename, app);
|
||||
|
||||
return g_file_set_contents (path, contents, -1, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
update_from_host (const char *basename, const char *contents, GError **error)
|
||||
{
|
||||
g_autofree char *path = g_build_filename (outdir, basename, NULL);
|
||||
|
||||
return g_file_set_contents (path, contents, -1, error);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
grant_permissions (const char *id, const char *app, gboolean write)
|
||||
{
|
||||
g_autoptr(GPtrArray) permissions = g_ptr_array_new ();
|
||||
GError *error = NULL;
|
||||
|
||||
g_ptr_array_add (permissions, "read");
|
||||
if (write)
|
||||
g_ptr_array_add (permissions, "write");
|
||||
g_ptr_array_add (permissions, NULL);
|
||||
|
||||
xdp_dbus_documents_call_grant_permissions_sync (documents,
|
||||
id,
|
||||
app,
|
||||
(const char **) permissions->pdata,
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_create_doc (void)
|
||||
{
|
||||
g_autofree char *doc_path = NULL;
|
||||
g_autofree char *doc_app_path = NULL;
|
||||
g_autofree char *host_path = NULL;
|
||||
g_autofree char *id = NULL;
|
||||
g_autofree char *id2 = NULL;
|
||||
g_autofree char *id3 = NULL;
|
||||
g_autofree char *id4 = NULL;
|
||||
g_autofree char *id5 = NULL;
|
||||
const char *basename = "a-file";
|
||||
GError *error = NULL;
|
||||
|
||||
if (!have_fuse)
|
||||
{
|
||||
g_test_skip ("this test requires FUSE");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Export a document */
|
||||
id = export_new_file (basename, "content", FALSE);
|
||||
|
||||
/* Ensure its there and not viewable by apps */
|
||||
assert_doc_has_contents (id, basename, NULL, "content");
|
||||
assert_host_has_contents (basename, "content");
|
||||
assert_doc_not_exist (id, basename, "com.test.App1");
|
||||
assert_doc_not_exist (id, basename, "com.test.App2");
|
||||
assert_doc_not_exist (id, "another-file", NULL);
|
||||
assert_doc_not_exist ("anotherid", basename, NULL);
|
||||
|
||||
/* Create a tmp file in same dir, ensure it works and can't be seen by other apps */
|
||||
assert_doc_not_exist (id, "tmp1", NULL);
|
||||
update_doc (id, "tmp1", NULL, "tmpdata1", &error);
|
||||
g_assert_no_error (error);
|
||||
assert_doc_has_contents (id, "tmp1", NULL, "tmpdata1");
|
||||
assert_doc_not_exist (id, "tmp1", "com.test.App1");
|
||||
|
||||
/* Let App 1 see the document (but not write) */
|
||||
grant_permissions (id, "com.test.App1", FALSE);
|
||||
|
||||
/* Ensure App 1 and only it can see the document and tmpfile */
|
||||
assert_doc_has_contents (id, basename, "com.test.App1", "content");
|
||||
assert_doc_not_exist (id, basename, "com.test.App2");
|
||||
assert_doc_not_exist (id, "tmp1", "com.test.App1");
|
||||
|
||||
/* Make sure App 1 can't create a tmpfile */
|
||||
assert_doc_not_exist (id, "tmp2", "com.test.App1");
|
||||
update_doc (id, "tmp2", "com.test.App1", "tmpdata2", &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES);
|
||||
g_clear_error (&error);
|
||||
assert_doc_not_exist (id, "tmp2", "com.test.App1");
|
||||
|
||||
/* Update the document contents, ensure this is propagater */
|
||||
update_doc (id, basename, NULL, "content2", &error);
|
||||
g_assert_no_error (error);
|
||||
assert_host_has_contents (basename, "content2");
|
||||
assert_doc_has_contents (id, basename, NULL, "content2");
|
||||
assert_doc_has_contents (id, basename, "com.test.App1", "content2");
|
||||
assert_doc_not_exist (id, basename, "com.test.App2");
|
||||
assert_doc_not_exist (id, "tmp1", "com.test.App2");
|
||||
|
||||
/* Update the document contents outside fuse fd, ensure this is propagater */
|
||||
update_from_host (basename, "content3", &error);
|
||||
g_assert_no_error (error);
|
||||
assert_host_has_contents (basename, "content3");
|
||||
assert_doc_has_contents (id, basename, NULL, "content3");
|
||||
assert_doc_has_contents (id, basename, "com.test.App1", "content3");
|
||||
assert_doc_not_exist (id, basename, "com.test.App2");
|
||||
assert_doc_not_exist (id, "tmp1", "com.test.App2");
|
||||
|
||||
/* Try to update the doc from an app that can't write to it */
|
||||
update_doc (id, basename, "com.test.App1", "content4", &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES);
|
||||
g_clear_error (&error);
|
||||
|
||||
/* Try to create a tmp file for an app that is not allowed */
|
||||
assert_doc_not_exist (id, "tmp2", "com.test.App1");
|
||||
update_doc (id, "tmp2", "com.test.App1", "tmpdata2", &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES);
|
||||
g_clear_error (&error);
|
||||
assert_doc_not_exist (id, "tmp2", "com.test.App1");
|
||||
assert_doc_not_exist (id, "tmp2", NULL);
|
||||
|
||||
/* Grant write permissions to App1 */
|
||||
grant_permissions (id, "com.test.App1", TRUE);
|
||||
|
||||
/* update the doc from an app with write access */
|
||||
update_doc (id, basename, "com.test.App1", "content5", &error);
|
||||
g_assert_no_error (error);
|
||||
assert_host_has_contents (basename, "content5");
|
||||
assert_doc_has_contents (id, basename, NULL, "content5");
|
||||
assert_doc_has_contents (id, basename, "com.test.App1", "content5");
|
||||
assert_doc_not_exist (id, basename, "com.test.App2");
|
||||
|
||||
/* Try to create a tmp file for an app */
|
||||
assert_doc_not_exist (id, "tmp3", "com.test.App1");
|
||||
update_doc (id, "tmp3", "com.test.App1", "tmpdata3", &error);
|
||||
g_assert_no_error (error);
|
||||
assert_doc_has_contents (id, "tmp3", "com.test.App1", "tmpdata3");
|
||||
assert_doc_not_exist (id, "tmp3", NULL);
|
||||
|
||||
/* Re-Create a file from a fuse document file, in various ways */
|
||||
doc_path = make_doc_path (id, basename, NULL);
|
||||
doc_app_path = make_doc_path (id, basename, "com.test.App1");
|
||||
host_path = g_build_filename (outdir, basename, NULL);
|
||||
id2 = export_file (doc_path, FALSE);
|
||||
g_assert_cmpstr (id, ==, id2);
|
||||
id3 = export_file (doc_app_path, FALSE);
|
||||
g_assert_cmpstr (id, ==, id3);
|
||||
id4 = export_file (host_path, FALSE);
|
||||
g_assert_cmpstr (id, ==, id4);
|
||||
|
||||
/* Ensure we can make a unique document */
|
||||
id5 = export_file (host_path, TRUE);
|
||||
g_assert_cmpstr (id, !=, id5);
|
||||
}
|
||||
|
||||
static void
|
||||
test_recursive_doc (void)
|
||||
{
|
||||
g_autofree char *id = NULL;
|
||||
g_autofree char *id2 = NULL;
|
||||
g_autofree char *id3 = NULL;
|
||||
const char *basename = "recursive-file";
|
||||
g_autofree char *path = NULL;
|
||||
g_autofree char *app_path = NULL;
|
||||
|
||||
if (!have_fuse)
|
||||
{
|
||||
g_test_skip ("this test requires FUSE");
|
||||
return;
|
||||
}
|
||||
|
||||
id = export_new_file (basename, "recursive-content", FALSE);
|
||||
|
||||
assert_doc_has_contents (id, basename, NULL, "recursive-content");
|
||||
|
||||
path = make_doc_path (id, basename, NULL);
|
||||
g_print ("path: %s\n", path);
|
||||
|
||||
id2 = export_file (path, FALSE);
|
||||
|
||||
g_assert_cmpstr (id, ==, id2);
|
||||
|
||||
grant_permissions (id, "com.test.App1", FALSE);
|
||||
|
||||
app_path = make_doc_path (id, basename, "com.test.App1");
|
||||
|
||||
id3 = export_file (app_path, FALSE);
|
||||
|
||||
g_assert_cmpstr (id, ==, id3);
|
||||
}
|
||||
|
||||
static void
|
||||
test_create_docs (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
g_autofree char *path1 = NULL;
|
||||
g_autofree char *path2 = NULL;
|
||||
int fd1, fd2;
|
||||
guint32 fd_ids[2];
|
||||
GUnixFDList *fd_list = NULL;
|
||||
gboolean res;
|
||||
char **out_doc_ids;
|
||||
g_autoptr(GVariant) out_extra = NULL;
|
||||
const char *permissions[] = { "read", NULL };
|
||||
const char *basenames[] = { "doc1", "doc2" };
|
||||
int i;
|
||||
|
||||
if (!have_fuse)
|
||||
{
|
||||
g_test_skip ("this test requires FUSE");
|
||||
return;
|
||||
}
|
||||
|
||||
path1 = g_build_filename (outdir, basenames[0], NULL);
|
||||
g_file_set_contents (path1, basenames[0], -1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
fd1 = open (path1, O_PATH | O_CLOEXEC);
|
||||
g_assert (fd1 >= 0);
|
||||
|
||||
path2 = g_build_filename (outdir, basenames[1], NULL);
|
||||
g_file_set_contents (path2, basenames[1], -1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
fd2 = open (path2, O_PATH | O_CLOEXEC);
|
||||
g_assert (fd2 >= 0);
|
||||
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
fd_ids[0] = g_unix_fd_list_append (fd_list, fd1, &error);
|
||||
g_assert_no_error (error);
|
||||
close (fd1);
|
||||
fd_ids[1] = g_unix_fd_list_append (fd_list, fd2, &error);
|
||||
g_assert_no_error (error);
|
||||
close (fd2);
|
||||
|
||||
res = xdp_dbus_documents_call_add_full_sync (documents,
|
||||
g_variant_new_fixed_array (G_VARIANT_TYPE_HANDLE,
|
||||
fd_ids, 2, sizeof (guint32)),
|
||||
0,
|
||||
"org.other.App",
|
||||
permissions,
|
||||
fd_list,
|
||||
&out_doc_ids,
|
||||
&out_extra,
|
||||
NULL,
|
||||
NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (res);
|
||||
|
||||
g_assert (g_strv_length (out_doc_ids) == 2);
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
const char *id = out_doc_ids[i];
|
||||
|
||||
/* Ensure its there and not viewable by apps */
|
||||
assert_doc_has_contents (id, basenames[i], NULL, basenames[i]);
|
||||
assert_host_has_contents (basenames[i], basenames[i]);
|
||||
assert_doc_not_exist (id, basenames[i], "com.test.App1");
|
||||
assert_doc_not_exist (id, basenames[i], "com.test.App2");
|
||||
assert_doc_not_exist (id, "another-file", NULL);
|
||||
assert_doc_not_exist ("anotherid", basenames[i], NULL);
|
||||
|
||||
assert_doc_has_contents (id, basenames[i], "org.other.App", basenames[i]);
|
||||
update_doc (id, basenames[i], "org.other.App", "tmpdata2", &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_ACCES);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
g_assert (g_variant_lookup_value (out_extra, "mountpoint", G_VARIANT_TYPE_VARIANT) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
global_setup (void)
|
||||
{
|
||||
gboolean inited;
|
||||
g_autofree gchar *fusermount = NULL;
|
||||
GError *error = NULL;
|
||||
g_autofree gchar *services = NULL;
|
||||
|
||||
fusermount = g_find_program_in_path ("fusermount");
|
||||
/* cache result so subsequent tests can be marked as skipped */
|
||||
have_fuse = (access ("/dev/fuse", W_OK) == 0 &&
|
||||
fusermount != NULL &&
|
||||
g_file_test (fusermount, G_FILE_TEST_IS_EXECUTABLE));
|
||||
|
||||
if (!have_fuse)
|
||||
return;
|
||||
|
||||
g_mkdtemp (outdir);
|
||||
g_print ("outdir: %s\n", outdir);
|
||||
|
||||
g_setenv ("XDG_RUNTIME_DIR", outdir, TRUE);
|
||||
g_setenv ("XDG_DATA_HOME", outdir, TRUE);
|
||||
|
||||
dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
|
||||
services = g_test_build_filename (G_TEST_BUILT, "services", NULL);
|
||||
g_test_dbus_add_service_dir (dbus, services);
|
||||
g_test_dbus_up (dbus);
|
||||
|
||||
/* g_test_dbus_up unsets this, so re-set */
|
||||
g_setenv ("XDG_RUNTIME_DIR", outdir, TRUE);
|
||||
|
||||
session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
documents = xdp_dbus_documents_proxy_new_sync (session_bus, 0,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (documents != NULL);
|
||||
|
||||
inited = xdp_dbus_documents_call_get_mount_point_sync (documents, &mountpoint,
|
||||
NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (inited);
|
||||
g_assert (mountpoint != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
global_teardown (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!have_fuse)
|
||||
return;
|
||||
|
||||
g_free (mountpoint);
|
||||
|
||||
g_object_unref (documents);
|
||||
|
||||
g_dbus_connection_close_sync (session_bus, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_object_unref (session_bus);
|
||||
|
||||
g_test_dbus_down (dbus);
|
||||
|
||||
g_object_unref (dbus);
|
||||
|
||||
/* We race on the unmount of the fuse fs, which causes the rm -rf to stop at the doc dir.
|
||||
This makes the chance of completely removing the directory higher */
|
||||
sleep (1);
|
||||
|
||||
glnx_shutil_rm_rf_at (-1, outdir, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int res;
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/db/create_doc", test_create_doc);
|
||||
g_test_add_func ("/db/recursive_doc", test_recursive_doc);
|
||||
g_test_add_func ("/db/create_docs", test_create_docs);
|
||||
|
||||
global_setup ();
|
||||
|
||||
res = g_test_run ();
|
||||
|
||||
global_teardown ();
|
||||
|
||||
return res;
|
||||
}
|
||||
359
tests/testdb.c
359
tests/testdb.c
@@ -1,359 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <flatpak-db.h>
|
||||
|
||||
/*
|
||||
static void
|
||||
dump_db (FlatpakDb *db)
|
||||
{
|
||||
g_autofree char *s = flatpak_db_print (db);
|
||||
g_printerr ("\n%s\n", s);
|
||||
}
|
||||
*/
|
||||
|
||||
static FlatpakDb *
|
||||
create_test_db (gboolean serialized)
|
||||
{
|
||||
FlatpakDb *db;
|
||||
|
||||
g_autoptr(FlatpakDbEntry) entry1 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry2 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry3 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry4 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry5 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry6 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry7 = NULL;
|
||||
GError *error = NULL;
|
||||
const char *permissions1[] = { "read", "write", NULL };
|
||||
const char *permissions2[] = { "read", NULL };
|
||||
const char *permissions3[] = { "write", NULL };
|
||||
|
||||
db = flatpak_db_new (NULL, FALSE, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (db != NULL);
|
||||
|
||||
{
|
||||
g_auto(GStrv) ids = flatpak_db_list_ids (db);
|
||||
g_assert (ids != NULL);
|
||||
g_assert (ids[0] == NULL);
|
||||
}
|
||||
|
||||
{
|
||||
g_auto(GStrv) apps = flatpak_db_list_apps (db);
|
||||
g_assert (apps != NULL);
|
||||
g_assert (apps[0] == NULL);
|
||||
}
|
||||
|
||||
entry1 = flatpak_db_entry_new (g_variant_new_string ("foo-data"));
|
||||
entry2 = flatpak_db_entry_set_app_permissions (entry1, "org.test.bapp", permissions2);
|
||||
entry3 = flatpak_db_entry_set_app_permissions (entry2, "org.test.app", permissions1);
|
||||
entry4 = flatpak_db_entry_set_app_permissions (entry3, "org.test.capp", permissions1);
|
||||
|
||||
flatpak_db_set_entry (db, "foo", entry4);
|
||||
|
||||
entry5 = flatpak_db_entry_new (g_variant_new_string ("bar-data"));
|
||||
entry6 = flatpak_db_entry_set_app_permissions (entry5, "org.test.app", permissions2);
|
||||
entry7 = flatpak_db_entry_set_app_permissions (entry6, "org.test.dapp", permissions3);
|
||||
|
||||
flatpak_db_set_entry (db, "bar", entry7);
|
||||
|
||||
if (serialized)
|
||||
flatpak_db_update (db);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
static void
|
||||
verify_test_db (FlatpakDb *db)
|
||||
{
|
||||
g_auto(GStrv) ids;
|
||||
g_autofree const char **apps1 = NULL;
|
||||
g_autofree const char **apps2 = NULL;
|
||||
g_auto(GStrv) all_apps = NULL;
|
||||
|
||||
ids = flatpak_db_list_ids (db);
|
||||
g_assert (g_strv_length (ids) == 2);
|
||||
g_assert (g_strv_contains ((const char **) ids, "foo"));
|
||||
g_assert (g_strv_contains ((const char **) ids, "bar"));
|
||||
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
g_autofree const char **permissions1 = NULL;
|
||||
g_autofree const char **permissions2 = NULL;
|
||||
g_autofree const char **permissions3 = NULL;
|
||||
g_autofree const char **permissions4 = NULL;
|
||||
g_autoptr(GVariant) data1 = NULL;
|
||||
|
||||
entry = flatpak_db_lookup (db, "foo");
|
||||
g_assert (entry != NULL);
|
||||
data1 = flatpak_db_entry_get_data (entry);
|
||||
g_assert (data1 != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (data1), ==, "s");
|
||||
g_assert_cmpstr (g_variant_get_string (data1, NULL), ==, "foo-data");
|
||||
apps1 = flatpak_db_entry_list_apps (entry);
|
||||
g_assert (g_strv_length ((char **) apps1) == 3);
|
||||
g_assert (g_strv_contains (apps1, "org.test.app"));
|
||||
g_assert (g_strv_contains (apps1, "org.test.bapp"));
|
||||
g_assert (g_strv_contains (apps1, "org.test.capp"));
|
||||
permissions1 = flatpak_db_entry_list_permissions (entry, "org.test.app");
|
||||
g_assert (g_strv_length ((char **) permissions1) == 2);
|
||||
g_assert (g_strv_contains (permissions1, "read"));
|
||||
g_assert (g_strv_contains (permissions1, "write"));
|
||||
permissions2 = flatpak_db_entry_list_permissions (entry, "org.test.bapp");
|
||||
g_assert (g_strv_length ((char **) permissions2) == 1);
|
||||
g_assert (g_strv_contains (permissions2, "read"));
|
||||
permissions3 = flatpak_db_entry_list_permissions (entry, "org.test.capp");
|
||||
g_assert (g_strv_length ((char **) permissions3) == 2);
|
||||
g_assert (g_strv_contains (permissions3, "read"));
|
||||
g_assert (g_strv_contains (permissions3, "write"));
|
||||
permissions4 = flatpak_db_entry_list_permissions (entry, "org.test.noapp");
|
||||
g_assert (permissions4 != NULL);
|
||||
g_assert (g_strv_length ((char **) permissions4) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
g_autofree const char **permissions5 = NULL;
|
||||
g_autofree const char **permissions6 = NULL;
|
||||
g_autoptr(GVariant) data2 = NULL;
|
||||
|
||||
entry = flatpak_db_lookup (db, "bar");
|
||||
g_assert (entry != NULL);
|
||||
data2 = flatpak_db_entry_get_data (entry);
|
||||
g_assert (data2 != NULL);
|
||||
g_assert_cmpstr (g_variant_get_type_string (data2), ==, "s");
|
||||
g_assert_cmpstr (g_variant_get_string (data2, NULL), ==, "bar-data");
|
||||
apps2 = flatpak_db_entry_list_apps (entry);
|
||||
g_assert (g_strv_length ((char **) apps2) == 2);
|
||||
g_assert (g_strv_contains (apps2, "org.test.app"));
|
||||
g_assert (g_strv_contains (apps2, "org.test.dapp"));
|
||||
permissions5 = flatpak_db_entry_list_permissions (entry, "org.test.app");
|
||||
g_assert (g_strv_length ((char **) permissions5) == 1);
|
||||
g_assert (g_strv_contains (permissions5, "read"));
|
||||
permissions6 = flatpak_db_entry_list_permissions (entry, "org.test.dapp");
|
||||
g_assert (g_strv_length ((char **) permissions6) == 1);
|
||||
g_assert (g_strv_contains (permissions6, "write"));
|
||||
}
|
||||
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry = NULL;
|
||||
entry = flatpak_db_lookup (db, "gazonk");
|
||||
g_assert (entry == NULL);
|
||||
}
|
||||
|
||||
all_apps = flatpak_db_list_apps (db);
|
||||
g_assert (g_strv_length (all_apps) == 4);
|
||||
g_assert (g_strv_contains ((const char **) all_apps, "org.test.app"));
|
||||
g_assert (g_strv_contains ((const char **) all_apps, "org.test.bapp"));
|
||||
g_assert (g_strv_contains ((const char **) all_apps, "org.test.capp"));
|
||||
g_assert (g_strv_contains ((const char **) all_apps, "org.test.dapp"));
|
||||
}
|
||||
|
||||
static void
|
||||
test_db_open (void)
|
||||
{
|
||||
GError *error = NULL;
|
||||
FlatpakDb *db;
|
||||
|
||||
db = flatpak_db_new (g_test_get_filename (G_TEST_DIST, "dbs", "does_not_exist", NULL), TRUE, &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT);
|
||||
g_assert (db == NULL);
|
||||
g_clear_error (&error);
|
||||
|
||||
db = flatpak_db_new (g_test_get_filename (G_TEST_DIST, "dbs", "does_not_exist", NULL), FALSE, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (db != NULL);
|
||||
g_clear_error (&error);
|
||||
g_object_unref (db);
|
||||
|
||||
db = flatpak_db_new (g_test_get_filename (G_TEST_DIST, "dbs", "no_tables", NULL), TRUE, &error);
|
||||
g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL);
|
||||
g_assert (db == NULL);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_serialize (void)
|
||||
{
|
||||
g_autoptr(FlatpakDb) db = NULL;
|
||||
g_autoptr(FlatpakDb) db2 = NULL;
|
||||
g_autofree char *dump1 = NULL;
|
||||
g_autofree char *dump2 = NULL;
|
||||
g_autofree char *dump3 = NULL;
|
||||
GError *error = NULL;
|
||||
char tmpfile[] = "/tmp/testdbXXXXXX";
|
||||
int fd;
|
||||
|
||||
db = create_test_db (FALSE);
|
||||
|
||||
verify_test_db (db);
|
||||
|
||||
dump1 = flatpak_db_print (db);
|
||||
|
||||
g_assert (flatpak_db_is_dirty (db));
|
||||
|
||||
flatpak_db_update (db);
|
||||
|
||||
verify_test_db (db);
|
||||
|
||||
g_assert (!flatpak_db_is_dirty (db));
|
||||
|
||||
dump2 = flatpak_db_print (db);
|
||||
|
||||
g_assert_cmpstr (dump1, ==, dump2);
|
||||
|
||||
fd = g_mkstemp (tmpfile);
|
||||
close (fd);
|
||||
|
||||
flatpak_db_set_path (db, tmpfile);
|
||||
|
||||
flatpak_db_save_content (db, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
db2 = flatpak_db_new (tmpfile, TRUE, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert (db2 != NULL);
|
||||
|
||||
dump3 = flatpak_db_print (db2);
|
||||
|
||||
g_assert_cmpstr (dump1, ==, dump3);
|
||||
|
||||
unlink (tmpfile);
|
||||
}
|
||||
|
||||
static void
|
||||
test_modify (void)
|
||||
{
|
||||
g_autoptr(FlatpakDb) db = NULL;
|
||||
const char *permissions[] = { "read", "write", "execute", NULL };
|
||||
const char *no_permissions[] = { NULL };
|
||||
|
||||
db = create_test_db (FALSE);
|
||||
|
||||
/* Add permission */
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry1 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry2 = NULL;
|
||||
|
||||
entry1 = flatpak_db_lookup (db, "foo");
|
||||
entry2 = flatpak_db_entry_set_app_permissions (entry1, "org.test.app", permissions);
|
||||
flatpak_db_set_entry (db, "foo", entry2);
|
||||
}
|
||||
|
||||
/* Add entry */
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry1 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry2 = NULL;
|
||||
|
||||
entry1 = flatpak_db_entry_new (g_variant_new_string ("gazonk-data"));
|
||||
entry2 = flatpak_db_entry_set_app_permissions (entry1, "org.test.eapp", permissions);
|
||||
flatpak_db_set_entry (db, "gazonk", entry2);
|
||||
}
|
||||
|
||||
/* Remove permission */
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry1 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry2 = NULL;
|
||||
|
||||
entry1 = flatpak_db_lookup (db, "bar");
|
||||
entry2 = flatpak_db_entry_set_app_permissions (entry1, "org.test.dapp", no_permissions);
|
||||
flatpak_db_set_entry (db, "bar", entry2);
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry5 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry6 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry7 = NULL;
|
||||
g_autofree const char **apps2 = NULL;
|
||||
g_auto(GStrv) apps3 = NULL;
|
||||
g_autofree const char **permissions1 = NULL;
|
||||
g_autofree const char **permissions2 = NULL;
|
||||
g_autofree const char **permissions3 = NULL;
|
||||
|
||||
entry5 = flatpak_db_lookup (db, "foo");
|
||||
permissions1 = flatpak_db_entry_list_permissions (entry5, "org.test.app");
|
||||
g_assert (g_strv_length ((char **) permissions1) == 3);
|
||||
g_assert (g_strv_contains (permissions1, "read"));
|
||||
g_assert (g_strv_contains (permissions1, "write"));
|
||||
g_assert (g_strv_contains (permissions1, "execute"));
|
||||
|
||||
entry6 = flatpak_db_lookup (db, "bar");
|
||||
permissions2 = flatpak_db_entry_list_permissions (entry6, "org.test.dapp");
|
||||
g_assert (g_strv_length ((char **) permissions2) == 0);
|
||||
|
||||
entry7 = flatpak_db_lookup (db, "gazonk");
|
||||
permissions3 = flatpak_db_entry_list_permissions (entry7, "org.test.eapp");
|
||||
g_assert (g_strv_length ((char **) permissions3) == 3);
|
||||
g_assert (g_strv_contains (permissions3, "read"));
|
||||
g_assert (g_strv_contains (permissions3, "write"));
|
||||
g_assert (g_strv_contains (permissions3, "execute"));
|
||||
|
||||
apps2 = flatpak_db_entry_list_apps (entry6);
|
||||
g_assert_cmpint (g_strv_length ((char **) apps2), ==, 1);
|
||||
g_assert (g_strv_contains (apps2, "org.test.app"));
|
||||
|
||||
apps3 = flatpak_db_list_apps (db);
|
||||
g_assert_cmpint (g_strv_length (apps3), ==, 4);
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.app"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.bapp"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.capp"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.eapp"));
|
||||
}
|
||||
|
||||
flatpak_db_update (db);
|
||||
|
||||
/* Verify after serialize */
|
||||
{
|
||||
g_autoptr(FlatpakDbEntry) entry5 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry6 = NULL;
|
||||
g_autoptr(FlatpakDbEntry) entry7 = NULL;
|
||||
g_autofree const char **apps2 = NULL;
|
||||
g_auto(GStrv) apps3 = NULL;
|
||||
g_autofree const char **permissions1 = NULL;
|
||||
g_autofree const char **permissions2 = NULL;
|
||||
g_autofree const char **permissions3 = NULL;
|
||||
|
||||
entry5 = flatpak_db_lookup (db, "foo");
|
||||
permissions1 = flatpak_db_entry_list_permissions (entry5, "org.test.app");
|
||||
g_assert (g_strv_length ((char **) permissions1) == 3);
|
||||
g_assert (g_strv_contains (permissions1, "read"));
|
||||
g_assert (g_strv_contains (permissions1, "write"));
|
||||
g_assert (g_strv_contains (permissions1, "execute"));
|
||||
|
||||
entry6 = flatpak_db_lookup (db, "bar");
|
||||
permissions2 = flatpak_db_entry_list_permissions (entry6, "org.test.dapp");
|
||||
g_assert (g_strv_length ((char **) permissions2) == 0);
|
||||
|
||||
entry7 = flatpak_db_lookup (db, "gazonk");
|
||||
permissions3 = flatpak_db_entry_list_permissions (entry7, "org.test.eapp");
|
||||
g_assert (g_strv_length ((char **) permissions3) == 3);
|
||||
g_assert (g_strv_contains (permissions3, "read"));
|
||||
g_assert (g_strv_contains (permissions3, "write"));
|
||||
g_assert (g_strv_contains (permissions3, "execute"));
|
||||
|
||||
apps2 = flatpak_db_entry_list_apps (entry6);
|
||||
g_assert_cmpint (g_strv_length ((char **) apps2), ==, 1);
|
||||
g_assert (g_strv_contains (apps2, "org.test.app"));
|
||||
|
||||
apps3 = flatpak_db_list_apps (db);
|
||||
g_assert_cmpint (g_strv_length (apps3), ==, 4);
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.app"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.bapp"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.capp"));
|
||||
g_assert (g_strv_contains ((const char **) apps3, "org.test.eapp"));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/db/open", test_db_open);
|
||||
g_test_add_func ("/db/serialize", test_serialize);
|
||||
g_test_add_func ("/db/modify", test_modify);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Reference in New Issue
Block a user