mirror of
https://github.com/flatpak/flatpak.git
synced 2026-09-18 02:38:10 -04:00
Validate extension directory, subdir_suffix, add_ld_path, and merge_dirs at parse time, rejecting absolute paths and paths with .. components that escape the intended mount point. This prevents extension metadata from mounting content at unintended locations inside the sandbox. Helps: https://github.com/flatpak/flatpak/security/advisories/GHSA-w69g-9x8j-7p8f
640 lines
22 KiB
C
640 lines
22 KiB
C
/* vi:set et sw=2 sts=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e-s:
|
|
* Copyright © 1995-1998 Free Software Foundation, Inc.
|
|
* Copyright © 2014-2019 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/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "flatpak-dir-utils-private.h"
|
|
|
|
#include <glib/gi18n-lib.h>
|
|
|
|
#include "flatpak-dir-private.h"
|
|
#include "flatpak-metadata-private.h"
|
|
#include "flatpak-utils-private.h"
|
|
#include "flatpak-utils-base-private.h"
|
|
|
|
char **
|
|
flatpak_list_deployed_refs (const char *type,
|
|
const char *name_prefix,
|
|
const char *arch,
|
|
const char *branch,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
gchar **ret = NULL;
|
|
g_autoptr(GPtrArray) names = NULL;
|
|
g_autoptr(GHashTable) hash = NULL;
|
|
g_autoptr(FlatpakDir) user_dir = NULL;
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
int i;
|
|
|
|
hash = g_hash_table_new_full ((GHashFunc)flatpak_decomposed_hash, (GEqualFunc)flatpak_decomposed_equal, (GDestroyNotify)flatpak_decomposed_unref, NULL);
|
|
|
|
user_dir = flatpak_dir_get_user ();
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (system_dirs == NULL)
|
|
goto out;
|
|
|
|
if (!flatpak_dir_collect_deployed_refs (user_dir, type, name_prefix,
|
|
arch, branch, hash, cancellable,
|
|
error))
|
|
goto out;
|
|
|
|
for (i = 0; i < system_dirs->len; i++)
|
|
{
|
|
FlatpakDir *system_dir = g_ptr_array_index (system_dirs, i);
|
|
if (!flatpak_dir_collect_deployed_refs (system_dir, type, name_prefix,
|
|
arch, branch, hash, cancellable,
|
|
error))
|
|
goto out;
|
|
}
|
|
|
|
names = g_ptr_array_new ();
|
|
|
|
GLNX_HASH_TABLE_FOREACH (hash, FlatpakDecomposed *, ref)
|
|
{
|
|
g_ptr_array_add (names, flatpak_decomposed_dup_id (ref));
|
|
}
|
|
|
|
g_ptr_array_sort (names, flatpak_strcmp0_ptr);
|
|
g_ptr_array_add (names, NULL);
|
|
|
|
ret = (char **) g_ptr_array_free (names, FALSE);
|
|
names = NULL;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
char **
|
|
flatpak_list_unmaintained_refs (const char *name_prefix,
|
|
const char *arch,
|
|
const char *branch,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
gchar **ret = NULL;
|
|
g_autoptr(GPtrArray) names = NULL;
|
|
g_autoptr(GHashTable) hash = NULL;
|
|
g_autoptr(FlatpakDir) user_dir = NULL;
|
|
const char *key;
|
|
GHashTableIter iter;
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
int i;
|
|
|
|
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
user_dir = flatpak_dir_get_user ();
|
|
|
|
if (!flatpak_dir_collect_unmaintained_refs (user_dir, name_prefix,
|
|
arch, branch, hash, cancellable,
|
|
error))
|
|
return NULL;
|
|
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (system_dirs == NULL)
|
|
return NULL;
|
|
|
|
for (i = 0; i < system_dirs->len; i++)
|
|
{
|
|
FlatpakDir *system_dir = g_ptr_array_index (system_dirs, i);
|
|
|
|
if (!flatpak_dir_collect_unmaintained_refs (system_dir, name_prefix,
|
|
arch, branch, hash, cancellable,
|
|
error))
|
|
return NULL;
|
|
}
|
|
|
|
names = g_ptr_array_new ();
|
|
g_hash_table_iter_init (&iter, hash);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL))
|
|
g_ptr_array_add (names, g_strdup (key));
|
|
|
|
g_ptr_array_sort (names, flatpak_strcmp0_ptr);
|
|
g_ptr_array_add (names, NULL);
|
|
|
|
ret = (char **) g_ptr_array_free (names, FALSE);
|
|
names = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
GFile *
|
|
flatpak_find_deploy_dir_for_ref (FlatpakDecomposed *ref,
|
|
FlatpakDir **dir_out,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(FlatpakDir) user_dir = NULL;
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
FlatpakDir *dir = NULL;
|
|
g_autoptr(GFile) deploy = NULL;
|
|
|
|
user_dir = flatpak_dir_get_user ();
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (system_dirs == NULL)
|
|
return NULL;
|
|
|
|
dir = user_dir;
|
|
deploy = flatpak_dir_get_if_deployed (dir, ref, NULL, cancellable);
|
|
if (deploy == NULL)
|
|
{
|
|
int i;
|
|
for (i = 0; deploy == NULL && i < system_dirs->len; i++)
|
|
{
|
|
dir = g_ptr_array_index (system_dirs, i);
|
|
deploy = flatpak_dir_get_if_deployed (dir, ref, NULL, cancellable);
|
|
if (deploy != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (deploy == NULL)
|
|
{
|
|
flatpak_fail_error (error, FLATPAK_ERROR_NOT_INSTALLED, _("%s not installed"), flatpak_decomposed_get_ref (ref));
|
|
return NULL;
|
|
}
|
|
|
|
if (dir_out)
|
|
*dir_out = g_object_ref (dir);
|
|
return g_steal_pointer (&deploy);
|
|
}
|
|
|
|
GFile *
|
|
flatpak_find_files_dir_for_ref (FlatpakDecomposed *ref,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GFile) deploy = NULL;
|
|
|
|
deploy = flatpak_find_deploy_dir_for_ref (ref, NULL, cancellable, error);
|
|
if (deploy == NULL)
|
|
return NULL;
|
|
|
|
return g_file_get_child (deploy, "files");
|
|
}
|
|
|
|
GFile *
|
|
flatpak_find_unmaintained_extension_dir_if_exists (const char *name,
|
|
const char *arch,
|
|
const char *branch,
|
|
GCancellable *cancellable)
|
|
{
|
|
g_autoptr(FlatpakDir) user_dir = NULL;
|
|
g_autoptr(GFile) extension_dir = NULL;
|
|
g_autoptr(GError) local_error = NULL;
|
|
|
|
user_dir = flatpak_dir_get_user ();
|
|
|
|
extension_dir = flatpak_dir_get_unmaintained_extension_dir_if_exists (user_dir, name, arch, branch, cancellable);
|
|
if (extension_dir == NULL)
|
|
{
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
int i;
|
|
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, &local_error);
|
|
if (system_dirs == NULL)
|
|
{
|
|
g_warning ("Could not get the system installations: %s", local_error->message);
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < system_dirs->len; i++)
|
|
{
|
|
FlatpakDir *system_dir = g_ptr_array_index (system_dirs, i);
|
|
extension_dir = flatpak_dir_get_unmaintained_extension_dir_if_exists (system_dir, name, arch, branch, cancellable);
|
|
if (extension_dir != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (extension_dir == NULL)
|
|
return NULL;
|
|
|
|
return g_steal_pointer (&extension_dir);
|
|
}
|
|
|
|
FlatpakDecomposed *
|
|
flatpak_find_current_ref (const char *app_id,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(FlatpakDecomposed) current_ref = NULL;
|
|
g_autoptr(FlatpakDir) user_dir = flatpak_dir_get_user ();
|
|
int i;
|
|
|
|
current_ref = flatpak_dir_current_ref (user_dir, app_id, NULL);
|
|
if (current_ref == NULL)
|
|
{
|
|
g_autoptr(GPtrArray) system_dirs = NULL;
|
|
|
|
system_dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (system_dirs == NULL)
|
|
return NULL;
|
|
|
|
for (i = 0; i < system_dirs->len; i++)
|
|
{
|
|
FlatpakDir *dir = g_ptr_array_index (system_dirs, i);
|
|
current_ref = flatpak_dir_current_ref (dir, app_id, cancellable);
|
|
if (current_ref != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (current_ref)
|
|
return g_steal_pointer (¤t_ref);
|
|
|
|
flatpak_fail_error (error, FLATPAK_ERROR_NOT_INSTALLED, _("%s not installed"), app_id);
|
|
return NULL;
|
|
}
|
|
|
|
FlatpakDeploy *
|
|
flatpak_find_deploy_for_ref_in (GPtrArray *dirs,
|
|
const char *ref_str,
|
|
const char *commit,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
FlatpakDeploy *deploy = NULL;
|
|
int i;
|
|
g_autoptr(GError) my_error = NULL;
|
|
|
|
g_autoptr(FlatpakDecomposed) ref = flatpak_decomposed_new_from_ref (ref_str, error);
|
|
if (ref == NULL)
|
|
return NULL;
|
|
|
|
for (i = 0; deploy == NULL && i < dirs->len; i++)
|
|
{
|
|
FlatpakDir *dir = g_ptr_array_index (dirs, i);
|
|
|
|
flatpak_log_dir_access (dir);
|
|
g_clear_error (&my_error);
|
|
deploy = flatpak_dir_load_deployed (dir, ref, commit, cancellable, &my_error);
|
|
}
|
|
|
|
if (deploy == NULL)
|
|
g_propagate_error (error, g_steal_pointer (&my_error));
|
|
|
|
return deploy;
|
|
}
|
|
|
|
FlatpakDeploy *
|
|
flatpak_find_deploy_for_ref (const char *ref,
|
|
const char *commit,
|
|
FlatpakDir *opt_user_dir,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GPtrArray) dirs = NULL;
|
|
|
|
dirs = flatpak_dir_get_system_list (cancellable, error);
|
|
if (dirs == NULL)
|
|
return NULL;
|
|
|
|
/* If an custom dir was passed, use that instead of the user dir.
|
|
* This is used when running apply-extra-data where if the target
|
|
* is a custom installation location the regular user one may not
|
|
* have the (possibly just installed in this transaction) runtime.
|
|
*/
|
|
if (opt_user_dir)
|
|
g_ptr_array_insert (dirs, 0, g_object_ref (opt_user_dir));
|
|
else
|
|
g_ptr_array_insert (dirs, 0, flatpak_dir_get_user ());
|
|
|
|
return flatpak_find_deploy_for_ref_in (dirs, ref, commit, cancellable, error);
|
|
}
|
|
|
|
void
|
|
flatpak_extension_free (FlatpakExtension *extension)
|
|
{
|
|
g_free (extension->id);
|
|
g_free (extension->installed_id);
|
|
g_free (extension->commit);
|
|
flatpak_decomposed_unref (extension->ref);
|
|
g_free (extension->directory);
|
|
g_free (extension->files_path);
|
|
g_free (extension->add_ld_path);
|
|
g_free (extension->subdir_suffix);
|
|
g_strfreev (extension->merge_dirs);
|
|
g_free (extension);
|
|
}
|
|
|
|
static int
|
|
flatpak_extension_compare (gconstpointer _a,
|
|
gconstpointer _b)
|
|
{
|
|
const FlatpakExtension *a = _a;
|
|
const FlatpakExtension *b = _b;
|
|
|
|
/* Subtraction would overflow for far-apart priorities */
|
|
if (b->priority > a->priority)
|
|
return 1;
|
|
else if (b->priority < a->priority)
|
|
return -1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static FlatpakExtension *
|
|
flatpak_extension_new (const char *id,
|
|
const char *extension,
|
|
FlatpakDecomposed *ref,
|
|
const char *directory,
|
|
const char *add_ld_path,
|
|
const char *subdir_suffix,
|
|
char **merge_dirs,
|
|
GFile *files,
|
|
GFile *deploy_dir,
|
|
gboolean is_unmaintained,
|
|
OstreeRepo *repo)
|
|
{
|
|
FlatpakExtension *ext = g_new0 (FlatpakExtension, 1);
|
|
g_autoptr(GBytes) deploy_data = NULL;
|
|
|
|
ext->id = g_strdup (id);
|
|
ext->installed_id = g_strdup (extension);
|
|
ext->ref = flatpak_decomposed_ref (ref);
|
|
ext->directory = g_strdup (directory);
|
|
ext->files_path = g_file_get_path (files);
|
|
ext->add_ld_path = g_strdup (add_ld_path);
|
|
ext->subdir_suffix = g_strdup (subdir_suffix);
|
|
ext->merge_dirs = g_strdupv (merge_dirs);
|
|
ext->is_unmaintained = is_unmaintained;
|
|
|
|
/* Unmaintained extensions won't have a deploy or commit; see
|
|
* https://github.com/flatpak/flatpak/issues/167 */
|
|
if (deploy_dir && !is_unmaintained)
|
|
{
|
|
deploy_data = flatpak_load_deploy_data (deploy_dir, ref, repo, FLATPAK_DEPLOY_VERSION_ANY, NULL, NULL);
|
|
if (deploy_data)
|
|
ext->commit = g_strdup (flatpak_deploy_data_get_commit (deploy_data));
|
|
}
|
|
|
|
if (is_unmaintained)
|
|
ext->priority = 1000;
|
|
else
|
|
{
|
|
g_autoptr(GKeyFile) keyfile = g_key_file_new ();
|
|
g_autofree char *metadata_path = g_build_filename (ext->files_path, "../metadata", NULL);
|
|
|
|
if (g_key_file_load_from_file (keyfile, metadata_path, G_KEY_FILE_NONE, NULL))
|
|
ext->priority = g_key_file_get_integer (keyfile,
|
|
FLATPAK_METADATA_GROUP_EXTENSION_OF,
|
|
FLATPAK_METADATA_KEY_PRIORITY,
|
|
NULL);
|
|
}
|
|
|
|
return ext;
|
|
}
|
|
|
|
static gboolean
|
|
relative_path_has_no_traversal (const char *path)
|
|
{
|
|
if (path == NULL || *path == '\0' || *path == '/')
|
|
return FALSE;
|
|
|
|
if (strcmp (path, "..") == 0 ||
|
|
g_str_has_prefix (path, "../") ||
|
|
strstr (path, "/../") != NULL ||
|
|
g_str_has_suffix (path, "/.."))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GList *
|
|
add_extension (GKeyFile *metakey,
|
|
const char *group,
|
|
const char *extension,
|
|
const char *arch,
|
|
const char *branch,
|
|
GList *res)
|
|
{
|
|
FlatpakExtension *ext;
|
|
g_autofree char *directory = g_key_file_get_string (metakey, group,
|
|
FLATPAK_METADATA_KEY_DIRECTORY,
|
|
NULL);
|
|
g_autofree char *add_ld_path = g_key_file_get_string (metakey, group,
|
|
FLATPAK_METADATA_KEY_ADD_LD_PATH,
|
|
NULL);
|
|
g_auto(GStrv) merge_dirs = g_key_file_get_string_list (metakey, group,
|
|
FLATPAK_METADATA_KEY_MERGE_DIRS,
|
|
NULL, NULL);
|
|
g_autofree char *enable_if = g_key_file_get_string (metakey, group,
|
|
FLATPAK_METADATA_KEY_ENABLE_IF,
|
|
NULL);
|
|
g_autofree char *subdir_suffix = g_key_file_get_string (metakey, group,
|
|
FLATPAK_METADATA_KEY_SUBDIRECTORY_SUFFIX,
|
|
NULL);
|
|
g_autoptr(FlatpakDecomposed) ref = NULL;
|
|
gboolean is_unmaintained = FALSE;
|
|
g_autoptr(GFile) files = NULL;
|
|
g_autoptr(GFile) deploy_dir = NULL;
|
|
g_autoptr(FlatpakDir) dir = NULL;
|
|
|
|
if (directory == NULL || !relative_path_has_no_traversal (directory))
|
|
{
|
|
g_warning ("Extension %s key %s is missing or has directory traversal, ignoring",
|
|
extension, FLATPAK_METADATA_KEY_DIRECTORY);
|
|
return res;
|
|
}
|
|
|
|
if (subdir_suffix != NULL && !relative_path_has_no_traversal (subdir_suffix))
|
|
{
|
|
g_warning ("Extension %s key %s is missing or has directory traversal, ignoring",
|
|
extension, FLATPAK_METADATA_KEY_SUBDIRECTORY_SUFFIX);
|
|
return res;
|
|
}
|
|
|
|
if (add_ld_path != NULL && !relative_path_has_no_traversal (add_ld_path))
|
|
{
|
|
g_warning ("Extension %s key %s is missing or has directory traversal, ignoring",
|
|
extension, FLATPAK_METADATA_KEY_ADD_LD_PATH);
|
|
return res;
|
|
}
|
|
|
|
if (merge_dirs != NULL)
|
|
{
|
|
for (size_t i = 0; merge_dirs[i] != NULL; i++)
|
|
{
|
|
if (!relative_path_has_no_traversal (merge_dirs[i]))
|
|
{
|
|
g_warning ("Extension %s key %s is missing or has directory traversal, ignoring",
|
|
extension, FLATPAK_METADATA_KEY_MERGE_DIRS);
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
ref = flatpak_decomposed_new_from_parts (FLATPAK_KINDS_RUNTIME, extension, arch, branch, NULL);
|
|
if (ref == NULL)
|
|
return res;
|
|
|
|
files = flatpak_find_unmaintained_extension_dir_if_exists (extension, arch, branch, NULL);
|
|
|
|
if (files == NULL)
|
|
{
|
|
deploy_dir = flatpak_find_deploy_dir_for_ref (ref, &dir, NULL, NULL);
|
|
if (deploy_dir)
|
|
files = g_file_get_child (deploy_dir, "files");
|
|
}
|
|
else
|
|
is_unmaintained = TRUE;
|
|
|
|
/* Prefer a full extension (org.freedesktop.Locale) over subdirectory ones (org.freedesktop.Locale.sv) */
|
|
if (files != NULL)
|
|
{
|
|
if (flatpak_extension_matches_reason (extension, enable_if, TRUE))
|
|
{
|
|
ext = flatpak_extension_new (extension, extension, ref, directory,
|
|
add_ld_path, subdir_suffix, merge_dirs,
|
|
files, deploy_dir, is_unmaintained,
|
|
is_unmaintained ? NULL : flatpak_dir_get_repo (dir));
|
|
res = g_list_prepend (res, ext);
|
|
}
|
|
}
|
|
else if (g_key_file_get_boolean (metakey, group,
|
|
FLATPAK_METADATA_KEY_SUBDIRECTORIES, NULL))
|
|
{
|
|
g_autofree char *prefix = g_strconcat (extension, ".", NULL);
|
|
g_auto(GStrv) ids = NULL;
|
|
g_auto(GStrv) unmaintained_refs = NULL;
|
|
int j;
|
|
|
|
ids = flatpak_list_deployed_refs ("runtime", prefix, arch, branch,
|
|
NULL, NULL);
|
|
for (j = 0; ids != NULL && ids[j] != NULL; j++)
|
|
{
|
|
const char *id = ids[j];
|
|
g_autofree char *extended_dir = g_build_filename (directory, id + strlen (prefix), NULL);
|
|
g_autoptr(FlatpakDecomposed) dir_ref = NULL;
|
|
g_autoptr(GFile) subdir_deploy_dir = NULL;
|
|
g_autoptr(GFile) subdir_files = NULL;
|
|
g_autoptr(FlatpakDir) subdir_dir = NULL;
|
|
|
|
dir_ref = flatpak_decomposed_new_from_parts (FLATPAK_KINDS_RUNTIME, id, arch, branch, NULL);
|
|
if (dir_ref == NULL)
|
|
continue;
|
|
|
|
subdir_deploy_dir = flatpak_find_deploy_dir_for_ref (dir_ref, &subdir_dir, NULL, NULL);
|
|
if (subdir_deploy_dir)
|
|
subdir_files = g_file_get_child (subdir_deploy_dir, "files");
|
|
|
|
if (subdir_files && flatpak_extension_matches_reason (id, enable_if, TRUE))
|
|
{
|
|
ext = flatpak_extension_new (extension, id, dir_ref, extended_dir,
|
|
add_ld_path, subdir_suffix, merge_dirs,
|
|
subdir_files, subdir_deploy_dir, FALSE,
|
|
flatpak_dir_get_repo (subdir_dir));
|
|
ext->needs_tmpfs = TRUE;
|
|
res = g_list_prepend (res, ext);
|
|
}
|
|
}
|
|
|
|
unmaintained_refs = flatpak_list_unmaintained_refs (prefix, arch, branch,
|
|
NULL, NULL);
|
|
for (j = 0; unmaintained_refs != NULL && unmaintained_refs[j] != NULL; j++)
|
|
{
|
|
g_autofree char *extended_dir = g_build_filename (directory, unmaintained_refs[j] + strlen (prefix), NULL);
|
|
g_autoptr(FlatpakDecomposed) dir_ref = NULL;
|
|
g_autoptr(GFile) subdir_files = flatpak_find_unmaintained_extension_dir_if_exists (unmaintained_refs[j], arch, branch, NULL);
|
|
|
|
dir_ref = flatpak_decomposed_new_from_parts (FLATPAK_KINDS_RUNTIME, unmaintained_refs[j], arch, branch, NULL);
|
|
if (dir_ref == NULL)
|
|
continue;
|
|
|
|
if (subdir_files && flatpak_extension_matches_reason (unmaintained_refs[j], enable_if, TRUE))
|
|
{
|
|
ext = flatpak_extension_new (extension, unmaintained_refs[j], dir_ref,
|
|
extended_dir, add_ld_path, subdir_suffix,
|
|
merge_dirs, subdir_files, NULL, TRUE, NULL);
|
|
ext->needs_tmpfs = TRUE;
|
|
res = g_list_prepend (res, ext);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
GList *
|
|
flatpak_list_extensions (GKeyFile *metakey,
|
|
const char *arch,
|
|
const char *default_branch)
|
|
{
|
|
g_auto(GStrv) groups = NULL;
|
|
int i, j;
|
|
GList *res;
|
|
|
|
res = NULL;
|
|
|
|
if (arch == NULL)
|
|
arch = flatpak_get_arch ();
|
|
|
|
groups = g_key_file_get_groups (metakey, NULL);
|
|
for (i = 0; groups[i] != NULL; i++)
|
|
{
|
|
char *extension;
|
|
|
|
if (g_str_has_prefix (groups[i], FLATPAK_METADATA_GROUP_PREFIX_EXTENSION) &&
|
|
*(extension = (groups[i] + strlen (FLATPAK_METADATA_GROUP_PREFIX_EXTENSION))) != 0)
|
|
{
|
|
g_autofree char *version = g_key_file_get_string (metakey, groups[i],
|
|
FLATPAK_METADATA_KEY_VERSION,
|
|
NULL);
|
|
g_auto(GStrv) versions = g_key_file_get_string_list (metakey, groups[i],
|
|
FLATPAK_METADATA_KEY_VERSIONS,
|
|
NULL, NULL);
|
|
g_autofree char *name = NULL;
|
|
const char *default_branches[] = { default_branch, NULL};
|
|
const char **branches;
|
|
|
|
flatpak_parse_extension_with_tag (extension, &name, NULL);
|
|
|
|
if (versions)
|
|
branches = (const char **) versions;
|
|
else
|
|
{
|
|
if (version)
|
|
default_branches[0] = version;
|
|
branches = default_branches;
|
|
}
|
|
|
|
for (j = 0; branches[j] != NULL; j++)
|
|
res = add_extension (metakey, groups[i], name, arch, branches[j], res);
|
|
}
|
|
}
|
|
|
|
return g_list_sort (g_list_reverse (res), flatpak_extension_compare);
|
|
}
|
|
|
|
void
|
|
flatpak_log_dir_access (FlatpakDir *dir)
|
|
{
|
|
if (dir != NULL)
|
|
{
|
|
GFile *dir_path = NULL;
|
|
g_autofree char *dir_path_str = NULL;
|
|
g_autofree char *dir_name = NULL;
|
|
|
|
dir_path = flatpak_dir_get_path (dir);
|
|
if (dir_path != NULL)
|
|
dir_path_str = g_file_get_path (dir_path);
|
|
dir_name = flatpak_dir_get_name (dir);
|
|
g_info ("Opening %s flatpak installation at path %s", dir_name, dir_path_str);
|
|
}
|
|
}
|