settings: change filename for per-connection metadata (previously UUID nm-loaded symlinks)

We may want to store meta-data for a profile to disk. The immediate
need are "tombstones": markers that the particular UUID is shadowed
and the profile does not exist (despite being in read-only location).

Change the filename of these symlinks from

  ".loaded-${UUID}.nmconnection"

to

  "${UUID}.nmmeta"

The leading dot is not desirable as tools tend to hide such files.
Use a different scheme for the filename that does not have the leading dot.
Note that nm_keyfile_utils_ignore_filename() would also ignore ".nmmeta"
as not a valid keyfile. This is just what we want, and influences the
choice of this file suffix.

Also, "nmmeta" is a better name, because this name alludes that there is
a wider use for the file: namely to have addtional per-profile metadata.
That is regardless that the upcoming first use will be only to store symlinks
to "/dev/null" to indicate the tombstones.

Note that per-profile metadata is not new. Currently we write the files

  /var/lib/NetworkManager/{seen-bssids,timestamps}

that have a similar purpose. Maybe the content from these files could one
day be migrated to the ".nmmeta" file. The naming scheme would make it
suitable.
This commit is contained in:
Thomas Haller 2019-07-15 16:53:58 +02:00
parent 050f61519c
commit 5ce589a775
5 changed files with 68 additions and 54 deletions

View file

@ -176,9 +176,9 @@ gboolean _nm_keyfile_has_values (GKeyFile *keyfile);
#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection"
#define NM_KEYFILE_PATH_PREFIX_NMLOADED ".loaded-"
#define NM_KEYFILE_PATH_SUFFIX_NMMETA ".nmmeta"
#define NM_KEYFILE_PATH_NMLOADED_NULL "/dev/null"
#define NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL "/dev/null"
gboolean nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension);

View file

@ -3981,7 +3981,7 @@ nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extensi
if (require_extension) {
if ( l <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)
|| !g_str_has_suffix (base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION))
|| !NM_STR_HAS_SUFFIX (base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION))
return TRUE;
return FALSE;
}
@ -3990,7 +3990,10 @@ nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extensi
if (base[l - 1] == '~')
return TRUE;
/* Ignore temporary files */
/* Ignore temporary files
*
* This check is also important to ignore .nmload files (see
* %NM_KEYFILE_PATH_SUFFIX_NMMETA). */
if (check_mkstemp_suffix (base))
return TRUE;

View file

@ -33,30 +33,71 @@
/*****************************************************************************/
const char *
nms_keyfile_loaded_uuid_is_filename (const char *filename,
guint *out_uuid_len)
{
const char *uuid;
const char *s;
gsize len;
s = strrchr (filename, '/');
if (s)
filename = &s[1];
len = strlen (filename);
if ( len <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)
|| memcmp (&filename[len - NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)],
NM_KEYFILE_PATH_SUFFIX_NMMETA,
NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA)) != 0) {
/* the filename does not have the right suffix. */
return NULL;
}
len -= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMMETA);
if (!NM_IN_SET (len, 36, 40)) {
/* the remaining part of the filename has not the right length to
* contain a UUID (according to nm_utils_is_uuid()). */
return NULL;
}
uuid = nm_strndup_a (100, filename, len, NULL);
if (!nm_utils_is_uuid (uuid))
return NULL;
NM_SET_OUT (out_uuid_len, len);
return filename;
}
char *
nms_keyfile_loaded_uuid_filename (const char *dirname,
const char *uuid,
gboolean temporary)
{
char filename[250];
char *s;
nm_assert (dirname && dirname[0] == '/');
nm_assert (uuid && nm_utils_is_uuid (uuid) && !strchr (uuid, '/'));
nm_assert ( nm_utils_is_uuid (uuid)
&& !strchr (uuid, '/'));
if (g_snprintf (filename,
sizeof (filename),
"%s%s%s%s",
NM_KEYFILE_PATH_PREFIX_NMLOADED,
"%s%s%s",
uuid,
NM_KEYFILE_PATH_SUFFIX_NMCONNECTION,
NM_KEYFILE_PATH_SUFFIX_NMMETA,
temporary ? "~" : "") >= sizeof (filename)) {
/* valid uuids are limited in length. The buffer should always be large
* enough. */
/* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always
* be large enough. */
nm_assert_not_reached ();
return NULL;
}
return g_build_filename (dirname, filename, NULL);
s = g_build_filename (dirname, filename, NULL);
nm_assert (nm_keyfile_utils_ignore_filename (s, FALSE));
return s;
}
gboolean
@ -68,48 +109,15 @@ nms_keyfile_loaded_uuid_read (const char *dirname,
struct stat *out_st)
{
const char *uuid;
const char *tmp;
gsize len;
guint uuid_len;
gs_free char *full_filename = NULL;
gs_free char *ln = NULL;
nm_assert (dirname && dirname[0] == '/');
nm_assert (filename && filename[0] && !strchr (filename, '/'));
if (filename[0] != '.') {
/* the hidden-uuid filename must start with '.'. That is,
* so that it does not conflict with regular keyfiles according
* to nm_keyfile_utils_ignore_filename(). */
return FALSE;
}
len = strlen (filename);
if ( len <= NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)
|| memcmp (filename, NM_KEYFILE_PATH_PREFIX_NMLOADED, NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)) != 0) {
/* the filename does not have the right prefix. */
return FALSE;
}
tmp = &filename[NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED)];
len -= NM_STRLEN (NM_KEYFILE_PATH_PREFIX_NMLOADED);
if ( len <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)
|| memcmp (&tmp[len - NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)],
NM_KEYFILE_PATH_SUFFIX_NMCONNECTION,
NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) != 0) {
/* the file does not have the right suffix. */
return FALSE;
}
len -= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION);
if (!NM_IN_SET (len, 36, 40)) {
/* the remaining part of the filename has not the right length to
* contain a UUID (according to nm_utils_is_uuid()). */
return FALSE;
}
uuid = nm_strndup_a (100, tmp, len, NULL);
if (!nm_utils_is_uuid (uuid))
uuid = nms_keyfile_loaded_uuid_is_filename (filename, &uuid_len);
if (!uuid)
return FALSE;
full_filename = g_build_filename (dirname, filename, NULL);
@ -124,7 +132,7 @@ nms_keyfile_loaded_uuid_read (const char *dirname,
if (!ln)
return FALSE;
NM_SET_OUT (out_uuid, g_strdup (uuid));
NM_SET_OUT (out_uuid, g_strndup (uuid, uuid_len));
NM_SET_OUT (out_full_filename, g_steal_pointer (&full_filename));
NM_SET_OUT (out_loaded_path, g_steal_pointer (&ln));
return TRUE;
@ -169,7 +177,8 @@ nms_keyfile_loaded_uuid_write (const char *dirname,
gs_free char *full_filename = NULL;
nm_assert (dirname && dirname[0] == '/');
nm_assert (uuid && nm_utils_is_uuid (uuid) && !strchr (uuid, '/'));
nm_assert ( nm_utils_is_uuid (uuid)
&& !strchr (uuid, '/'));
nm_assert (!loaded_path || loaded_path[0] == '/');
full_filename_tmp = nms_keyfile_loaded_uuid_filename (dirname, uuid, TRUE);

View file

@ -37,6 +37,9 @@ const char *nms_keyfile_utils_get_path (void);
/*****************************************************************************/
const char *nms_keyfile_loaded_uuid_is_filename (const char *filename,
guint *out_uuid_len);
char *nms_keyfile_loaded_uuid_filename (const char *dirname,
const char *uuid,
gboolean temporary);

View file

@ -2578,14 +2578,13 @@ static void
test_loaded_uuid (void)
{
const char *uuid = "3c03fd17-ddc3-4100-a954-88b6fafff959";
gs_free char *filename = g_strdup_printf ("%s%s%s",
NM_KEYFILE_PATH_PREFIX_NMLOADED,
gs_free char *filename = g_strdup_printf ("%s%s",
uuid,
NM_KEYFILE_PATH_SUFFIX_NMCONNECTION);
NM_KEYFILE_PATH_SUFFIX_NMMETA);
gs_free char *full_filename = g_strdup_printf ("%s/%s",
TEST_SCRATCH_DIR,
filename);
const char *loaded_path0 = NM_KEYFILE_PATH_NMLOADED_NULL;
const char *loaded_path0 = NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL;
const char *loaded_path1 = "/some/where/but/not/scratch/dir";
const char *filename2 = "foo1";
gs_free char *loaded_path2 = g_strdup_printf ("%s/%s",