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:
Alexander Larsson
2018-02-09 10:13:37 +01:00
committed by Atomic Bot
parent 0c3c42d8db
commit f2a6c1db8d
42 changed files with 19 additions and 8806 deletions

6
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"

View File

@@ -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>

View File

@@ -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 \

View File

@@ -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 */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

@@ -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

View File

@@ -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"

View File

@@ -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,

View File

@@ -1,2 +0,0 @@
libgvdb.a
libgvdb-shared.a

View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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;
}

View File

@@ -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__ */

View File

@@ -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>

View File

@@ -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)

View File

@@ -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>

View File

@@ -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

View File

@@ -1,4 +0,0 @@
[D-BUS Service]
Name=org.freedesktop.portal.Documents
Exec=@libexecdir@/xdg-document-portal
SystemdService=xdg-document-portal.service

View File

@@ -1,7 +0,0 @@
[Unit]
Description=flatpak document portal service
[Service]
BusName=org.freedesktop.portal.Documents
ExecStart=@libexecdir@/xdg-document-portal
Type=dbus

View File

@@ -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 */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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 */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -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);
}

View File

@@ -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 */

View File

@@ -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

View File

@@ -1,4 +0,0 @@
[D-BUS Service]
Name=org.freedesktop.impl.portal.PermissionStore
Exec=@libexecdir@/xdg-permission-store
SystemdService=xdg-permission-store.service

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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__ */

View File

@@ -1,7 +0,0 @@
[Unit]
Description=sandboxed app permission store
[Service]
BusName=org.freedesktop.impl.portal.PermissionStore
ExecStart=@libexecdir@/xdg-permission-store
Type=dbus

View File

@@ -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)

View File

Binary file not shown.

View File

@@ -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;
}

View File

@@ -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 ();
}