<commit_before>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2017 <NAME> <<EMAIL>>
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * 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.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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include "config.h"

#include <glib-object.h>
#include <gio/gio.h>

#include "fu-config.h"

#include "fwupd-error.h"
#include "fwupd-remote-private.h"

static void fu_config_finalize	 (GObject *obj);

struct _FuConfig
{
	GObject			 parent_instance;
	GKeyFile		*keyfile;
	GPtrArray		*remotes;
	GPtrArray		*monitors;
	GPtrArray		*blacklist_devices;
	GPtrArray		*blacklist_plugins;
	guint64			 archive_size_max;
};

G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT)

static GPtrArray *
fu_config_get_config_paths (void)
{
	GPtrArray *paths = g_ptr_array_new_with_free_func (g_free);
	const gchar *remotes_dir;
	const gchar *system_prefixlibdir = "/usr/lib/fwupd";
	g_autofree gchar *sysconfdir = NULL;

	/* only set by the self test program */
	remotes_dir = g_getenv ("FU_SELF_TEST_REMOTES_DIR");
	if (remotes_dir != NULL) {
		g_ptr_array_add (paths, g_strdup (remotes_dir));
		return paths;
	}

	/* use sysconfig, and then fall back to /etc */
	sysconfdir = g_build_filename (FWUPDCONFIGDIR, NULL);
	if (g_file_test (sysconfdir, G_FILE_TEST_EXISTS))
		g_ptr_array_add (paths, g_steal_pointer (&sysconfdir));

	/* add in system-wide locations */
	if (g_file_test (system_prefixlibdir, G_FILE_TEST_EXISTS))
		g_ptr_array_add (paths, g_strdup (system_prefixlibdir));

	return paths;
}

static void
fu_config_monitor_changed_cb (GFileMonitor *monitor,
			      GFile *file,
			      GFile *other_file,
			      GFileMonitorEvent event_type,
			      gpointer user_data)
{
	FuConfig *self = FU_CONFIG (user_data);
	g_autoptr(GError) error = NULL;
	g_autofree gchar *filename = g_file_get_path (file);
	g_debug ("%s changed, reloading all configs", filename);
	if (!fu_config_load (self, &error))
		g_warning ("failed to rescan config: %s", error->message);
}

static guint64
fu_config_get_remote_mtime (FuConfig *self, FwupdRemote *remote)
{
	g_autoptr(GFile) file = NULL;
	g_autoptr(GFileInfo) info = NULL;

	file = g_file_new_for_path (fwupd_remote_get_filename_cache (remote));
	if (!g_file_query_exists (file, NULL))
		return G_MAXUINT64;
	info = g_file_query_info (file,
				  G_FILE_ATTRIBUTE_TIME_MODIFIED,
				  G_FILE_QUERY_INFO_NONE,
				  NULL, NULL);
	if (info == NULL)
		return G_MAXUINT64;
	return g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
}

static gboolean
fu_config_add_inotify (FuConfig *self, const gchar *filename, GError **error)
{
	GFileMonitor *monitor;
	g_autoptr(GFile) file = g_file_new_for_path (filename);

	/* set up a notify watch */
	monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error);
	if (monitor == NULL)
		return FALSE;
	g_signal_connect (monitor, "changed",
			  G_CALLBACK (fu_config_monitor_changed_cb), self);
	g_ptr_array_add (self->monitors, monitor);
	return TRUE;
}

static gboolean
fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **error)
{
	const gchar *tmp;
	g_autofree gchar *path_remotes = NULL;
	g_autoptr(GDir) dir = NULL;

	path_remotes = g_build_filename (path, "remotes.d", NULL);
	if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS))
		return TRUE;
	dir = g_dir_open (path_remotes, 0, error);
	if (dir == NULL)
		return FALSE;
	while ((tmp = g_dir_read_name (dir)) != NULL) {
		g_autofree gchar *filename = g_build_filename (path_remotes, tmp, NULL);
		g_autoptr(FwupdRemote) remote = fwupd_remote_new ();

		/* skip invalid files */
		if (!g_str_has_suffix (tmp, ".conf")) {
			g_debug ("skipping invalid file %s", filename);
			continue;
		}

		/* load from keyfile */
		g_debug ("loading config from %s", filename);
		if (!fwupd_remote_load_from_filename (remote, filename,
						      NULL, error)) {
			g_prefix_error (error, "failed to load %s: ", filename);
			return FALSE;
		}

		/* watch the config file and the XML file itself */
		if (!fu_config_add_inotify (self, filename, error))
			return FALSE;
		if (!fu_config_add_inotify (self, fwupd_remote_get_filename_cache (remote), error))
			return FALSE;

		/* set mtime */
		fwupd_remote_set_mtime (remote, fu_config_get_remote_mtime (self, remote));<commit_msg>Correctly detect new remotes that are manually copied<commit_after>/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2017 <NAME> <<EMAIL>>
 *
 * Licensed under the GNU Lesser General Public License Version 2.1
 *
 * 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.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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include "config.h"

#include <glib-object.h>
#include <gio/gio.h>

#include "fu-config.h"

#include "fwupd-error.h"
#include "fwupd-remote-private.h"

static void fu_config_finalize	 (GObject *obj);

struct _FuConfig
{
	GObject			 parent_instance;
	GKeyFile		*keyfile;
	GPtrArray		*remotes;
	GPtrArray		*monitors;
	GPtrArray		*blacklist_devices;
	GPtrArray		*blacklist_plugins;
	guint64			 archive_size_max;
};

G_DEFINE_TYPE (FuConfig, fu_config, G_TYPE_OBJECT)

static GPtrArray *
fu_config_get_config_paths (void)
{
	GPtrArray *paths = g_ptr_array_new_with_free_func (g_free);
	const gchar *remotes_dir;
	const gchar *system_prefixlibdir = "/usr/lib/fwupd";
	g_autofree gchar *sysconfdir = NULL;

	/* only set by the self test program */
	remotes_dir = g_getenv ("FU_SELF_TEST_REMOTES_DIR");
	if (remotes_dir != NULL) {
		g_ptr_array_add (paths, g_strdup (remotes_dir));
		return paths;
	}

	/* use sysconfig, and then fall back to /etc */
	sysconfdir = g_build_filename (FWUPDCONFIGDIR, NULL);
	if (g_file_test (sysconfdir, G_FILE_TEST_EXISTS))
		g_ptr_array_add (paths, g_steal_pointer (&sysconfdir));

	/* add in system-wide locations */
	if (g_file_test (system_prefixlibdir, G_FILE_TEST_EXISTS))
		g_ptr_array_add (paths, g_strdup (system_prefixlibdir));

	return paths;
}

static void
fu_config_monitor_changed_cb (GFileMonitor *monitor,
			      GFile *file,
			      GFile *other_file,
			      GFileMonitorEvent event_type,
			      gpointer user_data)
{
	FuConfig *self = FU_CONFIG (user_data);
	g_autoptr(GError) error = NULL;
	g_autofree gchar *filename = g_file_get_path (file);
	g_debug ("%s changed, reloading all configs", filename);
	if (!fu_config_load (self, &error))
		g_warning ("failed to rescan config: %s", error->message);
}

static guint64
fu_config_get_remote_mtime (FuConfig *self, FwupdRemote *remote)
{
	g_autoptr(GFile) file = NULL;
	g_autoptr(GFileInfo) info = NULL;

	file = g_file_new_for_path (fwupd_remote_get_filename_cache (remote));
	if (!g_file_query_exists (file, NULL))
		return G_MAXUINT64;
	info = g_file_query_info (file,
				  G_FILE_ATTRIBUTE_TIME_MODIFIED,
				  G_FILE_QUERY_INFO_NONE,
				  NULL, NULL);
	if (info == NULL)
		return G_MAXUINT64;
	return g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
}

static gboolean
fu_config_add_inotify (FuConfig *self, const gchar *filename, GError **error)
{
	GFileMonitor *monitor;
	g_autoptr(GFile) file = g_file_new_for_path (filename);

	/* set up a notify watch */
	monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error);
	if (monitor == NULL)
		return FALSE;
	g_signal_connect (monitor, "changed",
			  G_CALLBACK (fu_config_monitor_changed_cb), self);
	g_ptr_array_add (self->monitors, monitor);
	return TRUE;
}

static gboolean
fu_config_add_remotes_for_path (FuConfig *self, const gchar *path, GError **error)
{
	const gchar *tmp;
	g_autofree gchar *path_remotes = NULL;
	g_autoptr(GDir) dir = NULL;

	path_remotes = g_build_filename (path, "remotes.d", NULL);
	if (!g_file_test (path_remotes, G_FILE_TEST_EXISTS))
		return TRUE;
	if (!fu_config_add_inotify (self, path_remotes, error))
		return FALSE;
	dir = g_dir_open (path_remotes, 0, error);
	if (dir == NULL)
		return FALSE;
	while ((tmp = g_dir_read_name (dir)) != NULL) {
		g_autofree gchar *filename = g_build_filename (path_remotes, tmp, NULL);
		g_autoptr(FwupdRemote) remote = fwupd_remote_new ();

		/* skip invalid files */
		if (!g_str_has_suffix (tmp, ".conf")) {
			g_debug ("skipping invalid file %s", filename);
			continue;
		}

		/* load from keyfile */
		g_debug ("loading config from %s", filename);
		if (!fwupd_remote_load_from_filename (remote, filename,
						      NULL, error)) {
			g_prefix_error (error, "failed to load %s: ", filename);
			return FALSE;
		}

		/* watch the config file and the XML file itself */
		if (!fu_config_add_inotify (self, filename, error))
			return FALSE;
		if (!fu_config_add_inotify (self, fwupd_remote_get_filename_cache (remote), error))
			return FALSE;

		/* set mtime */
		fwupd_remote_set_mtime (remote, fu_config_get_remote_mtime (self, remote));
{'fraction_non_alphanumeric': 0.10238637488860283, 'fraction_numerical': 0.006337261114961877, 'mean_word_length': 4.680539932508436, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2306271', 'n_tokens_mistral': 3832, 'n_tokens_neox': 3595, 'n_words': 1011}