6 #include <gio/gfiledescriptorbased.h>
12 test_basic_for_file (GFile *file,
17 s = g_file_get_basename (file);
18 g_assert_cmpstr (s, ==, "testfile");
21 s = g_file_get_uri (file);
22 g_assert_true (g_str_has_prefix (s, "file://"));
23 g_assert_true (g_str_has_suffix (s, suffix));
26 g_assert_true (g_file_has_uri_scheme (file, "file"));
27 s = g_file_get_uri_scheme (file);
28 g_assert_cmpstr (s, ==, "file");
37 file = g_file_new_for_path ("./some/directory/testfile");
38 test_basic_for_file (file, "/some/directory/testfile");
39 g_object_unref (file);
43 test_build_filename (void)
47 file = g_file_new_build_filename (".", "some", "directory", "testfile", NULL);
48 test_basic_for_file (file, "/some/directory/testfile");
49 g_object_unref (file);
51 file = g_file_new_build_filename ("testfile", NULL);
52 test_basic_for_file (file, "/testfile");
53 g_object_unref (file);
64 file = g_file_new_for_path ("./some/directory/testfile");
65 file2 = g_file_new_for_path ("./some/directory");
66 root = g_file_new_for_path ("/");
68 g_assert_true (g_file_has_parent (file, file2));
70 parent = g_file_get_parent (file);
71 g_assert_true (g_file_equal (parent, file2));
72 g_object_unref (parent);
74 g_assert_null (g_file_get_parent (root));
76 g_object_unref (file);
77 g_object_unref (file2);
78 g_object_unref (root);
88 file = g_file_new_for_path ("./some/directory");
89 child = g_file_get_child (file, "child");
90 g_assert_true (g_file_has_parent (child, file));
92 child2 = g_file_get_child_for_display_name (file, "child2", NULL);
93 g_assert_true (g_file_has_parent (child2, file));
95 g_object_unref (child);
96 g_object_unref (child2);
97 g_object_unref (file);
101 test_empty_path (void)
105 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2328");
106 g_test_summary ("Check that creating a file with an empty path results in errors");
108 /* Creating the file must always succeed. */
109 file = g_file_new_for_path ("");
110 g_assert_nonnull (file);
112 /* But then querying its path should indicate it’s invalid. */
113 g_assert_null (g_file_get_path (file));
114 g_assert_null (g_file_get_basename (file));
115 g_assert_null (g_file_get_parent (file));
117 g_object_unref (file);
126 GError *error = NULL;
128 datapath_f = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
130 file = g_file_get_child (datapath_f, "g-icon.c");
131 type = g_file_query_file_type (file, 0, NULL);
132 g_assert_cmpint (type, ==, G_FILE_TYPE_REGULAR);
133 g_object_unref (file);
135 file = g_file_get_child (datapath_f, "cert-tests");
136 type = g_file_query_file_type (file, 0, NULL);
137 g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
139 g_file_read (file, NULL, &error);
140 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
141 g_error_free (error);
142 g_object_unref (file);
144 g_object_unref (datapath_f);
148 test_parse_name (void)
153 file = g_file_new_for_uri ("file://somewhere");
154 name = g_file_get_parse_name (file);
155 g_assert_cmpstr (name, ==, "file://somewhere");
156 g_object_unref (file);
159 file = g_file_parse_name ("~foo");
160 name = g_file_get_parse_name (file);
161 g_assert_nonnull (name);
162 g_object_unref (file);
168 GMainContext *context;
170 GFileMonitor *monitor;
171 GOutputStream *ostream;
172 GInputStream *istream;
174 gint monitor_created;
175 gint monitor_deleted;
176 gint monitor_changed;
182 gboolean file_deleted;
187 monitor_changed (GFileMonitor *monitor,
190 GFileMonitorEvent event_type,
193 CreateDeleteData *data = user_data;
195 const gchar *peeked_path;
197 path = g_file_get_path (file);
198 peeked_path = g_file_peek_path (file);
199 g_assert_cmpstr (data->monitor_path, ==, path);
200 g_assert_cmpstr (path, ==, peeked_path);
203 if (event_type == G_FILE_MONITOR_EVENT_CREATED)
204 data->monitor_created++;
205 if (event_type == G_FILE_MONITOR_EVENT_DELETED)
206 data->monitor_deleted++;
207 if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
208 data->monitor_changed++;
210 g_main_context_wakeup (data->context);
214 iclosed_cb (GObject *source,
218 CreateDeleteData *data = user_data;
223 ret = g_input_stream_close_finish (data->istream, res, &error);
224 g_assert_no_error (error);
227 g_assert_true (g_input_stream_is_closed (data->istream));
229 ret = g_file_delete (data->file, NULL, &error);
231 g_assert_no_error (error);
233 data->file_deleted = TRUE;
234 g_main_context_wakeup (data->context);
238 read_cb (GObject *source,
242 CreateDeleteData *data = user_data;
247 size = g_input_stream_read_finish (data->istream, res, &error);
248 g_assert_no_error (error);
251 if (data->pos < strlen (data->data))
253 g_input_stream_read_async (data->istream,
254 data->buffer + data->pos,
255 strlen (data->data) - data->pos,
263 g_assert_cmpstr (data->buffer, ==, data->data);
264 g_assert_false (g_input_stream_is_closed (data->istream));
265 g_input_stream_close_async (data->istream, 0, NULL, iclosed_cb, data);
270 ipending_cb (GObject *source,
274 CreateDeleteData *data = user_data;
278 g_input_stream_read_finish (data->istream, res, &error);
279 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
280 g_error_free (error);
284 skipped_cb (GObject *source,
288 CreateDeleteData *data = user_data;
293 size = g_input_stream_skip_finish (data->istream, res, &error);
294 g_assert_no_error (error);
295 g_assert_cmpint (size, ==, data->pos);
297 g_input_stream_read_async (data->istream,
298 data->buffer + data->pos,
299 strlen (data->data) - data->pos,
304 /* check that we get a pending error */
305 g_input_stream_read_async (data->istream,
306 data->buffer + data->pos,
307 strlen (data->data) - data->pos,
315 opened_cb (GObject *source,
319 GFileInputStream *base;
320 CreateDeleteData *data = user_data;
324 base = g_file_read_finish (data->file, res, &error);
325 g_assert_no_error (error);
327 if (data->buffersize == 0)
328 data->istream = G_INPUT_STREAM (g_object_ref (base));
330 data->istream = g_buffered_input_stream_new_sized (G_INPUT_STREAM (base), data->buffersize);
331 g_object_unref (base);
333 data->buffer = g_new0 (gchar, strlen (data->data) + 1);
335 /* copy initial segment directly, then skip */
336 memcpy (data->buffer, data->data, 10);
339 g_input_stream_skip_async (data->istream,
348 oclosed_cb (GObject *source,
352 CreateDeleteData *data = user_data;
357 ret = g_output_stream_close_finish (data->ostream, res, &error);
358 g_assert_no_error (error);
360 g_assert_true (g_output_stream_is_closed (data->ostream));
362 g_file_read_async (data->file, 0, NULL, opened_cb, data);
366 written_cb (GObject *source,
370 CreateDeleteData *data = user_data;
375 size = g_output_stream_write_finish (data->ostream, res, &error);
376 g_assert_no_error (error);
379 if (data->pos < strlen (data->data))
381 g_output_stream_write_async (data->ostream,
382 data->data + data->pos,
383 strlen (data->data) - data->pos,
391 g_assert_false (g_output_stream_is_closed (data->ostream));
392 g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
397 opending_cb (GObject *source,
401 CreateDeleteData *data = user_data;
405 g_output_stream_write_finish (data->ostream, res, &error);
406 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
407 g_error_free (error);
411 created_cb (GObject *source,
415 GFileOutputStream *base;
416 CreateDeleteData *data = user_data;
420 base = g_file_create_finish (G_FILE (source), res, &error);
421 g_assert_no_error (error);
422 g_assert_true (g_file_query_exists (data->file, NULL));
424 if (data->buffersize == 0)
425 data->ostream = G_OUTPUT_STREAM (g_object_ref (base));
427 data->ostream = g_buffered_output_stream_new_sized (G_OUTPUT_STREAM (base), data->buffersize);
428 g_object_unref (base);
430 g_output_stream_write_async (data->ostream,
437 /* check that we get a pending error */
438 g_output_stream_write_async (data->ostream,
448 stop_timeout (gpointer user_data)
450 CreateDeleteData *data = user_data;
452 data->timed_out = TRUE;
453 g_main_context_wakeup (data->context);
455 return G_SOURCE_REMOVE;
459 * This test does a fully async create-write-read-delete.
463 test_create_delete (gconstpointer d)
466 CreateDeleteData *data;
467 GFileIOStream *iostream;
469 data = g_new0 (CreateDeleteData, 1);
471 data->buffersize = GPOINTER_TO_INT (d);
472 data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
475 data->file = g_file_new_tmp ("g_file_create_delete_XXXXXX",
477 g_assert_nonnull (data->file);
478 g_object_unref (iostream);
480 data->monitor_path = g_file_get_path (data->file);
481 remove (data->monitor_path);
483 g_assert_false (g_file_query_exists (data->file, NULL));
486 data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
487 g_assert_no_error (error);
489 /* This test doesn't work with GPollFileMonitor, because it assumes
490 * that the monitor will notice a create immediately followed by a
491 * delete, rather than coalescing them into nothing.
493 /* This test also doesn't work with GKqueueFileMonitor because of
494 * the same reason. Kqueue is able to return a kevent when a file is
495 * created or deleted in a directory. However, the kernel doesn't tell
496 * the program file names, so GKqueueFileMonitor has to calculate the
497 * difference itself. This is usually too slow for rapid file creation
498 * and deletion tests.
500 if (strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GPollFileMonitor") == 0 ||
501 strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GKqueueFileMonitor") == 0)
503 g_test_skip ("skipping test for this GFileMonitor implementation");
507 g_file_monitor_set_rate_limit (data->monitor, 100);
509 g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
511 /* Use the global default main context */
512 data->context = NULL;
513 data->timeout = g_timeout_add_seconds (10, stop_timeout, data);
515 g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
517 while (!data->timed_out &&
518 (data->monitor_created == 0 ||
519 data->monitor_deleted == 0 ||
520 data->monitor_changed == 0 ||
521 !data->file_deleted))
522 g_main_context_iteration (data->context, TRUE);
524 g_source_remove (data->timeout);
526 g_assert_false (data->timed_out);
527 g_assert_true (data->file_deleted);
528 g_assert_cmpint (data->monitor_created, ==, 1);
529 g_assert_cmpint (data->monitor_deleted, ==, 1);
530 g_assert_cmpint (data->monitor_changed, >, 0);
532 g_assert_false (g_file_monitor_is_cancelled (data->monitor));
533 g_file_monitor_cancel (data->monitor);
534 g_assert_true (g_file_monitor_is_cancelled (data->monitor));
536 g_clear_pointer (&data->context, g_main_context_unref);
537 g_object_unref (data->ostream);
538 g_object_unref (data->istream);
541 g_object_unref (data->monitor);
542 g_object_unref (data->file);
543 g_free (data->monitor_path);
544 g_free (data->buffer);
548 static const gchar *original_data =
550 " * g_file_replace_contents_async:\n"
553 static const gchar *replace_data =
555 " * g_file_replace_contents_async:\n"
556 " * @file: input #GFile.\n"
557 " * @contents: string of contents to replace the file with.\n"
558 " * @length: the length of @contents in bytes.\n"
559 " * @etag: (nullable): a new <link linkend=\"gfile-etag\">entity tag</link> for the @file, or %NULL\n"
560 " * @make_backup: %TRUE if a backup should be created.\n"
561 " * @flags: a set of #GFileCreateFlags.\n"
562 " * @cancellable: optional #GCancellable object, %NULL to ignore.\n"
563 " * @callback: a #GAsyncReadyCallback to call when the request is satisfied\n"
564 " * @user_data: the data to pass to callback function\n"
566 " * Starts an asynchronous replacement of @file with the given \n"
567 " * @contents of @length bytes. @etag will replace the document's\n"
568 " * current entity tag.\n"
570 " * When this operation has completed, @callback will be called with\n"
571 " * @user_user data, and the operation can be finalized with \n"
572 " * g_file_replace_contents_finish().\n"
574 " * If @cancellable is not %NULL, then the operation can be cancelled by\n"
575 " * triggering the cancellable object from another thread. If the operation\n"
576 " * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. \n"
578 " * If @make_backup is %TRUE, this function will attempt to \n"
579 " * make a backup of @file.\n"
590 static void replaced_cb (GObject *source,
595 loaded_cb (GObject *source,
599 ReplaceLoadData *data = user_data;
606 ret = g_file_load_contents_finish (data->file, res, &contents, &length, NULL, &error);
608 g_assert_no_error (error);
609 g_assert_cmpint (length, ==, strlen (data->data));
610 g_assert_cmpstr (contents, ==, data->data);
617 data->data = "pi pa po";
619 g_file_replace_contents_async (data->file,
632 ret = g_file_delete (data->file, NULL, &error);
633 g_assert_no_error (error);
635 g_assert_false (g_file_query_exists (data->file, NULL));
637 g_main_loop_quit (data->loop);
642 replaced_cb (GObject *source,
646 ReplaceLoadData *data = user_data;
650 g_file_replace_contents_finish (data->file, res, NULL, &error);
651 g_assert_no_error (error);
653 g_file_load_contents_async (data->file, NULL, loaded_cb, data);
657 test_replace_load (void)
659 ReplaceLoadData *data;
661 GFileIOStream *iostream;
663 data = g_new0 (ReplaceLoadData, 1);
665 data->data = replace_data;
667 data->file = g_file_new_tmp ("g_file_replace_load_XXXXXX",
669 g_assert_nonnull (data->file);
670 g_object_unref (iostream);
672 path = g_file_peek_path (data->file);
675 g_assert_false (g_file_query_exists (data->file, NULL));
677 data->loop = g_main_loop_new (NULL, FALSE);
679 g_file_replace_contents_async (data->file,
689 g_main_loop_run (data->loop);
691 g_main_loop_unref (data->loop);
692 g_object_unref (data->file);
697 test_replace_cancel (void)
699 GFile *tmpdir, *file;
700 GFileOutputStream *ostream;
701 GFileEnumerator *fenum;
703 GCancellable *cancellable;
706 gsize nwrote, length;
708 GError *error = NULL;
710 g_test_bug ("https://bugzilla.gnome.org/629301");
712 path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
713 g_assert_no_error (error);
714 tmpdir = g_file_new_for_path (path);
717 file = g_file_get_child (tmpdir, "file");
718 g_file_replace_contents (file,
720 strlen (original_data),
721 NULL, FALSE, 0, NULL,
723 g_assert_no_error (error);
725 ostream = g_file_replace (file, NULL, TRUE, 0, NULL, &error);
726 g_assert_no_error (error);
728 g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
729 replace_data, strlen (replace_data),
730 &nwrote, NULL, &error);
731 g_assert_no_error (error);
732 g_assert_cmpint (nwrote, ==, strlen (replace_data));
734 /* At this point there should be two files; the original and the
737 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
738 g_assert_no_error (error);
740 info = g_file_enumerator_next_file (fenum, NULL, &error);
741 g_assert_no_error (error);
742 g_assert_nonnull (info);
743 g_object_unref (info);
744 info = g_file_enumerator_next_file (fenum, NULL, &error);
745 g_assert_no_error (error);
746 g_assert_nonnull (info);
747 g_object_unref (info);
749 g_file_enumerator_close (fenum, NULL, &error);
750 g_assert_no_error (error);
751 g_object_unref (fenum);
753 /* Also test the g_file_enumerator_iterate() API */
754 fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
755 g_assert_no_error (error);
760 gboolean ret = g_file_enumerator_iterate (fenum, &info, NULL, NULL, &error);
762 g_assert_no_error (error);
767 g_assert_cmpint (count, ==, 2);
769 g_file_enumerator_close (fenum, NULL, &error);
770 g_assert_no_error (error);
771 g_object_unref (fenum);
773 /* Now test just getting child from the g_file_enumerator_iterate() API */
774 fenum = g_file_enumerate_children (tmpdir, "standard::name", 0, NULL, &error);
775 g_assert_no_error (error);
781 gboolean ret = g_file_enumerator_iterate (fenum, NULL, &child, NULL, &error);
784 g_assert_no_error (error);
789 g_assert_true (G_IS_FILE (child));
792 g_assert_cmpint (count, ==, 2);
794 g_file_enumerator_close (fenum, NULL, &error);
795 g_assert_no_error (error);
796 g_object_unref (fenum);
798 /* Make sure the temporary gets deleted even if we cancel. */
799 cancellable = g_cancellable_new ();
800 g_cancellable_cancel (cancellable);
801 g_output_stream_close (G_OUTPUT_STREAM (ostream), cancellable, &error);
802 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
803 g_clear_error (&error);
805 g_object_unref (cancellable);
806 g_object_unref (ostream);
808 /* Make sure that file contents wasn't actually replaced. */
809 g_file_load_contents (file,
815 g_assert_no_error (error);
816 g_assert_cmpstr (contents, ==, original_data);
819 g_file_delete (file, NULL, &error);
820 g_assert_no_error (error);
821 g_object_unref (file);
823 /* This will only succeed if the temp file was deleted. */
824 g_file_delete (tmpdir, NULL, &error);
825 g_assert_no_error (error);
826 g_object_unref (tmpdir);
830 test_replace_symlink (void)
833 gchar *tmpdir_path = NULL;
834 GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
835 GFileOutputStream *stream = NULL;
836 const gchar *new_contents = "this is a test message which should be written to source and not target";
838 GFileEnumerator *enumerator = NULL;
839 GFileInfo *info = NULL;
840 gchar *contents = NULL;
842 GError *local_error = NULL;
844 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325");
845 g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks");
847 /* Create a fresh, empty working directory. */
848 tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
849 g_assert_no_error (local_error);
850 tmpdir = g_file_new_for_path (tmpdir_path);
852 g_test_message ("Using temporary directory %s", tmpdir_path);
853 g_free (tmpdir_path);
855 /* Create symlink `source` which points to `target`. */
856 source_file = g_file_get_child (tmpdir, "source");
857 target_file = g_file_get_child (tmpdir, "target");
858 g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
859 g_assert_no_error (local_error);
861 /* Ensure that `target` doesn’t exist */
862 g_assert_false (g_file_query_exists (target_file, NULL));
864 /* Replace the `source` symlink with a regular file using
865 * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
866 * following the symlink */
867 stream = g_file_replace (source_file, NULL, FALSE /* no backup */,
868 G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
869 g_assert_no_error (local_error);
871 g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
872 &n_written, NULL, &local_error);
873 g_assert_no_error (local_error);
874 g_assert_cmpint (n_written, ==, strlen (new_contents));
876 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
877 g_assert_no_error (local_error);
879 g_clear_object (&stream);
881 /* At this point, there should still only be one file: `source`. It should
882 * now be a regular file. `target` should not exist. */
883 enumerator = g_file_enumerate_children (tmpdir,
884 G_FILE_ATTRIBUTE_STANDARD_NAME ","
885 G_FILE_ATTRIBUTE_STANDARD_TYPE,
886 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
887 g_assert_no_error (local_error);
889 info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
890 g_assert_no_error (local_error);
891 g_assert_nonnull (info);
893 g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
894 g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
896 g_clear_object (&info);
898 info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
899 g_assert_no_error (local_error);
900 g_assert_null (info);
902 g_file_enumerator_close (enumerator, NULL, &local_error);
903 g_assert_no_error (local_error);
904 g_clear_object (&enumerator);
906 /* Double-check that `target` doesn’t exist */
907 g_assert_false (g_file_query_exists (target_file, NULL));
909 /* Check the content of `source`. */
910 g_file_load_contents (source_file,
916 g_assert_no_error (local_error);
917 g_assert_cmpstr (contents, ==, new_contents);
918 g_assert_cmpuint (length, ==, strlen (new_contents));
922 g_file_delete (source_file, NULL, &local_error);
923 g_assert_no_error (local_error);
925 g_file_delete (tmpdir, NULL, &local_error);
926 g_assert_no_error (local_error);
928 g_clear_object (&target_file);
929 g_clear_object (&source_file);
930 g_clear_object (&tmpdir);
931 #else /* if !G_OS_UNIX */
932 g_test_skip ("Symlink replacement tests can only be run on Unix")
937 test_replace_symlink_using_etag (void)
940 gchar *tmpdir_path = NULL;
941 GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
942 GFileOutputStream *stream = NULL;
943 const gchar *old_contents = "this is a test message which should be written to target and then overwritten";
944 gchar *old_etag = NULL;
945 const gchar *new_contents = "this is an updated message";
947 gchar *contents = NULL;
949 GFileInfo *info = NULL;
950 GError *local_error = NULL;
952 g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2417");
953 g_test_summary ("Test that ETag checks work when replacing a file through a symlink");
955 /* Create a fresh, empty working directory. */
956 tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_using_etag_XXXXXX", &local_error);
957 g_assert_no_error (local_error);
958 tmpdir = g_file_new_for_path (tmpdir_path);
960 g_test_message ("Using temporary directory %s", tmpdir_path);
961 g_free (tmpdir_path);
963 /* Create symlink `source` which points to `target`. */
964 source_file = g_file_get_child (tmpdir, "source");
965 target_file = g_file_get_child (tmpdir, "target");
966 g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
967 g_assert_no_error (local_error);
969 /* Sleep for at least 1s to ensure the mtimes of `source` and `target` differ,
970 * as that’s what _g_local_file_info_create_etag() uses to create the ETag,
971 * and one failure mode we’re testing for is that the ETags of `source` and
972 * `target` are conflated. */
975 /* Create `target` with some arbitrary content. */
976 stream = g_file_create (target_file, G_FILE_CREATE_NONE, NULL, &local_error);
977 g_assert_no_error (local_error);
978 g_output_stream_write_all (G_OUTPUT_STREAM (stream), old_contents, strlen (old_contents),
979 &n_written, NULL, &local_error);
980 g_assert_no_error (local_error);
981 g_assert_cmpint (n_written, ==, strlen (old_contents));
983 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
984 g_assert_no_error (local_error);
986 old_etag = g_file_output_stream_get_etag (stream);
987 g_assert_nonnull (old_etag);
988 g_assert_cmpstr (old_etag, !=, "");
990 g_clear_object (&stream);
992 /* Sleep again to ensure the ETag changes again. */
995 /* Write out a new copy of the `target`, checking its ETag first. This should
996 * replace `target` by following the symlink. */
997 stream = g_file_replace (source_file, old_etag, FALSE /* no backup */,
998 G_FILE_CREATE_NONE, NULL, &local_error);
999 g_assert_no_error (local_error);
1001 g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
1002 &n_written, NULL, &local_error);
1003 g_assert_no_error (local_error);
1004 g_assert_cmpint (n_written, ==, strlen (new_contents));
1006 g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
1007 g_assert_no_error (local_error);
1009 g_clear_object (&stream);
1011 /* At this point, there should be a regular file, `target`, containing
1012 * @new_contents; and a symlink `source` which points to `target`. */
1013 g_assert_cmpint (g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_SYMBOLIC_LINK);
1014 g_assert_cmpint (g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_REGULAR);
1016 /* Check the content of `target`. */
1017 g_file_load_contents (target_file,
1023 g_assert_no_error (local_error);
1024 g_assert_cmpstr (contents, ==, new_contents);
1025 g_assert_cmpuint (length, ==, strlen (new_contents));
1028 /* And check its ETag value has changed. */
1029 info = g_file_query_info (target_file, G_FILE_ATTRIBUTE_ETAG_VALUE,
1030 G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1031 g_assert_no_error (local_error);
1032 g_assert_cmpstr (g_file_info_get_etag (info), !=, old_etag);
1034 g_clear_object (&info);
1038 g_file_delete (target_file, NULL, &local_error);
1039 g_assert_no_error (local_error);
1041 g_file_delete (source_file, NULL, &local_error);
1042 g_assert_no_error (local_error);
1044 g_file_delete (tmpdir, NULL, &local_error);
1045 g_assert_no_error (local_error);
1047 g_clear_object (&target_file);
1048 g_clear_object (&source_file);
1049 g_clear_object (&tmpdir);
1050 #else /* if !G_OS_UNIX */
1051 g_test_skip ("Symlink replacement tests can only be run on Unix")
1055 /* FIXME: These tests have only been checked on Linux. Most of them are probably
1056 * applicable on Windows, too, but that has not been tested yet.
1057 * See https://gitlab.gnome.org/GNOME/glib/-/issues/2325 */
1060 /* Different kinds of file which create_test_file() can create. */
1063 FILE_TEST_SETUP_TYPE_NONEXISTENT,
1064 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY,
1065 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY,
1066 FILE_TEST_SETUP_TYPE_DIRECTORY,
1067 FILE_TEST_SETUP_TYPE_SOCKET,
1068 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING,
1069 FILE_TEST_SETUP_TYPE_SYMLINK_VALID,
1070 } FileTestSetupType;
1072 /* Create file `tmpdir/basename`, of type @setup_type, and chmod it to
1073 * @setup_mode. Return the #GFile representing it. Abort on any errors. */
1075 create_test_file (GFile *tmpdir,
1076 const gchar *basename,
1077 FileTestSetupType setup_type,
1080 GFile *test_file = g_file_get_child (tmpdir, basename);
1081 gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1082 GFile *target_file = g_file_get_child (tmpdir, target_basename);
1083 GError *local_error = NULL;
1087 case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1088 /* Nothing to do here. */
1089 g_assert (setup_mode == 0);
1091 case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1092 case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1094 gchar *contents = NULL;
1096 if (setup_type == FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY)
1097 contents = g_strdup_printf ("this is some test content in %s", basename);
1099 contents = g_strdup ("");
1101 g_file_set_contents (g_file_peek_path (test_file), contents, -1, &local_error);
1102 g_assert_no_error (local_error);
1104 g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1105 setup_mode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1106 NULL, &local_error);
1107 g_assert_no_error (local_error);
1112 case FILE_TEST_SETUP_TYPE_DIRECTORY:
1113 g_assert (setup_mode == 0);
1115 g_file_make_directory (test_file, NULL, &local_error);
1116 g_assert_no_error (local_error);
1118 case FILE_TEST_SETUP_TYPE_SOCKET:
1119 g_assert_no_errno (mknod (g_file_peek_path (test_file), S_IFSOCK | setup_mode, 0));
1121 case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1122 g_file_set_contents (g_file_peek_path (target_file), "target file", -1, &local_error);
1123 g_assert_no_error (local_error);
1125 case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1126 /* Permissions on a symlink are not used by the kernel, so are only
1127 * applicable if the symlink is valid (and are applied to the target) */
1128 g_assert (setup_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || setup_mode == 0);
1130 g_file_make_symbolic_link (test_file, target_basename, NULL, &local_error);
1131 g_assert_no_error (local_error);
1133 if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1135 g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1136 setup_mode, G_FILE_QUERY_INFO_NONE,
1137 NULL, &local_error);
1138 g_assert_no_error (local_error);
1141 if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING)
1143 /* Ensure that the target doesn’t exist */
1144 g_assert_false (g_file_query_exists (target_file, NULL));
1148 g_assert_not_reached ();
1151 g_clear_object (&target_file);
1152 g_free (target_basename);
1154 return g_steal_pointer (&test_file);
1157 /* Check that @test_file is of the @expected_type, has the @expected_mode, and
1158 * (if it’s a regular file) has the @expected_contents or (if it’s a symlink)
1159 * has the symlink target given by @expected_contents.
1161 * @test_file must point to the file `tmpdir/basename`.
1163 * Aborts on any errors or mismatches against the expectations.
1166 check_test_file (GFile *test_file,
1168 const gchar *basename,
1169 FileTestSetupType expected_type,
1170 guint expected_mode,
1171 const gchar *expected_contents)
1173 gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1174 GFile *target_file = g_file_get_child (tmpdir, target_basename);
1175 GFileType test_file_type = g_file_query_file_type (test_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL);
1176 GFileInfo *info = NULL;
1177 GError *local_error = NULL;
1179 switch (expected_type)
1181 case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1182 g_assert (expected_mode == 0);
1183 g_assert (expected_contents == NULL);
1185 g_assert_false (g_file_query_exists (test_file, NULL));
1186 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_UNKNOWN);
1188 case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1189 case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1190 g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_EMPTY || expected_contents == NULL);
1191 g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY || expected_contents != NULL);
1193 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_REGULAR);
1195 info = g_file_query_info (test_file,
1196 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
1197 G_FILE_ATTRIBUTE_UNIX_MODE,
1198 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1199 g_assert_no_error (local_error);
1201 if (expected_type == FILE_TEST_SETUP_TYPE_REGULAR_EMPTY)
1202 g_assert_cmpint (g_file_info_get_size (info), ==, 0);
1204 g_assert_cmpint (g_file_info_get_size (info), >, 0);
1206 if (expected_contents != NULL)
1208 gchar *contents = NULL;
1211 g_file_get_contents (g_file_peek_path (test_file), &contents, &length, &local_error);
1212 g_assert_no_error (local_error);
1214 g_assert_cmpstr (contents, ==, expected_contents);
1218 g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1221 case FILE_TEST_SETUP_TYPE_DIRECTORY:
1222 g_assert (expected_mode == 0);
1223 g_assert (expected_contents == NULL);
1225 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_DIRECTORY);
1227 case FILE_TEST_SETUP_TYPE_SOCKET:
1228 g_assert (expected_contents == NULL);
1230 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SPECIAL);
1232 info = g_file_query_info (test_file,
1233 G_FILE_ATTRIBUTE_UNIX_MODE,
1234 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1235 g_assert_no_error (local_error);
1237 g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1239 case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1240 case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1242 GFile *symlink_target_file = NULL;
1244 /* Permissions on a symlink are not used by the kernel, so are only
1245 * applicable if the symlink is valid (and are applied to the target) */
1246 g_assert (expected_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || expected_mode == 0);
1247 g_assert (expected_contents != NULL);
1249 g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SYMBOLIC_LINK);
1251 info = g_file_query_info (test_file,
1252 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
1253 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1254 g_assert_no_error (local_error);
1256 g_assert_cmpstr (g_file_info_get_symlink_target (info), ==, expected_contents);
1258 symlink_target_file = g_file_get_child (tmpdir, g_file_info_get_symlink_target (info));
1259 if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1260 g_assert_true (g_file_query_exists (symlink_target_file, NULL));
1262 g_assert_false (g_file_query_exists (symlink_target_file, NULL));
1264 if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1266 GFileInfo *target_info = NULL;
1268 /* Need to re-query the info so we follow symlinks */
1269 target_info = g_file_query_info (test_file,
1270 G_FILE_ATTRIBUTE_UNIX_MODE,
1271 G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1272 g_assert_no_error (local_error);
1274 g_assert_cmpuint (g_file_info_get_attribute_uint32 (target_info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1276 g_clear_object (&target_info);
1279 g_clear_object (&symlink_target_file);
1283 g_assert_not_reached ();
1286 g_clear_object (&info);
1287 g_clear_object (&target_file);
1288 g_free (target_basename);
1291 #endif /* __linux__ */
1293 /* A big test for g_file_replace() and g_file_replace_readwrite(). The
1294 * @test_data is a boolean: %TRUE to test g_file_replace_readwrite(), %FALSE to
1295 * test g_file_replace(). The test setup and checks are identical for both
1296 * functions; in the case of testing g_file_replace_readwrite(), only the output
1297 * stream side of the returned #GIOStream is tested. i.e. We test the write
1298 * behaviour of both functions is identical.
1300 * This is intended to test all static behaviour of the function: for each test
1301 * scenario, a temporary directory is set up with a source file (and maybe some
1302 * other files) in a set configuration, g_file_replace{,_readwrite}() is called,
1303 * and the final state of the directory is checked.
1305 * This test does not check dynamic behaviour or race conditions. For example,
1306 * it does not test what happens if the source file is deleted from another
1307 * process half-way through a call to g_file_replace().
1310 test_replace (gconstpointer test_data)
1313 gboolean read_write = GPOINTER_TO_UINT (test_data);
1314 const gchar *new_contents = "this is a new test message which should be written to source";
1315 const gchar *original_source_contents = "this is some test content in source";
1316 const gchar *original_backup_contents = "this is some test content in source~";
1317 mode_t current_umask = umask (0);
1318 guint32 default_public_mode = 0666 & ~current_umask;
1319 guint32 default_private_mode = 0600;
1323 /* Arguments to pass to g_file_replace(). */
1324 gboolean replace_make_backup;
1325 GFileCreateFlags replace_flags;
1326 const gchar *replace_etag; /* (nullable) */
1328 /* File system setup. */
1329 FileTestSetupType setup_source_type;
1330 guint setup_source_mode;
1331 FileTestSetupType setup_backup_type;
1332 guint setup_backup_mode;
1334 /* Expected results. */
1335 gboolean expected_success;
1336 GQuark expected_error_domain;
1337 gint expected_error_code;
1339 /* Expected final file system state. */
1340 guint expected_n_files;
1341 FileTestSetupType expected_source_type;
1342 guint expected_source_mode;
1343 const gchar *expected_source_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1344 FileTestSetupType expected_backup_type;
1345 guint expected_backup_mode;
1346 const gchar *expected_backup_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1350 /* replace_make_backup == FALSE, replace_flags == NONE, replace_etag == NULL,
1351 * all the different values of setup_source_type, mostly with a backup
1352 * file created to check it’s not modified */
1354 FALSE, G_FILE_CREATE_NONE, NULL,
1355 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1356 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1358 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1359 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1362 FALSE, G_FILE_CREATE_NONE, NULL,
1363 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1364 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1366 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1367 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1370 FALSE, G_FILE_CREATE_NONE, NULL,
1371 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1372 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1374 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1375 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1378 FALSE, G_FILE_CREATE_NONE, NULL,
1379 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1380 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1381 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1382 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1383 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1386 FALSE, G_FILE_CREATE_NONE, NULL,
1387 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1388 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1389 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1390 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1391 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1394 FALSE, G_FILE_CREATE_NONE, NULL,
1395 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1396 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1398 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1399 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1402 FALSE, G_FILE_CREATE_NONE, NULL,
1403 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1404 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1406 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1407 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1410 /* replace_etag set to an invalid value, with setup_source_type as a
1411 * regular non-empty file; replacement should fail */
1413 FALSE, G_FILE_CREATE_NONE, "incorrect etag",
1414 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1415 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1416 FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1417 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1418 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1421 /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1422 * all the different values of setup_source_type, with a backup
1423 * file created to check it’s either replaced or the operation fails */
1425 TRUE, G_FILE_CREATE_NONE, NULL,
1426 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1427 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1429 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1430 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1433 TRUE, G_FILE_CREATE_NONE, NULL,
1434 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1435 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1437 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1438 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1441 TRUE, G_FILE_CREATE_NONE, NULL,
1442 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1443 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1445 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1446 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1449 TRUE, G_FILE_CREATE_NONE, NULL,
1450 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1451 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1452 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1453 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1454 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1457 TRUE, G_FILE_CREATE_NONE, NULL,
1458 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1459 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1460 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1461 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1462 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1465 TRUE, G_FILE_CREATE_NONE, NULL,
1466 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1467 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1469 /* The final situation here is a bit odd; the backup file is a bit
1470 * pointless as the original source file was a dangling symlink.
1471 * Theoretically the backup file should be that symlink, pointing to
1472 * `source-target`, and hence no longer dangling, as that file has now
1473 * been created as the new source content, since REPLACE_DESTINATION was
1474 * not specified. However, the code instead creates an empty regular
1475 * file as the backup. FIXME: This seems acceptable for now, but not
1476 * entirely ideal and would be good to fix at some point. */
1477 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1478 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0777 & ~current_umask, NULL,
1481 TRUE, G_FILE_CREATE_NONE, NULL,
1482 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1483 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1485 /* FIXME: The permissions for the backup file are just the default umask,
1486 * but should probably be the same as the permissions for the source
1487 * file (`default_public_mode`). This probably arises from the fact that
1488 * symlinks don’t have permissions. */
1489 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1490 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, 0777 & ~current_umask, "target file",
1493 /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1494 * setup_source_type is a regular file, with a backup file of every type
1495 * created to check it’s either replaced or the operation fails */
1497 TRUE, G_FILE_CREATE_NONE, NULL,
1498 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1499 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1501 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1502 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1505 TRUE, G_FILE_CREATE_NONE, NULL,
1506 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1507 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1509 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1510 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1513 TRUE, G_FILE_CREATE_NONE, NULL,
1514 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1515 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1517 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1518 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1521 TRUE, G_FILE_CREATE_NONE, NULL,
1522 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1523 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1524 FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1525 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1526 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1529 TRUE, G_FILE_CREATE_NONE, NULL,
1530 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1531 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1533 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1534 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1537 TRUE, G_FILE_CREATE_NONE, NULL,
1538 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1539 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1541 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1542 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1545 TRUE, G_FILE_CREATE_NONE, NULL,
1546 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1547 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1549 /* the third file is `source~-target`, the original target of the old
1551 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1552 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1555 /* replace_make_backup == FALSE, replace_flags == REPLACE_DESTINATION,
1556 * replace_etag == NULL, all the different values of setup_source_type,
1557 * mostly with a backup file created to check it’s not modified */
1559 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1560 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1561 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1563 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1564 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1567 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1568 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1569 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1571 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1572 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1575 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1576 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1577 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1579 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1580 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1583 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1584 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1585 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1586 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1587 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1588 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1591 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1592 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1593 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1594 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1595 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1596 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1599 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1600 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1601 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1603 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1604 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1607 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1608 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1609 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1611 /* the third file is `source-target`, the original target of the old
1613 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1614 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1617 /* replace_flags == REPLACE_DESTINATION, replace_etag set to an invalid
1618 * value, with setup_source_type as a regular non-empty file; replacement
1621 FALSE, G_FILE_CREATE_REPLACE_DESTINATION, "incorrect etag",
1622 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1623 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1624 FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1625 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1626 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1629 /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1630 * replace_etag == NULL, all the different values of setup_source_type,
1631 * with a backup file created to check it’s either replaced or the
1632 * operation fails */
1634 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1635 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1636 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1638 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1639 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1642 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1643 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1644 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1646 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1647 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1650 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1651 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1652 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1654 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1655 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1658 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1659 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1660 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1661 FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1662 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1663 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1666 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1667 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1668 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1669 FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1670 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1671 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1674 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1675 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1676 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1678 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1679 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, "source-target",
1682 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1683 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1684 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1686 /* the third file is `source-target`, the original target of the old
1688 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1689 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1692 /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1693 * replace_etag == NULL, setup_source_type is a regular file, with a
1694 * backup file of every type created to check it’s either replaced or the
1695 * operation fails */
1697 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1698 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1699 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1701 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1702 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1705 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1706 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1707 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1709 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1710 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1713 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1714 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1715 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1717 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1718 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1721 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1722 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1723 FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1724 FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1725 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1726 FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1729 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1730 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1731 FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1733 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1734 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1737 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1738 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1739 FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1741 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1742 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1745 TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1746 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1747 FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1749 /* the third file is `source~-target`, the original target of the old
1751 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1752 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1755 /* several different setups with replace_flags == PRIVATE */
1757 FALSE, G_FILE_CREATE_PRIVATE, NULL,
1758 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1759 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1761 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1762 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1765 FALSE, G_FILE_CREATE_PRIVATE, NULL,
1766 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1767 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1769 /* the file isn’t being replaced, so it should keep its existing permissions */
1770 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1771 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1774 FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1775 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1776 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1778 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1779 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1782 FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1783 FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1784 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1786 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1787 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1790 /* make the initial source file unreadable, so the replace operation
1793 FALSE, G_FILE_CREATE_NONE, NULL,
1794 FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0 /* most restrictive permissions */,
1795 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1796 FALSE, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1797 1, FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0, NULL,
1798 FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1803 g_test_summary ("Test various situations for g_file_replace()");
1805 /* Reset the umask after querying it above. There’s no way to query it without
1807 umask (current_umask);
1808 g_test_message ("Current umask: %u", current_umask);
1810 for (i = 0; i < G_N_ELEMENTS (tests); i++)
1812 gchar *tmpdir_path = NULL;
1813 GFile *tmpdir = NULL, *source_file = NULL, *backup_file = NULL;
1814 GFileOutputStream *output_stream = NULL;
1815 GFileIOStream *io_stream = NULL;
1816 GFileEnumerator *enumerator = NULL;
1817 GFileInfo *info = NULL;
1819 GError *local_error = NULL;
1821 /* Create a fresh, empty working directory. */
1822 tmpdir_path = g_dir_make_tmp ("g_file_replace_XXXXXX", &local_error);
1823 g_assert_no_error (local_error);
1824 tmpdir = g_file_new_for_path (tmpdir_path);
1826 g_test_message ("Test %" G_GSIZE_FORMAT ", using temporary directory %s", i, tmpdir_path);
1827 g_free (tmpdir_path);
1829 /* Set up the test directory. */
1830 source_file = create_test_file (tmpdir, "source", tests[i].setup_source_type, tests[i].setup_source_mode);
1831 backup_file = create_test_file (tmpdir, "source~", tests[i].setup_backup_type, tests[i].setup_backup_mode);
1833 /* Replace the source file. Check the error state only after finishing
1834 * writing, as the replace operation is split across g_file_replace() and
1835 * g_output_stream_close(). */
1837 io_stream = g_file_replace_readwrite (source_file,
1838 tests[i].replace_etag,
1839 tests[i].replace_make_backup,
1840 tests[i].replace_flags,
1844 output_stream = g_file_replace (source_file,
1845 tests[i].replace_etag,
1846 tests[i].replace_make_backup,
1847 tests[i].replace_flags,
1851 if (tests[i].expected_success)
1853 g_assert_no_error (local_error);
1855 g_assert_nonnull (io_stream);
1857 g_assert_nonnull (output_stream);
1860 /* Write new content to it. */
1861 if (io_stream != NULL)
1863 GOutputStream *io_output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
1866 g_output_stream_write_all (G_OUTPUT_STREAM (io_output_stream), new_contents, strlen (new_contents),
1867 &n_written, NULL, &local_error);
1869 if (tests[i].expected_success)
1871 g_assert_no_error (local_error);
1872 g_assert_cmpint (n_written, ==, strlen (new_contents));
1875 g_io_stream_close (G_IO_STREAM (io_stream), NULL, (local_error == NULL) ? &local_error : NULL);
1877 if (tests[i].expected_success)
1878 g_assert_no_error (local_error);
1880 else if (output_stream != NULL)
1884 g_output_stream_write_all (G_OUTPUT_STREAM (output_stream), new_contents, strlen (new_contents),
1885 &n_written, NULL, &local_error);
1887 if (tests[i].expected_success)
1889 g_assert_no_error (local_error);
1890 g_assert_cmpint (n_written, ==, strlen (new_contents));
1893 g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, (local_error == NULL) ? &local_error : NULL);
1895 if (tests[i].expected_success)
1896 g_assert_no_error (local_error);
1899 if (tests[i].expected_success)
1900 g_assert_no_error (local_error);
1902 g_assert_error (local_error, tests[i].expected_error_domain, tests[i].expected_error_code);
1904 g_clear_error (&local_error);
1905 g_clear_object (&io_stream);
1906 g_clear_object (&output_stream);
1908 /* Verify the final state of the directory. */
1909 enumerator = g_file_enumerate_children (tmpdir,
1910 G_FILE_ATTRIBUTE_STANDARD_NAME,
1911 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1912 g_assert_no_error (local_error);
1917 g_file_enumerator_iterate (enumerator, &info, NULL, NULL, &local_error);
1918 g_assert_no_error (local_error);
1923 while (info != NULL);
1925 g_clear_object (&enumerator);
1927 g_assert_cmpuint (n_files, ==, tests[i].expected_n_files);
1929 check_test_file (source_file, tmpdir, "source", tests[i].expected_source_type, tests[i].expected_source_mode, tests[i].expected_source_contents);
1930 check_test_file (backup_file, tmpdir, "source~", tests[i].expected_backup_type, tests[i].expected_backup_mode, tests[i].expected_backup_contents);
1932 /* Tidy up. Ignore failure apart from when deleting the directory, which
1933 * should be empty. */
1934 g_file_delete (source_file, NULL, NULL);
1935 g_file_delete (backup_file, NULL, NULL);
1937 /* Other files which are occasionally generated by the tests. */
1939 GFile *backup_target_file = g_file_get_child (tmpdir, "source~-target");
1940 g_file_delete (backup_target_file, NULL, NULL);
1941 g_clear_object (&backup_target_file);
1944 GFile *backup_target_file = g_file_get_child (tmpdir, "source-target");
1945 g_file_delete (backup_target_file, NULL, NULL);
1946 g_clear_object (&backup_target_file);
1949 g_file_delete (tmpdir, NULL, &local_error);
1950 g_assert_no_error (local_error);
1952 g_clear_object (&backup_file);
1953 g_clear_object (&source_file);
1954 g_clear_object (&tmpdir);
1956 #else /* if !__linux__ */
1957 g_test_skip ("File replacement tests can only be run on Linux");
1962 on_file_deleted (GObject *object,
1963 GAsyncResult *result,
1966 GError *local_error = NULL;
1967 GMainLoop *loop = user_data;
1969 (void) g_file_delete_finish ((GFile*)object, result, &local_error);
1970 g_assert_no_error (local_error);
1972 g_main_loop_quit (loop);
1976 test_async_delete (void)
1979 GFileIOStream *iostream;
1980 GError *local_error = NULL;
1981 GError **error = &local_error;
1984 file = g_file_new_tmp ("g_file_delete_XXXXXX",
1986 g_assert_no_error (local_error);
1987 g_object_unref (iostream);
1989 g_assert_true (g_file_query_exists (file, NULL));
1991 loop = g_main_loop_new (NULL, TRUE);
1993 g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop);
1995 g_main_loop_run (loop);
1997 g_assert_false (g_file_query_exists (file, NULL));
1999 g_main_loop_unref (loop);
2000 g_object_unref (file);
2004 test_copy_preserve_mode (void)
2007 mode_t current_umask = umask (0);
2010 guint32 source_mode;
2011 guint32 expected_destination_mode;
2012 gboolean create_destination_before_copy;
2013 GFileCopyFlags copy_flags;
2017 /* Overwriting the destination file should copy the permissions from the
2018 * source file, even if %G_FILE_COPY_ALL_METADATA is set: */
2019 { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2020 { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2021 /* The same behaviour should hold if the destination file is not being
2022 * overwritten because it doesn’t already exist: */
2023 { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2024 { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS },
2025 /* Anything with %G_FILE_COPY_TARGET_DEFAULT_PERMS should use the current
2026 * umask for the destination file: */
2027 { 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 },
2028 { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2029 { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2030 { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2034 /* Reset the umask after querying it above. There’s no way to query it without
2036 umask (current_umask);
2037 g_test_message ("Current umask: %u", current_umask);
2039 for (i = 0; i < G_N_ELEMENTS (vectors); i++)
2042 GFile *dest_tmpfile;
2043 GFileInfo *dest_info;
2044 GFileIOStream *iostream;
2045 GError *local_error = NULL;
2046 guint32 romode = vectors[i].source_mode;
2049 g_test_message ("Vector %" G_GSIZE_FORMAT, i);
2051 tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2052 &iostream, &local_error);
2053 g_assert_no_error (local_error);
2054 g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2055 g_assert_no_error (local_error);
2056 g_clear_object (&iostream);
2058 g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
2059 &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2060 NULL, &local_error);
2061 g_assert_no_error (local_error);
2063 dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2064 &iostream, &local_error);
2065 g_assert_no_error (local_error);
2066 g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2067 g_assert_no_error (local_error);
2068 g_clear_object (&iostream);
2070 if (!vectors[i].create_destination_before_copy)
2072 g_file_delete (dest_tmpfile, NULL, &local_error);
2073 g_assert_no_error (local_error);
2076 g_file_copy (tmpfile, dest_tmpfile, vectors[i].copy_flags,
2077 NULL, NULL, NULL, &local_error);
2078 g_assert_no_error (local_error);
2080 dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2081 NULL, &local_error);
2082 g_assert_no_error (local_error);
2084 dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
2086 g_assert_cmpint (dest_mode & ~S_IFMT, ==, vectors[i].expected_destination_mode);
2087 g_assert_cmpint (dest_mode & S_IFMT, ==, S_IFREG);
2089 (void) g_file_delete (tmpfile, NULL, NULL);
2090 (void) g_file_delete (dest_tmpfile, NULL, NULL);
2092 g_clear_object (&tmpfile);
2093 g_clear_object (&dest_tmpfile);
2094 g_clear_object (&dest_info);
2096 #else /* if !G_OS_UNIX */
2097 g_test_skip ("File permissions tests can only be run on Unix")
2102 splice_to_string (GInputStream *stream,
2105 GMemoryOutputStream *buffer = NULL;
2108 buffer = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
2109 if (g_output_stream_splice ((GOutputStream*)buffer, stream, 0, NULL, error) < 0)
2112 if (!g_output_stream_write ((GOutputStream*)buffer, "\0", 1, NULL, error))
2115 if (!g_output_stream_close ((GOutputStream*)buffer, NULL, error))
2118 ret = g_memory_output_stream_steal_data (buffer);
2120 g_clear_object (&buffer);
2125 get_size_from_du (const gchar *path, guint64 *size)
2131 GError *error = NULL;
2132 gchar *du_path = NULL;
2134 /* If we can’t find du, don’t try and run the test. */
2135 du_path = g_find_program_in_path ("du");
2136 if (du_path == NULL)
2140 du = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE,
2142 "du", "--bytes", "-s", path, NULL);
2143 g_assert_no_error (error);
2145 result = splice_to_string (g_subprocess_get_stdout_pipe (du), &error);
2146 g_assert_no_error (error);
2148 *size = g_ascii_strtoll (result, &endptr, 10);
2150 g_subprocess_wait (du, NULL, &error);
2151 g_assert_no_error (error);
2153 ok = g_subprocess_get_successful (du);
2155 g_object_unref (du);
2169 GError *error = NULL;
2173 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2174 file = g_file_new_for_path (path);
2176 if (!get_size_from_du (path, &size))
2178 g_test_message ("du not found or fail to run, skipping byte measurement");
2182 ok = g_file_measure_disk_usage (file,
2183 G_FILE_MEASURE_APPARENT_SIZE,
2192 g_assert_no_error (error);
2195 g_assert_cmpuint (num_bytes, ==, size);
2196 g_assert_cmpuint (num_dirs, ==, 6);
2197 g_assert_cmpuint (num_files, ==, 32);
2199 g_object_unref (file);
2204 guint64 expected_bytes;
2205 guint64 expected_dirs;
2206 guint64 expected_files;
2207 gint progress_count;
2208 guint64 progress_bytes;
2209 guint64 progress_dirs;
2210 guint64 progress_files;
2214 measure_progress (gboolean reporting,
2215 guint64 current_size,
2220 MeasureData *data = user_data;
2222 data->progress_count += 1;
2224 g_assert_cmpuint (current_size, >=, data->progress_bytes);
2225 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2226 g_assert_cmpuint (num_files, >=, data->progress_files);
2228 data->progress_bytes = current_size;
2229 data->progress_dirs = num_dirs;
2230 data->progress_files = num_files;
2234 measure_done (GObject *source,
2238 MeasureData *data = user_data;
2239 guint64 num_bytes, num_dirs, num_files;
2240 GError *error = NULL;
2243 ok = g_file_measure_disk_usage_finish (G_FILE (source), res, &num_bytes, &num_dirs, &num_files, &error);
2245 g_assert_no_error (error);
2247 if (data->expected_bytes > 0)
2248 g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
2249 g_assert_cmpuint (data->expected_dirs, ==, num_dirs);
2250 g_assert_cmpuint (data->expected_files, ==, num_files);
2252 g_assert_cmpuint (data->progress_count, >, 0);
2253 g_assert_cmpuint (num_bytes, >=, data->progress_bytes);
2254 g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2255 g_assert_cmpuint (num_files, >=, data->progress_files);
2258 g_object_unref (source);
2262 test_measure_async (void)
2268 data = g_new (MeasureData, 1);
2270 data->progress_count = 0;
2271 data->progress_bytes = 0;
2272 data->progress_files = 0;
2273 data->progress_dirs = 0;
2275 path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2276 file = g_file_new_for_path (path);
2278 if (!get_size_from_du (path, &data->expected_bytes))
2280 g_test_message ("du not found or fail to run, skipping byte measurement");
2281 data->expected_bytes = 0;
2286 data->expected_dirs = 6;
2287 data->expected_files = 32;
2289 g_file_measure_disk_usage_async (file,
2290 G_FILE_MEASURE_APPARENT_SIZE,
2292 measure_progress, data,
2293 measure_done, data);
2297 test_load_bytes (void)
2299 gchar filename[] = "g_file_load_bytes_XXXXXX";
2300 GError *error = NULL;
2307 fd = g_mkstemp (filename);
2308 g_assert_cmpint (fd, !=, -1);
2309 len = strlen ("test_load_bytes");
2310 ret = write (fd, "test_load_bytes", len);
2311 g_assert_cmpint (ret, ==, len);
2314 file = g_file_new_for_path (filename);
2315 bytes = g_file_load_bytes (file, NULL, NULL, &error);
2316 g_assert_no_error (error);
2317 g_assert_nonnull (bytes);
2318 g_assert_cmpint (len, ==, g_bytes_get_size (bytes));
2319 g_assert_cmpstr ("test_load_bytes", ==, (gchar *)g_bytes_get_data (bytes, NULL));
2321 g_file_delete (file, NULL, NULL);
2323 g_bytes_unref (bytes);
2324 g_object_unref (file);
2329 GMainLoop *main_loop;
2332 } LoadBytesAsyncData;
2335 test_load_bytes_cb (GObject *object,
2336 GAsyncResult *result,
2339 GFile *file = G_FILE (object);
2340 LoadBytesAsyncData *data = user_data;
2341 GError *error = NULL;
2343 data->bytes = g_file_load_bytes_finish (file, result, NULL, &error);
2344 g_assert_no_error (error);
2345 g_assert_nonnull (data->bytes);
2347 g_main_loop_quit (data->main_loop);
2351 test_load_bytes_async (void)
2353 LoadBytesAsyncData data = { 0 };
2354 gchar filename[] = "g_file_load_bytes_XXXXXX";
2359 fd = g_mkstemp (filename);
2360 g_assert_cmpint (fd, !=, -1);
2361 len = strlen ("test_load_bytes_async");
2362 ret = write (fd, "test_load_bytes_async", len);
2363 g_assert_cmpint (ret, ==, len);
2366 data.main_loop = g_main_loop_new (NULL, FALSE);
2367 data.file = g_file_new_for_path (filename);
2369 g_file_load_bytes_async (data.file, NULL, test_load_bytes_cb, &data);
2370 g_main_loop_run (data.main_loop);
2372 g_assert_cmpint (len, ==, g_bytes_get_size (data.bytes));
2373 g_assert_cmpstr ("test_load_bytes_async", ==, (gchar *)g_bytes_get_data (data.bytes, NULL));
2375 g_file_delete (data.file, NULL, NULL);
2376 g_object_unref (data.file);
2377 g_bytes_unref (data.bytes);
2378 g_main_loop_unref (data.main_loop);
2382 test_writev_helper (GOutputVector *vectors,
2384 gboolean use_bytes_written,
2385 const guint8 *expected_contents,
2386 gsize expected_length)
2389 GFileIOStream *iostream = NULL;
2390 GOutputStream *ostream;
2391 GError *error = NULL;
2392 gsize bytes_written = 0;
2397 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2399 g_assert_nonnull (file);
2400 g_assert_nonnull (iostream);
2402 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2404 res = g_output_stream_writev_all (ostream, vectors, n_vectors, use_bytes_written ? &bytes_written : NULL, NULL, &error);
2405 g_assert_no_error (error);
2406 g_assert_true (res);
2407 if (use_bytes_written)
2408 g_assert_cmpuint (bytes_written, ==, expected_length);
2410 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2411 g_assert_no_error (error);
2412 g_assert_true (res);
2413 g_object_unref (iostream);
2415 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2416 g_assert_no_error (error);
2417 g_assert_true (res);
2419 g_assert_cmpmem (contents, length, expected_contents, expected_length);
2423 g_file_delete (file, NULL, NULL);
2424 g_object_unref (file);
2427 /* Test that writev() on local file output streams works on a non-empty vector */
2431 GOutputVector vectors[3];
2432 const guint8 buffer[] = {1, 2, 3, 4, 5,
2433 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2436 vectors[0].buffer = buffer;
2437 vectors[0].size = 5;
2439 vectors[1].buffer = buffer + 5;
2440 vectors[1].size = 12;
2442 vectors[2].buffer = buffer + 5 + 12;
2443 vectors[2].size = 3;
2445 test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, buffer, sizeof buffer);
2448 /* Test that writev() on local file output streams works on a non-empty vector without returning bytes_written */
2450 test_writev_no_bytes_written (void)
2452 GOutputVector vectors[3];
2453 const guint8 buffer[] = {1, 2, 3, 4, 5,
2454 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2457 vectors[0].buffer = buffer;
2458 vectors[0].size = 5;
2460 vectors[1].buffer = buffer + 5;
2461 vectors[1].size = 12;
2463 vectors[2].buffer = buffer + 5 + 12;
2464 vectors[2].size = 3;
2466 test_writev_helper (vectors, G_N_ELEMENTS (vectors), FALSE, buffer, sizeof buffer);
2469 /* Test that writev() on local file output streams works on 0 vectors */
2471 test_writev_no_vectors (void)
2473 test_writev_helper (NULL, 0, TRUE, NULL, 0);
2476 /* Test that writev() on local file output streams works on empty vectors */
2478 test_writev_empty_vectors (void)
2480 GOutputVector vectors[3];
2482 vectors[0].buffer = NULL;
2483 vectors[0].size = 0;
2484 vectors[1].buffer = NULL;
2485 vectors[1].size = 0;
2486 vectors[2].buffer = NULL;
2487 vectors[2].size = 0;
2489 test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, NULL, 0);
2492 /* Test that writev() fails if the sum of sizes in the vector is too big */
2494 test_writev_too_big_vectors (void)
2497 GFileIOStream *iostream = NULL;
2498 GOutputStream *ostream;
2499 GError *error = NULL;
2500 gsize bytes_written = 0;
2504 GOutputVector vectors[3];
2506 vectors[0].buffer = (void*) 1;
2507 vectors[0].size = G_MAXSIZE / 2;
2509 vectors[1].buffer = (void*) 1;
2510 vectors[1].size = G_MAXSIZE / 2;
2512 vectors[2].buffer = (void*) 1;
2513 vectors[2].size = G_MAXSIZE / 2;
2515 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2517 g_assert_nonnull (file);
2518 g_assert_nonnull (iostream);
2520 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2522 res = g_output_stream_writev_all (ostream, vectors, G_N_ELEMENTS (vectors), &bytes_written, NULL, &error);
2523 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
2524 g_assert_cmpuint (bytes_written, ==, 0);
2525 g_assert_false (res);
2526 g_clear_error (&error);
2528 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2529 g_assert_no_error (error);
2530 g_assert_true (res);
2531 g_object_unref (iostream);
2533 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2534 g_assert_no_error (error);
2535 g_assert_true (res);
2537 g_assert_cmpmem (contents, length, NULL, 0);
2541 g_file_delete (file, NULL, NULL);
2542 g_object_unref (file);
2547 gsize bytes_written;
2548 GOutputVector *vectors;
2555 test_writev_async_cb (GObject *object,
2556 GAsyncResult *result,
2559 GOutputStream *ostream = G_OUTPUT_STREAM (object);
2560 WritevAsyncData *data = user_data;
2561 GError *error = NULL;
2562 gsize bytes_written;
2565 res = g_output_stream_writev_finish (ostream, result, &bytes_written, &error);
2566 g_assert_true (res);
2567 g_assert_no_error (error);
2568 data->bytes_written += bytes_written;
2570 /* skip vectors that have been written in full */
2571 while (data->n_vectors > 0 && bytes_written >= data->vectors[0].size)
2573 bytes_written -= data->vectors[0].size;
2577 /* skip partially written vector data */
2578 if (bytes_written > 0 && data->n_vectors > 0)
2580 data->vectors[0].size -= bytes_written;
2581 data->vectors[0].buffer = ((guint8 *) data->vectors[0].buffer) + bytes_written;
2584 if (data->n_vectors > 0)
2585 g_output_stream_writev_async (ostream, data->vectors, data->n_vectors, 0, NULL, test_writev_async_cb, &data);
2588 /* Test that writev_async() on local file output streams works on a non-empty vector */
2590 test_writev_async (void)
2592 WritevAsyncData data = { 0 };
2594 GFileIOStream *iostream = NULL;
2595 GOutputVector vectors[3];
2596 const guint8 buffer[] = {1, 2, 3, 4, 5,
2597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2599 GOutputStream *ostream;
2600 GError *error = NULL;
2605 vectors[0].buffer = buffer;
2606 vectors[0].size = 5;
2608 vectors[1].buffer = buffer + 5;
2609 vectors[1].size = 12;
2611 vectors[2].buffer = buffer + 5 + 12;
2612 vectors[2].size = 3;
2614 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2616 g_assert_nonnull (file);
2617 g_assert_nonnull (iostream);
2619 data.vectors = vectors;
2620 data.n_vectors = G_N_ELEMENTS (vectors);
2622 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2624 g_output_stream_writev_async (ostream, data.vectors, data.n_vectors, 0, NULL, test_writev_async_cb, &data);
2626 while (data.n_vectors > 0)
2627 g_main_context_iteration (NULL, TRUE);
2629 g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
2631 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2632 g_assert_no_error (error);
2633 g_assert_true (res);
2634 g_object_unref (iostream);
2636 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2637 g_assert_no_error (error);
2638 g_assert_true (res);
2640 g_assert_cmpmem (contents, length, buffer, sizeof buffer);
2644 g_file_delete (file, NULL, NULL);
2645 g_object_unref (file);
2649 test_writev_all_cb (GObject *object,
2650 GAsyncResult *result,
2653 GOutputStream *ostream = G_OUTPUT_STREAM (object);
2654 WritevAsyncData *data = user_data;
2656 g_output_stream_writev_all_finish (ostream, result, &data->bytes_written, &data->error);
2660 /* Test that writev_async_all() on local file output streams works on a non-empty vector */
2662 test_writev_async_all (void)
2664 WritevAsyncData data = { 0 };
2666 GFileIOStream *iostream = NULL;
2667 GOutputStream *ostream;
2668 GOutputVector vectors[3];
2669 const guint8 buffer[] = {1, 2, 3, 4, 5,
2670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2672 GError *error = NULL;
2677 vectors[0].buffer = buffer;
2678 vectors[0].size = 5;
2680 vectors[1].buffer = buffer + 5;
2681 vectors[1].size = 12;
2683 vectors[2].buffer = buffer + 5 + 12;
2684 vectors[2].size = 3;
2686 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2688 g_assert_nonnull (file);
2689 g_assert_nonnull (iostream);
2691 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2693 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
2696 g_main_context_iteration (NULL, TRUE);
2698 g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
2699 g_assert_no_error (data.error);
2701 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2702 g_assert_no_error (error);
2703 g_assert_true (res);
2704 g_object_unref (iostream);
2706 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2707 g_assert_no_error (error);
2708 g_assert_true (res);
2710 g_assert_cmpmem (contents, length, buffer, sizeof buffer);
2714 g_file_delete (file, NULL, NULL);
2715 g_object_unref (file);
2718 /* Test that writev_async_all() on local file output streams handles cancellation correctly */
2720 test_writev_async_all_cancellation (void)
2722 WritevAsyncData data = { 0 };
2724 GFileIOStream *iostream = NULL;
2725 GOutputVector vectors[3];
2726 const guint8 buffer[] = {1, 2, 3, 4, 5,
2727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
2729 GOutputStream *ostream;
2730 GError *error = NULL;
2734 GCancellable *cancellable;
2736 vectors[0].buffer = buffer;
2737 vectors[0].size = 5;
2739 vectors[1].buffer = buffer + 5;
2740 vectors[1].size = 12;
2742 vectors[2].buffer = buffer + 5 + 12;
2743 vectors[2].size = 3;
2745 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2747 g_assert_nonnull (file);
2748 g_assert_nonnull (iostream);
2750 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2752 cancellable = g_cancellable_new ();
2753 g_cancellable_cancel (cancellable);
2755 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, cancellable, test_writev_all_cb, &data);
2758 g_main_context_iteration (NULL, TRUE);
2760 g_assert_cmpuint (data.bytes_written, ==, 0);
2761 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2762 g_clear_error (&data.error);
2764 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2765 g_assert_no_error (error);
2766 g_assert_true (res);
2767 g_object_unref (iostream);
2769 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2770 g_assert_no_error (error);
2771 g_assert_true (res);
2772 g_assert_cmpuint (length, ==, 0);
2776 g_file_delete (file, NULL, NULL);
2777 g_object_unref (file);
2778 g_object_unref (cancellable);
2781 /* Test that writev_async_all() with empty vectors is handled correctly */
2783 test_writev_async_all_empty_vectors (void)
2785 WritevAsyncData data = { 0 };
2787 GFileIOStream *iostream = NULL;
2788 GOutputVector vectors[3];
2789 GOutputStream *ostream;
2790 GError *error = NULL;
2795 vectors[0].buffer = NULL;
2796 vectors[0].size = 0;
2798 vectors[1].buffer = NULL;
2799 vectors[1].size = 0;
2801 vectors[2].buffer = NULL;
2802 vectors[2].size = 0;
2804 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2806 g_assert_nonnull (file);
2807 g_assert_nonnull (iostream);
2809 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2811 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
2814 g_main_context_iteration (NULL, TRUE);
2816 g_assert_cmpuint (data.bytes_written, ==, 0);
2817 g_assert_no_error (data.error);
2818 g_clear_error (&data.error);
2820 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2821 g_assert_no_error (error);
2822 g_assert_true (res);
2823 g_object_unref (iostream);
2825 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2826 g_assert_no_error (error);
2827 g_assert_true (res);
2828 g_assert_cmpuint (length, ==, 0);
2832 g_file_delete (file, NULL, NULL);
2833 g_object_unref (file);
2836 /* Test that writev_async_all() with no vectors is handled correctly */
2838 test_writev_async_all_no_vectors (void)
2840 WritevAsyncData data = { 0 };
2842 GFileIOStream *iostream = NULL;
2843 GOutputStream *ostream;
2844 GError *error = NULL;
2849 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2851 g_assert_nonnull (file);
2852 g_assert_nonnull (iostream);
2854 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2856 g_output_stream_writev_all_async (ostream, NULL, 0, 0, NULL, test_writev_all_cb, &data);
2859 g_main_context_iteration (NULL, TRUE);
2861 g_assert_cmpuint (data.bytes_written, ==, 0);
2862 g_assert_no_error (data.error);
2863 g_clear_error (&data.error);
2865 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2866 g_assert_no_error (error);
2867 g_assert_true (res);
2868 g_object_unref (iostream);
2870 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2871 g_assert_no_error (error);
2872 g_assert_true (res);
2873 g_assert_cmpuint (length, ==, 0);
2877 g_file_delete (file, NULL, NULL);
2878 g_object_unref (file);
2881 /* Test that writev_async_all() with too big vectors is handled correctly */
2883 test_writev_async_all_too_big_vectors (void)
2885 WritevAsyncData data = { 0 };
2887 GFileIOStream *iostream = NULL;
2888 GOutputVector vectors[3];
2889 GOutputStream *ostream;
2890 GError *error = NULL;
2895 vectors[0].buffer = (void*) 1;
2896 vectors[0].size = G_MAXSIZE / 2;
2898 vectors[1].buffer = (void*) 1;
2899 vectors[1].size = G_MAXSIZE / 2;
2901 vectors[2].buffer = (void*) 1;
2902 vectors[2].size = G_MAXSIZE / 2;
2904 file = g_file_new_tmp ("g_file_writev_XXXXXX",
2906 g_assert_nonnull (file);
2907 g_assert_nonnull (iostream);
2909 ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2911 g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
2914 g_main_context_iteration (NULL, TRUE);
2916 g_assert_cmpuint (data.bytes_written, ==, 0);
2917 g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
2918 g_clear_error (&data.error);
2920 res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2921 g_assert_no_error (error);
2922 g_assert_true (res);
2923 g_object_unref (iostream);
2925 res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
2926 g_assert_no_error (error);
2927 g_assert_true (res);
2928 g_assert_cmpuint (length, ==, 0);
2932 g_file_delete (file, NULL, NULL);
2933 g_object_unref (file);
2937 test_build_attribute_list_for_copy (void)
2940 GFileIOStream *iostream;
2941 GError *error = NULL;
2942 const GFileCopyFlags test_flags[] =
2945 G_FILE_COPY_TARGET_DEFAULT_PERMS,
2946 G_FILE_COPY_ALL_METADATA,
2947 G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_PERMS,
2951 gchar *attrs_with_commas;
2953 tmpfile = g_file_new_tmp ("tmp-build-attribute-list-for-copyXXXXXX",
2955 g_assert_no_error (error);
2956 g_io_stream_close ((GIOStream*)iostream, NULL, &error);
2957 g_assert_no_error (error);
2958 g_clear_object (&iostream);
2960 for (i = 0; i < G_N_ELEMENTS (test_flags); i++)
2962 GFileCopyFlags flags = test_flags[i];
2964 attrs = g_file_build_attribute_list_for_copy (tmpfile, flags, NULL, &error);
2965 g_test_message ("Attributes for copy: %s", attrs);
2966 g_assert_no_error (error);
2967 g_assert_nonnull (attrs);
2968 attrs_with_commas = g_strconcat (",", attrs, ",", NULL);
2971 /* See g_local_file_class_init for reference. */
2972 if (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
2973 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
2975 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
2977 if (flags & G_FILE_COPY_ALL_METADATA)
2979 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
2980 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
2984 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
2985 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
2989 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
2990 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ","));
2991 if (flags & G_FILE_COPY_ALL_METADATA)
2993 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
2994 g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
2998 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
2999 g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
3002 g_free (attrs_with_commas);
3005 (void) g_file_delete (tmpfile, NULL, NULL);
3006 g_clear_object (&tmpfile);
3010 main (int argc, char *argv[])
3012 setlocale (LC_ALL, "");
3014 g_test_init (&argc, &argv, NULL);
3016 g_test_add_func ("/file/basic", test_basic);
3017 g_test_add_func ("/file/build-filename", test_build_filename);
3018 g_test_add_func ("/file/parent", test_parent);
3019 g_test_add_func ("/file/child", test_child);
3020 g_test_add_func ("/file/empty-path", test_empty_path);
3021 g_test_add_func ("/file/type", test_type);
3022 g_test_add_func ("/file/parse-name", test_parse_name);
3023 g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
3024 g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
3025 g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
3026 g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
3027 g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
3028 g_test_add_func ("/file/replace-load", test_replace_load);
3029 g_test_add_func ("/file/replace-cancel", test_replace_cancel);
3030 g_test_add_func ("/file/replace-symlink", test_replace_symlink);
3031 g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
3032 g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
3033 g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
3034 g_test_add_func ("/file/async-delete", test_async_delete);
3035 g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
3036 g_test_add_func ("/file/measure", test_measure);
3037 g_test_add_func ("/file/measure-async", test_measure_async);
3038 g_test_add_func ("/file/load-bytes", test_load_bytes);
3039 g_test_add_func ("/file/load-bytes-async", test_load_bytes_async);
3040 g_test_add_func ("/file/writev", test_writev);
3041 g_test_add_func ("/file/writev/no-bytes-written", test_writev_no_bytes_written);
3042 g_test_add_func ("/file/writev/no-vectors", test_writev_no_vectors);
3043 g_test_add_func ("/file/writev/empty-vectors", test_writev_empty_vectors);
3044 g_test_add_func ("/file/writev/too-big-vectors", test_writev_too_big_vectors);
3045 g_test_add_func ("/file/writev/async", test_writev_async);
3046 g_test_add_func ("/file/writev/async_all", test_writev_async_all);
3047 g_test_add_func ("/file/writev/async_all-empty-vectors", test_writev_async_all_empty_vectors);
3048 g_test_add_func ("/file/writev/async_all-no-vectors", test_writev_async_all_no_vectors);
3049 g_test_add_func ("/file/writev/async_all-to-big-vectors", test_writev_async_all_too_big_vectors);
3050 g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
3051 g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
3053 return g_test_run ();