From 9e59f7fb8dda3cb26eae134d922c1a8a30712e1d Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 21 Oct 2020 19:29:53 +0200 Subject: [PATCH 01/27] io: introduce read_uint_at helper Analogous to bolt_read_int_at, but for unsigned integers; uses bolt_read_value_at and bolt_str_parse_as_unit internally. --- common/bolt-io.c | 19 +++++++++++++++++++ common/bolt-io.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index 18d9f6f..d39880f 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -518,6 +518,25 @@ bolt_read_int_at (int dirfd, return bolt_str_parse_as_int (str, val, error); } +gboolean +bolt_read_uint_at (int dirfd, + const char *name, + guint *val, + GError **error) +{ + g_autofree char *str = NULL; + + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + str = bolt_read_value_at (dirfd, name, error); + + if (str == NULL) + return FALSE; + + return bolt_str_parse_as_uint (str, val, error); +} + gboolean bolt_verify_uid (int dirfd, const char *want, diff --git a/common/bolt-io.h b/common/bolt-io.h index 669997b..ff7ab73 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -101,6 +101,11 @@ gboolean bolt_read_int_at (int dirfd, gint *val, GError **error); +gboolean bolt_read_uint_at (int dirfd, + const char *name, + guint *val, + GError **error); + gboolean bolt_verify_uid (int dirfd, const char *uid, GError **error); -- GitLab From e213b63a5eade8329a4914cd95cef681f19e577d Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 16:03:13 +0100 Subject: [PATCH 02/27] io: define overwrite open flags globally Create a define of open flags that is typically used to create or overwrite new files; with a plain text spelling out of the flags. This is done so that they can be reused in other functions. --- common/bolt-io.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/bolt-io.c b/common/bolt-io.c index d39880f..bb15417 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -51,6 +51,11 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE, fclose); +/* standard open flags for overwriting a file, i.e. close on + * exec (3), open in write only mode, truncate before writing, + * and create it if it does not yet exist */ +#define BOLT_O_OVERWRITE (O_CLOEXEC | O_WRONLY | O_TRUNC | O_CREAT) + int bolt_open (const char *path, int flags, int mode, GError **error) { @@ -589,7 +594,7 @@ bolt_file_write_all (const char *fn, g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - fd = bolt_open (fn, O_CLOEXEC | O_WRONLY | O_TRUNC | O_CREAT, 0666, error); + fd = bolt_open (fn, BOLT_O_OVERWRITE, 0666, error); if (fd < 0) return FALSE; -- GitLab From 1fc1ac1b1f6982b1c7e2d973ae87457096eadfe0 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 17:00:28 +0100 Subject: [PATCH 03/27] io: new write_file_at helper This is like the existing `bolt_file_write_all`, except it takes a file descriptor to a directory to be able to specify the parent directory. Will create a new file or overwrite an existing. Does not do atomic io or the rename-to-do-atomic-io rename dance. --- common/bolt-io.c | 29 +++++++++++++++++++++++++++++ common/bolt-io.h | 6 ++++++ 2 files changed, 35 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index bb15417..d201e86 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -401,6 +401,35 @@ bolt_unlink_at (int dirfd, return TRUE; } +gboolean +bolt_write_file_at (int dirfd, + const char *name, + const char *data, + gssize len, + GError **error) +{ + int fd; + gboolean ok; + + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + fd = bolt_openat (dirfd, name, BOLT_O_OVERWRITE, 0666, error); + + if (fd < 0) + return FALSE; + + ok = bolt_write_all (fd, data, len, error); + + if (!ok) + (void) close (fd); + else + ok = bolt_close (fd, error); + + return ok; +} + char * bolt_read_value_at (int dirfd, const char *name, diff --git a/common/bolt-io.h b/common/bolt-io.h index ff7ab73..f280c1c 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -87,6 +87,12 @@ gboolean bolt_unlink_at (int dirfd, int flag, GError **error); +gboolean bolt_write_file_at (int dirfd, + const char *name, + const char *data, + gssize len, + GError **error); + char * bolt_read_value_at (int dirfd, const char *name, GError **error); -- GitLab From d87f29207d2d9ff1d02b936cb8e514043716dc78 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 17:02:59 +0100 Subject: [PATCH 04/27] test/common: checks for bolt_write_file_at Basically the same test as test_io_file_write_all: write data, check it is all there, overwrite the file, check it got overwritten and truncated. --- tests/test-common.c | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index a6d0f08..330ed1c 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -932,6 +932,46 @@ test_io_verify (TestIO *tt, gconstpointer user_data) unlinkat (dirfd (d), "unique_id", 0); } +static void +test_io_write_file_at (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) dir = NULL; + g_autofree char *path = NULL; + g_autofree char *data = NULL; + static const char *ref = "The world is everything that is the case."; + gboolean ok; + gsize len; + + dir = bolt_opendir (tt->path, &error); + g_assert_no_error (error); + g_assert_nonnull (dir); + + ok = bolt_write_file_at (dirfd (dir), "test.txt", ref, -1, &error); + + g_assert_no_error (error); + g_assert_true (ok); + + path = g_build_filename (tt->path, "test.txt", NULL); + ok = g_file_get_contents (path, &data, &len, &error); + g_assert_no_error (error); + g_assert_true (ok); + g_assert_cmpuint (strlen (ref), ==, len); + g_assert_cmpstr (ref, ==, data); + + g_clear_pointer (&data, g_free); + ok = bolt_file_write_all (path, ref, 5, &error); + + g_assert_no_error (error); + g_assert_true (ok); + + ok = g_file_get_contents (path, &data, &len, &error); + g_assert_no_error (error); + g_assert_true (ok); + g_assert_cmpuint (len, ==, 5); + g_assert_true (strncmp (data, ref, 5) == 0); +} + static void test_io_file_write_all (TestIO *tt, gconstpointer user_data) { @@ -2119,6 +2159,13 @@ main (int argc, char **argv) test_io_verify, test_io_tear_down); + g_test_add ("/common/io/write_file_at", + TestIO, + NULL, + test_io_setup, + test_io_write_file_at, + test_io_tear_down); + g_test_add ("/common/io/file_write_all", TestIO, NULL, -- GitLab From 1a0b621b2d04c766870b6911b436e5235abd9842 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 17:04:13 +0100 Subject: [PATCH 05/27] io: use write_file_at in file_write_all Re-implement bolt_file_write_all in terms of bolt_write_file_at, since open (...) <=> openat (AT_FDWCD, ...). --- common/bolt-io.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/common/bolt-io.c b/common/bolt-io.c index d201e86..3a0647f 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -616,26 +616,11 @@ bolt_file_write_all (const char *fn, gssize n, GError **error) { - int fd = -1; - gboolean ok; - g_return_val_if_fail (fn != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - fd = bolt_open (fn, BOLT_O_OVERWRITE, 0666, error); - - if (fd < 0) - return FALSE; - - ok = bolt_write_all (fd, data, n, error); - - if (ok) - ok = bolt_close (fd, error); - else - (void) close (fd); - - return ok; + return bolt_write_file_at (AT_FDCWD, fn, data, n, error); } gboolean -- GitLab From 79f3b11b7f7c53e039138674acbedd262fb65982 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 18:04:04 +0100 Subject: [PATCH 06/27] test/common: check for read_int_at Test case for bolt_read_int_at. Duplicates the test table for test_str_parse_int for now. --- tests/test-common.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 330ed1c..8f322e5 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -972,6 +972,67 @@ test_io_write_file_at (TestIO *tt, gconstpointer user_data) g_assert_true (strncmp (data, ref, 5) == 0); } +static void +test_io_read_int_at (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) dir = NULL; + gboolean ok; + struct + { + const char *str; + gint val; + gboolean error; + } table[] = { + {"0", 0, FALSE}, + {"1", 1, FALSE}, + {"-1", -1, FALSE}, +#if __SIZEOF_INT__ == 4 + {"2147483647", 2147483647, FALSE}, /* MAX_INT */ + {"-2147483648", -2147483648, FALSE}, /* MIN_INT */ + {"2147483648", 0, TRUE}, /* MAX_INT + 1 */ + {"-2147483649", 0, TRUE}, /* MIN_INT - 1 */ +#elif __SIZEOF_INT__ == 8 + {"9223372036854775807", 9223372036854775807, FALSE}, /* MAX_INT */ + {"-9223372036854775808", -9223372036854775808, FALSE}, /* MIN_INT */ + {"9223372036854775808", 0, TRUE}, /* MAX_INT + 1 */ + {"-9223372036854775809", 0, TRUE}, /* MIN_INT - 1 */ +#else + #warning __SIZEOF_INT__ not handled +#endif + {"notanint", 0, TRUE}, + {"9223372036854775808", 0, TRUE}, /* overflow */ + {"-9223372036854775809", 0, TRUE}, /* underflow */ + }; + + dir = bolt_opendir (tt->path, &error); + g_assert_no_error (error); + g_assert_nonnull (dir); + + for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + { + g_autoptr(GError) err = NULL; + const char *txt = table[i].str; + gint v; + + ok = bolt_write_file_at (dirfd (dir), "int.txt", txt, -1, &err); + g_assert_true (ok); + + ok = bolt_read_int_at (dirfd (dir), "int.txt", &v, &err); + if (table[i].error) + { + g_assert_nonnull (err); + g_assert_false (ok); + } + else + { + g_assert_no_error (err); + g_assert_cmpint (table[i].val, ==, v); + g_assert_true (ok); + } + } +} + static void test_io_file_write_all (TestIO *tt, gconstpointer user_data) { @@ -2166,6 +2227,13 @@ main (int argc, char **argv) test_io_write_file_at, test_io_tear_down); + g_test_add ("/common/io/read_int_at", + TestIO, + NULL, + test_io_setup, + test_io_read_int_at, + test_io_tear_down); + g_test_add ("/common/io/file_write_all", TestIO, NULL, -- GitLab From f34c5edf6bf98f0ec7722eb9d1fa94ba701aea82 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 18:05:18 +0100 Subject: [PATCH 07/27] io: new bolt_write_int_at method Add a new helper that writes a plain int to a file, internally using bolt_write_file_at. --- common/bolt-io.c | 19 +++++++++++++++++++ common/bolt-io.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index 3a0647f..19c24fb 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -533,6 +533,25 @@ retry: return n > 0; } +gboolean +bolt_write_int_at (int dirfd, + const char *name, + gint val, + GError **error) +{ + char buf[256] = {0, }; + gsize n; + + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + n = g_snprintf (buf, sizeof (buf), "%d", val); + + g_assert (n < sizeof (buf)); + + return bolt_write_file_at (dirfd, name, buf, n, error); +} + gboolean bolt_read_int_at (int dirfd, const char *name, diff --git a/common/bolt-io.h b/common/bolt-io.h index f280c1c..a232174 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -102,6 +102,11 @@ gboolean bolt_write_char_at (int dirfd, char value, GError **error); +gboolean bolt_write_int_at (int dirfd, + const char *name, + gint val, + GError **error); + gboolean bolt_read_int_at (int dirfd, const char *name, gint *val, -- GitLab From b479e8a3cbdf1c1396b8f366156d0e46546c0b2b Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 18:06:25 +0100 Subject: [PATCH 08/27] test/common: simple check for write_int_at Basic checks for bolt_write_int_at. Uses bolt_read_int_at to verify the integer got written properly. --- tests/test-common.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 8f322e5..5759c0e 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -972,6 +972,34 @@ test_io_write_file_at (TestIO *tt, gconstpointer user_data) g_assert_true (strncmp (data, ref, 5) == 0); } +static void +test_io_write_int_at (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) dir = NULL; + gboolean ok; + int tests[] = {0, 1, 42, G_MAXINT}; + + dir = bolt_opendir (tt->path, &error); + g_assert_no_error (error); + g_assert_nonnull (dir); + + for (gsize i = 0; i < G_N_ELEMENTS (tests); i++) + { + g_autoptr(GError) err = NULL; + int ref = tests[i]; + int val; + + ok = bolt_write_int_at (dirfd (dir), "int.txt", ref, &err); + g_assert_true (ok); + + ok = bolt_read_int_at (dirfd (dir), "int.txt", &val, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_cmpint (val, ==, ref); + } +} + static void test_io_read_int_at (TestIO *tt, gconstpointer user_data) { @@ -2227,6 +2255,13 @@ main (int argc, char **argv) test_io_write_file_at, test_io_tear_down); + g_test_add ("/common/io/write_int_at", + TestIO, + NULL, + test_io_setup, + test_io_write_int_at, + test_io_tear_down); + g_test_add ("/common/io/read_int_at", TestIO, NULL, -- GitLab From 988ed461d94f6390cbc179a249161c6126fe7b04 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:00:47 +0100 Subject: [PATCH 09/27] test/common: simple check for read_uint_at Test case for bolt_read_uint_at. Duplicates the test table for test_str_parse_uint for now. --- tests/test-common.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 5759c0e..0cd5efd 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -1061,6 +1061,65 @@ test_io_read_int_at (TestIO *tt, gconstpointer user_data) } } +static void +test_io_read_uint_at (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) dir = NULL; + gboolean ok; + struct + { + const char *str; + guint val; + gboolean error; + } table[] = { + {"0", 0, FALSE}, + {"1", 1, FALSE}, + {"-1", 0, TRUE}, /* negative */ +#if __SIZEOF_INT__ == 4 + {"4294967295", 4294967295, FALSE}, /* MAX_UINT */ + {"4294967296", 0, TRUE}, /* MAX_UINT + 1 */ +#elif __SIZEOF_INT__ == 8 + {"18446744073709551615", 18446744073709551615, FALSE}, /* MAX_INT */ + {"18446744073709551616", 0, TRUE}, /* MAX_INT + 1 */ +#else + #warning __SIZEOF_INT__ not handled +#endif + {"notanint", 0, TRUE}, + {"18446744073709551617", 0, TRUE}, /* overflow */ + }; + + dir = bolt_opendir (tt->path, &error); + g_assert_no_error (error); + g_assert_nonnull (dir); + + for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + { + g_autoptr(GError) err = NULL; + const char *txt = table[i].str; + guint v; + + if (g_test_verbose ()) + g_test_message ("bolt_read_uint: '%s'", table[i].str); + + ok = bolt_write_file_at (dirfd (dir), "uint.txt", txt, -1, &err); + g_assert_true (ok); + + ok = bolt_read_uint_at (dirfd (dir), "uint.txt", &v, &err); + if (table[i].error) + { + g_assert_nonnull (err); + g_assert_false (ok); + } + else + { + g_assert_no_error (err); + g_assert_cmpuint (table[i].val, ==, v); + g_assert_true (ok); + } + } +} + static void test_io_file_write_all (TestIO *tt, gconstpointer user_data) { @@ -2269,6 +2328,13 @@ main (int argc, char **argv) test_io_read_int_at, test_io_tear_down); + g_test_add ("/common/io/read_uint_at", + TestIO, + NULL, + test_io_setup, + test_io_read_uint_at, + test_io_tear_down); + g_test_add ("/common/io/file_write_all", TestIO, NULL, -- GitLab From 0668da406ae5b97a3c72090f433738133d2be861 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:04:25 +0100 Subject: [PATCH 10/27] io: introduce bolt_write_uint_at helper Small helper which writes a plain unsigned integer to a file. Uses bolt_write_file_at internally. --- common/bolt-io.c | 19 +++++++++++++++++++ common/bolt-io.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index 19c24fb..1d6490d 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -571,6 +571,25 @@ bolt_read_int_at (int dirfd, return bolt_str_parse_as_int (str, val, error); } +gboolean +bolt_write_uint_at (int dirfd, + const char *name, + guint val, + GError **error) +{ + char buf[256] = {0, }; + gsize n; + + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + n = g_snprintf (buf, sizeof (buf), "%u", val); + + g_assert (n < sizeof (buf)); + + return bolt_write_file_at (dirfd, name, buf, n, error); +} + gboolean bolt_read_uint_at (int dirfd, const char *name, diff --git a/common/bolt-io.h b/common/bolt-io.h index a232174..33eb4bb 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -112,6 +112,11 @@ gboolean bolt_read_int_at (int dirfd, gint *val, GError **error); +gboolean bolt_write_uint_at (int dirfd, + const char *name, + guint val, + GError **error); + gboolean bolt_read_uint_at (int dirfd, const char *name, guint *val, -- GitLab From 7b574f3ed058ffe6afa87eab9bc89f0adb241a00 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:05:08 +0100 Subject: [PATCH 11/27] test/common: simple checks for write_uint_at Basic test cases for writing an unsigned integer to disk. The data is verify via bolt_read_unit_at. --- tests/test-common.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 0cd5efd..e717298 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -1061,6 +1061,34 @@ test_io_read_int_at (TestIO *tt, gconstpointer user_data) } } +static void +test_io_write_uint_at (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) dir = NULL; + gboolean ok; + unsigned int tests[] = {42, 0, 1, G_MAXUINT}; + + dir = bolt_opendir (tt->path, &error); + g_assert_no_error (error); + g_assert_nonnull (dir); + + for (gsize i = 0; i < G_N_ELEMENTS (tests); i++) + { + g_autoptr(GError) err = NULL; + unsigned int ref = tests[i]; + unsigned int val; + + ok = bolt_write_uint_at (dirfd (dir), "uint.txt", ref, &err); + g_assert_true (ok); + + ok = bolt_read_uint_at (dirfd (dir), "uint.txt", &val, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_cmpint (val, ==, ref); + } +} + static void test_io_read_uint_at (TestIO *tt, gconstpointer user_data) { @@ -2328,6 +2356,13 @@ main (int argc, char **argv) test_io_read_int_at, test_io_tear_down); + g_test_add ("/common/io/write_uint_at", + TestIO, + NULL, + test_io_setup, + test_io_write_uint_at, + test_io_tear_down); + g_test_add ("/common/io/read_uint_at", TestIO, NULL, -- GitLab From c57d3904b6d5d238ba73faf850d296719f27f6dd Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:12:46 +0100 Subject: [PATCH 12/27] =?UTF-8?q?test/common:=20global=20str=20=E2=86=92?= =?UTF-8?q?=20uint=20test=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the test table for string to unsigned integer conversion, which was duplicated in two different test cases. --- tests/test-common.c | 95 +++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 54 deletions(-) diff --git a/tests/test-common.c b/tests/test-common.c index e717298..443fe0a 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -60,6 +60,31 @@ typedef struct int dummy; } TestDummy; +/* test tables for string to number conversions */ + +struct +{ + const char *str; + guint val; + gboolean error; +} str_to_uint_table[] = { + {"0", 0, FALSE}, + {"1", 1, FALSE}, + {"-1", 0, TRUE}, /* negative */ +#if __SIZEOF_INT__ == 4 + {"4294967295", 4294967295, FALSE}, /* MAX_UINT */ + {"4294967296", 0, TRUE}, /* MAX_UINT + 1 */ +#elif __SIZEOF_INT__ == 8 + {"18446744073709551615", 18446744073709551615, FALSE}, /* MAX_INT */ + {"18446744073709551616", 0, TRUE}, /* MAX_INT + 1 */ +#else +#warning __SIZEOF_INT__ not handled +#endif + {"notanint", 0, TRUE}, + {"18446744073709551617", 0, TRUE}, /* overflow */ +}; + + #define TEST_DBUS_GRESOURCE_PATH "/bolt/tests/exported/example.bolt.xml" #define TEST_DBUS_INTERFACE "org.gnome.bolt.Example" @@ -1095,46 +1120,27 @@ test_io_read_uint_at (TestIO *tt, gconstpointer user_data) g_autoptr(GError) error = NULL; g_autoptr(DIR) dir = NULL; gboolean ok; - struct - { - const char *str; - guint val; - gboolean error; - } table[] = { - {"0", 0, FALSE}, - {"1", 1, FALSE}, - {"-1", 0, TRUE}, /* negative */ -#if __SIZEOF_INT__ == 4 - {"4294967295", 4294967295, FALSE}, /* MAX_UINT */ - {"4294967296", 0, TRUE}, /* MAX_UINT + 1 */ -#elif __SIZEOF_INT__ == 8 - {"18446744073709551615", 18446744073709551615, FALSE}, /* MAX_INT */ - {"18446744073709551616", 0, TRUE}, /* MAX_INT + 1 */ -#else - #warning __SIZEOF_INT__ not handled -#endif - {"notanint", 0, TRUE}, - {"18446744073709551617", 0, TRUE}, /* overflow */ - }; dir = bolt_opendir (tt->path, &error); g_assert_no_error (error); g_assert_nonnull (dir); - for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + for (gsize i = 0; i < G_N_ELEMENTS (str_to_uint_table); i++) { g_autoptr(GError) err = NULL; - const char *txt = table[i].str; + const char *txt = str_to_uint_table[i].str; + gboolean expect_error = str_to_uint_table[i].error; + guint val = str_to_uint_table[i].val; guint v; if (g_test_verbose ()) - g_test_message ("bolt_read_uint: '%s'", table[i].str); + g_test_message ("bolt_read_uint: '%s'", txt); ok = bolt_write_file_at (dirfd (dir), "uint.txt", txt, -1, &err); g_assert_true (ok); ok = bolt_read_uint_at (dirfd (dir), "uint.txt", &v, &err); - if (table[i].error) + if (expect_error) { g_assert_nonnull (err); g_assert_false (ok); @@ -1142,7 +1148,7 @@ test_io_read_uint_at (TestIO *tt, gconstpointer user_data) else { g_assert_no_error (err); - g_assert_cmpuint (table[i].val, ==, v); + g_assert_cmpuint (val, ==, v); g_assert_true (ok); } } @@ -1598,42 +1604,23 @@ test_str_parse_int (TestRng *tt, gconstpointer user_data) static void test_str_parse_uint (TestRng *tt, gconstpointer user_data) { - struct - { - const char *str; - guint val; - gboolean error; - } table[] = { - {"0", 0, FALSE}, - {"1", 1, FALSE}, - {"-1", 0, TRUE}, /* negative */ -#if __SIZEOF_INT__ == 4 - {"4294967295", 4294967295, FALSE}, /* MAX_UINT */ - {"4294967296", 0, TRUE}, /* MAX_UINT + 1 */ -#elif __SIZEOF_INT__ == 8 - {"18446744073709551615", 18446744073709551615, FALSE}, /* MAX_INT */ - {"18446744073709551616", 0, TRUE}, /* MAX_INT + 1 */ -#else - #warning __SIZEOF_INT__ not handled -#endif - {"notanint", 0, TRUE}, - {"18446744073709551617", 0, TRUE}, /* overflow */ - }; - - for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + for (gsize i = 0; i < G_N_ELEMENTS (str_to_uint_table); i++) { g_autoptr(GError) error = NULL; + const char *txt = str_to_uint_table[i].str; + gboolean expect_error = str_to_uint_table[i].error; + guint val = str_to_uint_table[i].val; gboolean ok; guint v; errno = 0; - ok = bolt_str_parse_as_uint (table[i].str, &v, &error); + ok = bolt_str_parse_as_uint (txt, &v, &error); if (g_test_verbose ()) - g_test_message ("parsing '%s', expecting: %s", table[i].str, - (table[i].error ? "error" : "success")); + g_test_message ("parsing '%s', expecting: %s", txt, + (expect_error ? "error" : "success")); - if (table[i].error) + if (expect_error) { int err = errno; @@ -1644,7 +1631,7 @@ test_str_parse_uint (TestRng *tt, gconstpointer user_data) } else { - g_assert_cmpuint (table[i].val, ==, v); + g_assert_cmpuint (val, ==, v); g_assert_true (ok); } } -- GitLab From 6aba5f2a8c3e4b844e462070102bb6c0430953f3 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:20:11 +0100 Subject: [PATCH 13/27] =?UTF-8?q?test/common:=20global=20str=20=E2=86=92?= =?UTF-8?q?=20int=20test=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the test table for string to integer conversion, which was duplicated in two different test cases. --- tests/test-common.c | 100 +++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 61 deletions(-) diff --git a/tests/test-common.c b/tests/test-common.c index 443fe0a..644a95e 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -61,6 +61,32 @@ typedef struct } TestDummy; /* test tables for string to number conversions */ +struct +{ + const char *str; + gint val; + gboolean error; +} str_to_int_table[] = { + {"0", 0, FALSE}, + {"1", 1, FALSE}, + {"-1", -1, FALSE}, +#if __SIZEOF_INT__ == 4 + {"2147483647", 2147483647, FALSE}, /* MAX_INT */ + {"-2147483648", -2147483648, FALSE}, /* MIN_INT */ + {"2147483648", 0, TRUE}, /* MAX_INT + 1 */ + {"-2147483649", 0, TRUE}, /* MIN_INT - 1 */ +#elif __SIZEOF_INT__ == 8 + {"9223372036854775807", 9223372036854775807, FALSE}, /* MAX_INT */ + {"-9223372036854775808", -9223372036854775808, FALSE}, /* MIN_INT */ + {"9223372036854775808", 0, TRUE}, /* MAX_INT + 1 */ + {"-9223372036854775809", 0, TRUE}, /* MIN_INT - 1 */ +#else +#warning __SIZEOF_INT__ not handled +#endif + {"notanint", 0, TRUE}, + {"9223372036854775808", 0, TRUE}, /* overflow */ + {"-9223372036854775809", 0, TRUE}, /* underflow */ +}; struct { @@ -1031,48 +1057,24 @@ test_io_read_int_at (TestIO *tt, gconstpointer user_data) g_autoptr(GError) error = NULL; g_autoptr(DIR) dir = NULL; gboolean ok; - struct - { - const char *str; - gint val; - gboolean error; - } table[] = { - {"0", 0, FALSE}, - {"1", 1, FALSE}, - {"-1", -1, FALSE}, -#if __SIZEOF_INT__ == 4 - {"2147483647", 2147483647, FALSE}, /* MAX_INT */ - {"-2147483648", -2147483648, FALSE}, /* MIN_INT */ - {"2147483648", 0, TRUE}, /* MAX_INT + 1 */ - {"-2147483649", 0, TRUE}, /* MIN_INT - 1 */ -#elif __SIZEOF_INT__ == 8 - {"9223372036854775807", 9223372036854775807, FALSE}, /* MAX_INT */ - {"-9223372036854775808", -9223372036854775808, FALSE}, /* MIN_INT */ - {"9223372036854775808", 0, TRUE}, /* MAX_INT + 1 */ - {"-9223372036854775809", 0, TRUE}, /* MIN_INT - 1 */ -#else - #warning __SIZEOF_INT__ not handled -#endif - {"notanint", 0, TRUE}, - {"9223372036854775808", 0, TRUE}, /* overflow */ - {"-9223372036854775809", 0, TRUE}, /* underflow */ - }; dir = bolt_opendir (tt->path, &error); g_assert_no_error (error); g_assert_nonnull (dir); - for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + for (gsize i = 0; i < G_N_ELEMENTS (str_to_int_table); i++) { g_autoptr(GError) err = NULL; - const char *txt = table[i].str; + const char *txt = str_to_int_table[i].str; + gboolean expect_error = str_to_int_table[i].error; + gint val = str_to_int_table[i].val; gint v; ok = bolt_write_file_at (dirfd (dir), "int.txt", txt, -1, &err); g_assert_true (ok); ok = bolt_read_int_at (dirfd (dir), "int.txt", &v, &err); - if (table[i].error) + if (expect_error) { g_assert_nonnull (err); g_assert_false (ok); @@ -1080,7 +1082,7 @@ test_io_read_int_at (TestIO *tt, gconstpointer user_data) else { g_assert_no_error (err); - g_assert_cmpint (table[i].val, ==, v); + g_assert_cmpint (val, ==, v); g_assert_true (ok); } } @@ -1549,43 +1551,19 @@ test_str_erase (TestRng *tt, gconstpointer user_data) static void test_str_parse_int (TestRng *tt, gconstpointer user_data) { - struct - { - const char *str; - gint val; - gboolean error; - } table[] = { - {"0", 0, FALSE}, - {"1", 1, FALSE}, - {"-1", -1, FALSE}, -#if __SIZEOF_INT__ == 4 - {"2147483647", 2147483647, FALSE}, /* MAX_INT */ - {"-2147483648", -2147483648, FALSE}, /* MIN_INT */ - {"2147483648", 0, TRUE}, /* MAX_INT + 1 */ - {"-2147483649", 0, TRUE}, /* MIN_INT - 1 */ -#elif __SIZEOF_INT__ == 8 - {"9223372036854775807", 9223372036854775807, FALSE}, /* MAX_INT */ - {"-9223372036854775808", -9223372036854775808, FALSE}, /* MIN_INT */ - {"9223372036854775808", 0, TRUE}, /* MAX_INT + 1 */ - {"-9223372036854775809", 0, TRUE}, /* MIN_INT - 1 */ -#else - #warning __SIZEOF_INT__ not handled -#endif - {"notanint", 0, TRUE}, - {"9223372036854775808", 0, TRUE}, /* overflow */ - {"-9223372036854775809", 0, TRUE}, /* underflow */ - }; - - for (gsize i = 0; i < G_N_ELEMENTS (table); i++) + for (gsize i = 0; i < G_N_ELEMENTS (str_to_int_table); i++) { g_autoptr(GError) error = NULL; + const char *txt = str_to_int_table[i].str; + gboolean expect_error = str_to_int_table[i].error; + gint val = str_to_int_table[i].val; gboolean ok; gint v; errno = 0; - ok = bolt_str_parse_as_int (table[i].str, &v, &error); + ok = bolt_str_parse_as_int (txt, &v, &error); - if (table[i].error) + if (expect_error) { int err = errno; @@ -1595,7 +1573,7 @@ test_str_parse_int (TestRng *tt, gconstpointer user_data) } else { - g_assert_cmpint (table[i].val, ==, v); + g_assert_cmpint (val, ==, v); g_assert_true (ok); } } -- GitLab From 7e9957f73110bcad8c758badf95406f711f3cba1 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 19:23:14 +0100 Subject: [PATCH 14/27] test/common: tests for read_uint_at error checks Simple checks that we get the expected errors for non existent files and files containing unexpected data. --- tests/test-common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 644a95e..e1a002c 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -723,6 +723,7 @@ test_io_errors (TestIO *tt, gconstpointer user_data) struct stat st; char buffer[256] = {0, }; gboolean ok; + unsigned int uiv; int fd = -1; int iv; int r; @@ -879,6 +880,17 @@ test_io_errors (TestIO *tt, gconstpointer user_data) g_assert_false (ok); g_clear_pointer (&err, g_error_free); + /* read_uint_at */ + ok = bolt_read_uint_at (dirfd (root), "NONEXISTENT", &uiv, &err); + g_assert_error (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_false (ok); + g_clear_pointer (&err, g_error_free); + + ok = bolt_read_uint_at (dirfd (root), "readonly", &uiv, &err); + g_assert_error (err, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); + g_assert_false (ok); + g_clear_pointer (&err, g_error_free); + /* pipe error checking */ fd = bolt_mkfifo (tt->path, 0600, &err); g_assert_error (err, G_IO_ERROR, G_IO_ERROR_EXISTS); -- GitLab From 8f910eb7bf0af527a7a16a6f6fde6c7f284acf46 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 20:31:04 +0100 Subject: [PATCH 15/27] io: bolt_dir_is_empty helper --- common/bolt-io.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ common/bolt-io.h | 4 ++++ 2 files changed, 48 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index 1d6490d..ba7f0de 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -924,6 +924,50 @@ bolt_copy_bytes (int fd_from, return len == 0; } +gboolean +bolt_dir_is_empty (DIR *dir, + gboolean *empty, + GError **error) +{ + struct dirent *de = NULL; + long n; + + g_return_val_if_fail (dir != NULL, FALSE); + g_return_val_if_fail (empty != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + *empty = TRUE; + + n = telldir (dir); + if (n == -1) + { + int code = errno; + + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (code), + "telldir(3) failed: %s", + g_strerror (code)); + + return FALSE; + } + + rewinddir (dir); + + while ((de = readdir (dir)) != NULL) + { + + if (!g_strcmp0 (de->d_name, ".") || + !g_strcmp0 (de->d_name, "..")) + continue; + + *empty = FALSE; + break; + } + + seekdir (dir, n); + + return TRUE; +} /* auto cleanup helpers */ void diff --git a/common/bolt-io.h b/common/bolt-io.h index 33eb4bb..8b5983e 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -167,6 +167,10 @@ gboolean bolt_copy_bytes (int fd_from, size_t len, GError **error); +gboolean bolt_dir_is_empty (DIR *dir, + gboolean *empty, + GError **error); + /* auto cleanup for I/O handles */ void bolt_cleanup_close_intpr (int *fd); #define bolt_autoclose bolt_cleanup (bolt_cleanup_close_intpr) -- GitLab From 89e2010c0d83290c780f909fc6cd1fd883859087 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 26 Oct 2020 20:31:11 +0100 Subject: [PATCH 16/27] test/common: bolt_dir_is_empty checks --- tests/test-common.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index e1a002c..21379ff 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -1292,6 +1293,72 @@ test_io_copy_bytes (TestIO *tt, gconstpointer user_data) chksum); } +static void +test_io_dir_is_empty (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) err = NULL; + g_autoptr(DIR) root = NULL; + struct dirent *de = NULL; + gboolean empty; + gboolean ok; + long pos; + + root = bolt_opendir (tt->path, &err); + g_assert_no_error (err); + g_assert_nonnull (root); + + empty = FALSE; + ok = bolt_dir_is_empty (root, &empty, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_true (empty); + + ok = bolt_write_file_at (dirfd (root), "a", "a", -1, &err); + g_assert_no_error (err); + g_assert_true (ok); + + empty = TRUE; + ok = bolt_dir_is_empty (root, &empty, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_false (empty); + + /* check that we don't mess with the dir pointer offset, + * by creating a second file, iterating exactly once + * and then making sure we are at the same position + * after the call to bolt_dir_is_empty */ + + ok = bolt_write_file_at (dirfd (root), "b", "b", -1, &err); + g_assert_no_error (err); + g_assert_true (ok); + + empty = TRUE; + ok = bolt_dir_is_empty (root, &empty, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_false (empty); + + while ((de = readdir (root)) != NULL) + { + + if (!g_strcmp0 (de->d_name, ".") || + !g_strcmp0 (de->d_name, "..")) + continue; + + break; + } + + pos = telldir (root); + + empty = TRUE; + ok = bolt_dir_is_empty (root, &empty, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_false (empty); + + g_assert_cmpint (telldir (root), ==, pos); +} + static void test_autoclose (TestIO *tt, gconstpointer user_data) { @@ -2361,6 +2428,13 @@ main (int argc, char **argv) test_io_copy_bytes, test_io_tear_down); + g_test_add ("/common/io/dir_is_empty", + TestIO, + NULL, + test_io_setup, + test_io_dir_is_empty, + test_io_tear_down); + g_test_add ("/common/io/autoclose", TestIO, NULL, -- GitLab From d65638f1f375efbbaff9231dc35f19cfce7378b1 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 16:56:52 +0100 Subject: [PATCH 17/27] io: new mkdirat wrapper Add a simple mkdirat(2) wrapper for GError based error reporting. --- common/bolt-io.c | 28 ++++++++++++++++++++++++++++ common/bolt-io.h | 5 +++++ 2 files changed, 33 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index ba7f0de..9b1bd1f 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -323,6 +323,34 @@ bolt_closedir (DIR *d, } +gboolean +bolt_mkdirat (int dirfd, + const char *name, + mode_t mode, + GError **error) +{ + int r = 0; + + g_return_val_if_fail (name != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + r = mkdirat (dirfd, name, mode); + + if (r < 0) + { + g_set_error (error, + G_IO_ERROR, + g_io_error_from_errno (errno), + "failed to create directory '%s': %s", + name, + g_strerror (errno)); + return FALSE; + } + + return TRUE; +} + + gboolean bolt_rmdir (const char *name, GError **error) diff --git a/common/bolt-io.h b/common/bolt-io.h index 8b5983e..d4ccb45 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -70,6 +70,11 @@ DIR * bolt_opendir_at (int dirfd, gboolean bolt_closedir (DIR *d, GError **error); +gboolean bolt_mkdirat (int dirfd, + const char *name, + mode_t mode, + GError **error); + gboolean bolt_rmdir (const char *name, GError **error); -- GitLab From e41e7c2d1429586f6abadbae399240cd9ee222c2 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 16:57:49 +0100 Subject: [PATCH 18/27] test/common: checks for new mkdirat wrapper Check basic functionality and error reporting for bolt_mkdirat. --- tests/test-common.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 21379ff..085ae64 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -942,6 +942,34 @@ test_io_errors (TestIO *tt, gconstpointer user_data) g_clear_pointer (&err, g_error_free); } +static void +test_io_mkdirat (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) error = NULL; + g_autoptr(DIR) d = NULL; + struct stat st; + gboolean ok; + + d = bolt_opendir (tt->path, &error); + + g_assert_no_error (error); + g_assert_nonnull (d); + + ok = bolt_mkdirat (dirfd (d), "directory", 0666, &error); + g_assert_no_error (error); + g_assert_true (ok); + + ok = bolt_fstatat (dirfd (d), "directory", &st, 0, &error); + g_assert_no_error (error); + g_assert_true (ok); + + g_assert_true (S_ISDIR (st.st_mode)); + + ok = bolt_mkdirat (dirfd (d), "directory", 0666, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS); + g_assert_false (ok); +} + static void test_io_verify (TestIO *tt, gconstpointer user_data) { @@ -2372,6 +2400,13 @@ main (int argc, char **argv) test_io_errors, test_io_tear_down); + g_test_add ("/common/io/mkdirat", + TestIO, + NULL, + test_io_setup, + test_io_mkdirat, + test_io_tear_down); + g_test_add ("/common/io/verify", TestIO, NULL, -- GitLab From e2744ee15ddd3317b411bb95f911174f5c0bd2c9 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 16:59:00 +0100 Subject: [PATCH 19/27] io: add renameat wrapper Add a simple wrapper for renameat(2), mainly for GError based error reporting. --- common/bolt-io.c | 28 ++++++++++++++++++++++++++++ common/bolt-io.h | 6 ++++++ 2 files changed, 34 insertions(+) diff --git a/common/bolt-io.c b/common/bolt-io.c index 9b1bd1f..063dd57 100644 --- a/common/bolt-io.c +++ b/common/bolt-io.c @@ -895,6 +895,34 @@ bolt_rename (const char *from, return FALSE; } +gboolean +bolt_renameat (int from_dir, + const char *from, + int to_dir, + const char *to, + GError **error) +{ + int code; + int r; + + g_return_val_if_fail (from != NULL, FALSE); + g_return_val_if_fail (to != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + r = renameat (from_dir, from, to_dir, to); + + if (r == 0) + return TRUE; + + code = errno; + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (code), + "could not rename '%s' to '%s': %s", + from, to, g_strerror (code)); + + return FALSE; +} + #if !HAVE_FN_COPY_FILE_RANGE static loff_t copy_file_range (int fd_in, diff --git a/common/bolt-io.h b/common/bolt-io.h index d4ccb45..d856582 100644 --- a/common/bolt-io.h +++ b/common/bolt-io.h @@ -167,6 +167,12 @@ gboolean bolt_rename (const char *from, const char *to, GError **error); +gboolean bolt_renameat (int from_dir, + const char *from, + int to_dir, + const char *to, + GError **error); + gboolean bolt_copy_bytes (int fd_from, int fd_to, size_t len, -- GitLab From da70b288e5d36128ebc133db4374d0dcd305d16c Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 17:02:20 +0100 Subject: [PATCH 20/27] test/common: checks for bolt_renameat wrapper Checks for various invocations of bolt_renameat, including error reporting. --- tests/test-common.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/tests/test-common.c b/tests/test-common.c index 085ae64..2134c49 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -1232,6 +1232,67 @@ test_io_file_write_all (TestIO *tt, gconstpointer user_data) g_assert_true (strncmp (data, ref, 5) == 0); } +static void +test_io_renameat (TestIO *tt, gconstpointer user_data) +{ + g_autoptr(GError) err = NULL; + g_autoptr(DIR) root = NULL; + g_autoptr(DIR) subdir = NULL; + struct stat st; + gboolean ok; + + root = bolt_opendir (tt->path, &err); + g_assert_no_error (err); + g_assert_nonnull (root); + + ok = bolt_write_file_at (dirfd (root), "a", "a", -1, &err); + g_assert_no_error (err); + g_assert_true (ok); + + ok = bolt_mkdirat (dirfd (root), "subdir", 0777, &err); + g_assert_no_error (err); + g_assert_true (ok); + + subdir = bolt_opendir_at (dirfd (root), "subdir", O_RDONLY, &err); + g_assert_no_error (err); + g_assert_nonnull (subdir); + + ok = bolt_renameat (dirfd (root), "a", + dirfd (subdir), "b", + &err); + + g_assert_no_error (err); + g_assert_true (ok); + + ok = bolt_fstatat (dirfd (subdir), "b", &st, 0, &err); + g_assert_no_error (err); + g_assert_true (ok); + + g_assert_true (S_ISREG (st.st_mode)); + + ok = bolt_renameat (dirfd (subdir), "b", + dirfd (subdir), "c", + &err); + + g_assert_no_error (err); + g_assert_true (ok); + + memset (&st, 0, sizeof (st)); + ok = bolt_fstatat (dirfd (subdir), "c", &st, 0, &err); + g_assert_no_error (err); + g_assert_true (ok); + + g_assert_true (S_ISREG (st.st_mode)); + + /* error reporting: file not found */ + ok = bolt_renameat (dirfd (subdir), "b", + dirfd (subdir), "c", + &err); + + g_assert_error (err, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert_false (ok); +} + static void test_io_copy_bytes (TestIO *tt, gconstpointer user_data) { @@ -2456,6 +2517,13 @@ main (int argc, char **argv) test_io_file_write_all, test_io_tear_down); + g_test_add ("/common/io/renameat", + TestIO, + NULL, + test_io_setup, + test_io_renameat, + test_io_tear_down); + g_test_add ("/common/io/copy_bytes", TestIO, NULL, -- GitLab From 374bf33b5b17e7bd4c4332704a1948b9f0ba357c Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 21 Oct 2020 10:17:59 +0200 Subject: [PATCH 21/27] manager: extract store initialization Instead of initializing the store in the basic object init method, create a new method that bundles all store related initialization and call that from bolt_manager_initialize. This prepares for the possibility that store initialization can fail. --- boltd/bolt-manager.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/boltd/bolt-manager.c b/boltd/bolt-manager.c index ea4a605..6f4e53d 100644 --- a/boltd/bolt-manager.c +++ b/boltd/bolt-manager.c @@ -53,6 +53,8 @@ static gboolean bolt_manager_initialize (GInitable *initable, GCancellable *cancellable, GError **error); +static void bolt_manager_store_init (BoltManager *mgr); + /* internal manager functions */ static void manager_sd_notify_status (BoltManager *mgr); @@ -352,7 +354,6 @@ static void bolt_manager_init (BoltManager *mgr) { mgr->devices = g_ptr_array_new_with_free_func (g_object_unref); - mgr->store = bolt_store_new (bolt_get_store_path ()); mgr->probing_roots = g_ptr_array_new_with_free_func (g_free); mgr->probing_tsettle = PROBING_SETTLE_TIME_MS; /* milliseconds */ @@ -362,14 +363,6 @@ bolt_manager_init (BoltManager *mgr) /* default configuration */ mgr->policy = BOLT_POLICY_AUTO; mgr->authmode = BOLT_AUTH_ENABLED; - - g_signal_connect_object (mgr->store, "device-added", - G_CALLBACK (handle_store_device_added), - mgr, 0); - - g_signal_connect_object (mgr->store, "device-removed", - G_CALLBACK (handle_store_device_removed), - mgr, 0); } static void @@ -487,6 +480,8 @@ bolt_manager_initialize (GInitable *initable, mgr = BOLT_MANAGER (initable); + bolt_manager_store_init (mgr); + /* load dynamic user configuration */ manager_load_user_config (mgr); @@ -579,6 +574,22 @@ bolt_manager_initialize (GInitable *initable, return TRUE; } +static void +bolt_manager_store_init (BoltManager *mgr) +{ + bolt_info (LOG_TOPIC ("manager"), "initializing store"); + + mgr->store = bolt_store_new (bolt_get_store_path ()); + + g_signal_connect_object (mgr->store, "device-added", + G_CALLBACK (handle_store_device_added), + mgr, 0); + + g_signal_connect_object (mgr->store, "device-removed", + G_CALLBACK (handle_store_device_removed), + mgr, 0); +} + /* internal functions */ static void manager_sd_notify_status (BoltManager *mgr) -- GitLab From acd72a98a6c4c460fb41da8bb781cbcfed4204de Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 21 Oct 2020 12:15:04 +0200 Subject: [PATCH 22/27] store: convert to be initable Convert the store use the GInitable interface. This prepares for store on-disk initialization that can fail. Currently, nothing is actually done in initialize and thus it will never fail. Adapt all tests to check for potential store creation errors and also convert the manager's store initialization method to handle the error. --- boltd/bolt-manager.c | 18 +++++++++++++----- boltd/bolt-store.c | 39 +++++++++++++++++++++++++++++++-------- boltd/bolt-store.h | 3 ++- tests/test-store.c | 6 +++--- tests/test-sysfs.c | 5 ++++- 5 files changed, 53 insertions(+), 18 deletions(-) diff --git a/boltd/bolt-manager.c b/boltd/bolt-manager.c index 6f4e53d..6b3b635 100644 --- a/boltd/bolt-manager.c +++ b/boltd/bolt-manager.c @@ -53,7 +53,8 @@ static gboolean bolt_manager_initialize (GInitable *initable, GCancellable *cancellable, GError **error); -static void bolt_manager_store_init (BoltManager *mgr); +static gboolean bolt_manager_store_init (BoltManager *mgr, + GError **error); /* internal manager functions */ static void manager_sd_notify_status (BoltManager *mgr); @@ -480,7 +481,10 @@ bolt_manager_initialize (GInitable *initable, mgr = BOLT_MANAGER (initable); - bolt_manager_store_init (mgr); + /* store setup */ + ok = bolt_manager_store_init (mgr, error); + if (!ok) + return FALSE; /* load dynamic user configuration */ manager_load_user_config (mgr); @@ -574,12 +578,14 @@ bolt_manager_initialize (GInitable *initable, return TRUE; } -static void -bolt_manager_store_init (BoltManager *mgr) +static gboolean +bolt_manager_store_init (BoltManager *mgr, GError **error) { bolt_info (LOG_TOPIC ("manager"), "initializing store"); - mgr->store = bolt_store_new (bolt_get_store_path ()); + mgr->store = bolt_store_new (bolt_get_store_path (), error); + if (mgr->store == NULL) + return FALSE; g_signal_connect_object (mgr->store, "device-added", G_CALLBACK (handle_store_device_added), @@ -588,6 +594,8 @@ bolt_manager_store_init (BoltManager *mgr) g_signal_connect_object (mgr->store, "device-removed", G_CALLBACK (handle_store_device_removed), mgr, 0); + + return TRUE; } /* internal functions */ diff --git a/boltd/bolt-store.c b/boltd/bolt-store.c index 0e85783..944a0af 100644 --- a/boltd/bolt-store.c +++ b/boltd/bolt-store.c @@ -34,6 +34,13 @@ /* ************************************ */ /* BoltStore */ +static void bolt_store_initable_iface_init (GInitableIface *iface); + + +static gboolean bolt_store_initialize (GInitable *initable, + GCancellable *cancellable, + GError **error); + struct _BoltStore { GObject object; @@ -66,9 +73,11 @@ enum { static guint signals[SIGNAL_LAST] = {0}; -G_DEFINE_TYPE (BoltStore, - bolt_store, - G_TYPE_OBJECT) +G_DEFINE_TYPE_WITH_CODE (BoltStore, + bolt_store, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + bolt_store_initable_iface_init)); static void @@ -190,6 +199,20 @@ bolt_store_class_init (BoltStoreClass *klass) 1, G_TYPE_STRING); } +static void +bolt_store_initable_iface_init (GInitableIface *iface) +{ + iface->init = bolt_store_initialize; +} + +static gboolean +bolt_store_initialize (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} + /* internal methods */ #define DOMAIN_GROUP "domain" #define DEVICE_GROUP "device" @@ -200,16 +223,16 @@ bolt_store_class_init (BoltStoreClass *klass) /* public methods */ BoltStore * -bolt_store_new (const char *path) +bolt_store_new (const char *path, GError **error) { g_autoptr(GFile) root = NULL; BoltStore *store; root = g_file_new_for_path (path); - store = g_object_new (BOLT_TYPE_STORE, - "root", root, - NULL); - + store = g_initable_new (BOLT_TYPE_STORE, + NULL, error, + "root", root, + NULL); return store; } diff --git a/boltd/bolt-store.h b/boltd/bolt-store.h index e9c6504..b28fd80 100644 --- a/boltd/bolt-store.h +++ b/boltd/bolt-store.h @@ -34,7 +34,8 @@ G_BEGIN_DECLS #define BOLT_TYPE_STORE bolt_store_get_type () G_DECLARE_FINAL_TYPE (BoltStore, bolt_store, BOLT, STORE, GObject); -BoltStore * bolt_store_new (const char *path); +BoltStore * bolt_store_new (const char *path, + GError **error); GKeyFile * bolt_store_config_load (BoltStore *store, GError **error); diff --git a/tests/test-store.c b/tests/test-store.c index 655d1d2..924754a 100644 --- a/tests/test-store.c +++ b/tests/test-store.c @@ -66,11 +66,11 @@ test_store_setup (TestStore *tt, gconstpointer user_data) } - tt->store = bolt_store_new (tt->path); + tt->store = bolt_store_new (tt->path, &error); if (tt->store == NULL) { - g_critical ("Could not create store at %s", - tt->path); + g_critical ("Could not create store at %s: %s", + tt->path, error->message); return; } diff --git a/tests/test-sysfs.c b/tests/test-sysfs.c index fc071a2..9b9b3ed 100644 --- a/tests/test-sysfs.c +++ b/tests/test-sysfs.c @@ -1104,7 +1104,10 @@ test_bootacl_update_offline (TestBootacl *tt, gconstpointer user) guint k; dir = bolt_tmp_dir_make ("bolt.sysfs.XXXXXX", NULL); - store = bolt_store_new (dir); + store = bolt_store_new (dir, &err); + + g_assert_no_error (err); + g_assert_nonnull (store); ok = bolt_store_put_domain (store, dom, &err); g_assert_no_error (err); -- GitLab From f5a7fa0d572fde5e64f504fc3e011414f8a35500 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 13 Oct 2020 16:40:41 +0200 Subject: [PATCH 23/27] store: introduce store versioning Add version information to the on-disk store and expose that information via a new "version" store object property. The on-disk information is stored in a new 'version' file, that is located at the root of the store. In case no such file is found, the store version is defined as 0 (zero). When a store is opened, and the root of the store is completely empty (i.e. no sub-directories or the version file is present), the store is assumed to be new and is initialized by creating the 'version' containing the BOLT_STORE_VERSION number. --- boltd/bolt-store.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ boltd/bolt-store.h | 4 +++ 2 files changed, 84 insertions(+) diff --git a/boltd/bolt-store.c b/boltd/bolt-store.c index 944a0af..8af2585 100644 --- a/boltd/bolt-store.c +++ b/boltd/bolt-store.c @@ -41,6 +41,9 @@ static gboolean bolt_store_initialize (GInitable *initable, GCancellable *cancellable, GError **error); +static gboolean bolt_store_init_store (DIR *root, + GError **error); + struct _BoltStore { GObject object; @@ -50,6 +53,8 @@ struct _BoltStore GFile *devices; GFile *keys; GFile *times; + + guint version; }; @@ -57,6 +62,7 @@ enum { PROP_STORE_0, PROP_ROOT, + PROP_VERSION, PROP_STORE_LAST }; @@ -113,6 +119,10 @@ bolt_store_get_property (GObject *object, g_value_set_object (value, store->root); break; + case PROP_VERSION: + g_value_set_uint (value, store->version); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -174,6 +184,13 @@ bolt_store_class_init (BoltStoreClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME); + store_props[PROP_VERSION] = + g_param_spec_uint ("version", + NULL, NULL, + 0, G_MAXUINT, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (gobject_class, PROP_STORE_LAST, store_props); @@ -210,6 +227,30 @@ bolt_store_initialize (GInitable *initable, GCancellable *cancellable, GError **error) { + g_autoptr(GError) err = NULL; + g_autoptr(DIR) root = NULL; + g_autofree char *path = NULL; + BoltStore *store = BOLT_STORE (initable); + gboolean ok; + + path = g_file_get_path (store->root); + root = bolt_opendir (path, error); + + if (root == NULL) + return FALSE; + + ok = bolt_store_init_store (root, error); + if (!ok) + return FALSE; + + ok = bolt_read_uint_at (dirfd (root), + "version", + &store->version, + &err); + + if (!ok && !bolt_err_notfound (err)) + return bolt_error_propagate (error, &err); + return TRUE; } @@ -220,6 +261,37 @@ bolt_store_initialize (GInitable *initable, #define CFG_FILE "boltd.conf" +static gboolean +bolt_store_init_store (DIR *root, + GError **error) +{ + gboolean empty; + gboolean ok; + + /* initialize an empty store with the basic layout, + * which currently is just a 'version' field, since + * all other directories are created on-demand */ + + ok = bolt_dir_is_empty (root, &empty, error); + if (!ok) + return FALSE; + + bolt_debug (LOG_TOPIC ("store"), "needs init: %s", + bolt_yesno (empty)); + + if (!empty) + return TRUE; + + bolt_info (LOG_TOPIC ("store"), "initializing"); + + /* store is empty, create the 'version' file */ + ok = bolt_write_uint_at (dirfd (root), + "version", + BOLT_STORE_VERSION, + error); + return ok; +} + /* public methods */ BoltStore * @@ -236,6 +308,14 @@ bolt_store_new (const char *path, GError **error) return store; } +guint +bolt_store_get_version (BoltStore *store) +{ + g_return_val_if_fail (BOLT_IS_STORE (store), 0); + + return store->version; +} + GKeyFile * bolt_store_config_load (BoltStore *store, GError **error) diff --git a/boltd/bolt-store.h b/boltd/bolt-store.h index b28fd80..8deffd1 100644 --- a/boltd/bolt-store.h +++ b/boltd/bolt-store.h @@ -30,6 +30,8 @@ G_BEGIN_DECLS +#define BOLT_STORE_VERSION 1 + /* BoltStore - database for devices, keys */ #define BOLT_TYPE_STORE bolt_store_get_type () G_DECLARE_FINAL_TYPE (BoltStore, bolt_store, BOLT, STORE, GObject); @@ -37,6 +39,8 @@ G_DECLARE_FINAL_TYPE (BoltStore, bolt_store, BOLT, STORE, GObject); BoltStore * bolt_store_new (const char *path, GError **error); +guint bolt_store_get_version (BoltStore *store); + GKeyFile * bolt_store_config_load (BoltStore *store, GError **error); -- GitLab From 1b0f7aa96c954442913be89a9faa65e49d1b0ad6 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 19:49:30 +0100 Subject: [PATCH 24/27] store: introduce store upgrades Add a new function to upgrade the store from version "0" to "1". Except the addition of the 'version' file there is no difference between the two versions and thus creating said 'version' file is all the store upgrade does. This can still be useful, because it can be used as a marker, e.g. the manager can use it to clean up the store once when upgrading from version 0. --- boltd/bolt-store.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ boltd/bolt-store.h | 5 +++++ 2 files changed, 58 insertions(+) diff --git a/boltd/bolt-store.c b/boltd/bolt-store.c index 8af2585..f771dca 100644 --- a/boltd/bolt-store.c +++ b/boltd/bolt-store.c @@ -1269,3 +1269,56 @@ bolt_store_has_journal (BoltStore *store, return g_file_query_exists (journal, NULL); } + +gboolean +bolt_store_upgrade (BoltStore *store, + gboolean *upgrade, + GError **error) +{ + g_autoptr(DIR) root = NULL; + g_autofree char *path = NULL; + gboolean need_upgrade; + gboolean ok; + + g_return_val_if_fail (BOLT_IS_STORE (store), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + need_upgrade = store->version != BOLT_STORE_VERSION; + + if (upgrade) + *upgrade = need_upgrade; + + if (!need_upgrade) + return TRUE; + + path = g_file_get_path (store->root); + root = bolt_opendir (path, error); + + if (!root) + return FALSE; + + ok = bolt_write_int_at (dirfd (root), + ".version-upgrade", + BOLT_STORE_VERSION, + error); + if (!ok) + return FALSE; + + ok = bolt_renameat (dirfd (root), + ".version-upgrade", + dirfd (root), + "version", + error); + + if (!ok) + { + bolt_unlink_at (dirfd (root), ".version-upgrade", 0, NULL); + return FALSE; + } + + store->version = BOLT_STORE_VERSION; + g_object_notify_by_pspec (G_OBJECT (store), + store_props[PROP_VERSION]); + + return ok; +} diff --git a/boltd/bolt-store.h b/boltd/bolt-store.h index 8deffd1..1cb6d46 100644 --- a/boltd/bolt-store.h +++ b/boltd/bolt-store.h @@ -144,4 +144,9 @@ gboolean bolt_store_has_journal (BoltStore *store, const char *type, const char *name); +/* store upgrades */ +gboolean bolt_store_upgrade (BoltStore *store, + gboolean *upgrade, + GError **error); + G_END_DECLS -- GitLab From ef6e6d1ca5fac79a01cfb36e401c99d0f645ec84 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 28 Oct 2020 19:50:58 +0100 Subject: [PATCH 25/27] manager: upgrade the store Use the new store upgrade mechanism to upgrade the store. Currently nothing is done if an upgrade happens, but it will be used to clean up stale domains, which might have accumulated due to the ice lake domain uuid instability. --- boltd/bolt-manager.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/boltd/bolt-manager.c b/boltd/bolt-manager.c index 6b3b635..6fc88e7 100644 --- a/boltd/bolt-manager.c +++ b/boltd/bolt-manager.c @@ -56,6 +56,8 @@ static gboolean bolt_manager_initialize (GInitable *initable, static gboolean bolt_manager_store_init (BoltManager *mgr, GError **error); +static void bolt_manager_store_upgrade (BoltManager *mgr); + /* internal manager functions */ static void manager_sd_notify_status (BoltManager *mgr); @@ -573,6 +575,9 @@ bolt_manager_initialize (GInitable *initable, udev_enumerate_unref (enumerate); + /* upgrade the store, if needed */ + bolt_manager_store_upgrade (mgr); + manager_sd_notify_status (mgr); return TRUE; @@ -598,6 +603,36 @@ bolt_manager_store_init (BoltManager *mgr, GError **error) return TRUE; } +static void +bolt_manager_store_upgrade (BoltManager *mgr) +{ + g_autoptr(GError) err = NULL; + BoltStore *store = mgr->store; + guint ver; + gboolean ok; + + ver = bolt_store_get_version (store); + + if (ver == BOLT_STORE_VERSION) + { + bolt_debug (LOG_TOPIC ("store"), "store is up to date"); + return; + } + + bolt_info (LOG_TOPIC ("store"), "attempting upgrade from '%d'", + ver); + + ok = bolt_store_upgrade (store, NULL, &err); + if (!ok) + { + bolt_warn_err (err, LOG_TOPIC ("store"), "upgrade failed"); + return; + } + + bolt_info (LOG_TOPIC ("store"), "upgraded to version '%d'", + ver); +} + /* internal functions */ static void manager_sd_notify_status (BoltManager *mgr) -- GitLab From 70d27660a4d39b2eaa988f8e4017d4a2dfd09b3f Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Tue, 27 Oct 2020 16:20:22 +0100 Subject: [PATCH 26/27] test/store: checks for version Add basic checks for the version property. Check it matches the store code version. --- tests/test-store.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test-store.c b/tests/test-store.c index 924754a..63c45cd 100644 --- a/tests/test-store.c +++ b/tests/test-store.c @@ -105,12 +105,19 @@ test_store_basic (TestStore *tt, gconstpointer user_data) g_autofree char *path = NULL; char uid[] = "fbc83890-e9bf-45e5-a777-b3728490989c"; BoltKeyState keystate; + guint version; gboolean ok; g_object_get (tt->store, "root", &root, NULL); path = g_file_get_path (root); g_assert_cmpstr (tt->path, ==, path); + g_object_get (tt->store, "version", &version, NULL); + g_assert_cmpuint (version, ==, BOLT_STORE_VERSION); + + version = bolt_store_get_version (tt->store); + g_assert_cmpuint (version, ==, BOLT_STORE_VERSION); + dev = g_object_new (BOLT_TYPE_DEVICE, "uid", uid, "name", "Laptop", -- GitLab From 8ca11b19726b863ec00c9bd49aff98c585a90cf4 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Wed, 4 Nov 2020 17:41:09 +0100 Subject: [PATCH 27/27] test/store: upgrade test Add a store upgrade test: force the store to have version 0 and then upgrade it to 1. The only difference between the to is the presence of the "version" file (which must contain the version info, i.e. "1"). Check that calling the upgrade function again does not change anything. --- tests/test-store.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/test-store.c b/tests/test-store.c index 63c45cd..93ce1ea 100644 --- a/tests/test-store.c +++ b/tests/test-store.c @@ -827,6 +827,79 @@ test_store_journal (TestStore *tt, gconstpointer user_data) } +static void +test_store_upgrade (TestStore *tt, gconstpointer user_data) +{ + g_autoptr(BoltDevice) dev = NULL; + g_autoptr(GError) err = NULL; + g_autoptr(DIR) root = NULL; + char uid[] = "fbc83890-e9bf-45e5-a777-b3728490989c"; + guint version; + gboolean up; + gboolean ok; + + /* simulate a version 0 store, i.e. has some entries, + * but no 'version' file */ + + root = bolt_opendir (tt->path, &err); + g_assert_no_error (err); + g_assert_nonnull (root); + + version = bolt_store_get_version (tt->store); + g_assert_cmpuint (version, ==, BOLT_STORE_VERSION); + + dev = g_object_new (BOLT_TYPE_DEVICE, + "uid", uid, + "name", "Laptop", + "vendor", "GNOME.org", + "status", BOLT_STATUS_DISCONNECTED, + NULL); + + ok = bolt_store_put_device (tt->store, dev, BOLT_POLICY_AUTO, NULL, &err); + g_assert_no_error (err); + g_assert_true (ok); + + /* close the store, delete 'version' */ + g_clear_object (&tt->store); + + ok = bolt_unlink_at (dirfd (root), "version", 0, &err); + g_assert_no_error (err); + g_assert_true (ok); + + /* re-create the store object */ + tt->store = bolt_store_new (tt->path, &err); + g_assert_no_error (err); + g_assert_nonnull (tt->store); + + version = bolt_store_get_version (tt->store); + g_assert_cmpuint (version, ==, 0); + + /* no upgrade the store */ + ok = bolt_store_upgrade (tt->store, &up, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_true (up); + + /* assert the upgrade changed the version */ + version = bolt_store_get_version (tt->store); + g_assert_cmpuint (version, ==, BOLT_STORE_VERSION); + + /* upgrade again, check it did not do anything */ + ok = bolt_store_upgrade (tt->store, &up, &err); + g_assert_no_error (err); + g_assert_true (ok); + g_assert_false (up); + + version = bolt_store_get_version (tt->store); + g_assert_cmpuint (version, ==, BOLT_STORE_VERSION); + + /* ensure 'upgrade' argument is optional */ + ok = bolt_store_upgrade (tt->store, NULL, &err); + g_assert_no_error (err); + g_assert_true (ok); + +} + int main (int argc, char **argv) { @@ -893,5 +966,12 @@ main (int argc, char **argv) test_store_journal, test_store_tear_down); + g_test_add ("/daemon/store/upgrade", + TestStore, + NULL, + test_store_setup, + test_store_upgrade, + test_store_tear_down); + return g_test_run (); } -- GitLab