8 #include <gio/gfiledescriptorbased.h>
20 test_basic_for_file (GFile *file,
25 s = g_file_get_basename (file);
26 g_assert_cmpstr (s, ==, "testfile");
29 s = g_file_get_uri (file);
30 g_assert_true (g_str_has_prefix (s, "file://"));
31 g_assert_true (g_str_has_suffix (s, suffix));
34 g_assert_true (g_file_has_uri_scheme (file, "file"));
35 s = g_file_get_uri_scheme (file);
36 g_assert_cmpstr (s, ==, "file");
45 file = g_file_new_for_path ("./some/directory/testfile");
46 test_basic_for_file (file, "/some/directory/testfile");
47 g_object_unref (file);
51 test_build_filename (void)
55 file = g_file_new_build_filename (".", "some", "directory", "testfile", NULL);
56 test_basic_for_file (file, "/some/directory/testfile");
57 g_object_unref (file);
59 file = g_file_new_build_filename ("testfile", NULL);
60 test_basic_for_file (file, "/testfile");
61 g_object_unref (file);
65 test_build_filenamev (void)
69 const gchar *args[] = { ".", "some", "directory", "testfile", NULL };
70 file = g_file_new_build_filenamev (args);
71 test_basic_for_file (file, "/some/directory/testfile");
72 g_object_unref (file);
74 const gchar *brgs[] = { "testfile", NULL };
75 file = g_file_new_build_filenamev (brgs);
76 test_basic_for_file (file, "/testfile");
77 g_object_unref (file);
88 file = g_file_new_for_path ("./some/directory/testfile");
89 file2 = g_file_new_for_path ("./some/directory");
90 root = g_file_new_for_path ("/");
92 g_assert_true (g_file_has_parent (file, file2));
94 parent = g_file_get_parent (file);
95 g_assert_true (g_file_equal (parent, file2));
96 g_object_unref (parent);
98 g_assert_null (g_file_get_parent (root));
100 g_object_unref (file);
101 g_object_unref (file2);
102 g_object_unref (root);
112 file = g_file_new_for_path ("./some/directory");
113 child = g_file_get_child (file, "child");
114 g_assert_true (g_file_has_parent (child, file));
116 child2 = g_file_get_child_for_display_name (file, "child2", NULL);
117 g_assert_true (g_file_has_parent (child2, file));
119 g_object_unref (child);
120 g_object_unref (child2);
121 g_object_unref (file);
125 test_empty_path (void)
129 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2328");
130 g_test_summary ("Check that creating a file with an empty path results in errors");
132 /* Creating the file must always succeed. */
133 file = g_file_new_for_path ("");
134 g_assert_nonnull (file);
136 /* But then querying its path should indicate it’s invalid. */
137 g_assert_null (g_file_get_path (file));
138 g_assert_null (g_file_get_basename (file));
139 g_assert_null (g_file_get_parent (file));
141 g_object_unref (file);
150 GError *error = NULL;
152 datapath_f = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
154 file = g_file_get_child (datapath_f, "g-icon.c");
155 type = g_file_query_file_type (file, 0, NULL);
156 g_assert_cmpint (type, ==, G_FILE_TYPE_REGULAR);
157 g_object_unref (file);
159 file = g_file_get_child (datapath_f, "cert-tests");
160 type = g_file_query_file_type (file, 0, NULL);
161 g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
163 g_file_read (file, NULL, &error);
164 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
165 g_error_free (error);
166 g_object_unref (file);
168 g_object_unref (datapath_f);
172 test_parse_name (void)
177 file = g_file_new_for_uri ("file://somewhere");
178 name = g_file_get_parse_name (file);
179 g_assert_cmpstr (name, ==, "file://somewhere");
180 g_object_unref (file);
183 file = g_file_parse_name ("~foo");
184 name = g_file_get_parse_name (file);
185 g_assert_nonnull (name);
186 g_object_unref (file);
192 GMainContext *context;
194 GFileMonitor *monitor;
195 GOutputStream *ostream;
196 GInputStream *istream;
198 gint monitor_created;
199 gint monitor_deleted;
200 gint monitor_changed;
206 gboolean file_deleted;
211 monitor_changed (GFileMonitor *monitor,
214 GFileMonitorEvent event_type,
217 CreateDeleteData *data = user_data;
219 const gchar *peeked_path;
221 path = g_file_get_path (file);
222 peeked_path = g_file_peek_path (file);
223 g_assert_cmpstr (data->monitor_path, ==, path);
224 g_assert_cmpstr (path, ==, peeked_path);
227 if (event_type == G_FILE_MONITOR_EVENT_CREATED)
228 data->monitor_created++;
229 if (event_type == G_FILE_MONITOR_EVENT_DELETED)
230 data->monitor_deleted++;
231 if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
232 data->monitor_changed++;
234 g_main_context_wakeup (data->context);
238 iclosed_cb (GObject *source,
242 CreateDeleteData *data = user_data;
247 ret = g_input_stream_close_finish (data->istream, res, &error);
248 g_assert_no_error (error);
251 g_assert_true (g_input_stream_is_closed (data->istream));
253 ret = g_file_delete (data->file, NULL, &error);
255 g_assert_no_error (error);
257 data->file_deleted = TRUE;
258 g_main_context_wakeup (data->context);
262 read_cb (GObject *source,
266 CreateDeleteData *data = user_data;
271 size = g_input_stream_read_finish (data->istream, res, &error);
272 g_assert_no_error (error);
275 if (data->pos < strlen (data->data))
277 g_input_stream_read_async (data->istream,
278 data->buffer + data->pos,
279 strlen (data->data) - data->pos,
287 g_assert_cmpstr (data->buffer, ==, data->data);
288 g_assert_false (g_input_stream_is_closed (data->istream));
289 g_input_stream_close_async (data->istream, 0, NULL, iclosed_cb, data);
294 ipending_cb (GObject *source,
298 CreateDeleteData *data = user_data;
302 g_input_stream_read_finish (data->istream, res, &error);
303 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
304 g_error_free (error);
308 skipped_cb (GObject *source,
312 CreateDeleteData *data = user_data;
317 size = g_input_stream_skip_finish (data->istream, res, &error);
318 g_assert_no_error (error);
319 g_assert_cmpint (size, ==, data->pos);
321 g_input_stream_read_async (data->istream,
322 data->buffer + data->pos,
323 strlen (data->data) - data->pos,
328 /* check that we get a pending error */
329 g_input_stream_read_async (data->istream,
330 data->buffer + data->pos,
331 strlen (data->data) - data->pos,
339 opened_cb (GObject *source,
343 GFileInputStream *base;
344 CreateDeleteData *data = user_data;
348 base = g_file_read_finish (data->file, res, &error);
349 g_assert_no_error (error);
351 if (data->buffersize == 0)
352 data->istream = G_INPUT_STREAM (g_object_ref (base));
354 data->istream = g_buffered_input_stream_new_sized (G_INPUT_STREAM (base), data->buffersize);
355 g_object_unref (base);
357 data->buffer = g_new0 (gchar, strlen (data->data) + 1);
359 /* copy initial segment directly, then skip */
360 memcpy (data->buffer, data->data, 10);
363 g_input_stream_skip_async (data->istream,
372 oclosed_cb (GObject *source,
376 CreateDeleteData *data = user_data;
381 ret = g_output_stream_close_finish (data->ostream, res, &error);
382 g_assert_no_error (error);
384 g_assert_true (g_output_stream_is_closed (data->ostream));
386 g_file_read_async (data->file, 0, NULL, opened_cb, data);
390 written_cb (GObject *source,
394 CreateDeleteData *data = user_data;
399 size = g_output_stream_write_finish (data->ostream, res, &error);
400 g_assert_no_error (error);
403 if (data->pos < strlen (data->data))
405 g_output_stream_write_async (data->ostream,
406 data->data + data->pos,
407 strlen (data->data) - data->pos,
415 g_assert_false (g_output_stream_is_closed (data->ostream));
416 g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
421 opending_cb (GObject *source,
425 CreateDeleteData *data = user_data;
429 g_output_stream_write_finish (data->ostream, res, &error);
430 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
431 g_error_free (error);
435 created_cb (GObject *source,
439 GFileOutputStream *base;
440 CreateDeleteData *data = user_data;
444 base = g_file_create_finish (G_FILE (source), res, &error);
445 g_assert_no_error (error);
446 g_assert_true (g_file_query_exists (data->file, NULL));
448 if (data->buffersize == 0)
449 data->ostream = G_OUTPUT_STREAM (g_object_ref (base));
451 data->ostream = g_buffered_output_stream_new_sized (G_OUTPUT_STREAM (base), data->buffersize);
452 g_object_unref (base);
454 g_output_stream_write_async (data->ostream,
461 /* check that we get a pending error */
462 g_output_stream_write_async (data->ostream,
472 stop_timeout (gpointer user_data)
474 CreateDeleteData *data = user_data;
476 data->timed_out = TRUE;
477 g_main_context_wakeup (data->context);
481 * This test does a fully async create-write-read-delete.
485 test_create_delete (gconstpointer d)
488 CreateDeleteData *data;
489 GFileIOStream *iostream;
491 data = g_new0 (CreateDeleteData, 1);
493 data->buffersize = GPOINTER_TO_INT (d);
494 data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
497 data->file = g_file_new_tmp ("g_file_create_delete_XXXXXX",
499 g_assert_nonnull (data->file);
500 g_object_unref (iostream);
502 data->monitor_path = g_file_get_path (data->file);
503 remove (data->monitor_path);
505 g_assert_false (g_file_query_exists (data->file, NULL));
508 data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
509 g_assert_no_error (error);
511 /* This test doesn't work with GPollFileMonitor, because it assumes
512 * that the monitor will notice a create immediately followed by a
513 * delete, rather than coalescing them into nothing.
515 /* This test also doesn't work with GKqueueFileMonitor because of
516 * the same reason. Kqueue is able to return a kevent when a file is
517 * created or deleted in a directory. However, the kernel doesn't tell
518 * the program file names, so GKqueueFileMonitor has to calculate the
519 * difference itself. This is usually too slow for rapid file creation
520 * and deletion tests.
522 if (strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GPollFileMonitor") == 0 ||
523 strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GKqueueFileMonitor") == 0)
525 g_test_skip ("skipping test for this GFileMonitor implementation");
529 g_file_monitor_set_rate_limit (data->monitor, 100);
531 g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
533 /* Use the global default main context */
534 data->context = NULL;
535 data->timeout = g_timeout_add_seconds_once (10, stop_timeout, data);
537 g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
539 while (!data->timed_out &&
540 (data->monitor_created == 0 ||
541 data->monitor_deleted == 0 ||
542 data->monitor_changed == 0 ||
543 !data->file_deleted))
544 g_main_context_iteration (data->context, TRUE);
546 g_source_remove (data->timeout);
548 g_assert_false (data->timed_out);
549 g_assert_true (data->file_deleted);
550 g_assert_cmpint (data->monitor_created, ==, 1);
551 g_assert_cmpint (data->monitor_deleted, ==, 1);
552 g_assert_cmpint (data->monitor_changed, >, 0);
554 g_assert_false (g_file_monitor_is_cancelled (data->monitor));
555 g_file_monitor_cancel (data->monitor);
556 g_assert_true (g_file_monitor_is_cancelled (data->monitor));
558 g_clear_pointer (&data->context, g_main_context_unref);
559 g_object_unref (data->ostream);
560 g_object_unref (data->istream);
563 g_object_unref (data->monitor);
564 g_object_unref (data->file);
565 g_free (data->monitor_path);
566 g_free (data->buffer);
570 static const gchar *original_data =
572 " * g_file_replace_contents_async:\n"
575 static const gchar *replace_data =
577 " * g_file_replace_contents_async:\n"
578 " * @file: input #GFile.\n"
579 " * @contents: string of contents to replace the file with.\n"
580 " * @length: the length of @contents in bytes.\n"
581 " * @etag: (nullable): a new <link linkend=\"gfile-etag\">entity tag</link> for the @file, or %NULL\n"
582 " * @make_backup: %TRUE if a backup should be created.\n"
583 " * @flags: a set of #GFileCreateFlags.\n"
584 " * @cancellable: optional #GCancellable object, %NULL to ignore.\n"
585 " * @callback: a #GAsyncReadyCallback to call when the request is satisfied\n"
586 " * @user_data: the data to pass to callback function\n"
588 " * Starts an asynchronous replacement of @file with the given \n"
589 " * @contents of @length bytes. @etag will replace the document's\n"
590 " * current entity tag.\n"
592 " * When this operation has completed, @callback will be called with\n"
593 " * @user_user data, and the operation can be finalized with \n"
594 " * g_file_replace_contents_finish().\n"
596 " * If @cancellable is not %NULL, then the operation can be cancelled by\n"
597 " * triggering the cancellable object from another thread. If the operation\n"
598 " * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. \n"
600 " * If @make_backup is %TRUE, this function will attempt to \n"
601 " * make a backup of @file.\n"
612 static void replaced_cb (GObject *source,
617 loaded_cb (GObject *source,
621 ReplaceLoadData *data = user_data;
628 ret = g_file_load_contents_finish (data->file, res, &contents, &length, NULL, &error);
630 g_assert_no_error (error);
631 g_assert_cmpint (length, ==, strlen (data->data));
632 g_assert_cmpstr (contents, ==, data->data);
639 data->data = "pi pa po";
641 g_file_replace_contents_async (data->file,
654 ret = g_file_delete (data->file, NULL, &error);
655 g_assert_no_error (error);
657 g_assert_false (g_file_query_exists (data->file, NULL));
659 g_main_loop_quit (data->loop);
664 replaced_cb (GObject *source,
668 ReplaceLoadData *data = user_data;
672 g_file_replace_contents_finish (data->file, res, NULL, &error);
673 g_assert_no_error (error);
675 g_file_load_contents_async (data->file, NULL, loaded_cb, data);
679 test_replace_load (void)
681 ReplaceLoadData *data;
683 GFileIOStream *iostream;
685 data = g_new0 (ReplaceLoadData, 1);
687 data->data = replace_data;
689 data->file = g_file_new_tmp ("g_file_replace_load_XXXXXX",
691 g_assert_nonnull (data->file);
692 g_object_unref (iostream);
694 path = g_file_peek_path (data->file);
697 g_assert_false (g_file_query_exists (data->file, NULL));
699 data->loop = g_main_loop_new (NULL, FALSE);
701 g_file_replace_contents_async (data->file,
711 g_main_loop_run (data->loop);
713 g_main_loop_unref (data->loop);
714 g_object_unref (data->file);
719 test_replace_cancel (void)
721 GFile *tmpdir, *file;
722 GFileOutputStream *ostream;
723 GFileEnumerator *fenum;
725 GCancellable *cancellable;
728 gsize nwrote, length;
730 GError *error = NULL;
732 g_test_bug ("https://bugzilla.gnome.org/629301");
734 path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
735 g_assert_no_error (error);
736 tmpdir = g_file_new_for_path (path);
739 file = g_file_get_child (tmpdir, "file");
740 g_file_replace_contents (file,
742 strlen (original_data),
743 NULL, FALSE, 0, NULL,
745 g_assert_no_error (error);
747 ostream = g_file_replace (file, NULL, TRUE, 0, NULL, &error);
748 g_assert_no_error (error);
750 g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
751 replace_data, strlen (replace_data),
752 &nwrote, NULL, &error);
753 g_assert_no_error (error);
754 g_assert_cmpint (nwrote, ==, strlen (replace_data));
756 /* At this point there should be two files; the original and the
759 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
760 g_assert_no_error (error);
762 info = g_file_enumerator_next_file (fenum, NULL, &error);
763 g_assert_no_error (error);
764 g_assert_nonnull (info);
765 g_object_unref (info);
766 info = g_file_enumerator_next_file (fenum, NULL, &error);
767 g_assert_no_error (error);
768 g_assert_nonnull (info);
769 g_object_unref (info);
771 g_file_enumerator_close (fenum, NULL, &error);
772 g_assert_no_error (error);
773 g_object_unref (fenum);
775 /* Also test the g_file_enumerator_iterate() API */
776 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
777 g_assert_no_error (error);
782 gboolean ret = g_file_enumerator_iterate (fenum, &info, NULL, NULL, &error);
784 g_assert_no_error (error);
789 g_assert_cmpint (count, ==, 2);
791 g_file_enumerator_close (fenum, NULL, &error);
792 g_assert_no_error (error);
793 g_object_unref (fenum);
795 /* Now test just getting child from the g_file_enumerator_iterate() API */
796 fenum = g_file_enumerate_children (tmpdir, "standard::name", 0, NULL, &error);
797 g_assert_no_error (error);
803 gboolean ret = g_file_enumerator_iterate (fenum, NULL, &child, NULL, &error);
806 g_assert_no_error (error);
811 g_assert_true (G_IS_FILE (child));
814 g_assert_cmpint (count, ==, 2);
816 g_file_enumerator_close (fenum, NULL, &error);
817 g_assert_no_error (error);
818 g_object_unref (fenum);
820 /* Make sure the temporary gets deleted even if we cancel. */
821 cancellable = g_cancellable_new ();
822 g_cancellable_cancel (cancellable);
823 g_output_stream_close (G_OUTPUT_STREAM (ostream), cancellable, &error);
824 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
825 g_clear_error (&error);
827 g_object_unref (cancellable);
828 g_object_unref (ostream);
830 /* Make sure that file contents wasn't actually replaced. */
831 g_file_load_contents (file,
837 g_assert_no_error (error);
838 g_assert_cmpstr (contents, ==, original_data);
841 g_file_delete (file, NULL, &error);
842 g_assert_no_error (error);
843 g_object_unref (file);
845 /* This will only succeed if the temp file was deleted. */
846 g_file_delete (tmpdir, NULL, &error);
847 g_assert_no_error (error);
848 g_object_unref (tmpdir);
852 test_replace_symlink (void)
855 gchar *tmpdir_path = NULL;
856 GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
857 GFileOutputStream *stream = NULL;
858 const gchar *new_contents = "this is a test message which should be written to source and not target";
860 GFileEnumerator *enumerator = NULL;
861 GFileInfo *info = NULL;
862 gchar *contents = NULL;
864 GError *local_error = NULL;
866 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325");
867 g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks");
869 /* Create a fresh, empty working directory. */
870 tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
871 g_assert_no_error (local_error);
872 tmpdir = g_file_new_for_path (tmpdir_path);
874 g_test_message ("Using temporary directory %s", tmpdir_path);
875 g_free (tmpdir_path);
877 source_file = g_file_get_child (tmpdir, "source");
878 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
879 "*assertion*symlink_value*failed*");
880 g_assert_false (g_file_make_symbolic_link (source_file, NULL, NULL, &local_error));
881 g_assert_no_error (local_error);
882 g_test_assert_expected_messages ();
884 g_assert_false (g_file_make_symbolic_link (source_file, "", NULL, &local_error));
885 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
886 g_clear_object (&source_file);
887 g_clear_error (&local_error);
889 /* Create symlink `source` which points to `target`. */
890 source_file = g_file_get_child (tmpdir, "source");
891 target_file = g_file_get_child (tmpdir, "target");
892 g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
893 g_assert_no_error (local_error);
895 /* Ensure that `target` doesn’t exist */
896 g_assert_false (g_file_query_exists (target_file, NULL));
898 /* Replace the `source` symlink with a regular file using
899 * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
900 * following the symlink */
901 stream = g_file_replace (source_file, NULL, FALSE /* no backup */,
902 G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
903 g_assert_no_error (local_error);
905 g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
906 &n_written, NULL, &local_error);
907 g_assert_no_error (local_error);
908 g_assert_cmpint (n_written, ==, strlen (new_contents));
910 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
911 g_assert_no_error (local_error);
913 g_clear_object (&stream);
915 /* At this point, there should still only be one file: `source`. It should
916 * now be a regular file. `target` should not exist. */
917 enumerator = g_file_enumerate_children (tmpdir,
918 G_FILE_ATTRIBUTE_STANDARD_NAME ","
919 G_FILE_ATTRIBUTE_STANDARD_TYPE,
920 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
921 g_assert_no_error (local_error);
923 info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
924 g_assert_no_error (local_error);
925 g_assert_nonnull (info);
927 g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
928 g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
930 g_clear_object (&info);
932 info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
933 g_assert_no_error (local_error);
934 g_assert_null (info);
936 g_file_enumerator_close (enumerator, NULL, &local_error);
937 g_assert_no_error (local_error);
938 g_clear_object (&enumerator);
940 /* Double-check that `target` doesn’t exist */
941 g_assert_false (g_file_query_exists (target_file, NULL));
943 /* Check the content of `source`. */
944 g_file_load_contents (source_file,
950 g_assert_no_error (local_error);
951 g_assert_cmpstr (contents, ==, new_contents);
952 g_assert_cmpuint (length, ==, strlen (new_contents));
956 g_file_delete (source_file, NULL, &local_error);
957 g_assert_no_error (local_error);
959 g_file_delete (tmpdir, NULL, &local_error);
960 g_assert_no_error (local_error);
962 g_clear_object (&target_file);
963 g_clear_object (&source_file);
964 g_clear_object (&tmpdir);
965 #else /* if !G_OS_UNIX */
966 g_test_skip ("Symlink replacement tests can only be run on Unix")
971 test_replace_symlink_using_etag (void)
974 gchar *tmpdir_path = NULL;
975 GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
976 GFileOutputStream *stream = NULL;
977 const gchar *old_contents = "this is a test message which should be written to target and then overwritten";
978 gchar *old_etag = NULL;
979 const gchar *new_contents = "this is an updated message";
981 gchar *contents = NULL;
983 GFileInfo *info = NULL;
984 GError *local_error = NULL;
986 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2417");
987 g_test_summary ("Test that ETag checks work when replacing a file through a symlink");
989 /* Create a fresh, empty working directory. */
990 tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_using_etag_XXXXXX", &local_error);
991 g_assert_no_error (local_error);
992 tmpdir = g_file_new_for_path (tmpdir_path);
994 g_test_message ("Using temporary directory %s", tmpdir_path);
995 g_free (tmpdir_path);
997 /* Create symlink `source` which points to `target`. */
998 source_file = g_file_get_child (tmpdir, "source");
999 target_file = g_file_get_child (tmpdir, "target");
1000 g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
1001 g_assert_no_error (local_error);
1003 /* Sleep for at least 1s to ensure the mtimes of `source` and `target` differ,
1004 * as that’s what _g_local_file_info_create_etag() uses to create the ETag,
1005 * and one failure mode we’re testing for is that the ETags of `source` and
1006 * `target` are conflated. */
1009 /* Create `target` with some arbitrary content. */
1010 stream = g_file_create (target_file, G_FILE_CREATE_NONE, NULL, &local_error);
1011 g_assert_no_error (local_error);
1012 g_output_stream_write_all (G_OUTPUT_STREAM (stream), old_contents, strlen (old_contents),
1013 &n_written, NULL, &local_error);
1014 g_assert_no_error (local_error);
1015 g_assert_cmpint (n_written, ==, strlen (old_contents));
1017 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
1018 g_assert_no_error (local_error);
1020 old_etag = g_file_output_stream_get_etag (stream);
1021 g_assert_nonnull (old_etag);
1022 g_assert_cmpstr (old_etag, !=, "");
1024 g_clear_object (&stream);
1026 /* Sleep again to ensure the ETag changes again. */
1029 /* Write out a new copy of the `target`, checking its ETag first. This should
1030 * replace `target` by following the symlink. */
1031 stream = g_file_replace (source_file, old_etag, FALSE /* no backup */,
1032 G_FILE_CREATE_NONE, NULL, &local_error);
1033 g_assert_no_error (local_error);
1035 g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
1036 &n_written, NULL, &local_error);
1037 g_assert_no_error (local_error);
1038 g_assert_cmpint (n_written, ==, strlen (new_contents));
1040 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
1041 g_assert_no_error (local_error);
1043 g_clear_object (&stream);
1045 /* At this point, there should be a regular file, `target`, containing
1046 * @new_contents; and a symlink `source` which points to `target`. */
1047 g_assert_cmpint (g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_SYMBOLIC_LINK);
1048 g_assert_cmpint (g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_REGULAR);
1050 /* Check the content of `target`. */
1051 g_file_load_contents (target_file,
1057 g_assert_no_error (local_error);
1058 g_assert_cmpstr (contents, ==, new_contents);
1059 g_assert_cmpuint (length, ==, strlen (new_contents));
1062 /* And check its ETag value has changed. */
1063 info = g_file_query_info (target_file, G_FILE_ATTRIBUTE_ETAG_VALUE,
1064 G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1065 g_assert_no_error (local_error);
1066 g_assert_cmpstr (g_file_info_get_etag (info), !=, old_etag);
1068 g_clear_object (&info);
1072 g_file_delete (target_file, NULL, &local_error);
1073 g_assert_no_error (local_error);
1075 g_file_delete (source_file, NULL, &local_error);
1076 g_assert_no_error (local_error);
1078 g_file_delete (tmpdir, NULL, &local_error);
1079 g_assert_no_error (local_error);
1081 g_clear_object (&target_file);
1082 g_clear_object (&source_file);
1083 g_clear_object (&tmpdir);
1084 #else /* if !G_OS_UNIX */
1085 g_test_skip ("Symlink replacement tests can only be run on Unix")
1089 /* FIXME: These tests have only been checked on Linux. Most of them are probably
1090 * applicable on Windows, too, but that has not been tested yet.
1091 * See https://gitlab.gnome.org/GNOME/glib/-/issues/2325 */
1094 /* Different kinds of file which create_test_file() can create. */
1097 FILE_TEST_SETUP_TYPE_NONEXISTENT,
1098 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY,
1099 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY,
1100 FILE_TEST_SETUP_TYPE_DIRECTORY,
1101 FILE_TEST_SETUP_TYPE_SOCKET,
1102 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING,
1103 FILE_TEST_SETUP_TYPE_SYMLINK_VALID,
1104 } FileTestSetupType;
1106 /* Create file `tmpdir/basename`, of type @setup_type, and chmod it to
1107 * @setup_mode. Return the #GFile representing it. Abort on any errors. */
1109 create_test_file (GFile *tmpdir,
1110 const gchar *basename,
1111 FileTestSetupType setup_type,
1114 GFile *test_file = g_file_get_child (tmpdir, basename);
1115 gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1116 GFile *target_file = g_file_get_child (tmpdir, target_basename);
1117 GError *local_error = NULL;
1121 case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1122 /* Nothing to do here. */
1123 g_assert (setup_mode == 0);
1125 case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1126 case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1128 gchar *contents = NULL;
1130 if (setup_type == FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY)
1131 contents = g_strdup_printf ("this is some test content in %s", basename);
1133 contents = g_strdup ("");
1135 g_file_set_contents (g_file_peek_path (test_file), contents, -1, &local_error);
1136 g_assert_no_error (local_error);
1138 g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1139 setup_mode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1140 NULL, &local_error);
1141 g_assert_no_error (local_error);
1146 case FILE_TEST_SETUP_TYPE_DIRECTORY:
1147 g_assert (setup_mode == 0);
1149 g_file_make_directory (test_file, NULL, &local_error);
1150 g_assert_no_error (local_error);
1152 case FILE_TEST_SETUP_TYPE_SOCKET:
1153 g_assert_no_errno (mknod (g_file_peek_path (test_file), S_IFSOCK | setup_mode, 0));
1155 case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1156 g_file_set_contents (g_file_peek_path (target_file), "target file", -1, &local_error);
1157 g_assert_no_error (local_error);
1159 case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1160 /* Permissions on a symlink are not used by the kernel, so are only
1161 * applicable if the symlink is valid (and are applied to the target) */
1162 g_assert (setup_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || setup_mode == 0);
1164 g_file_make_symbolic_link (test_file, target_basename, NULL, &local_error);
1165 g_assert_no_error (local_error);
1167 if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1169 g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1170 setup_mode, G_FILE_QUERY_INFO_NONE,
1171 NULL, &local_error);
1172 g_assert_no_error (local_error);
1175 if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING)
1177 /* Ensure that the target doesn’t exist */
1178 g_assert_false (g_file_query_exists (target_file, NULL));
1182 g_assert_not_reached ();
1185 g_clear_object (&target_file);
1186 g_free (target_basename);
1188 return g_steal_pointer (&test_file);
1191 /* Check that @test_file is of the @expected_type, has the @expected_mode, and
1192 * (if it’s a regular file) has the @expected_contents or (if it’s a symlink)
1193 * has the symlink target given by @expected_contents.
1195 * @test_file must point to the file `tmpdir/basename`.
1197 * Aborts on any errors or mismatches against the expectations.
1200 check_test_file (GFile *test_file,
1202 const gchar *basename,
1203 FileTestSetupType expected_type,
1204 guint expected_mode,
1205 const gchar *expected_contents)
1207 gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1208 GFile *target_file = g_file_get_child (tmpdir, target_basename);
1209 GFileType test_file_type = g_file_query_file_type (test_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL);
1210 GFileInfo *info = NULL;
1211 GError *local_error = NULL;
1213 switch (expected_type)
1215 case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1216 g_assert (expected_mode == 0);
1217 g_assert (expected_contents == NULL);
1219 g_assert_false (g_file_query_exists (test_file, NULL));
1220 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_UNKNOWN);
1222 case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1223 case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1224 g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_EMPTY || expected_contents == NULL);
1225 g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY || expected_contents != NULL);
1227 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_REGULAR);
1229 info = g_file_query_info (test_file,
1230 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
1231 G_FILE_ATTRIBUTE_UNIX_MODE,
1232 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1233 g_assert_no_error (local_error);
1235 if (expected_type == FILE_TEST_SETUP_TYPE_REGULAR_EMPTY)
1236 g_assert_cmpint (g_file_info_get_size (info), ==, 0);
1238 g_assert_cmpint (g_file_info_get_size (info), >, 0);
1240 if (expected_contents != NULL)
1242 gchar *contents = NULL;
1245 g_file_get_contents (g_file_peek_path (test_file), &contents, &length, &local_error);
1246 g_assert_no_error (local_error);
1248 g_assert_cmpstr (contents, ==, expected_contents);
1252 g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1255 case FILE_TEST_SETUP_TYPE_DIRECTORY:
1256 g_assert (expected_mode == 0);
1257 g_assert (expected_contents == NULL);
1259 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_DIRECTORY);
1261 case FILE_TEST_SETUP_TYPE_SOCKET:
1262 g_assert (expected_contents == NULL);
1264 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SPECIAL);
1266 info = g_file_query_info (test_file,
1267 G_FILE_ATTRIBUTE_UNIX_MODE,
1268 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1269 g_assert_no_error (local_error);
1271 g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1273 case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1274 case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1276 GFile *symlink_target_file = NULL;
1278 /* Permissions on a symlink are not used by the kernel, so are only
1279 * applicable if the symlink is valid (and are applied to the target) */
1280 g_assert (expected_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || expected_mode == 0);
1281 g_assert (expected_contents != NULL);
1283 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SYMBOLIC_LINK);
1285 info = g_file_query_info (test_file,
1286 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
1287 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1288 g_assert_no_error (local_error);
1290 g_assert_cmpstr (g_file_info_get_symlink_target (info), ==, expected_contents);
1292 symlink_target_file = g_file_get_child (tmpdir, g_file_info_get_symlink_target (info));
1293 if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1294 g_assert_true (g_file_query_exists (symlink_target_file, NULL));
1296 g_assert_false (g_file_query_exists (symlink_target_file, NULL));
1298 if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1300 GFileInfo *target_info = NULL;
1302 /* Need to re-query the info so we follow symlinks */
1303 target_info = g_file_query_info (test_file,
1304 G_FILE_ATTRIBUTE_UNIX_MODE,
1305 G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1306 g_assert_no_error (local_error);
1308 g_assert_cmpuint (g_file_info_get_attribute_uint32 (target_info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1310 g_clear_object (&target_info);
1313 g_clear_object (&symlink_target_file);
1317 g_assert_not_reached ();
1320 g_clear_object (&info);
1321 g_clear_object (&target_file);
1322 g_free (target_basename);
1325 #endif /* __linux__ */
1329 * check_cap_dac_override:
1330 * @tmpdir: A temporary directory in which we can create and delete files
1332 * Check whether the current process can bypass DAC permissions.
1334 * Traditionally, "privileged" processes (those with effective uid 0)
1335 * could do this (and bypass many other checks), and "unprivileged"
1336 * processes could not.
1338 * In Linux, the special powers of euid 0 are divided into many
1339 * capabilities: see `capabilities(7)`. The one we are interested in
1340 * here is `CAP_DAC_OVERRIDE`.
1342 * We do this generically instead of actually looking at the capability
1343 * bits, so that the right thing will happen on non-Linux Unix
1344 * implementations, in particular if they have something equivalent to
1345 * but not identical to Linux permissions.
1347 * Returns: %TRUE if we have Linux `CAP_DAC_OVERRIDE` or equivalent
1351 check_cap_dac_override (const char *tmpdir)
1353 gchar *dac_denies_write;
1357 dac_denies_write = g_build_filename (tmpdir, "dac-denies-write", NULL);
1358 inside = g_build_filename (dac_denies_write, "inside", NULL);
1360 g_assert_no_errno (mkdir (dac_denies_write, S_IRWXU));
1361 g_assert_no_errno (chmod (dac_denies_write, 0));
1363 if (mkdir (inside, S_IRWXU) == 0)
1365 g_test_message ("Looks like we have CAP_DAC_OVERRIDE or equivalent");
1366 g_assert_no_errno (rmdir (inside));
1371 int saved_errno = errno;
1373 g_test_message ("We do not have CAP_DAC_OVERRIDE or equivalent");
1374 g_assert_cmpint (saved_errno, ==, EACCES);
1378 g_assert_no_errno (chmod (dac_denies_write, S_IRWXU));
1379 g_assert_no_errno (rmdir (dac_denies_write));
1380 g_free (dac_denies_write);
1386 /* A big test for g_file_replace() and g_file_replace_readwrite(). The
1387 * @test_data is a boolean: %TRUE to test g_file_replace_readwrite(), %FALSE to
1388 * test g_file_replace(). The test setup and checks are identical for both
1389 * functions; in the case of testing g_file_replace_readwrite(), only the output
1390 * stream side of the returned #GIOStream is tested. i.e. We test the write
1391 * behaviour of both functions is identical.
1393 * This is intended to test all static behaviour of the function: for each test
1394 * scenario, a temporary directory is set up with a source file (and maybe some
1395 * other files) in a set configuration, g_file_replace{,_readwrite}() is called,
1396 * and the final state of the directory is checked.
1398 * This test does not check dynamic behaviour or race conditions. For example,
1399 * it does not test what happens if the source file is deleted from another
1400 * process half-way through a call to g_file_replace().
1403 test_replace (gconstpointer test_data)
1406 gboolean read_write = GPOINTER_TO_UINT (test_data);
1407 const gchar *new_contents = "this is a new test message which should be written to source";
1408 const gchar *original_source_contents = "this is some test content in source";
1409 const gchar *original_backup_contents = "this is some test content in source~";
1410 mode_t current_umask = umask (0);
1411 guint32 default_public_mode = 0666 & ~current_umask;
1412 guint32 default_private_mode = 0600;
1416 /* Arguments to pass to g_file_replace(). */
1417 gboolean replace_make_backup;
1418 GFileCreateFlags replace_flags;
1419 const gchar *replace_etag; /* (nullable) */
1421 /* File system setup. */
1422 FileTestSetupType setup_source_type;
1423 guint setup_source_mode;
1424 FileTestSetupType setup_backup_type;
1425 guint setup_backup_mode;
1426 gboolean skip_if_cap_dac_override;
1428 /* Expected results. */
1429 gboolean expected_success;
1430 GQuark expected_error_domain;
1431 gint expected_error_code;
1433 /* Expected final file system state. */
1434 guint expected_n_files;
1435 FileTestSetupType expected_source_type;
1436 guint expected_source_mode;
1437 const gchar *expected_source_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1438 FileTestSetupType expected_backup_type;
1439 guint expected_backup_mode;
1440 const gchar *expected_backup_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1444 /* replace_make_backup == FALSE, replace_flags == NONE, replace_etag == NULL,
1445 * all the different values of setup_source_type, mostly with a backup
1446 * file created to check it’s not modified */
1448 FALSE, G_FILE_CREATE_NONE, NULL,
1449 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1450 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1452 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1453 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1456 FALSE, G_FILE_CREATE_NONE, NULL,
1457 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1458 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1460 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1461 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1464 FALSE, G_FILE_CREATE_NONE, NULL,
1465 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1466 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1468 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1469 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1472 FALSE, G_FILE_CREATE_NONE, NULL,
1473 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1474 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1475 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1476 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1477 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1480 FALSE, G_FILE_CREATE_NONE, NULL,
1481 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1482 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1483 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1484 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1485 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1488 FALSE, G_FILE_CREATE_NONE, NULL,
1489 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1490 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1492 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1493 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1496 FALSE, G_FILE_CREATE_NONE, NULL,
1497 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1498 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1500 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1501 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1504 /* replace_etag set to an invalid value, with setup_source_type as a
1505 * regular non-empty file; replacement should fail */
1507 FALSE, G_FILE_CREATE_NONE, "incorrect etag",
1508 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1509 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1510 FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1511 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1512 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1515 /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1516 * all the different values of setup_source_type, with a backup
1517 * file created to check it’s either replaced or the operation fails */
1519 TRUE, G_FILE_CREATE_NONE, NULL,
1520 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1521 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1523 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1524 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1527 TRUE, G_FILE_CREATE_NONE, NULL,
1528 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1529 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1531 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1532 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1535 TRUE, G_FILE_CREATE_NONE, NULL,
1536 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1537 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1539 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1540 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1543 TRUE, G_FILE_CREATE_NONE, NULL,
1544 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1545 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1546 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1547 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1548 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1551 TRUE, G_FILE_CREATE_NONE, NULL,
1552 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1553 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1554 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1555 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1556 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1559 TRUE, G_FILE_CREATE_NONE, NULL,
1560 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1561 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1563 /* The final situation here is a bit odd; the backup file is a bit
1564 * pointless as the original source file was a dangling symlink.
1565 * Theoretically the backup file should be that symlink, pointing to
1566 * `source-target`, and hence no longer dangling, as that file has now
1567 * been created as the new source content, since REPLACE_DESTINATION was
1568 * not specified. However, the code instead creates an empty regular
1569 * file as the backup. FIXME: This seems acceptable for now, but not
1570 * entirely ideal and would be good to fix at some point. */
1571 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1572 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0777 & ~current_umask, NULL,
1575 TRUE, G_FILE_CREATE_NONE, NULL,
1576 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1577 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1579 /* FIXME: The permissions for the backup file are just the default umask,
1580 * but should probably be the same as the permissions for the source
1581 * file (`default_public_mode`). This probably arises from the fact that
1582 * symlinks don’t have permissions. */
1583 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1584 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, 0777 & ~current_umask, "target file",
1587 /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1588 * setup_source_type is a regular file, with a backup file of every type
1589 * created to check it’s either replaced or the operation fails */
1591 TRUE, G_FILE_CREATE_NONE, NULL,
1592 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1593 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1595 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1596 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1599 TRUE, G_FILE_CREATE_NONE, NULL,
1600 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1601 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
1603 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1604 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1607 TRUE, G_FILE_CREATE_NONE, NULL,
1608 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1609 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1611 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1612 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1615 TRUE, G_FILE_CREATE_NONE, NULL,
1616 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1617 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
1618 FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1619 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1620 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1623 TRUE, G_FILE_CREATE_NONE, NULL,
1624 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1625 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
1627 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1628 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1631 TRUE, G_FILE_CREATE_NONE, NULL,
1632 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1633 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
1635 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1636 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1639 TRUE, G_FILE_CREATE_NONE, NULL,
1640 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1641 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
1643 /* the third file is `source~-target`, the original target of the old
1645 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1646 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1649 /* replace_make_backup == FALSE, replace_flags == REPLACE_DESTINATION,
1650 * replace_etag == NULL, all the different values of setup_source_type,
1651 * mostly with a backup file created to check it’s not modified */
1653 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1654 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1655 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1657 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1658 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1661 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1662 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1663 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1665 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1666 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1669 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1670 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1671 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1673 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1674 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1677 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1678 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1679 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1680 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1681 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1682 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1685 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1686 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1687 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1688 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1689 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1690 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1693 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1694 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1695 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1697 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1698 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1701 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1702 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1703 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1705 /* the third file is `source-target`, the original target of the old
1707 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1708 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1711 /* replace_flags == REPLACE_DESTINATION, replace_etag set to an invalid
1712 * value, with setup_source_type as a regular non-empty file; replacement
1715 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, "incorrect etag",
1716 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1717 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1718 FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1719 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1720 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1723 /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1724 * replace_etag == NULL, all the different values of setup_source_type,
1725 * with a backup file created to check it’s either replaced or the
1726 * operation fails */
1728 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1729 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1730 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1732 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1733 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1736 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1737 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1738 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1740 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1741 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1744 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1745 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1746 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1748 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1749 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1752 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1753 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1754 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1755 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1756 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1757 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1760 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1761 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1762 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1763 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1764 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1765 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1768 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1769 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1770 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1772 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1773 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, "source-target",
1776 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1777 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1778 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1780 /* the third file is `source-target`, the original target of the old
1782 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1783 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1786 /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1787 * replace_etag == NULL, setup_source_type is a regular file, with a
1788 * backup file of every type created to check it’s either replaced or the
1789 * operation fails */
1791 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1792 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1793 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1795 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1796 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1799 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1800 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1801 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
1803 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1804 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1807 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1808 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1809 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1811 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1812 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1815 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1816 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1817 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
1818 FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1819 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1820 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1823 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1824 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1825 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
1827 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1828 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1831 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1832 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1833 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
1835 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1836 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1839 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1840 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1841 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
1843 /* the third file is `source~-target`, the original target of the old
1845 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1846 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1849 /* several different setups with replace_flags == PRIVATE */
1851 FALSE, G_FILE_CREATE_PRIVATE, NULL,
1852 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1853 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1855 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1856 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1859 FALSE, G_FILE_CREATE_PRIVATE, NULL,
1860 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1861 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1863 /* the file isn’t being replaced, so it should keep its existing permissions */
1864 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1865 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1868 FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1869 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1870 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1872 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1873 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1876 FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1877 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1878 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1880 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1881 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1884 /* make the initial source file unreadable, so the replace operation
1887 * Permissions are ignored if we have CAP_DAC_OVERRIDE or equivalent,
1888 * and in particular if we're root. In this scenario,we need to skip it */
1890 FALSE, G_FILE_CREATE_NONE, NULL,
1891 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0 /* most restrictive permissions */,
1892 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, TRUE,
1893 FALSE, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1894 1, FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0, NULL,
1895 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1900 g_test_summary ("Test various situations for g_file_replace()");
1902 /* Reset the umask after querying it above. There’s no way to query it without
1904 umask (current_umask);
1905 g_test_message ("Current umask: %u", current_umask);
1907 for (i = 0; i < G_N_ELEMENTS (tests); i++)
1909 gchar *tmpdir_path = NULL;
1910 GFile *tmpdir = NULL, *source_file = NULL, *backup_file = NULL;
1911 GFileOutputStream *output_stream = NULL;
1912 GFileIOStream *io_stream = NULL;
1913 GFileEnumerator *enumerator = NULL;
1914 GFileInfo *info = NULL;
1916 GError *local_error = NULL;
1918 /* Create a fresh, empty working directory. */
1919 tmpdir_path = g_dir_make_tmp ("g_file_replace_XXXXXX", &local_error);
1920 g_assert_no_error (local_error);
1921 tmpdir = g_file_new_for_path (tmpdir_path);
1923 g_test_message ("Test %" G_GSIZE_FORMAT ", using temporary directory %s", i, tmpdir_path);
1925 if (tests[i].skip_if_cap_dac_override && check_cap_dac_override (tmpdir_path))
1927 g_test_message ("Skipping test as process has CAP_DAC_OVERRIDE capability and the test checks permissions");
1929 g_file_delete (tmpdir, NULL, &local_error);
1930 g_assert_no_error (local_error);
1931 g_clear_object (&tmpdir);
1932 g_free (tmpdir_path);
1937 g_free (tmpdir_path);
1939 /* Set up the test directory. */
1940 source_file = create_test_file (tmpdir, "source", tests[i].setup_source_type, tests[i].setup_source_mode);
1941 backup_file = create_test_file (tmpdir, "source~", tests[i].setup_backup_type, tests[i].setup_backup_mode);
1943 /* Replace the source file. Check the error state only after finishing
1944 * writing, as the replace operation is split across g_file_replace() and
1945 * g_output_stream_close(). */
1947 io_stream = g_file_replace_readwrite (source_file,
1948 tests[i].replace_etag,
1949 tests[i].replace_make_backup,
1950 tests[i].replace_flags,
1954 output_stream = g_file_replace (source_file,
1955 tests[i].replace_etag,
1956 tests[i].replace_make_backup,
1957 tests[i].replace_flags,
1961 if (tests[i].expected_success)
1963 g_assert_no_error (local_error);
1965 g_assert_nonnull (io_stream);
1967 g_assert_nonnull (output_stream);
1970 /* Write new content to it. */
1971 if (io_stream != NULL)
1973 GOutputStream *io_output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
1976 g_output_stream_write_all (G_OUTPUT_STREAM (io_output_stream), new_contents, strlen (new_contents),
1977 &n_written, NULL, &local_error);
1979 if (tests[i].expected_success)
1981 g_assert_no_error (local_error);
1982 g_assert_cmpint (n_written, ==, strlen (new_contents));
1985 g_io_stream_close (G_IO_STREAM (io_stream), NULL, (local_error == NULL) ? &local_error : NULL);
1987 if (tests[i].expected_success)
1988 g_assert_no_error (local_error);
1990 else if (output_stream != NULL)
1994 g_output_stream_write_all (G_OUTPUT_STREAM (output_stream), new_contents, strlen (new_contents),
1995 &n_written, NULL, &local_error);
1997 if (tests[i].expected_success)
1999 g_assert_no_error (local_error);
2000 g_assert_cmpint (n_written, ==, strlen (new_contents));
2003 g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, (local_error == NULL) ? &local_error : NULL);
2005 if (tests[i].expected_success)
2006 g_assert_no_error (local_error);
2009 if (tests[i].expected_success)
2010 g_assert_no_error (local_error);
2012 g_assert_error (local_error, tests[i].expected_error_domain, tests[i].expected_error_code);
2014 g_clear_error (&local_error);
2015 g_clear_object (&io_stream);
2016 g_clear_object (&output_stream);
2018 /* Verify the final state of the directory. */
2019 enumerator = g_file_enumerate_children (tmpdir,
2020 G_FILE_ATTRIBUTE_STANDARD_NAME,
2021 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
2022 g_assert_no_error (local_error);
2027 g_file_enumerator_iterate (enumerator, &info, NULL, NULL, &local_error);
2028 g_assert_no_error (local_error);
2033 while (info != NULL);
2035 g_clear_object (&enumerator);
2037 g_assert_cmpuint (n_files, ==, tests[i].expected_n_files);
2039 check_test_file (source_file, tmpdir, "source", tests[i].expected_source_type, tests[i].expected_source_mode, tests[i].expected_source_contents);
2040 check_test_file (backup_file, tmpdir, "source~", tests[i].expected_backup_type, tests[i].expected_backup_mode, tests[i].expected_backup_contents);
2042 /* Tidy up. Ignore failure apart from when deleting the directory, which
2043 * should be empty. */
2044 g_file_delete (source_file, NULL, NULL);
2045 g_file_delete (backup_file, NULL, NULL);
2047 /* Other files which are occasionally generated by the tests. */
2049 GFile *backup_target_file = g_file_get_child (tmpdir, "source~-target");
2050 g_file_delete (backup_target_file, NULL, NULL);
2051 g_clear_object (&backup_target_file);
2054 GFile *backup_target_file = g_file_get_child (tmpdir, "source-target");
2055 g_file_delete (backup_target_file, NULL, NULL);
2056 g_clear_object (&backup_target_file);
2059 g_file_delete (tmpdir, NULL, &local_error);
2060 g_assert_no_error (local_error);
2062 g_clear_object (&backup_file);
2063 g_clear_object (&source_file);
2064 g_clear_object (&tmpdir);
2066 #else /* if !__linux__ */
2067 g_test_skip ("File replacement tests can only be run on Linux");
2072 on_new_tmp_done (GObject *object,
2073 GAsyncResult *result,
2079 GFileIOStream *iostream;
2080 GError *error = NULL;
2081 GMainLoop *loop = user_data;
2083 GFile *tmpdir = NULL;
2085 g_assert_null (object);
2087 file = g_file_new_tmp_finish (result, &iostream, &error);
2088 g_assert_no_error (error);
2090 g_assert_true (g_file_query_exists (file, NULL));
2092 basename = g_file_get_basename (file);
2093 g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_async_"));
2095 info = g_file_io_stream_query_info (iostream, G_FILE_ATTRIBUTE_STANDARD_TYPE,
2097 g_assert_no_error (error);
2099 g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
2100 g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2101 g_assert_no_error (error);
2103 parent = g_file_get_parent (file);
2104 tmpdir = g_file_new_for_path (g_get_tmp_dir ());
2106 g_assert_true (g_file_equal (tmpdir, parent));
2108 g_main_loop_quit (loop);
2110 g_object_unref (file);
2111 g_object_unref (parent);
2112 g_object_unref (iostream);
2113 g_object_unref (info);
2115 g_object_unref (tmpdir);
2119 on_new_tmp_error (GObject *object,
2120 GAsyncResult *result,
2123 GFileIOStream *iostream = (GFileIOStream*) &on_new_tmp_error;
2124 AsyncErrorData *error_data = user_data;
2126 g_assert_null (object);
2128 g_assert_null (g_file_new_tmp_finish (result, &iostream, error_data->error));
2129 g_assert_nonnull (error_data->error);
2130 g_assert_null (iostream);
2132 g_main_loop_quit (error_data->loop);
2136 test_async_new_tmp (void)
2139 GError *error = NULL;
2140 GCancellable *cancellable;
2141 AsyncErrorData error_data = { .error = &error };
2143 loop = g_main_loop_new (NULL, TRUE);
2144 error_data.loop = loop;
2146 g_file_new_tmp_async ("g_file_new_tmp_async_XXXXXX",
2147 G_PRIORITY_DEFAULT, NULL,
2148 on_new_tmp_done, loop);
2149 g_main_loop_run (loop);
2151 g_file_new_tmp_async ("g_file_new_tmp_async_invalid_template",
2152 G_PRIORITY_DEFAULT, NULL,
2153 on_new_tmp_error, &error_data);
2154 g_main_loop_run (loop);
2155 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
2156 g_clear_error (&error);
2158 cancellable = g_cancellable_new ();
2159 g_file_new_tmp_async ("g_file_new_tmp_async_cancelled_XXXXXX",
2160 G_PRIORITY_DEFAULT, cancellable,
2161 on_new_tmp_error, &error_data);
2162 g_cancellable_cancel (cancellable);
2163 g_main_loop_run (loop);
2164 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2165 g_clear_object (&cancellable);
2166 g_clear_error (&error);
2168 g_main_loop_unref (loop);
2172 on_new_tmp_dir_done (GObject *object,
2173 GAsyncResult *result,
2179 GError *error = NULL;
2180 GMainLoop *loop = user_data;
2182 GFile *tmpdir = NULL;
2184 g_assert_null (object);
2186 file = g_file_new_tmp_dir_finish (result, &error);
2187 g_assert_no_error (error);
2189 g_assert_true (g_file_query_exists (file, NULL));
2191 basename = g_file_get_basename (file);
2192 g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_dir_async_"));
2194 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
2195 G_FILE_QUERY_INFO_NONE, NULL, &error);
2196 g_assert_no_error (error);
2198 g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_DIRECTORY);
2200 parent = g_file_get_parent (file);
2201 tmpdir = g_file_new_for_path (g_get_tmp_dir ());
2203 g_assert_true (g_file_equal (tmpdir, parent));
2205 g_main_loop_quit (loop);
2207 g_object_unref (file);
2208 g_object_unref (parent);
2209 g_object_unref (info);
2211 g_object_unref (tmpdir);
2215 on_new_tmp_dir_error (GObject *object,
2216 GAsyncResult *result,
2219 AsyncErrorData *error_data = user_data;
2221 g_assert_null (object);
2223 g_assert_null (g_file_new_tmp_dir_finish (result, error_data->error));
2224 g_assert_nonnull (error_data->error);
2226 g_main_loop_quit (error_data->loop);
2230 test_async_new_tmp_dir (void)
2233 GError *error = NULL;
2234 GCancellable *cancellable;
2235 AsyncErrorData error_data = { .error = &error };
2237 loop = g_main_loop_new (NULL, TRUE);
2238 error_data.loop = loop;
2240 g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_XXXXXX",
2241 G_PRIORITY_DEFAULT, NULL,
2242 on_new_tmp_dir_done, loop);
2243 g_main_loop_run (loop);
2245 g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async",
2246 G_PRIORITY_DEFAULT, NULL,
2247 on_new_tmp_dir_error, &error_data);
2248 g_main_loop_run (loop);
2249 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
2250 g_clear_error (&error);
2252 cancellable = g_cancellable_new ();
2253 g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_cancelled_XXXXXX",
2254 G_PRIORITY_DEFAULT, cancellable,
2255 on_new_tmp_dir_error, &error_data);
2256 g_cancellable_cancel (cancellable);
2257 g_main_loop_run (loop);
2258 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2259 g_clear_object (&cancellable);
2260 g_clear_error (&error);
2262 g_main_loop_unref (loop);
2266 on_file_deleted (GObject *object,
2267 GAsyncResult *result,
2270 GError *local_error = NULL;
2271 GMainLoop *loop = user_data;
2273 (void) g_file_delete_finish ((GFile*)object, result, &local_error);
2274 g_assert_no_error (local_error);
2276 g_main_loop_quit (loop);
2280 test_async_delete (void)
2283 GFileIOStream *iostream;
2284 GError *local_error = NULL;
2285 GError **error = &local_error;
2288 file = g_file_new_tmp ("g_file_delete_XXXXXX",
2290 g_assert_no_error (local_error);
2291 g_object_unref (iostream);
2293 g_assert_true (g_file_query_exists (file, NULL));
2295 loop = g_main_loop_new (NULL, TRUE);
2297 g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop);
2299 g_main_loop_run (loop);
2301 g_assert_false (g_file_query_exists (file, NULL));
2303 g_main_loop_unref (loop);
2304 g_object_unref (file);
2308 on_symlink_done (GObject *object,
2309 GAsyncResult *result,
2312 GFile *file = (GFile *) object;
2313 GError *error = NULL;
2314 GMainLoop *loop = user_data;
2316 g_assert_true (g_file_make_symbolic_link_finish (file, result, &error));
2317 g_assert_no_error (error);
2319 g_main_loop_quit (loop);
2323 on_symlink_error (GObject *object,
2324 GAsyncResult *result,
2327 GFile *file = (GFile *) object;
2328 GError *error = NULL;
2329 AsyncErrorData *data = user_data;
2331 g_assert_false (g_file_make_symbolic_link_finish (file, result, &error));
2332 g_assert_nonnull (error);
2333 g_propagate_error (data->error, g_steal_pointer (&error));
2335 g_main_loop_quit (data->loop);
2339 test_async_make_symlink (void)
2344 GFileInfo *link_info;
2345 GFileIOStream *iostream;
2346 GError *error = NULL;
2347 GCancellable *cancellable;
2349 AsyncErrorData error_data = {0};
2353 target = g_file_new_tmp ("g_file_symlink_target_XXXXXX", &iostream, &error);
2354 g_assert_no_error (error);
2356 g_io_stream_close ((GIOStream *) iostream, NULL, &error);
2357 g_assert_no_error (error);
2358 g_object_unref (iostream);
2360 g_assert_true (g_file_query_exists (target, NULL));
2362 loop = g_main_loop_new (NULL, TRUE);
2363 error_data.loop = loop;
2364 error_data.error = &error;
2366 tmpdir_path = g_dir_make_tmp ("g_file_symlink_XXXXXX", &error);
2367 g_assert_no_error (error);
2369 parent_dir = g_file_new_for_path (tmpdir_path);
2370 g_assert_true (g_file_query_exists (parent_dir, NULL));
2372 link = g_file_get_child (parent_dir, "symlink");
2373 g_assert_false (g_file_query_exists (link, NULL));
2375 g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
2376 "*assertion*symlink_value*failed*");
2377 g_file_make_symbolic_link_async (link, NULL,
2378 G_PRIORITY_DEFAULT, NULL,
2379 on_symlink_done, loop);
2380 g_test_assert_expected_messages ();
2382 g_file_make_symbolic_link_async (link, "",
2383 G_PRIORITY_DEFAULT, NULL,
2384 on_symlink_error, &error_data);
2385 g_main_loop_run (loop);
2386 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
2387 g_clear_error (&error);
2389 target_path = g_file_get_path (target);
2390 g_file_make_symbolic_link_async (link, target_path,
2391 G_PRIORITY_DEFAULT, NULL,
2392 on_symlink_done, loop);
2393 g_main_loop_run (loop);
2395 g_assert_true (g_file_query_exists (link, NULL));
2396 link_info = g_file_query_info (link,
2397 G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
2398 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
2399 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2402 g_assert_no_error (error);
2404 g_assert_true (g_file_info_get_is_symlink (link_info));
2405 g_assert_cmpstr (target_path, ==, g_file_info_get_symlink_target (link_info));
2407 /* Try creating it again, it fails */
2408 g_file_make_symbolic_link_async (link, target_path,
2409 G_PRIORITY_DEFAULT, NULL,
2410 on_symlink_error, &error_data);
2411 g_main_loop_run (loop);
2412 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
2413 g_clear_error (&error);
2415 cancellable = g_cancellable_new ();
2416 g_file_make_symbolic_link_async (link, target_path,
2417 G_PRIORITY_DEFAULT, cancellable,
2418 on_symlink_error, &error_data);
2419 g_cancellable_cancel (cancellable);
2420 g_main_loop_run (loop);
2421 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2422 g_clear_error (&error);
2423 g_clear_object (&cancellable);
2425 g_main_loop_unref (loop);
2426 g_object_unref (target);
2427 g_object_unref (parent_dir);
2428 g_object_unref (link);
2429 g_object_unref (link_info);
2430 g_free (tmpdir_path);
2431 g_free (target_path);
2435 test_copy_preserve_mode (void)
2438 mode_t current_umask = umask (0);
2441 guint32 source_mode;
2442 guint32 expected_destination_mode;
2443 gboolean create_destination_before_copy;
2444 GFileCopyFlags copy_flags;
2448 /* Overwriting the destination file should copy the permissions from the
2449 * source file, even if %G_FILE_COPY_ALL_METADATA is set: */
2450 { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2451 { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2452 /* The same behaviour should hold if the destination file is not being
2453 * overwritten because it doesn’t already exist: */
2454 { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2455 { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS },
2456 /* Anything with %G_FILE_COPY_TARGET_DEFAULT_PERMS should use the current
2457 * umask for the destination file: */
2458 { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2459 { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2460 { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2461 { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2465 /* Reset the umask after querying it above. There’s no way to query it without
2467 umask (current_umask);
2468 g_test_message ("Current umask: %u", current_umask);
2470 for (i = 0; i < G_N_ELEMENTS (vectors); i++)
2473 GFile *dest_tmpfile;
2474 GFileInfo *dest_info;
2475 GFileIOStream *iostream;
2476 GError *local_error = NULL;
2477 guint32 romode = vectors[i].source_mode;
2480 g_test_message ("Vector %" G_GSIZE_FORMAT, i);
2482 tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2483 &iostream, &local_error);
2484 g_assert_no_error (local_error);
2485 g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2486 g_assert_no_error (local_error);
2487 g_clear_object (&iostream);
2489 g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
2490 &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2491 NULL, &local_error);
2492 g_assert_no_error (local_error);
2494 dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2495 &iostream, &local_error);
2496 g_assert_no_error (local_error);
2497 g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2498 g_assert_no_error (local_error);
2499 g_clear_object (&iostream);
2501 if (!vectors[i].create_destination_before_copy)
2503 g_file_delete (dest_tmpfile, NULL, &local_error);
2504 g_assert_no_error (local_error);
2507 g_file_copy (tmpfile, dest_tmpfile, vectors[i].copy_flags,
2508 NULL, NULL, NULL, &local_error);
2509 g_assert_no_error (local_error);
2511 dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2512 NULL, &local_error);
2513 g_assert_no_error (local_error);
2515 dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
2517 g_assert_cmpint (dest_mode & ~S_IFMT, ==, vectors[i].expected_destination_mode);
2518 g_assert_cmpint (dest_mode & S_IFMT, ==, S_IFREG);
2520 (void) g_file_delete (tmpfile, NULL, NULL);
2521 (void) g_file_delete (dest_tmpfile, NULL, NULL);
2523 g_clear_object (&tmpfile);
2524 g_clear_object (&dest_tmpfile);
2525 g_clear_object (&dest_info);
2527 #else /* if !G_OS_UNIX */
2528 g_test_skip ("File permissions tests can only be run on Unix")
2534 goffset current_num_bytes;
2535 goffset total_num_bytes;
2539 file_copy_progress_cb (goffset current_num_bytes,
2540 goffset total_num_bytes,
2543 CopyProgressData *prev_data = user_data;
2545 g_assert_cmpuint (total_num_bytes, ==, prev_data->total_num_bytes);
2546 g_assert_cmpuint (current_num_bytes, >=, prev_data->current_num_bytes);
2548 /* Update it for the next callback. */
2549 prev_data->current_num_bytes = current_num_bytes;
2553 test_copy_progress (void)
2555 GFile *src_tmpfile = NULL;
2556 GFile *dest_tmpfile = NULL;
2557 GFileIOStream *iostream;
2558 GOutputStream *ostream;
2559 GError *local_error = NULL;
2560 const guint8 buffer[] = { 1, 2, 3, 4, 5 };
2561 CopyProgressData progress_data;
2563 src_tmpfile = g_file_new_tmp ("tmp-copy-progressXXXXXX",
2564 &iostream, &local_error);
2565 g_assert_no_error (local_error);
2567 /* Write some content to the file for testing. */
2568 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2569 g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &local_error);
2570 g_assert_no_error (local_error);
2572 g_io_stream_close ((GIOStream *) iostream, NULL, &local_error);
2573 g_assert_no_error (local_error);
2574 g_clear_object (&iostream);
2576 /* Grab a unique destination filename. */
2577 dest_tmpfile = g_file_new_tmp ("tmp-copy-progressXXXXXX",
2578 &iostream, &local_error);
2579 g_assert_no_error (local_error);
2580 g_io_stream_close ((GIOStream *) iostream, NULL, &local_error);
2581 g_assert_no_error (local_error);
2582 g_clear_object (&iostream);
2584 /* Set the progress data to an initial offset of zero. The callback will
2585 * assert that progress is non-decreasing and reaches the total length of
2587 progress_data.current_num_bytes = 0;
2588 progress_data.total_num_bytes = sizeof (buffer);
2590 /* Copy the file with progress reporting. */
2591 g_file_copy (src_tmpfile, dest_tmpfile, G_FILE_COPY_OVERWRITE,
2592 NULL, file_copy_progress_cb, &progress_data, &local_error);
2593 g_assert_no_error (local_error);
2595 g_assert_cmpuint (progress_data.current_num_bytes, ==, progress_data.total_num_bytes);
2596 g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
2599 (void) g_file_delete (src_tmpfile, NULL, NULL);
2600 (void) g_file_delete (dest_tmpfile, NULL, NULL);
2602 g_clear_object (&src_tmpfile);
2603 g_clear_object (&dest_tmpfile);
2613 GError *error = NULL;
2617 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2618 file = g_file_new_for_path (path);
2620 ok = g_file_measure_disk_usage (file,
2621 G_FILE_MEASURE_APPARENT_SIZE,
2630 g_assert_no_error (error);
2632 g_assert_cmpuint (num_bytes, ==, 74469);
2633 g_assert_cmpuint (num_dirs, ==, 6);
2634 g_assert_cmpuint (num_files, ==, 32);
2636 g_object_unref (file);
2641 guint64 expected_bytes;
2642 guint64 expected_dirs;
2643 guint64 expected_files;
2644 gint progress_count;
2645 guint64 progress_bytes;
2646 guint64 progress_dirs;
2647 guint64 progress_files;
2651 measure_progress (gboolean reporting,
2652 guint64 current_size,
2657 MeasureData *data = user_data;
2659 data->progress_count += 1;
2661 g_assert_cmpuint (current_size, >=, data->progress_bytes);
2662 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2663 g_assert_cmpuint (num_files, >=, data->progress_files);
2665 data->progress_bytes = current_size;
2666 data->progress_dirs = num_dirs;
2667 data->progress_files = num_files;
2671 measure_done (GObject *source,
2675 MeasureData *data = user_data;
2676 guint64 num_bytes, num_dirs, num_files;
2677 GError *error = NULL;
2680 ok = g_file_measure_disk_usage_finish (G_FILE (source), res, &num_bytes, &num_dirs, &num_files, &error);
2682 g_assert_no_error (error);
2684 g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
2685 g_assert_cmpuint (data->expected_dirs, ==, num_dirs);
2686 g_assert_cmpuint (data->expected_files, ==, num_files);
2688 g_assert_cmpuint (data->progress_count, >, 0);
2689 g_assert_cmpuint (num_bytes, >=, data->progress_bytes);
2690 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2691 g_assert_cmpuint (num_files, >=, data->progress_files);
2694 g_object_unref (source);
2698 test_measure_async (void)
2704 data = g_new (MeasureData, 1);
2706 data->progress_count = 0;
2707 data->progress_bytes = 0;
2708 data->progress_files = 0;
2709 data->progress_dirs = 0;
2711 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2712 file = g_file_new_for_path (path);
2715 data->expected_bytes = 74469;
2716 data->expected_dirs = 6;
2717 data->expected_files = 32;
2719 g_file_measure_disk_usage_async (file,
2720 G_FILE_MEASURE_APPARENT_SIZE,
2722 measure_progress, data,
2723 measure_done, data);
2727 test_load_bytes (void)
2729 gchar filename[] = "g_file_load_bytes_XXXXXX";
2730 GError *error = NULL;
2737 fd = g_mkstemp (filename);
2738 g_assert_cmpint (fd, !=, -1);
2739 len = strlen ("test_load_bytes");
2740 ret = write (fd, "test_load_bytes", len);
2741 g_assert_cmpint (ret, ==, len);
2744 file = g_file_new_for_path (filename);
2745 bytes = g_file_load_bytes (file, NULL, NULL, &error);
2746 g_assert_no_error (error);
2747 g_assert_nonnull (bytes);
2748 g_assert_cmpint (len, ==, g_bytes_get_size (bytes));
2749 g_assert_cmpstr ("test_load_bytes", ==, (gchar *)g_bytes_get_data (bytes, NULL));
2751 g_file_delete (file, NULL, NULL);
2753 g_bytes_unref (bytes);
2754 g_object_unref (file);
2759 GMainLoop *main_loop;
2762 } LoadBytesAsyncData;
2765 test_load_bytes_cb (GObject *object,
2766 GAsyncResult *result,
2769 GFile *file = G_FILE (object);
2770 LoadBytesAsyncData *data = user_data;
2771 GError *error = NULL;
2773 data->bytes = g_file_load_bytes_finish (file, result, NULL, &error);
2774 g_assert_no_error (error);
2775 g_assert_nonnull (data->bytes);
2777 g_main_loop_quit (data->main_loop);
2781 test_load_bytes_async (void)
2783 LoadBytesAsyncData data = { 0 };
2784 gchar filename[] = "g_file_load_bytes_XXXXXX";
2789 fd = g_mkstemp (filename);
2790 g_assert_cmpint (fd, !=, -1);
2791 len = strlen ("test_load_bytes_async");
2792 ret = write (fd, "test_load_bytes_async", len);
2793 g_assert_cmpint (ret, ==, len);
2796 data.main_loop = g_main_loop_new (NULL, FALSE);
2797 data.file = g_file_new_for_path (filename);
2799 g_file_load_bytes_async (data.file, NULL, test_load_bytes_cb, &data);
2800 g_main_loop_run (data.main_loop);
2802 g_assert_cmpint (len, ==, g_bytes_get_size (data.bytes));
2803 g_assert_cmpstr ("test_load_bytes_async", ==, (gchar *)g_bytes_get_data (data.bytes, NULL));
2805 g_file_delete (data.file, NULL, NULL);
2806 g_object_unref (data.file);
2807 g_bytes_unref (data.bytes);
2808 g_main_loop_unref (data.main_loop);
2812 test_writev_helper (GOutputVector *vectors,
2814 gboolean use_bytes_written,
2815 const guint8 *expected_contents,
2816 gsize expected_length)
2819 GFileIOStream *iostream = NULL;
2820 GOutputStream *ostream;
2821 GError *error = NULL;
2822 gsize bytes_written = 0;
2827 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2829 g_assert_nonnull (file);
2830 g_assert_nonnull (iostream);
2832 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2834 res = g_output_stream_writev_all (ostream, vectors, n_vectors, use_bytes_written ? &bytes_written : NULL, NULL, &error);
2835 g_assert_no_error (error);
2836 g_assert_true (res);
2837 if (use_bytes_written)
2838 g_assert_cmpuint (bytes_written, ==, expected_length);
2840 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2841 g_assert_no_error (error);
2842 g_assert_true (res);
2843 g_object_unref (iostream);
2845 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2846 g_assert_no_error (error);
2847 g_assert_true (res);
2849 g_assert_cmpmem (contents, length, expected_contents, expected_length);
2853 g_file_delete (file, NULL, NULL);
2854 g_object_unref (file);
2857 /* Test that writev() on local file output streams works on a non-empty vector */
2861 GOutputVector vectors[3];
2862 const guint8 buffer[] = {1, 2, 3, 4, 5,
2863 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2866 vectors[0].buffer = buffer;
2867 vectors[0].size = 5;
2869 vectors[1].buffer = buffer + 5;
2870 vectors[1].size = 12;
2872 vectors[2].buffer = buffer + 5 + 12;
2873 vectors[2].size = 3;
2875 test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, buffer, sizeof buffer);
2878 /* Test that writev() on local file output streams works on a non-empty vector without returning bytes_written */
2880 test_writev_no_bytes_written (void)
2882 GOutputVector vectors[3];
2883 const guint8 buffer[] = {1, 2, 3, 4, 5,
2884 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2887 vectors[0].buffer = buffer;
2888 vectors[0].size = 5;
2890 vectors[1].buffer = buffer + 5;
2891 vectors[1].size = 12;
2893 vectors[2].buffer = buffer + 5 + 12;
2894 vectors[2].size = 3;
2896 test_writev_helper (vectors, G_N_ELEMENTS (vectors), FALSE, buffer, sizeof buffer);
2899 /* Test that writev() on local file output streams works on 0 vectors */
2901 test_writev_no_vectors (void)
2903 test_writev_helper (NULL, 0, TRUE, NULL, 0);
2906 /* Test that writev() on local file output streams works on empty vectors */
2908 test_writev_empty_vectors (void)
2910 GOutputVector vectors[3];
2912 vectors[0].buffer = NULL;
2913 vectors[0].size = 0;
2914 vectors[1].buffer = NULL;
2915 vectors[1].size = 0;
2916 vectors[2].buffer = NULL;
2917 vectors[2].size = 0;
2919 test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, NULL, 0);
2922 /* Test that writev() fails if the sum of sizes in the vector is too big */
2924 test_writev_too_big_vectors (void)
2927 GFileIOStream *iostream = NULL;
2928 GOutputStream *ostream;
2929 GError *error = NULL;
2930 gsize bytes_written = 0;
2934 GOutputVector vectors[3];
2936 vectors[0].buffer = (void*) 1;
2937 vectors[0].size = G_MAXSIZE / 2;
2939 vectors[1].buffer = (void*) 1;
2940 vectors[1].size = G_MAXSIZE / 2;
2942 vectors[2].buffer = (void*) 1;
2943 vectors[2].size = G_MAXSIZE / 2;
2945 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2947 g_assert_nonnull (file);
2948 g_assert_nonnull (iostream);
2950 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2952 res = g_output_stream_writev_all (ostream, vectors, G_N_ELEMENTS (vectors), &bytes_written, NULL, &error);
2953 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
2954 g_assert_cmpuint (bytes_written, ==, 0);
2955 g_assert_false (res);
2956 g_clear_error (&error);
2958 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2959 g_assert_no_error (error);
2960 g_assert_true (res);
2961 g_object_unref (iostream);
2963 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2964 g_assert_no_error (error);
2965 g_assert_true (res);
2967 g_assert_cmpmem (contents, length, NULL, 0);
2971 g_file_delete (file, NULL, NULL);
2972 g_object_unref (file);
2977 gsize bytes_written;
2978 GOutputVector *vectors;
2985 test_writev_async_cb (GObject *object,
2986 GAsyncResult *result,
2989 GOutputStream *ostream = G_OUTPUT_STREAM (object);
2990 WritevAsyncData *data = user_data;
2991 GError *error = NULL;
2992 gsize bytes_written;
2995 res = g_output_stream_writev_finish (ostream, result, &bytes_written, &error);
2996 g_assert_true (res);
2997 g_assert_no_error (error);
2998 data->bytes_written += bytes_written;
3000 /* skip vectors that have been written in full */
3001 while (data->n_vectors > 0 && bytes_written >= data->vectors[0].size)
3003 bytes_written -= data->vectors[0].size;
3007 /* skip partially written vector data */
3008 if (bytes_written > 0 && data->n_vectors > 0)
3010 data->vectors[0].size -= bytes_written;
3011 data->vectors[0].buffer = ((guint8 *) data->vectors[0].buffer) + bytes_written;
3014 if (data->n_vectors > 0)
3015 g_output_stream_writev_async (ostream, data->vectors, data->n_vectors, 0, NULL, test_writev_async_cb, &data);
3018 /* Test that writev_async() on local file output streams works on a non-empty vector */
3020 test_writev_async (void)
3022 WritevAsyncData data = { 0 };
3024 GFileIOStream *iostream = NULL;
3025 GOutputVector vectors[3];
3026 const guint8 buffer[] = {1, 2, 3, 4, 5,
3027 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3029 GOutputStream *ostream;
3030 GError *error = NULL;
3035 vectors[0].buffer = buffer;
3036 vectors[0].size = 5;
3038 vectors[1].buffer = buffer + 5;
3039 vectors[1].size = 12;
3041 vectors[2].buffer = buffer + 5 + 12;
3042 vectors[2].size = 3;
3044 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3046 g_assert_nonnull (file);
3047 g_assert_nonnull (iostream);
3049 data.vectors = vectors;
3050 data.n_vectors = G_N_ELEMENTS (vectors);
3052 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3054 g_output_stream_writev_async (ostream, data.vectors, data.n_vectors, 0, NULL, test_writev_async_cb, &data);
3056 while (data.n_vectors > 0)
3057 g_main_context_iteration (NULL, TRUE);
3059 g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
3061 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3062 g_assert_no_error (error);
3063 g_assert_true (res);
3064 g_object_unref (iostream);
3066 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3067 g_assert_no_error (error);
3068 g_assert_true (res);
3070 g_assert_cmpmem (contents, length, buffer, sizeof buffer);
3074 g_file_delete (file, NULL, NULL);
3075 g_object_unref (file);
3079 test_writev_all_cb (GObject *object,
3080 GAsyncResult *result,
3083 GOutputStream *ostream = G_OUTPUT_STREAM (object);
3084 WritevAsyncData *data = user_data;
3086 g_output_stream_writev_all_finish (ostream, result, &data->bytes_written, &data->error);
3090 /* Test that writev_async_all() on local file output streams works on a non-empty vector */
3092 test_writev_async_all (void)
3094 WritevAsyncData data = { 0 };
3096 GFileIOStream *iostream = NULL;
3097 GOutputStream *ostream;
3098 GOutputVector vectors[3];
3099 const guint8 buffer[] = {1, 2, 3, 4, 5,
3100 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3102 GError *error = NULL;
3107 vectors[0].buffer = buffer;
3108 vectors[0].size = 5;
3110 vectors[1].buffer = buffer + 5;
3111 vectors[1].size = 12;
3113 vectors[2].buffer = buffer + 5 + 12;
3114 vectors[2].size = 3;
3116 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3118 g_assert_nonnull (file);
3119 g_assert_nonnull (iostream);
3121 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3123 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3126 g_main_context_iteration (NULL, TRUE);
3128 g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
3129 g_assert_no_error (data.error);
3131 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3132 g_assert_no_error (error);
3133 g_assert_true (res);
3134 g_object_unref (iostream);
3136 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3137 g_assert_no_error (error);
3138 g_assert_true (res);
3140 g_assert_cmpmem (contents, length, buffer, sizeof buffer);
3144 g_file_delete (file, NULL, NULL);
3145 g_object_unref (file);
3148 /* Test that writev_async_all() on local file output streams handles cancellation correctly */
3150 test_writev_async_all_cancellation (void)
3152 WritevAsyncData data = { 0 };
3154 GFileIOStream *iostream = NULL;
3155 GOutputVector vectors[3];
3156 const guint8 buffer[] = {1, 2, 3, 4, 5,
3157 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3159 GOutputStream *ostream;
3160 GError *error = NULL;
3164 GCancellable *cancellable;
3166 vectors[0].buffer = buffer;
3167 vectors[0].size = 5;
3169 vectors[1].buffer = buffer + 5;
3170 vectors[1].size = 12;
3172 vectors[2].buffer = buffer + 5 + 12;
3173 vectors[2].size = 3;
3175 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3177 g_assert_nonnull (file);
3178 g_assert_nonnull (iostream);
3180 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3182 cancellable = g_cancellable_new ();
3183 g_cancellable_cancel (cancellable);
3185 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, cancellable, test_writev_all_cb, &data);
3188 g_main_context_iteration (NULL, TRUE);
3190 g_assert_cmpuint (data.bytes_written, ==, 0);
3191 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
3192 g_clear_error (&data.error);
3194 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3195 g_assert_no_error (error);
3196 g_assert_true (res);
3197 g_object_unref (iostream);
3199 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3200 g_assert_no_error (error);
3201 g_assert_true (res);
3202 g_assert_cmpuint (length, ==, 0);
3206 g_file_delete (file, NULL, NULL);
3207 g_object_unref (file);
3208 g_object_unref (cancellable);
3211 /* Test that writev_async_all() with empty vectors is handled correctly */
3213 test_writev_async_all_empty_vectors (void)
3215 WritevAsyncData data = { 0 };
3217 GFileIOStream *iostream = NULL;
3218 GOutputVector vectors[3];
3219 GOutputStream *ostream;
3220 GError *error = NULL;
3225 vectors[0].buffer = NULL;
3226 vectors[0].size = 0;
3228 vectors[1].buffer = NULL;
3229 vectors[1].size = 0;
3231 vectors[2].buffer = NULL;
3232 vectors[2].size = 0;
3234 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3236 g_assert_nonnull (file);
3237 g_assert_nonnull (iostream);
3239 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3241 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3244 g_main_context_iteration (NULL, TRUE);
3246 g_assert_cmpuint (data.bytes_written, ==, 0);
3247 g_assert_no_error (data.error);
3248 g_clear_error (&data.error);
3250 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3251 g_assert_no_error (error);
3252 g_assert_true (res);
3253 g_object_unref (iostream);
3255 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3256 g_assert_no_error (error);
3257 g_assert_true (res);
3258 g_assert_cmpuint (length, ==, 0);
3262 g_file_delete (file, NULL, NULL);
3263 g_object_unref (file);
3266 /* Test that writev_async_all() with no vectors is handled correctly */
3268 test_writev_async_all_no_vectors (void)
3270 WritevAsyncData data = { 0 };
3272 GFileIOStream *iostream = NULL;
3273 GOutputStream *ostream;
3274 GError *error = NULL;
3279 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3281 g_assert_nonnull (file);
3282 g_assert_nonnull (iostream);
3284 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3286 g_output_stream_writev_all_async (ostream, NULL, 0, 0, NULL, test_writev_all_cb, &data);
3289 g_main_context_iteration (NULL, TRUE);
3291 g_assert_cmpuint (data.bytes_written, ==, 0);
3292 g_assert_no_error (data.error);
3293 g_clear_error (&data.error);
3295 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3296 g_assert_no_error (error);
3297 g_assert_true (res);
3298 g_object_unref (iostream);
3300 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3301 g_assert_no_error (error);
3302 g_assert_true (res);
3303 g_assert_cmpuint (length, ==, 0);
3307 g_file_delete (file, NULL, NULL);
3308 g_object_unref (file);
3311 /* Test that writev_async_all() with too big vectors is handled correctly */
3313 test_writev_async_all_too_big_vectors (void)
3315 WritevAsyncData data = { 0 };
3317 GFileIOStream *iostream = NULL;
3318 GOutputVector vectors[3];
3319 GOutputStream *ostream;
3320 GError *error = NULL;
3325 vectors[0].buffer = (void*) 1;
3326 vectors[0].size = G_MAXSIZE / 2;
3328 vectors[1].buffer = (void*) 1;
3329 vectors[1].size = G_MAXSIZE / 2;
3331 vectors[2].buffer = (void*) 1;
3332 vectors[2].size = G_MAXSIZE / 2;
3334 file = g_file_new_tmp ("g_file_writev_XXXXXX",
3336 g_assert_nonnull (file);
3337 g_assert_nonnull (iostream);
3339 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3341 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3344 g_main_context_iteration (NULL, TRUE);
3346 g_assert_cmpuint (data.bytes_written, ==, 0);
3347 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
3348 g_clear_error (&data.error);
3350 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3351 g_assert_no_error (error);
3352 g_assert_true (res);
3353 g_object_unref (iostream);
3355 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3356 g_assert_no_error (error);
3357 g_assert_true (res);
3358 g_assert_cmpuint (length, ==, 0);
3362 g_file_delete (file, NULL, NULL);
3363 g_object_unref (file);
3367 test_build_attribute_list_for_copy (void)
3370 GFileIOStream *iostream;
3371 GError *error = NULL;
3372 const GFileCopyFlags test_flags[] =
3375 G_FILE_COPY_TARGET_DEFAULT_PERMS,
3376 G_FILE_COPY_ALL_METADATA,
3377 G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_PERMS,
3381 gchar *attrs_with_commas;
3383 tmpfile = g_file_new_tmp ("tmp-build-attribute-list-for-copyXXXXXX",
3385 g_assert_no_error (error);
3386 g_io_stream_close ((GIOStream*)iostream, NULL, &error);
3387 g_assert_no_error (error);
3388 g_clear_object (&iostream);
3390 for (i = 0; i < G_N_ELEMENTS (test_flags); i++)
3392 GFileCopyFlags flags = test_flags[i];
3394 attrs = g_file_build_attribute_list_for_copy (tmpfile, flags, NULL, &error);
3395 g_test_message ("Attributes for copy: %s", attrs);
3396 g_assert_no_error (error);
3397 g_assert_nonnull (attrs);
3398 attrs_with_commas = g_strconcat (",", attrs, ",", NULL);
3401 /* See g_local_file_class_init for reference. */
3402 if (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
3403 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
3405 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
3407 if (flags & G_FILE_COPY_ALL_METADATA)
3409 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
3410 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
3414 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
3415 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
3419 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3420 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ","));
3421 if (flags & G_FILE_COPY_ALL_METADATA)
3423 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3424 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
3428 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3429 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
3432 #ifdef HAVE_UTIMENSAT
3433 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3434 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ","));
3435 if (flags & G_FILE_COPY_ALL_METADATA)
3437 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3438 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
3442 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3443 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
3446 g_free (attrs_with_commas);
3449 (void) g_file_delete (tmpfile, NULL, NULL);
3450 g_clear_object (&tmpfile);
3461 test_move_async_cb (GObject *object,
3462 GAsyncResult *result,
3465 GFile *file = G_FILE (object);
3466 MoveAsyncData *data = user_data;
3467 GError *error = NULL;
3469 data->res = g_file_move_finish (file, result, &error);
3470 data->error = error;
3476 goffset total_num_bytes;
3477 } MoveAsyncProgressData;
3480 test_move_async_progress_cb (goffset current_num_bytes,
3481 goffset total_num_bytes,
3484 MoveAsyncProgressData *data = user_data;
3485 data->total_num_bytes = total_num_bytes;
3488 /* Test that move_async() moves the file correctly */
3490 test_move_async (void)
3492 MoveAsyncData data = { 0 };
3493 MoveAsyncProgressData progress_data = { 0 };
3495 GFileIOStream *iostream;
3496 GOutputStream *ostream;
3498 gchar *destination_path;
3499 GError *error = NULL;
3501 const guint8 buffer[] = {1, 2, 3, 4, 5};
3503 source = g_file_new_tmp ("g_file_move_XXXXXX", &iostream, NULL);
3505 destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_move_target", NULL);
3506 destination = g_file_new_for_path (destination_path);
3508 g_assert_nonnull (source);
3509 g_assert_nonnull (iostream);
3511 res = g_file_query_exists (source, NULL);
3512 g_assert_true (res);
3513 res = g_file_query_exists (destination, NULL);
3514 g_assert_false (res);
3516 // Write a known amount of bytes to the file, so we can test the progress callback against it
3517 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3518 g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
3519 g_assert_no_error (error);
3521 g_file_move_async (source,
3526 test_move_async_progress_cb,
3532 g_main_context_iteration (NULL, TRUE);
3534 g_assert_no_error (data.error);
3535 g_assert_true (data.res);
3536 g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
3538 res = g_file_query_exists (source, NULL);
3539 g_assert_false (res);
3540 res = g_file_query_exists (destination, NULL);
3541 g_assert_true (res);
3543 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3544 g_assert_no_error (error);
3545 g_assert_true (res);
3546 g_object_unref (iostream);
3548 res = g_file_delete (destination, NULL, &error);
3549 g_assert_no_error (error);
3550 g_assert_true (res);
3552 g_object_unref (source);
3553 g_object_unref (destination);
3555 g_free (destination_path);
3559 create_command_line_app_info (const char *name,
3560 const char *command_line,
3561 const char *default_for_type)
3564 GError *error = NULL;
3566 info = g_app_info_create_from_commandline (command_line,
3568 G_APP_INFO_CREATE_NONE,
3570 g_assert_no_error (error);
3572 g_app_info_set_as_default_for_type (info, default_for_type, &error);
3573 g_assert_no_error (error);
3575 return g_steal_pointer (&info);
3579 test_query_default_handler_uri (void)
3581 GError *error = NULL;
3583 GAppInfo *default_info;
3585 GFile *invalid_file;
3587 #if defined(G_OS_WIN32) || defined(__APPLE__)
3588 g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
3592 info = create_command_line_app_info ("Gio File Handler", "true",
3593 "x-scheme-handler/gio-file");
3594 g_assert_true (G_IS_APP_INFO (info));
3596 file = g_file_new_for_uri ("gio-file://hello-gio!");
3597 default_info = g_file_query_default_handler (file, NULL, &error);
3598 g_assert_no_error (error);
3599 g_assert_true (g_app_info_equal (default_info, info));
3601 invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
3602 g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
3603 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
3604 g_clear_error (&error);
3606 g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &error);
3607 g_assert_no_error (error);
3608 g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
3610 g_object_unref (default_info);
3611 g_object_unref (info);
3612 g_object_unref (file);
3613 g_object_unref (invalid_file);
3617 test_query_zero_length_content_type (void)
3620 GFileInfo *file_info;
3621 GError *error = NULL;
3622 GFileIOStream *iostream;
3624 g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=755795");
3625 /* Historically, GLib used to explicitly consider zero-size files as text/plain,
3626 * so they opened in a text editor. In 2.76, we changed that to application/x-zerosize,
3627 * because that’s what xdgmime uses:
3628 * - https://gitlab.gnome.org/GNOME/glib/-/blob/2.74.0/gio/glocalfileinfo.c#L1360-1369
3629 * - https://bugzilla.gnome.org/show_bug.cgi?id=755795
3630 * - https://gitlab.gnome.org/GNOME/glib/-/issues/2777
3632 g_test_summary ("empty files should always be considered application/x-zerosize");
3634 empty_file = g_file_new_tmp ("empty-file-XXXXXX", &iostream, &error);
3635 g_assert_no_error (error);
3637 g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3638 g_assert_no_error (error);
3639 g_clear_object (&iostream);
3642 g_file_query_info (empty_file,
3643 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
3644 G_FILE_QUERY_INFO_NONE,
3646 g_assert_no_error (error);
3649 g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "application/x-zerosize");
3651 g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "public.text");
3654 g_clear_object (&file_info);
3655 g_clear_object (&empty_file);
3659 test_query_default_handler_file (void)
3661 GError *error = NULL;
3663 GAppInfo *default_info;
3666 GFile *invalid_file;
3667 GFileIOStream *iostream;
3668 GOutputStream *output_stream;
3669 const char buffer[] = "Text file!\n";
3670 const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
3672 #if defined(G_OS_WIN32) || defined(__APPLE__)
3673 g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
3677 text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
3678 g_assert_no_error (error);
3680 output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3681 g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
3682 NULL, NULL, &error);
3683 g_assert_no_error (error);
3685 g_output_stream_flush (output_stream, NULL, &error);
3686 g_assert_no_error (error);
3688 g_output_stream_close (output_stream, NULL, &error);
3689 g_assert_no_error (error);
3690 g_clear_object (&iostream);
3692 info = create_command_line_app_info ("Text handler", "true", "text/plain");
3693 g_assert_true (G_IS_APP_INFO (info));
3695 default_info = g_file_query_default_handler (text_file, NULL, &error);
3696 g_assert_no_error (error);
3697 g_assert_true (g_app_info_equal (default_info, info));
3699 invalid_file = g_file_new_for_path ("/hopefully/this-does-not-exists");
3700 g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
3701 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
3702 g_clear_error (&error);
3704 binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
3705 g_assert_no_error (error);
3707 output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3708 g_output_stream_write_all (output_stream, binary_buffer,
3709 G_N_ELEMENTS (binary_buffer),
3710 NULL, NULL, &error);
3711 g_assert_no_error (error);
3713 g_output_stream_flush (output_stream, NULL, &error);
3714 g_assert_no_error (error);
3716 g_output_stream_close (output_stream, NULL, &error);
3717 g_assert_no_error (error);
3718 g_clear_object (&iostream);
3720 g_assert_null (g_file_query_default_handler (binary_file, NULL, &error));
3721 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
3722 g_clear_error (&error);
3724 g_app_info_remove_supports_type (info, "text/plain", &error);
3725 g_assert_no_error (error);
3726 g_app_info_reset_type_associations ("text/plain");
3728 g_object_unref (default_info);
3729 g_object_unref (info);
3730 g_object_unref (text_file);
3731 g_object_unref (binary_file);
3732 g_object_unref (invalid_file);
3739 } QueryDefaultHandlerData;
3742 on_query_default (GObject *source,
3743 GAsyncResult *result,
3746 QueryDefaultHandlerData *data = user_data;
3748 data->info = g_file_query_default_handler_finish (G_FILE (source), result,
3750 g_main_loop_quit (data->loop);
3754 test_query_default_handler_file_async (void)
3756 QueryDefaultHandlerData data = {0};
3757 GCancellable *cancellable;
3761 GFile *invalid_file;
3762 GFileIOStream *iostream;
3763 GOutputStream *output_stream;
3764 const char buffer[] = "Text file!\n";
3765 const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
3766 GError *error = NULL;
3768 #if defined(G_OS_WIN32) || defined(__APPLE__)
3769 g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
3773 data.loop = g_main_loop_new (NULL, FALSE);
3775 text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
3776 g_assert_no_error (error);
3778 output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3779 g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
3780 NULL, NULL, &error);
3781 g_assert_no_error (error);
3783 g_output_stream_close (output_stream, NULL, &error);
3784 g_assert_no_error (error);
3785 g_clear_object (&iostream);
3787 info = create_command_line_app_info ("Text handler", "true", "text/plain");
3788 g_assert_true (G_IS_APP_INFO (info));
3790 g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
3791 NULL, on_query_default,
3793 g_main_loop_run (data.loop);
3794 g_assert_no_error (data.error);
3795 g_assert_true (g_app_info_equal (data.info, info));
3796 g_clear_object (&data.info);
3798 invalid_file = g_file_new_for_path ("/hopefully/this/.file/does-not-exists");
3799 g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
3800 NULL, on_query_default,
3802 g_main_loop_run (data.loop);
3803 g_assert_null (data.info);
3804 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
3805 g_clear_error (&data.error);
3807 cancellable = g_cancellable_new ();
3808 g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
3809 cancellable, on_query_default,
3811 g_cancellable_cancel (cancellable);
3812 g_main_loop_run (data.loop);
3813 g_assert_null (data.info);
3814 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
3815 g_clear_error (&data.error);
3817 binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
3818 g_assert_no_error (error);
3820 output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3821 g_output_stream_write_all (output_stream, binary_buffer,
3822 G_N_ELEMENTS (binary_buffer),
3823 NULL, NULL, &error);
3824 g_assert_no_error (error);
3826 g_output_stream_close (output_stream, NULL, &error);
3827 g_assert_no_error (error);
3828 g_clear_object (&iostream);
3830 g_file_query_default_handler_async (binary_file, G_PRIORITY_DEFAULT,
3831 NULL, on_query_default,
3833 g_main_loop_run (data.loop);
3834 g_assert_null (data.info);
3835 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
3836 g_clear_error (&data.error);
3838 g_app_info_remove_supports_type (info, "text/plain", &error);
3839 g_assert_no_error (error);
3840 g_app_info_reset_type_associations ("text/plain");
3842 g_main_loop_unref (data.loop);
3843 g_object_unref (info);
3844 g_object_unref (text_file);
3845 g_object_unref (binary_file);
3846 g_object_unref (invalid_file);
3850 test_query_default_handler_uri_async (void)
3852 QueryDefaultHandlerData data = {0};
3853 GCancellable *cancellable;
3856 GFile *invalid_file;
3858 #if defined(G_OS_WIN32) || defined(__APPLE__)
3859 g_test_skip ("Default URI handlers are not currently supported on Windows or macOS");
3863 info = create_command_line_app_info ("Gio File Handler", "true",
3864 "x-scheme-handler/gio-file");
3865 g_assert_true (G_IS_APP_INFO (info));
3867 data.loop = g_main_loop_new (NULL, FALSE);
3869 file = g_file_new_for_uri ("gio-file://hello-gio!");
3870 g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
3871 NULL, on_query_default,
3873 g_main_loop_run (data.loop);
3874 g_assert_no_error (data.error);
3875 g_assert_true (g_app_info_equal (data.info, info));
3876 g_clear_object (&data.info);
3878 invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
3879 g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
3880 NULL, on_query_default,
3882 g_main_loop_run (data.loop);
3883 g_assert_null (data.info);
3884 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
3885 g_clear_error (&data.error);
3887 cancellable = g_cancellable_new ();
3888 g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
3889 cancellable, on_query_default,
3891 g_cancellable_cancel (cancellable);
3892 g_main_loop_run (data.loop);
3893 g_assert_null (data.info);
3894 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
3895 g_clear_error (&data.error);
3897 g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &data.error);
3898 g_assert_no_error (data.error);
3899 g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
3901 g_main_loop_unref (data.loop);
3902 g_object_unref (info);
3903 g_object_unref (file);
3904 g_object_unref (invalid_file);
3908 test_enumerator_cancellation (void)
3910 GCancellable *cancellable;
3911 GFileEnumerator *enumerator;
3914 GError *error = NULL;
3916 dir = g_file_new_for_path (g_get_tmp_dir ());
3917 g_assert_nonnull (dir);
3919 enumerator = g_file_enumerate_children (dir,
3920 G_FILE_ATTRIBUTE_STANDARD_NAME,
3921 G_FILE_QUERY_INFO_NONE,
3924 g_assert_nonnull (enumerator);
3926 cancellable = g_cancellable_new ();
3927 g_cancellable_cancel (cancellable);
3928 info = g_file_enumerator_next_file (enumerator, cancellable, &error);
3929 g_assert_null (info);
3930 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
3932 g_error_free (error);
3933 g_object_unref (cancellable);
3934 g_object_unref (enumerator);
3935 g_object_unref (dir);
3939 test_from_uri_ignores_fragment (void)
3943 file = g_file_new_for_uri ("file:///tmp/foo#bar");
3944 path = g_file_get_path (file);
3946 g_assert_cmpstr (path, ==, "\\tmp\\foo");
3948 g_assert_cmpstr (path, ==, "/tmp/foo");
3951 g_object_unref (file);
3955 test_from_uri_ignores_query_string (void)
3959 file = g_file_new_for_uri ("file:///tmp/foo?bar");
3960 path = g_file_get_path (file);
3962 g_assert_cmpstr (path, ==, "\\tmp\\foo");
3964 g_assert_cmpstr (path, ==, "/tmp/foo");
3967 g_object_unref (file);
3971 main (int argc, char *argv[])
3973 setlocale (LC_ALL, "");
3975 g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
3977 g_test_add_func ("/file/basic", test_basic);
3978 g_test_add_func ("/file/build-filename", test_build_filename);
3979 g_test_add_func ("/file/build-filenamev", test_build_filenamev);
3980 g_test_add_func ("/file/parent", test_parent);
3981 g_test_add_func ("/file/child", test_child);
3982 g_test_add_func ("/file/empty-path", test_empty_path);
3983 g_test_add_func ("/file/type", test_type);
3984 g_test_add_func ("/file/parse-name", test_parse_name);
3985 g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
3986 g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
3987 g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
3988 g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
3989 g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
3990 g_test_add_func ("/file/replace-load", test_replace_load);
3991 g_test_add_func ("/file/replace-cancel", test_replace_cancel);
3992 g_test_add_func ("/file/replace-symlink", test_replace_symlink);
3993 g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
3994 g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
3995 g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
3996 g_test_add_func ("/file/async-new-tmp", test_async_new_tmp);
3997 g_test_add_func ("/file/async-new-tmp-dir", test_async_new_tmp_dir);
3998 g_test_add_func ("/file/async-delete", test_async_delete);
3999 g_test_add_func ("/file/async-make-symlink", test_async_make_symlink);
4000 g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
4001 g_test_add_func ("/file/copy/progress", test_copy_progress);
4002 g_test_add_func ("/file/measure", test_measure);
4003 g_test_add_func ("/file/measure-async", test_measure_async);
4004 g_test_add_func ("/file/load-bytes", test_load_bytes);
4005 g_test_add_func ("/file/load-bytes-async", test_load_bytes_async);
4006 g_test_add_func ("/file/writev", test_writev);
4007 g_test_add_func ("/file/writev/no-bytes-written", test_writev_no_bytes_written);
4008 g_test_add_func ("/file/writev/no-vectors", test_writev_no_vectors);
4009 g_test_add_func ("/file/writev/empty-vectors", test_writev_empty_vectors);
4010 g_test_add_func ("/file/writev/too-big-vectors", test_writev_too_big_vectors);
4011 g_test_add_func ("/file/writev/async", test_writev_async);
4012 g_test_add_func ("/file/writev/async_all", test_writev_async_all);
4013 g_test_add_func ("/file/writev/async_all-empty-vectors", test_writev_async_all_empty_vectors);
4014 g_test_add_func ("/file/writev/async_all-no-vectors", test_writev_async_all_no_vectors);
4015 g_test_add_func ("/file/writev/async_all-to-big-vectors", test_writev_async_all_too_big_vectors);
4016 g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
4017 g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
4018 g_test_add_func ("/file/move_async", test_move_async);
4019 g_test_add_func ("/file/query-zero-length-content-type", test_query_zero_length_content_type);
4020 g_test_add_func ("/file/query-default-handler-file", test_query_default_handler_file);
4021 g_test_add_func ("/file/query-default-handler-file-async", test_query_default_handler_file_async);
4022 g_test_add_func ("/file/query-default-handler-uri", test_query_default_handler_uri);
4023 g_test_add_func ("/file/query-default-handler-uri-async", test_query_default_handler_uri_async);
4024 g_test_add_func ("/file/enumerator-cancellation", test_enumerator_cancellation);
4025 g_test_add_func ("/file/from-uri/ignores-query-string", test_from_uri_ignores_query_string);
4026 g_test_add_func ("/file/from-uri/ignores-fragment", test_from_uri_ignores_fragment);
4028 return g_test_run ();