summaryrefslogtreecommitdiff
path: root/gio/tests/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'gio/tests/file.c')
-rw-r--r--gio/tests/file.c977
1 files changed, 844 insertions, 133 deletions
diff --git a/gio/tests/file.c b/gio/tests/file.c
index a849e83cf..754c6c326 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -1,3 +1,5 @@
+#include "config.h"
+
#include <locale.h>
#include <string.h>
#include <stdio.h>
@@ -8,6 +10,12 @@
#include <sys/stat.h>
#endif
+typedef struct
+{
+ GMainLoop *loop;
+ GError **error;
+} AsyncErrorData;
+
static void
test_basic_for_file (GFile *file,
const gchar *suffix)
@@ -444,15 +452,13 @@ created_cb (GObject *source,
data);
}
-static gboolean
+static void
stop_timeout (gpointer user_data)
{
CreateDeleteData *data = user_data;
data->timed_out = TRUE;
g_main_context_wakeup (data->context);
-
- return G_SOURCE_REMOVE;
}
/*
@@ -510,7 +516,7 @@ test_create_delete (gconstpointer d)
/* Use the global default main context */
data->context = NULL;
- data->timeout = g_timeout_add_seconds (10, stop_timeout, data);
+ data->timeout = g_timeout_add_seconds_once (10, stop_timeout, data);
g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
@@ -852,6 +858,18 @@ test_replace_symlink (void)
g_test_message ("Using temporary directory %s", tmpdir_path);
g_free (tmpdir_path);
+ source_file = g_file_get_child (tmpdir, "source");
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion*symlink_value*failed*");
+ g_assert_false (g_file_make_symbolic_link (source_file, NULL, NULL, &local_error));
+ g_assert_no_error (local_error);
+ g_test_assert_expected_messages ();
+
+ g_assert_false (g_file_make_symbolic_link (source_file, "", NULL, &local_error));
+ g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
+ g_clear_object (&source_file);
+ g_clear_error (&local_error);
+
/* Create symlink `source` which points to `target`. */
source_file = g_file_get_child (tmpdir, "source");
target_file = g_file_get_child (tmpdir, "target");
@@ -1290,6 +1308,65 @@ check_test_file (GFile *test_file,
#endif /* __linux__ */
+#ifdef __linux__
+/*
+ * check_cap_dac_override:
+ * @tmpdir: A temporary directory in which we can create and delete files
+ *
+ * Check whether the current process can bypass DAC permissions.
+ *
+ * Traditionally, "privileged" processes (those with effective uid 0)
+ * could do this (and bypass many other checks), and "unprivileged"
+ * processes could not.
+ *
+ * In Linux, the special powers of euid 0 are divided into many
+ * capabilities: see `capabilities(7)`. The one we are interested in
+ * here is `CAP_DAC_OVERRIDE`.
+ *
+ * We do this generically instead of actually looking at the capability
+ * bits, so that the right thing will happen on non-Linux Unix
+ * implementations, in particular if they have something equivalent to
+ * but not identical to Linux permissions.
+ *
+ * Returns: %TRUE if we have Linux `CAP_DAC_OVERRIDE` or equivalent
+ * privileges
+ */
+static gboolean
+check_cap_dac_override (const char *tmpdir)
+{
+ gchar *dac_denies_write;
+ gchar *inside;
+ gboolean have_cap;
+
+ dac_denies_write = g_build_filename (tmpdir, "dac-denies-write", NULL);
+ inside = g_build_filename (dac_denies_write, "inside", NULL);
+
+ g_assert_no_errno (mkdir (dac_denies_write, S_IRWXU));
+ g_assert_no_errno (chmod (dac_denies_write, 0));
+
+ if (mkdir (inside, S_IRWXU) == 0)
+ {
+ g_test_message ("Looks like we have CAP_DAC_OVERRIDE or equivalent");
+ g_assert_no_errno (rmdir (inside));
+ have_cap = TRUE;
+ }
+ else
+ {
+ int saved_errno = errno;
+
+ g_test_message ("We do not have CAP_DAC_OVERRIDE or equivalent");
+ g_assert_cmpint (saved_errno, ==, EACCES);
+ have_cap = FALSE;
+ }
+
+ g_assert_no_errno (chmod (dac_denies_write, S_IRWXU));
+ g_assert_no_errno (rmdir (dac_denies_write));
+ g_free (dac_denies_write);
+ g_free (inside);
+ return have_cap;
+}
+#endif
+
/* A big test for g_file_replace() and g_file_replace_readwrite(). The
* @test_data is a boolean: %TRUE to test g_file_replace_readwrite(), %FALSE to
* test g_file_replace(). The test setup and checks are identical for both
@@ -1330,6 +1407,7 @@ test_replace (gconstpointer test_data)
guint setup_source_mode;
FileTestSetupType setup_backup_type;
guint setup_backup_mode;
+ gboolean skip_if_cap_dac_override;
/* Expected results. */
gboolean expected_success;
@@ -1353,7 +1431,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1361,7 +1439,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1369,7 +1447,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1377,7 +1455,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1385,7 +1463,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1393,7 +1471,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1401,7 +1479,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1412,7 +1490,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_NONE, "incorrect etag",
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1424,7 +1502,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1432,7 +1510,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
@@ -1440,7 +1518,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1448,7 +1526,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1456,7 +1534,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1464,7 +1542,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
/* The final situation here is a bit odd; the backup file is a bit
* pointless as the original source file was a dangling symlink.
@@ -1480,7 +1558,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
/* FIXME: The permissions for the backup file are just the default umask,
* but should probably be the same as the permissions for the source
@@ -1496,7 +1574,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1504,7 +1582,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1512,7 +1590,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1520,7 +1598,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
+ FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
@@ -1528,7 +1606,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
+ FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1536,7 +1614,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
+ FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1544,7 +1622,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
+ FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
TRUE, 0, 0,
/* the third file is `source~-target`, the original target of the old
* backup symlink */
@@ -1558,7 +1636,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1566,7 +1644,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1574,7 +1652,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1582,7 +1660,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1590,7 +1668,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1598,7 +1676,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1606,7 +1684,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
/* the third file is `source-target`, the original target of the old
* source file */
@@ -1620,7 +1698,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_REPLACE_DESTINATION, "incorrect etag",
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1633,7 +1711,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1641,7 +1719,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
@@ -1649,7 +1727,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1657,7 +1735,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1665,7 +1743,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
@@ -1673,7 +1751,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, "source-target",
@@ -1681,7 +1759,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
/* the third file is `source-target`, the original target of the old
* source file */
@@ -1696,7 +1774,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1704,7 +1782,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1712,7 +1790,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
+ FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1720,7 +1798,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
+ FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
@@ -1728,7 +1806,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
+ FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1736,7 +1814,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
+ FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
TRUE, 0, 0,
2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
@@ -1744,7 +1822,7 @@ test_replace (gconstpointer test_data)
{
TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
+ FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
TRUE, 0, 0,
/* the third file is `source~-target`, the original target of the old
* backup symlink */
@@ -1756,7 +1834,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_PRIVATE, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1764,7 +1842,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_PRIVATE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
/* the file isn’t being replaced, so it should keep its existing permissions */
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
@@ -1773,7 +1851,7 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1781,18 +1859,21 @@ test_replace (gconstpointer test_data)
{
FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
TRUE, 0, 0,
1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
},
/* make the initial source file unreadable, so the replace operation
- * should fail */
+ * should fail
+ *
+ * Permissions are ignored if we have CAP_DAC_OVERRIDE or equivalent,
+ * and in particular if we're root. In this scenario,we need to skip it */
{
FALSE, G_FILE_CREATE_NONE, NULL,
FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0 /* most restrictive permissions */,
- FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
+ FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, TRUE,
FALSE, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1, FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0, NULL,
FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
@@ -1824,6 +1905,19 @@ test_replace (gconstpointer test_data)
tmpdir = g_file_new_for_path (tmpdir_path);
g_test_message ("Test %" G_GSIZE_FORMAT ", using temporary directory %s", i, tmpdir_path);
+
+ if (tests[i].skip_if_cap_dac_override && check_cap_dac_override (tmpdir_path))
+ {
+ g_test_message ("Skipping test as process has CAP_DAC_OVERRIDE capability and the test checks permissions");
+
+ g_file_delete (tmpdir, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_clear_object (&tmpdir);
+ g_free (tmpdir_path);
+
+ continue;
+ }
+
g_free (tmpdir_path);
/* Set up the test directory. */
@@ -1959,6 +2053,200 @@ test_replace (gconstpointer test_data)
}
static void
+on_new_tmp_done (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file;
+ GFile *parent;
+ GFileInfo *info;
+ GFileIOStream *iostream;
+ GError *error = NULL;
+ GMainLoop *loop = user_data;
+ gchar *basename;
+ GFile *tmpdir = NULL;
+
+ g_assert_null (object);
+
+ file = g_file_new_tmp_finish (result, &iostream, &error);
+ g_assert_no_error (error);
+
+ g_assert_true (g_file_query_exists (file, NULL));
+
+ basename = g_file_get_basename (file);
+ g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_async_"));
+
+ info = g_file_io_stream_query_info (iostream, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
+ g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
+ g_assert_no_error (error);
+
+ parent = g_file_get_parent (file);
+ tmpdir = g_file_new_for_path (g_get_tmp_dir ());
+
+ g_assert_true (g_file_equal (tmpdir, parent));
+
+ g_main_loop_quit (loop);
+
+ g_object_unref (file);
+ g_object_unref (parent);
+ g_object_unref (iostream);
+ g_object_unref (info);
+ g_free (basename);
+ g_object_unref (tmpdir);
+}
+
+static void
+on_new_tmp_error (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFileIOStream *iostream = (GFileIOStream*) &on_new_tmp_error;
+ AsyncErrorData *error_data = user_data;
+
+ g_assert_null (object);
+
+ g_assert_null (g_file_new_tmp_finish (result, &iostream, error_data->error));
+ g_assert_nonnull (error_data->error);
+ g_assert_null (iostream);
+
+ g_main_loop_quit (error_data->loop);
+}
+
+static void
+test_async_new_tmp (void)
+{
+ GMainLoop *loop;
+ GError *error = NULL;
+ GCancellable *cancellable;
+ AsyncErrorData error_data = { .error = &error };
+
+ loop = g_main_loop_new (NULL, TRUE);
+ error_data.loop = loop;
+
+ g_file_new_tmp_async ("g_file_new_tmp_async_XXXXXX",
+ G_PRIORITY_DEFAULT, NULL,
+ on_new_tmp_done, loop);
+ g_main_loop_run (loop);
+
+ g_file_new_tmp_async ("g_file_new_tmp_async_invalid_template",
+ G_PRIORITY_DEFAULT, NULL,
+ on_new_tmp_error, &error_data);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+ g_clear_error (&error);
+
+ cancellable = g_cancellable_new ();
+ g_file_new_tmp_async ("g_file_new_tmp_async_cancelled_XXXXXX",
+ G_PRIORITY_DEFAULT, cancellable,
+ on_new_tmp_error, &error_data);
+ g_cancellable_cancel (cancellable);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_object (&cancellable);
+ g_clear_error (&error);
+
+ g_main_loop_unref (loop);
+}
+
+static void
+on_new_tmp_dir_done (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file;
+ GFile *parent;
+ GFileInfo *info;
+ GError *error = NULL;
+ GMainLoop *loop = user_data;
+ gchar *basename;
+ GFile *tmpdir = NULL;
+
+ g_assert_null (object);
+
+ file = g_file_new_tmp_dir_finish (result, &error);
+ g_assert_no_error (error);
+
+ g_assert_true (g_file_query_exists (file, NULL));
+
+ basename = g_file_get_basename (file);
+ g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_dir_async_"));
+
+ info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE, NULL, &error);
+ g_assert_no_error (error);
+
+ g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_DIRECTORY);
+
+ parent = g_file_get_parent (file);
+ tmpdir = g_file_new_for_path (g_get_tmp_dir ());
+
+ g_assert_true (g_file_equal (tmpdir, parent));
+
+ g_main_loop_quit (loop);
+
+ g_object_unref (file);
+ g_object_unref (parent);
+ g_object_unref (info);
+ g_free (basename);
+ g_object_unref (tmpdir);
+}
+
+static void
+on_new_tmp_dir_error (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ AsyncErrorData *error_data = user_data;
+
+ g_assert_null (object);
+
+ g_assert_null (g_file_new_tmp_dir_finish (result, error_data->error));
+ g_assert_nonnull (error_data->error);
+
+ g_main_loop_quit (error_data->loop);
+}
+
+static void
+test_async_new_tmp_dir (void)
+{
+ GMainLoop *loop;
+ GError *error = NULL;
+ GCancellable *cancellable;
+ AsyncErrorData error_data = { .error = &error };
+
+ loop = g_main_loop_new (NULL, TRUE);
+ error_data.loop = loop;
+
+ g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_XXXXXX",
+ G_PRIORITY_DEFAULT, NULL,
+ on_new_tmp_dir_done, loop);
+ g_main_loop_run (loop);
+
+ g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async",
+ G_PRIORITY_DEFAULT, NULL,
+ on_new_tmp_dir_error, &error_data);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
+ g_clear_error (&error);
+
+ cancellable = g_cancellable_new ();
+ g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_cancelled_XXXXXX",
+ G_PRIORITY_DEFAULT, cancellable,
+ on_new_tmp_dir_error, &error_data);
+ g_cancellable_cancel (cancellable);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_object (&cancellable);
+ g_clear_error (&error);
+
+ g_main_loop_unref (loop);
+}
+
+static void
on_file_deleted (GObject *object,
GAsyncResult *result,
gpointer user_data)
@@ -2001,6 +2289,133 @@ test_async_delete (void)
}
static void
+on_symlink_done (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = (GFile *) object;
+ GError *error = NULL;
+ GMainLoop *loop = user_data;
+
+ g_assert_true (g_file_make_symbolic_link_finish (file, result, &error));
+ g_assert_no_error (error);
+
+ g_main_loop_quit (loop);
+}
+
+static void
+on_symlink_error (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = (GFile *) object;
+ GError *error = NULL;
+ AsyncErrorData *data = user_data;
+
+ g_assert_false (g_file_make_symbolic_link_finish (file, result, &error));
+ g_assert_nonnull (error);
+ g_propagate_error (data->error, g_steal_pointer (&error));
+
+ g_main_loop_quit (data->loop);
+}
+
+static void
+test_async_make_symlink (void)
+{
+ GFile *link;
+ GFile *parent_dir;
+ GFile *target;
+ GFileInfo *link_info;
+ GFileIOStream *iostream;
+ GError *error = NULL;
+ GCancellable *cancellable;
+ GMainLoop *loop;
+ AsyncErrorData error_data = {0};
+ gchar *tmpdir_path;
+ gchar *target_path;
+
+ target = g_file_new_tmp ("g_file_symlink_target_XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ g_io_stream_close ((GIOStream *) iostream, NULL, &error);
+ g_assert_no_error (error);
+ g_object_unref (iostream);
+
+ g_assert_true (g_file_query_exists (target, NULL));
+
+ loop = g_main_loop_new (NULL, TRUE);
+ error_data.loop = loop;
+ error_data.error = &error;
+
+ tmpdir_path = g_dir_make_tmp ("g_file_symlink_XXXXXX", &error);
+ g_assert_no_error (error);
+
+ parent_dir = g_file_new_for_path (tmpdir_path);
+ g_assert_true (g_file_query_exists (parent_dir, NULL));
+
+ link = g_file_get_child (parent_dir, "symlink");
+ g_assert_false (g_file_query_exists (link, NULL));
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion*symlink_value*failed*");
+ g_file_make_symbolic_link_async (link, NULL,
+ G_PRIORITY_DEFAULT, NULL,
+ on_symlink_done, loop);
+ g_test_assert_expected_messages ();
+
+ g_file_make_symbolic_link_async (link, "",
+ G_PRIORITY_DEFAULT, NULL,
+ on_symlink_error, &error_data);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
+ g_clear_error (&error);
+
+ target_path = g_file_get_path (target);
+ g_file_make_symbolic_link_async (link, target_path,
+ G_PRIORITY_DEFAULT, NULL,
+ on_symlink_done, loop);
+ g_main_loop_run (loop);
+
+ g_assert_true (g_file_query_exists (link, NULL));
+ link_info = g_file_query_info (link,
+ G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
+ G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL,
+ &error);
+ g_assert_no_error (error);
+
+ g_assert_true (g_file_info_get_is_symlink (link_info));
+ g_assert_cmpstr (target_path, ==, g_file_info_get_symlink_target (link_info));
+
+ /* Try creating it again, it fails */
+ g_file_make_symbolic_link_async (link, target_path,
+ G_PRIORITY_DEFAULT, NULL,
+ on_symlink_error, &error_data);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
+ g_clear_error (&error);
+
+ cancellable = g_cancellable_new ();
+ g_file_make_symbolic_link_async (link, target_path,
+ G_PRIORITY_DEFAULT, cancellable,
+ on_symlink_error, &error_data);
+ g_cancellable_cancel (cancellable);
+ g_main_loop_run (loop);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_error (&error);
+ g_clear_object (&cancellable);
+
+ g_main_loop_unref (loop);
+ g_object_unref (target);
+ g_object_unref (parent_dir);
+ g_object_unref (link);
+ g_object_unref (link_info);
+ g_free (tmpdir_path);
+ g_free (target_path);
+}
+
+static void
test_copy_preserve_mode (void)
{
#ifdef G_OS_UNIX
@@ -2098,71 +2513,10 @@ test_copy_preserve_mode (void)
#endif
}
-static gchar *
-splice_to_string (GInputStream *stream,
- GError **error)
-{
- GMemoryOutputStream *buffer = NULL;
- char *ret = NULL;
-
- buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
- if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
- goto out;
-
- if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
- goto out;
-
- if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
- goto out;
-
- ret = g_memory_output_stream_steal_data (buffer);
- out:
- g_clear_object (&buffer);
- return ret;
-}
-
-static gboolean
-get_size_from_du (const gchar *path, guint64 *size)
-{
- GSubprocess *du;
- gboolean ok;
- gchar *result;
- gchar *endptr;
- GError *error = NULL;
- gchar *du_path = NULL;
-
- /* If we can’t find du, don’t try and run the test. */
- du_path = g_find_program_in_path ("du");
- if (du_path == NULL)
- return FALSE;
- g_free (du_path);
-
- du = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE,
- &error,
- "du", "--bytes", "-s", path, NULL);
- g_assert_no_error (error);
-
- result = splice_to_string (g_subprocess_get_stdout_pipe (du), &error);
- g_assert_no_error (error);
-
- *size = g_ascii_strtoll (result, &endptr, 10);
-
- g_subprocess_wait (du, NULL, &error);
- g_assert_no_error (error);
-
- ok = g_subprocess_get_successful (du);
-
- g_object_unref (du);
- g_free (result);
-
- return ok;
-}
-
static void
test_measure (void)
{
GFile *file;
- guint64 size;
guint64 num_bytes;
guint64 num_dirs;
guint64 num_files;
@@ -2173,12 +2527,6 @@ test_measure (void)
path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
file = g_file_new_for_path (path);
- if (!get_size_from_du (path, &size))
- {
- g_test_message ("du not found or fail to run, skipping byte measurement");
- size = 0;
- }
-
ok = g_file_measure_disk_usage (file,
G_FILE_MEASURE_APPARENT_SIZE,
NULL,
@@ -2191,8 +2539,7 @@ test_measure (void)
g_assert_true (ok);
g_assert_no_error (error);
- if (size > 0)
- g_assert_cmpuint (num_bytes, ==, size);
+ g_assert_cmpuint (num_bytes, ==, 74478);
g_assert_cmpuint (num_dirs, ==, 6);
g_assert_cmpuint (num_files, ==, 32);
@@ -2244,8 +2591,7 @@ measure_done (GObject *source,
g_assert_true (ok);
g_assert_no_error (error);
- if (data->expected_bytes > 0)
- g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
+ g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
g_assert_cmpuint (data->expected_dirs, ==, num_dirs);
g_assert_cmpuint (data->expected_files, ==, num_files);
@@ -2274,15 +2620,9 @@ test_measure_async (void)
path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
file = g_file_new_for_path (path);
-
- if (!get_size_from_du (path, &data->expected_bytes))
- {
- g_test_message ("du not found or fail to run, skipping byte measurement");
- data->expected_bytes = 0;
- }
-
g_free (path);
+ data->expected_bytes = 74478;
data->expected_dirs = 6;
data->expected_files = 32;
@@ -2999,6 +3339,20 @@ test_build_attribute_list_for_copy (void)
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
}
#endif
+#ifdef HAVE_UTIMENSAT
+ g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
+ g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ","));
+ if (flags & G_FILE_COPY_ALL_METADATA)
+ {
+ g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
+ g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
+ }
+ else
+ {
+ g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
+ g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
+ }
+#endif
g_free (attrs_with_commas);
}
@@ -3111,12 +3465,361 @@ test_move_async (void)
g_free (destination_path);
}
+static GAppInfo *
+create_command_line_app_info (const char *name,
+ const char *command_line,
+ const char *default_for_type)
+{
+ GAppInfo *info;
+ GError *error = NULL;
+
+ info = g_app_info_create_from_commandline (command_line,
+ name,
+ G_APP_INFO_CREATE_NONE,
+ &error);
+ g_assert_no_error (error);
+
+ g_app_info_set_as_default_for_type (info, default_for_type, &error);
+ g_assert_no_error (error);
+
+ return g_steal_pointer (&info);
+}
+
+static void
+test_query_default_handler_uri (void)
+{
+ GError *error = NULL;
+ GAppInfo *info;
+ GAppInfo *default_info;
+ GFile *file;
+ GFile *invalid_file;
+
+#if defined(G_OS_WIN32) || defined(__APPLE__)
+ g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
+ return;
+#endif
+
+ info = create_command_line_app_info ("Gio File Handler", "true",
+ "x-scheme-handler/gio-file");
+ g_assert_true (G_IS_APP_INFO (info));
+
+ file = g_file_new_for_uri ("gio-file://hello-gio!");
+ default_info = g_file_query_default_handler (file, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_true (g_app_info_equal (default_info, info));
+
+ invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
+ g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_clear_error (&error);
+
+ g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &error);
+ g_assert_no_error (error);
+ g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
+
+ g_object_unref (default_info);
+ g_object_unref (info);
+ g_object_unref (file);
+ g_object_unref (invalid_file);
+}
+
+static void
+test_query_zero_length_content_type (void)
+{
+ GFile *empty_file;
+ GFileInfo *file_info;
+ GError *error = NULL;
+ GFileIOStream *iostream;
+
+ g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=755795");
+ /* Historically, GLib used to explicitly consider zero-size files as text/plain,
+ * so they opened in a text editor. In 2.76, we changed that to application/x-zerosize,
+ * because that’s what xdgmime uses:
+ * - https://gitlab.gnome.org/GNOME/glib/-/blob/2.74.0/gio/glocalfileinfo.c#L1360-1369
+ * - https://bugzilla.gnome.org/show_bug.cgi?id=755795
+ * - https://gitlab.gnome.org/GNOME/glib/-/issues/2777
+ */
+ g_test_summary ("empty files should always be considered application/x-zerosize");
+
+ empty_file = g_file_new_tmp ("empty-file-XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
+ g_assert_no_error (error);
+ g_clear_object (&iostream);
+
+ file_info =
+ g_file_query_info (empty_file,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, &error);
+ g_assert_no_error (error);
+
+#ifndef __APPLE__
+ g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "application/x-zerosize");
+#else
+ g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "public.text");
+#endif
+
+ g_clear_object (&file_info);
+ g_clear_object (&empty_file);
+}
+
+static void
+test_query_default_handler_file (void)
+{
+ GError *error = NULL;
+ GAppInfo *info;
+ GAppInfo *default_info;
+ GFile *text_file;
+ GFile *binary_file;
+ GFile *invalid_file;
+ GFileIOStream *iostream;
+ GOutputStream *output_stream;
+ const char buffer[] = "Text file!\n";
+ const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
+
+#if defined(G_OS_WIN32) || defined(__APPLE__)
+ g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
+ return;
+#endif
+
+ text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
+ g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
+ NULL, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_flush (output_stream, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_close (output_stream, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_object (&iostream);
+
+ info = create_command_line_app_info ("Text handler", "true", "text/plain");
+ g_assert_true (G_IS_APP_INFO (info));
+
+ default_info = g_file_query_default_handler (text_file, NULL, &error);
+ g_assert_no_error (error);
+ g_assert_true (g_app_info_equal (default_info, info));
+
+ invalid_file = g_file_new_for_path ("/hopefully/this-does-not-exists");
+ g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ g_clear_error (&error);
+
+ binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
+ g_output_stream_write_all (output_stream, binary_buffer,
+ G_N_ELEMENTS (binary_buffer),
+ NULL, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_flush (output_stream, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_close (output_stream, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_object (&iostream);
+
+ g_assert_null (g_file_query_default_handler (binary_file, NULL, &error));
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_clear_error (&error);
+
+ g_app_info_remove_supports_type (info, "text/plain", &error);
+ g_assert_no_error (error);
+ g_app_info_reset_type_associations ("text/plain");
+
+ g_object_unref (default_info);
+ g_object_unref (info);
+ g_object_unref (text_file);
+ g_object_unref (binary_file);
+ g_object_unref (invalid_file);
+}
+
+typedef struct {
+ GMainLoop *loop;
+ GAppInfo *info;
+ GError *error;
+} QueryDefaultHandlerData;
+
+static void
+on_query_default (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ QueryDefaultHandlerData *data = user_data;
+
+ data->info = g_file_query_default_handler_finish (G_FILE (source), result,
+ &data->error);
+ g_main_loop_quit (data->loop);
+}
+
+static void
+test_query_default_handler_file_async (void)
+{
+ QueryDefaultHandlerData data = {0};
+ GCancellable *cancellable;
+ GAppInfo *info;
+ GFile *text_file;
+ GFile *binary_file;
+ GFile *invalid_file;
+ GFileIOStream *iostream;
+ GOutputStream *output_stream;
+ const char buffer[] = "Text file!\n";
+ const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
+ GError *error = NULL;
+
+#if defined(G_OS_WIN32) || defined(__APPLE__)
+ g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
+ return;
+#endif
+
+ data.loop = g_main_loop_new (NULL, FALSE);
+
+ text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
+ g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
+ NULL, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_close (output_stream, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_object (&iostream);
+
+ info = create_command_line_app_info ("Text handler", "true", "text/plain");
+ g_assert_true (G_IS_APP_INFO (info));
+
+ g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
+ NULL, on_query_default,
+ &data);
+ g_main_loop_run (data.loop);
+ g_assert_no_error (data.error);
+ g_assert_true (g_app_info_equal (data.info, info));
+ g_clear_object (&data.info);
+
+ invalid_file = g_file_new_for_path ("/hopefully/this/.file/does-not-exists");
+ g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
+ NULL, on_query_default,
+ &data);
+ g_main_loop_run (data.loop);
+ g_assert_null (data.info);
+ g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
+ g_clear_error (&data.error);
+
+ cancellable = g_cancellable_new ();
+ g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
+ cancellable, on_query_default,
+ &data);
+ g_cancellable_cancel (cancellable);
+ g_main_loop_run (data.loop);
+ g_assert_null (data.info);
+ g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_error (&data.error);
+
+ binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
+ g_assert_no_error (error);
+
+ output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
+ g_output_stream_write_all (output_stream, binary_buffer,
+ G_N_ELEMENTS (binary_buffer),
+ NULL, NULL, &error);
+ g_assert_no_error (error);
+
+ g_output_stream_close (output_stream, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_object (&iostream);
+
+ g_file_query_default_handler_async (binary_file, G_PRIORITY_DEFAULT,
+ NULL, on_query_default,
+ &data);
+ g_main_loop_run (data.loop);
+ g_assert_null (data.info);
+ g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_clear_error (&data.error);
+
+ g_app_info_remove_supports_type (info, "text/plain", &error);
+ g_assert_no_error (error);
+ g_app_info_reset_type_associations ("text/plain");
+
+ g_main_loop_unref (data.loop);
+ g_object_unref (info);
+ g_object_unref (text_file);
+ g_object_unref (binary_file);
+ g_object_unref (invalid_file);
+}
+
+static void
+test_query_default_handler_uri_async (void)
+{
+ QueryDefaultHandlerData data = {0};
+ GCancellable *cancellable;
+ GAppInfo *info;
+ GFile *file;
+ GFile *invalid_file;
+
+#if defined(G_OS_WIN32) || defined(__APPLE__)
+ g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
+ return;
+#endif
+
+ info = create_command_line_app_info ("Gio File Handler", "true",
+ "x-scheme-handler/gio-file");
+ g_assert_true (G_IS_APP_INFO (info));
+
+ data.loop = g_main_loop_new (NULL, FALSE);
+
+ file = g_file_new_for_uri ("gio-file://hello-gio!");
+ g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
+ NULL, on_query_default,
+ &data);
+ g_main_loop_run (data.loop);
+ g_assert_no_error (data.error);
+ g_assert_true (g_app_info_equal (data.info, info));
+ g_clear_object (&data.info);
+
+ invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
+ g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
+ NULL, on_query_default,
+ &data);
+ g_main_loop_run (data.loop);
+ g_assert_null (data.info);
+ g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+ g_clear_error (&data.error);
+
+ cancellable = g_cancellable_new ();
+ g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
+ cancellable, on_query_default,
+ &data);
+ g_cancellable_cancel (cancellable);
+ g_main_loop_run (data.loop);
+ g_assert_null (data.info);
+ g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_clear_error (&data.error);
+
+ g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &data.error);
+ g_assert_no_error (data.error);
+ g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
+
+ g_main_loop_unref (data.loop);
+ g_object_unref (info);
+ g_object_unref (file);
+ g_object_unref (invalid_file);
+}
+
int
main (int argc, char *argv[])
{
setlocale (LC_ALL, "");
- g_test_init (&argc, &argv, NULL);
+ g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
g_test_add_func ("/file/basic", test_basic);
g_test_add_func ("/file/build-filename", test_build_filename);
@@ -3136,7 +3839,10 @@ main (int argc, char *argv[])
g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
+ g_test_add_func ("/file/async-new-tmp", test_async_new_tmp);
+ g_test_add_func ("/file/async-new-tmp-dir", test_async_new_tmp_dir);
g_test_add_func ("/file/async-delete", test_async_delete);
+ g_test_add_func ("/file/async-make-symlink", test_async_make_symlink);
g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
g_test_add_func ("/file/measure", test_measure);
g_test_add_func ("/file/measure-async", test_measure_async);
@@ -3155,6 +3861,11 @@ main (int argc, char *argv[])
g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
g_test_add_func ("/file/move_async", test_move_async);
+ g_test_add_func ("/file/query-zero-length-content-type", test_query_zero_length_content_type);
+ g_test_add_func ("/file/query-default-handler-file", test_query_default_handler_file);
+ g_test_add_func ("/file/query-default-handler-file-async", test_query_default_handler_file_async);
+ g_test_add_func ("/file/query-default-handler-uri", test_query_default_handler_uri);
+ g_test_add_func ("/file/query-default-handler-uri-async", test_query_default_handler_uri_async);
return g_test_run ();
}