Branch data Line data Source code
1 : : #include "config.h"
2 : :
3 : : #include <locale.h>
4 : : #include <string.h>
5 : : #include <stdio.h>
6 : : #include <stdlib.h>
7 : : #include <gio/gio.h>
8 : : #include <gio/gfiledescriptorbased.h>
9 : : #include <glib/gstdio.h>
10 : : #ifdef G_OS_UNIX
11 : : #include <sys/stat.h>
12 : : #endif
13 : :
14 : : typedef struct
15 : : {
16 : : GMainLoop *loop;
17 : : GError **error;
18 : : } AsyncErrorData;
19 : :
20 : : static void
21 : 5 : test_basic_for_file (GFile *file,
22 : : const gchar *suffix)
23 : : {
24 : : gchar *s;
25 : :
26 : 5 : s = g_file_get_basename (file);
27 : 5 : g_assert_cmpstr (s, ==, "testfile");
28 : 5 : g_free (s);
29 : :
30 : 5 : s = g_file_get_uri (file);
31 : 5 : g_assert_true (g_str_has_prefix (s, "file://"));
32 : 5 : g_assert_true (g_str_has_suffix (s, suffix));
33 : 5 : g_free (s);
34 : :
35 : 5 : g_assert_true (g_file_has_uri_scheme (file, "file"));
36 : 5 : s = g_file_get_uri_scheme (file);
37 : 5 : g_assert_cmpstr (s, ==, "file");
38 : 5 : g_free (s);
39 : 5 : }
40 : :
41 : : static void
42 : 1 : test_basic (void)
43 : : {
44 : : GFile *file;
45 : :
46 : 1 : file = g_file_new_for_path ("./some/directory/testfile");
47 : 1 : test_basic_for_file (file, "/some/directory/testfile");
48 : 1 : g_object_unref (file);
49 : 1 : }
50 : :
51 : : static void
52 : 1 : test_build_filename (void)
53 : : {
54 : : GFile *file;
55 : :
56 : 1 : file = g_file_new_build_filename (".", "some", "directory", "testfile", NULL);
57 : 1 : test_basic_for_file (file, "/some/directory/testfile");
58 : 1 : g_object_unref (file);
59 : :
60 : 1 : file = g_file_new_build_filename ("testfile", NULL);
61 : 1 : test_basic_for_file (file, "/testfile");
62 : 1 : g_object_unref (file);
63 : 1 : }
64 : :
65 : : static void
66 : 1 : test_build_filenamev (void)
67 : : {
68 : : GFile *file;
69 : :
70 : 1 : const gchar *args[] = { ".", "some", "directory", "testfile", NULL };
71 : 1 : file = g_file_new_build_filenamev (args);
72 : 1 : test_basic_for_file (file, "/some/directory/testfile");
73 : 1 : g_object_unref (file);
74 : :
75 : 1 : const gchar *brgs[] = { "testfile", NULL };
76 : 1 : file = g_file_new_build_filenamev (brgs);
77 : 1 : test_basic_for_file (file, "/testfile");
78 : 1 : g_object_unref (file);
79 : 1 : }
80 : :
81 : : static void
82 : 1 : test_parent (void)
83 : : {
84 : : GFile *file;
85 : : GFile *file2;
86 : : GFile *parent;
87 : : GFile *root;
88 : :
89 : 1 : file = g_file_new_for_path ("./some/directory/testfile");
90 : 1 : file2 = g_file_new_for_path ("./some/directory");
91 : 1 : root = g_file_new_for_path ("/");
92 : :
93 : 1 : g_assert_true (g_file_has_parent (file, file2));
94 : :
95 : 1 : parent = g_file_get_parent (file);
96 : 1 : g_assert_true (g_file_equal (parent, file2));
97 : 1 : g_object_unref (parent);
98 : :
99 : 1 : g_assert_null (g_file_get_parent (root));
100 : :
101 : 1 : g_object_unref (file);
102 : 1 : g_object_unref (file2);
103 : 1 : g_object_unref (root);
104 : 1 : }
105 : :
106 : : static void
107 : 1 : test_child (void)
108 : : {
109 : : GFile *file;
110 : : GFile *child;
111 : : GFile *child2;
112 : :
113 : 1 : file = g_file_new_for_path ("./some/directory");
114 : 1 : child = g_file_get_child (file, "child");
115 : 1 : g_assert_true (g_file_has_parent (child, file));
116 : :
117 : 1 : child2 = g_file_get_child_for_display_name (file, "child2", NULL);
118 : 1 : g_assert_true (g_file_has_parent (child2, file));
119 : :
120 : 1 : g_object_unref (child);
121 : 1 : g_object_unref (child2);
122 : 1 : g_object_unref (file);
123 : 1 : }
124 : :
125 : : static void
126 : 1 : test_empty_path (void)
127 : : {
128 : 1 : GFile *file = NULL;
129 : :
130 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2328");
131 : 1 : g_test_summary ("Check that creating a file with an empty path results in errors");
132 : :
133 : : /* Creating the file must always succeed. */
134 : 1 : file = g_file_new_for_path ("");
135 : 1 : g_assert_nonnull (file);
136 : :
137 : : /* But then querying its path should indicate it’s invalid. */
138 : 1 : g_assert_null (g_file_get_path (file));
139 : 1 : g_assert_null (g_file_get_basename (file));
140 : 1 : g_assert_null (g_file_get_parent (file));
141 : :
142 : 1 : g_object_unref (file);
143 : 1 : }
144 : :
145 : : static void
146 : 1 : test_type (void)
147 : : {
148 : : GFile *datapath_f;
149 : : GFile *file;
150 : : GFileType type;
151 : 1 : GError *error = NULL;
152 : :
153 : 1 : datapath_f = g_file_new_for_path (g_test_get_dir (G_TEST_DIST));
154 : :
155 : 1 : file = g_file_get_child (datapath_f, "g-icon.c");
156 : 1 : type = g_file_query_file_type (file, 0, NULL);
157 : 1 : g_assert_cmpint (type, ==, G_FILE_TYPE_REGULAR);
158 : 1 : g_object_unref (file);
159 : :
160 : 1 : file = g_file_get_child (datapath_f, "cert-tests");
161 : 1 : type = g_file_query_file_type (file, 0, NULL);
162 : 1 : g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
163 : :
164 : 1 : g_file_read (file, NULL, &error);
165 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY);
166 : 1 : g_error_free (error);
167 : 1 : g_object_unref (file);
168 : :
169 : 1 : g_object_unref (datapath_f);
170 : 1 : }
171 : :
172 : : static void
173 : 1 : test_parse_name (void)
174 : : {
175 : : GFile *file;
176 : : gchar *name;
177 : :
178 : 1 : file = g_file_new_for_uri ("file://somewhere");
179 : 1 : name = g_file_get_parse_name (file);
180 : 1 : g_assert_cmpstr (name, ==, "file://somewhere");
181 : 1 : g_object_unref (file);
182 : 1 : g_free (name);
183 : :
184 : 1 : file = g_file_parse_name ("~foo");
185 : 1 : name = g_file_get_parse_name (file);
186 : 1 : g_assert_nonnull (name);
187 : 1 : g_object_unref (file);
188 : 1 : g_free (name);
189 : 1 : }
190 : :
191 : : typedef struct
192 : : {
193 : : GMainContext *context;
194 : : GFile *file;
195 : : GFileMonitor *monitor;
196 : : GOutputStream *ostream;
197 : : GInputStream *istream;
198 : : gint buffersize;
199 : : gint monitor_created;
200 : : gint monitor_deleted;
201 : : gint monitor_changed;
202 : : gchar *monitor_path;
203 : : gsize pos;
204 : : const gchar *data;
205 : : gchar *buffer;
206 : : guint timeout;
207 : : gboolean file_deleted;
208 : : gboolean timed_out;
209 : : } CreateDeleteData;
210 : :
211 : : static void
212 : 22 : monitor_changed (GFileMonitor *monitor,
213 : : GFile *file,
214 : : GFile *other_file,
215 : : GFileMonitorEvent event_type,
216 : : gpointer user_data)
217 : : {
218 : 22 : CreateDeleteData *data = user_data;
219 : : gchar *path;
220 : : const gchar *peeked_path;
221 : :
222 : 22 : path = g_file_get_path (file);
223 : 22 : peeked_path = g_file_peek_path (file);
224 : 22 : g_assert_cmpstr (data->monitor_path, ==, path);
225 : 22 : g_assert_cmpstr (path, ==, peeked_path);
226 : 22 : g_free (path);
227 : :
228 : 22 : if (event_type == G_FILE_MONITOR_EVENT_CREATED)
229 : 5 : data->monitor_created++;
230 : 22 : if (event_type == G_FILE_MONITOR_EVENT_DELETED)
231 : 5 : data->monitor_deleted++;
232 : 22 : if (event_type == G_FILE_MONITOR_EVENT_CHANGED)
233 : 7 : data->monitor_changed++;
234 : :
235 : 22 : g_main_context_wakeup (data->context);
236 : 22 : }
237 : :
238 : : static void
239 : 5 : iclosed_cb (GObject *source,
240 : : GAsyncResult *res,
241 : : gpointer user_data)
242 : : {
243 : 5 : CreateDeleteData *data = user_data;
244 : : GError *error;
245 : : gboolean ret;
246 : :
247 : 5 : error = NULL;
248 : 5 : ret = g_input_stream_close_finish (data->istream, res, &error);
249 : 5 : g_assert_no_error (error);
250 : 5 : g_assert_true (ret);
251 : :
252 : 5 : g_assert_true (g_input_stream_is_closed (data->istream));
253 : :
254 : 5 : ret = g_file_delete (data->file, NULL, &error);
255 : 5 : g_assert_true (ret);
256 : 5 : g_assert_no_error (error);
257 : :
258 : 5 : data->file_deleted = TRUE;
259 : 5 : g_main_context_wakeup (data->context);
260 : 5 : }
261 : :
262 : : static void
263 : 5 : read_cb (GObject *source,
264 : : GAsyncResult *res,
265 : : gpointer user_data)
266 : : {
267 : 5 : CreateDeleteData *data = user_data;
268 : : GError *error;
269 : : gssize size;
270 : :
271 : 5 : error = NULL;
272 : 5 : size = g_input_stream_read_finish (data->istream, res, &error);
273 : 5 : g_assert_no_error (error);
274 : :
275 : 5 : data->pos += size;
276 : 5 : if (data->pos < strlen (data->data))
277 : : {
278 : 0 : g_input_stream_read_async (data->istream,
279 : 0 : data->buffer + data->pos,
280 : 0 : strlen (data->data) - data->pos,
281 : : 0,
282 : : NULL,
283 : : read_cb,
284 : : data);
285 : : }
286 : : else
287 : : {
288 : 5 : g_assert_cmpstr (data->buffer, ==, data->data);
289 : 5 : g_assert_false (g_input_stream_is_closed (data->istream));
290 : 5 : g_input_stream_close_async (data->istream, 0, NULL, iclosed_cb, data);
291 : : }
292 : 5 : }
293 : :
294 : : static void
295 : 5 : ipending_cb (GObject *source,
296 : : GAsyncResult *res,
297 : : gpointer user_data)
298 : : {
299 : 5 : CreateDeleteData *data = user_data;
300 : : GError *error;
301 : :
302 : 5 : error = NULL;
303 : 5 : g_input_stream_read_finish (data->istream, res, &error);
304 : 5 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
305 : 5 : g_error_free (error);
306 : 5 : }
307 : :
308 : : static void
309 : 5 : skipped_cb (GObject *source,
310 : : GAsyncResult *res,
311 : : gpointer user_data)
312 : : {
313 : 5 : CreateDeleteData *data = user_data;
314 : : GError *error;
315 : : gssize size;
316 : :
317 : 5 : error = NULL;
318 : 5 : size = g_input_stream_skip_finish (data->istream, res, &error);
319 : 5 : g_assert_no_error (error);
320 : 5 : g_assert_cmpint (size, ==, data->pos);
321 : :
322 : 5 : g_input_stream_read_async (data->istream,
323 : 5 : data->buffer + data->pos,
324 : 5 : strlen (data->data) - data->pos,
325 : : 0,
326 : : NULL,
327 : : read_cb,
328 : : data);
329 : : /* check that we get a pending error */
330 : 5 : g_input_stream_read_async (data->istream,
331 : 5 : data->buffer + data->pos,
332 : 5 : strlen (data->data) - data->pos,
333 : : 0,
334 : : NULL,
335 : : ipending_cb,
336 : : data);
337 : 5 : }
338 : :
339 : : static void
340 : 5 : opened_cb (GObject *source,
341 : : GAsyncResult *res,
342 : : gpointer user_data)
343 : : {
344 : : GFileInputStream *base;
345 : 5 : CreateDeleteData *data = user_data;
346 : : GError *error;
347 : :
348 : 5 : error = NULL;
349 : 5 : base = g_file_read_finish (data->file, res, &error);
350 : 5 : g_assert_no_error (error);
351 : :
352 : 5 : if (data->buffersize == 0)
353 : 1 : data->istream = G_INPUT_STREAM (g_object_ref (base));
354 : : else
355 : 4 : data->istream = g_buffered_input_stream_new_sized (G_INPUT_STREAM (base), data->buffersize);
356 : 5 : g_object_unref (base);
357 : :
358 : 5 : data->buffer = g_new0 (gchar, strlen (data->data) + 1);
359 : :
360 : : /* copy initial segment directly, then skip */
361 : 5 : memcpy (data->buffer, data->data, 10);
362 : 5 : data->pos = 10;
363 : :
364 : 5 : g_input_stream_skip_async (data->istream,
365 : : 10,
366 : : 0,
367 : : NULL,
368 : : skipped_cb,
369 : : data);
370 : 5 : }
371 : :
372 : : static void
373 : 5 : oclosed_cb (GObject *source,
374 : : GAsyncResult *res,
375 : : gpointer user_data)
376 : : {
377 : 5 : CreateDeleteData *data = user_data;
378 : : GError *error;
379 : : gboolean ret;
380 : :
381 : 5 : error = NULL;
382 : 5 : ret = g_output_stream_close_finish (data->ostream, res, &error);
383 : 5 : g_assert_no_error (error);
384 : 5 : g_assert_true (ret);
385 : 5 : g_assert_true (g_output_stream_is_closed (data->ostream));
386 : :
387 : 5 : g_file_read_async (data->file, 0, NULL, opened_cb, data);
388 : 5 : }
389 : :
390 : : static void
391 : 71 : written_cb (GObject *source,
392 : : GAsyncResult *res,
393 : : gpointer user_data)
394 : : {
395 : 71 : CreateDeleteData *data = user_data;
396 : : gssize size;
397 : : GError *error;
398 : :
399 : 71 : error = NULL;
400 : 71 : size = g_output_stream_write_finish (data->ostream, res, &error);
401 : 71 : g_assert_no_error (error);
402 : :
403 : 71 : data->pos += size;
404 : 71 : if (data->pos < strlen (data->data))
405 : : {
406 : 66 : g_output_stream_write_async (data->ostream,
407 : 66 : data->data + data->pos,
408 : 66 : strlen (data->data) - data->pos,
409 : : 0,
410 : : NULL,
411 : : written_cb,
412 : : data);
413 : : }
414 : : else
415 : : {
416 : 5 : g_assert_false (g_output_stream_is_closed (data->ostream));
417 : 5 : g_output_stream_close_async (data->ostream, 0, NULL, oclosed_cb, data);
418 : : }
419 : 71 : }
420 : :
421 : : static void
422 : 5 : opending_cb (GObject *source,
423 : : GAsyncResult *res,
424 : : gpointer user_data)
425 : : {
426 : 5 : CreateDeleteData *data = user_data;
427 : : GError *error;
428 : :
429 : 5 : error = NULL;
430 : 5 : g_output_stream_write_finish (data->ostream, res, &error);
431 : 5 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_PENDING);
432 : 5 : g_error_free (error);
433 : 5 : }
434 : :
435 : : static void
436 : 5 : created_cb (GObject *source,
437 : : GAsyncResult *res,
438 : : gpointer user_data)
439 : : {
440 : : GFileOutputStream *base;
441 : 5 : CreateDeleteData *data = user_data;
442 : : GError *error;
443 : :
444 : 5 : error = NULL;
445 : 5 : base = g_file_create_finish (G_FILE (source), res, &error);
446 : 5 : g_assert_no_error (error);
447 : 5 : g_assert_true (g_file_query_exists (data->file, NULL));
448 : :
449 : 5 : if (data->buffersize == 0)
450 : 1 : data->ostream = G_OUTPUT_STREAM (g_object_ref (base));
451 : : else
452 : 4 : data->ostream = g_buffered_output_stream_new_sized (G_OUTPUT_STREAM (base), data->buffersize);
453 : 5 : g_object_unref (base);
454 : :
455 : 5 : g_output_stream_write_async (data->ostream,
456 : 5 : data->data,
457 : 5 : strlen (data->data),
458 : : 0,
459 : : NULL,
460 : : written_cb,
461 : : data);
462 : : /* check that we get a pending error */
463 : 5 : g_output_stream_write_async (data->ostream,
464 : 5 : data->data,
465 : 5 : strlen (data->data),
466 : : 0,
467 : : NULL,
468 : : opending_cb,
469 : : data);
470 : 5 : }
471 : :
472 : : static void
473 : 0 : stop_timeout (gpointer user_data)
474 : : {
475 : 0 : CreateDeleteData *data = user_data;
476 : :
477 : 0 : data->timed_out = TRUE;
478 : 0 : g_main_context_wakeup (data->context);
479 : 0 : }
480 : :
481 : : /*
482 : : * This test does a fully async create-write-read-delete.
483 : : * Callbackistan.
484 : : */
485 : : static void
486 : 5 : test_create_delete (gconstpointer d)
487 : : {
488 : : GError *error;
489 : : CreateDeleteData *data;
490 : : GFileIOStream *iostream;
491 : :
492 : 5 : data = g_new0 (CreateDeleteData, 1);
493 : :
494 : 5 : data->buffersize = GPOINTER_TO_INT (d);
495 : 5 : data->data = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVXYZ0123456789";
496 : 5 : data->pos = 0;
497 : :
498 : 5 : data->file = g_file_new_tmp ("g_file_create_delete_XXXXXX",
499 : : &iostream, NULL);
500 : 5 : g_assert_nonnull (data->file);
501 : 5 : g_object_unref (iostream);
502 : :
503 : 5 : data->monitor_path = g_file_get_path (data->file);
504 : 5 : remove (data->monitor_path);
505 : :
506 : 5 : g_assert_false (g_file_query_exists (data->file, NULL));
507 : :
508 : 5 : error = NULL;
509 : 5 : data->monitor = g_file_monitor_file (data->file, 0, NULL, &error);
510 : 5 : g_assert_no_error (error);
511 : :
512 : : /* This test doesn't work with GPollFileMonitor, because it assumes
513 : : * that the monitor will notice a create immediately followed by a
514 : : * delete, rather than coalescing them into nothing.
515 : : */
516 : : /* This test also doesn't work with GKqueueFileMonitor because of
517 : : * the same reason. Kqueue is able to return a kevent when a file is
518 : : * created or deleted in a directory. However, the kernel doesn't tell
519 : : * the program file names, so GKqueueFileMonitor has to calculate the
520 : : * difference itself. This is usually too slow for rapid file creation
521 : : * and deletion tests.
522 : : */
523 : 5 : if (strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GPollFileMonitor") == 0 ||
524 : 5 : strcmp (G_OBJECT_TYPE_NAME (data->monitor), "GKqueueFileMonitor") == 0)
525 : : {
526 : 0 : g_test_skip ("skipping test for this GFileMonitor implementation");
527 : 0 : goto skip;
528 : : }
529 : :
530 : 5 : g_file_monitor_set_rate_limit (data->monitor, 100);
531 : :
532 : 5 : g_signal_connect (data->monitor, "changed", G_CALLBACK (monitor_changed), data);
533 : :
534 : : /* Use the global default main context */
535 : 5 : data->context = NULL;
536 : 5 : data->timeout = g_timeout_add_seconds_once (10, stop_timeout, data);
537 : :
538 : 5 : g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
539 : :
540 : 137 : while (!data->timed_out &&
541 : 137 : (data->monitor_created == 0 ||
542 : 124 : data->monitor_deleted == 0 ||
543 : 5 : data->monitor_changed == 0 ||
544 : 5 : !data->file_deleted))
545 : 132 : g_main_context_iteration (data->context, TRUE);
546 : :
547 : 5 : g_source_remove (data->timeout);
548 : :
549 : 5 : g_assert_false (data->timed_out);
550 : 5 : g_assert_true (data->file_deleted);
551 : 5 : g_assert_cmpint (data->monitor_created, ==, 1);
552 : 5 : g_assert_cmpint (data->monitor_deleted, ==, 1);
553 : 5 : g_assert_cmpint (data->monitor_changed, >, 0);
554 : :
555 : 5 : g_assert_false (g_file_monitor_is_cancelled (data->monitor));
556 : 5 : g_file_monitor_cancel (data->monitor);
557 : 5 : g_assert_true (g_file_monitor_is_cancelled (data->monitor));
558 : :
559 : 5 : g_clear_pointer (&data->context, g_main_context_unref);
560 : 5 : g_object_unref (data->ostream);
561 : 5 : g_object_unref (data->istream);
562 : :
563 : 5 : skip:
564 : 5 : g_object_unref (data->monitor);
565 : 5 : g_object_unref (data->file);
566 : 5 : g_free (data->monitor_path);
567 : 5 : g_free (data->buffer);
568 : 5 : g_free (data);
569 : 5 : }
570 : :
571 : : static const gchar *original_data =
572 : : "/**\n"
573 : : " * g_file_replace_contents_async:\n"
574 : : "**/\n";
575 : :
576 : : static const gchar *replace_data =
577 : : "/**\n"
578 : : " * g_file_replace_contents_async:\n"
579 : : " * @file: input #GFile.\n"
580 : : " * @contents: string of contents to replace the file with.\n"
581 : : " * @length: the length of @contents in bytes.\n"
582 : : " * @etag: (nullable): a new <link linkend=\"gfile-etag\">entity tag</link> for the @file, or %NULL\n"
583 : : " * @make_backup: %TRUE if a backup should be created.\n"
584 : : " * @flags: a set of #GFileCreateFlags.\n"
585 : : " * @cancellable: optional #GCancellable object, %NULL to ignore.\n"
586 : : " * @callback: a #GAsyncReadyCallback to call when the request is satisfied\n"
587 : : " * @user_data: the data to pass to callback function\n"
588 : : " * \n"
589 : : " * Starts an asynchronous replacement of @file with the given \n"
590 : : " * @contents of @length bytes. @etag will replace the document's\n"
591 : : " * current entity tag.\n"
592 : : " * \n"
593 : : " * When this operation has completed, @callback will be called with\n"
594 : : " * @user_user data, and the operation can be finalized with \n"
595 : : " * g_file_replace_contents_finish().\n"
596 : : " * \n"
597 : : " * If @cancellable is not %NULL, then the operation can be cancelled by\n"
598 : : " * triggering the cancellable object from another thread. If the operation\n"
599 : : " * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. \n"
600 : : " * \n"
601 : : " * If @make_backup is %TRUE, this function will attempt to \n"
602 : : " * make a backup of @file.\n"
603 : : " **/\n";
604 : :
605 : : typedef struct
606 : : {
607 : : GFile *file;
608 : : const gchar *data;
609 : : GMainLoop *loop;
610 : : gboolean again;
611 : : } ReplaceLoadData;
612 : :
613 : : static void replaced_cb (GObject *source,
614 : : GAsyncResult *res,
615 : : gpointer user_data);
616 : :
617 : : static void
618 : 2 : loaded_cb (GObject *source,
619 : : GAsyncResult *res,
620 : : gpointer user_data)
621 : : {
622 : 2 : ReplaceLoadData *data = user_data;
623 : : gboolean ret;
624 : : GError *error;
625 : : gchar *contents;
626 : : gsize length;
627 : :
628 : 2 : error = NULL;
629 : 2 : ret = g_file_load_contents_finish (data->file, res, &contents, &length, NULL, &error);
630 : 2 : g_assert_true (ret);
631 : 2 : g_assert_no_error (error);
632 : 2 : g_assert_cmpint (length, ==, strlen (data->data));
633 : 2 : g_assert_cmpstr (contents, ==, data->data);
634 : :
635 : 2 : g_free (contents);
636 : :
637 : 2 : if (data->again)
638 : : {
639 : 1 : data->again = FALSE;
640 : 1 : data->data = "pi pa po";
641 : :
642 : 1 : g_file_replace_contents_async (data->file,
643 : 1 : data->data,
644 : 1 : strlen (data->data),
645 : : NULL,
646 : : FALSE,
647 : : 0,
648 : : NULL,
649 : : replaced_cb,
650 : : data);
651 : : }
652 : : else
653 : : {
654 : 1 : error = NULL;
655 : 1 : ret = g_file_delete (data->file, NULL, &error);
656 : 1 : g_assert_no_error (error);
657 : 1 : g_assert_true (ret);
658 : 1 : g_assert_false (g_file_query_exists (data->file, NULL));
659 : :
660 : 1 : g_main_loop_quit (data->loop);
661 : : }
662 : 2 : }
663 : :
664 : : static void
665 : 2 : replaced_cb (GObject *source,
666 : : GAsyncResult *res,
667 : : gpointer user_data)
668 : : {
669 : 2 : ReplaceLoadData *data = user_data;
670 : : GError *error;
671 : :
672 : 2 : error = NULL;
673 : 2 : g_file_replace_contents_finish (data->file, res, NULL, &error);
674 : 2 : g_assert_no_error (error);
675 : :
676 : 2 : g_file_load_contents_async (data->file, NULL, loaded_cb, data);
677 : 2 : }
678 : :
679 : : static void
680 : 1 : test_replace_load (void)
681 : : {
682 : : ReplaceLoadData *data;
683 : : const gchar *path;
684 : : GFileIOStream *iostream;
685 : :
686 : 1 : data = g_new0 (ReplaceLoadData, 1);
687 : 1 : data->again = TRUE;
688 : 1 : data->data = replace_data;
689 : :
690 : 1 : data->file = g_file_new_tmp ("g_file_replace_load_XXXXXX",
691 : : &iostream, NULL);
692 : 1 : g_assert_nonnull (data->file);
693 : 1 : g_object_unref (iostream);
694 : :
695 : 1 : path = g_file_peek_path (data->file);
696 : 1 : remove (path);
697 : :
698 : 1 : g_assert_false (g_file_query_exists (data->file, NULL));
699 : :
700 : 1 : data->loop = g_main_loop_new (NULL, FALSE);
701 : :
702 : 1 : g_file_replace_contents_async (data->file,
703 : 1 : data->data,
704 : 1 : strlen (data->data),
705 : : NULL,
706 : : FALSE,
707 : : 0,
708 : : NULL,
709 : : replaced_cb,
710 : : data);
711 : :
712 : 1 : g_main_loop_run (data->loop);
713 : :
714 : 1 : g_main_loop_unref (data->loop);
715 : 1 : g_object_unref (data->file);
716 : 1 : g_free (data);
717 : 1 : }
718 : :
719 : : static void
720 : 1 : test_replace_cancel (void)
721 : : {
722 : : GFile *tmpdir, *file;
723 : : GFileOutputStream *ostream;
724 : : GFileEnumerator *fenum;
725 : : GFileInfo *info;
726 : : GCancellable *cancellable;
727 : : gchar *path;
728 : : gchar *contents;
729 : : gsize nwrote, length;
730 : : guint count;
731 : 1 : GError *error = NULL;
732 : :
733 : 1 : g_test_bug ("https://bugzilla.gnome.org/629301");
734 : :
735 : 1 : path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
736 : 1 : g_assert_no_error (error);
737 : 1 : tmpdir = g_file_new_for_path (path);
738 : 1 : g_free (path);
739 : :
740 : 1 : file = g_file_get_child (tmpdir, "file");
741 : 1 : g_file_replace_contents (file,
742 : : original_data,
743 : : strlen (original_data),
744 : : NULL, FALSE, 0, NULL,
745 : : NULL, &error);
746 : 1 : g_assert_no_error (error);
747 : :
748 : 1 : ostream = g_file_replace (file, NULL, TRUE, 0, NULL, &error);
749 : 1 : g_assert_no_error (error);
750 : :
751 : 1 : g_output_stream_write_all (G_OUTPUT_STREAM (ostream),
752 : : replace_data, strlen (replace_data),
753 : : &nwrote, NULL, &error);
754 : 1 : g_assert_no_error (error);
755 : 1 : g_assert_cmpint (nwrote, ==, strlen (replace_data));
756 : :
757 : : /* At this point there should be two files; the original and the
758 : : * temporary.
759 : : */
760 : 1 : fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
761 : 1 : g_assert_no_error (error);
762 : :
763 : 1 : info = g_file_enumerator_next_file (fenum, NULL, &error);
764 : 1 : g_assert_no_error (error);
765 : 1 : g_assert_nonnull (info);
766 : 1 : g_object_unref (info);
767 : 1 : info = g_file_enumerator_next_file (fenum, NULL, &error);
768 : 1 : g_assert_no_error (error);
769 : 1 : g_assert_nonnull (info);
770 : 1 : g_object_unref (info);
771 : :
772 : 1 : g_file_enumerator_close (fenum, NULL, &error);
773 : 1 : g_assert_no_error (error);
774 : 1 : g_object_unref (fenum);
775 : :
776 : : /* Also test the g_file_enumerator_iterate() API */
777 : 1 : fenum = g_file_enumerate_children (tmpdir, NULL, 0, NULL, &error);
778 : 1 : g_assert_no_error (error);
779 : 1 : count = 0;
780 : :
781 : : while (TRUE)
782 : 2 : {
783 : 3 : gboolean ret = g_file_enumerator_iterate (fenum, &info, NULL, NULL, &error);
784 : 3 : g_assert_true (ret);
785 : 3 : g_assert_no_error (error);
786 : 3 : if (!info)
787 : 1 : break;
788 : 2 : count++;
789 : : }
790 : 1 : g_assert_cmpint (count, ==, 2);
791 : :
792 : 1 : g_file_enumerator_close (fenum, NULL, &error);
793 : 1 : g_assert_no_error (error);
794 : 1 : g_object_unref (fenum);
795 : :
796 : : /* Now test just getting child from the g_file_enumerator_iterate() API */
797 : 1 : fenum = g_file_enumerate_children (tmpdir, "standard::name", 0, NULL, &error);
798 : 1 : g_assert_no_error (error);
799 : 1 : count = 0;
800 : :
801 : : while (TRUE)
802 : 2 : {
803 : : GFile *child;
804 : 3 : gboolean ret = g_file_enumerator_iterate (fenum, NULL, &child, NULL, &error);
805 : :
806 : 3 : g_assert_true (ret);
807 : 3 : g_assert_no_error (error);
808 : :
809 : 3 : if (!child)
810 : 1 : break;
811 : :
812 : 2 : g_assert_true (G_IS_FILE (child));
813 : 2 : count++;
814 : : }
815 : 1 : g_assert_cmpint (count, ==, 2);
816 : :
817 : 1 : g_file_enumerator_close (fenum, NULL, &error);
818 : 1 : g_assert_no_error (error);
819 : 1 : g_object_unref (fenum);
820 : :
821 : : /* Make sure the temporary gets deleted even if we cancel. */
822 : 1 : cancellable = g_cancellable_new ();
823 : 1 : g_cancellable_cancel (cancellable);
824 : 1 : g_output_stream_close (G_OUTPUT_STREAM (ostream), cancellable, &error);
825 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
826 : 1 : g_clear_error (&error);
827 : :
828 : 1 : g_object_unref (cancellable);
829 : 1 : g_object_unref (ostream);
830 : :
831 : : /* Make sure that file contents wasn't actually replaced. */
832 : 1 : g_file_load_contents (file,
833 : : NULL,
834 : : &contents,
835 : : &length,
836 : : NULL,
837 : : &error);
838 : 1 : g_assert_no_error (error);
839 : 1 : g_assert_cmpstr (contents, ==, original_data);
840 : 1 : g_free (contents);
841 : :
842 : 1 : g_file_delete (file, NULL, &error);
843 : 1 : g_assert_no_error (error);
844 : 1 : g_object_unref (file);
845 : :
846 : : /* This will only succeed if the temp file was deleted. */
847 : 1 : g_file_delete (tmpdir, NULL, &error);
848 : 1 : g_assert_no_error (error);
849 : 1 : g_object_unref (tmpdir);
850 : 1 : }
851 : :
852 : : static void
853 : 1 : test_replace_symlink (void)
854 : : {
855 : : #ifdef G_OS_UNIX
856 : 1 : gchar *tmpdir_path = NULL;
857 : 1 : GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
858 : 1 : GFileOutputStream *stream = NULL;
859 : 1 : const gchar *new_contents = "this is a test message which should be written to source and not target";
860 : : gsize n_written;
861 : 1 : GFileEnumerator *enumerator = NULL;
862 : 1 : GFileInfo *info = NULL;
863 : 1 : gchar *contents = NULL;
864 : 1 : gsize length = 0;
865 : 1 : GError *local_error = NULL;
866 : :
867 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2325");
868 : 1 : g_test_summary ("Test that G_FILE_CREATE_REPLACE_DESTINATION doesn’t follow symlinks");
869 : :
870 : : /* Create a fresh, empty working directory. */
871 : 1 : tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
872 : 1 : g_assert_no_error (local_error);
873 : 1 : tmpdir = g_file_new_for_path (tmpdir_path);
874 : :
875 : 1 : g_test_message ("Using temporary directory %s", tmpdir_path);
876 : 1 : g_free (tmpdir_path);
877 : :
878 : 1 : source_file = g_file_get_child (tmpdir, "source");
879 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
880 : : "*assertion*symlink_value*failed*");
881 : 1 : g_assert_false (g_file_make_symbolic_link (source_file, NULL, NULL, &local_error));
882 : 1 : g_assert_no_error (local_error);
883 : 1 : g_test_assert_expected_messages ();
884 : :
885 : 1 : g_assert_false (g_file_make_symbolic_link (source_file, "", NULL, &local_error));
886 : 1 : g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
887 : 1 : g_clear_object (&source_file);
888 : 1 : g_clear_error (&local_error);
889 : :
890 : : /* Create symlink `source` which points to `target`. */
891 : 1 : source_file = g_file_get_child (tmpdir, "source");
892 : 1 : target_file = g_file_get_child (tmpdir, "target");
893 : 1 : g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
894 : 1 : g_assert_no_error (local_error);
895 : :
896 : : /* Ensure that `target` doesn’t exist */
897 : 1 : g_assert_false (g_file_query_exists (target_file, NULL));
898 : :
899 : : /* Replace the `source` symlink with a regular file using
900 : : * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
901 : : * following the symlink */
902 : 1 : stream = g_file_replace (source_file, NULL, FALSE /* no backup */,
903 : : G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
904 : 1 : g_assert_no_error (local_error);
905 : :
906 : 1 : g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
907 : : &n_written, NULL, &local_error);
908 : 1 : g_assert_no_error (local_error);
909 : 1 : g_assert_cmpint (n_written, ==, strlen (new_contents));
910 : :
911 : 1 : g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
912 : 1 : g_assert_no_error (local_error);
913 : :
914 : 1 : g_clear_object (&stream);
915 : :
916 : : /* At this point, there should still only be one file: `source`. It should
917 : : * now be a regular file. `target` should not exist. */
918 : 1 : enumerator = g_file_enumerate_children (tmpdir,
919 : : G_FILE_ATTRIBUTE_STANDARD_NAME ","
920 : : G_FILE_ATTRIBUTE_STANDARD_TYPE,
921 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
922 : 1 : g_assert_no_error (local_error);
923 : :
924 : 1 : info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
925 : 1 : g_assert_no_error (local_error);
926 : 1 : g_assert_nonnull (info);
927 : :
928 : 1 : g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
929 : 1 : g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
930 : :
931 : 1 : g_clear_object (&info);
932 : :
933 : 1 : info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
934 : 1 : g_assert_no_error (local_error);
935 : 1 : g_assert_null (info);
936 : :
937 : 1 : g_file_enumerator_close (enumerator, NULL, &local_error);
938 : 1 : g_assert_no_error (local_error);
939 : 1 : g_clear_object (&enumerator);
940 : :
941 : : /* Double-check that `target` doesn’t exist */
942 : 1 : g_assert_false (g_file_query_exists (target_file, NULL));
943 : :
944 : : /* Check the content of `source`. */
945 : 1 : g_file_load_contents (source_file,
946 : : NULL,
947 : : &contents,
948 : : &length,
949 : : NULL,
950 : : &local_error);
951 : 1 : g_assert_no_error (local_error);
952 : 1 : g_assert_cmpstr (contents, ==, new_contents);
953 : 1 : g_assert_cmpuint (length, ==, strlen (new_contents));
954 : 1 : g_free (contents);
955 : :
956 : : /* Tidy up. */
957 : 1 : g_file_delete (source_file, NULL, &local_error);
958 : 1 : g_assert_no_error (local_error);
959 : :
960 : 1 : g_file_delete (tmpdir, NULL, &local_error);
961 : 1 : g_assert_no_error (local_error);
962 : :
963 : 1 : g_clear_object (&target_file);
964 : 1 : g_clear_object (&source_file);
965 : 1 : g_clear_object (&tmpdir);
966 : : #else /* if !G_OS_UNIX */
967 : : g_test_skip ("Symlink replacement tests can only be run on Unix")
968 : : #endif
969 : 1 : }
970 : :
971 : : static void
972 : 1 : test_replace_symlink_using_etag (void)
973 : : {
974 : : #ifdef G_OS_UNIX
975 : 1 : gchar *tmpdir_path = NULL;
976 : 1 : GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
977 : 1 : GFileOutputStream *stream = NULL;
978 : 1 : const gchar *old_contents = "this is a test message which should be written to target and then overwritten";
979 : 1 : gchar *old_etag = NULL;
980 : 1 : const gchar *new_contents = "this is an updated message";
981 : : gsize n_written;
982 : 1 : gchar *contents = NULL;
983 : 1 : gsize length = 0;
984 : 1 : GFileInfo *info = NULL;
985 : 1 : GError *local_error = NULL;
986 : :
987 : 1 : g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2417");
988 : 1 : g_test_summary ("Test that ETag checks work when replacing a file through a symlink");
989 : :
990 : : /* Create a fresh, empty working directory. */
991 : 1 : tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_using_etag_XXXXXX", &local_error);
992 : 1 : g_assert_no_error (local_error);
993 : 1 : tmpdir = g_file_new_for_path (tmpdir_path);
994 : :
995 : 1 : g_test_message ("Using temporary directory %s", tmpdir_path);
996 : 1 : g_free (tmpdir_path);
997 : :
998 : : /* Create symlink `source` which points to `target`. */
999 : 1 : source_file = g_file_get_child (tmpdir, "source");
1000 : 1 : target_file = g_file_get_child (tmpdir, "target");
1001 : 1 : g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
1002 : 1 : g_assert_no_error (local_error);
1003 : :
1004 : : /* Sleep for at least 1s to ensure the mtimes of `source` and `target` differ,
1005 : : * as that’s what _g_local_file_info_create_etag() uses to create the ETag,
1006 : : * and one failure mode we’re testing for is that the ETags of `source` and
1007 : : * `target` are conflated. */
1008 : 1 : sleep (1);
1009 : :
1010 : : /* Create `target` with some arbitrary content. */
1011 : 1 : stream = g_file_create (target_file, G_FILE_CREATE_NONE, NULL, &local_error);
1012 : 1 : g_assert_no_error (local_error);
1013 : 1 : g_output_stream_write_all (G_OUTPUT_STREAM (stream), old_contents, strlen (old_contents),
1014 : : &n_written, NULL, &local_error);
1015 : 1 : g_assert_no_error (local_error);
1016 : 1 : g_assert_cmpint (n_written, ==, strlen (old_contents));
1017 : :
1018 : 1 : g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
1019 : 1 : g_assert_no_error (local_error);
1020 : :
1021 : 1 : old_etag = g_file_output_stream_get_etag (stream);
1022 : 1 : g_assert_nonnull (old_etag);
1023 : 1 : g_assert_cmpstr (old_etag, !=, "");
1024 : :
1025 : 1 : g_clear_object (&stream);
1026 : :
1027 : : /* Sleep again to ensure the ETag changes again. */
1028 : 1 : sleep (1);
1029 : :
1030 : : /* Write out a new copy of the `target`, checking its ETag first. This should
1031 : : * replace `target` by following the symlink. */
1032 : 1 : stream = g_file_replace (source_file, old_etag, FALSE /* no backup */,
1033 : : G_FILE_CREATE_NONE, NULL, &local_error);
1034 : 1 : g_assert_no_error (local_error);
1035 : :
1036 : 1 : g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
1037 : : &n_written, NULL, &local_error);
1038 : 1 : g_assert_no_error (local_error);
1039 : 1 : g_assert_cmpint (n_written, ==, strlen (new_contents));
1040 : :
1041 : 1 : g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
1042 : 1 : g_assert_no_error (local_error);
1043 : :
1044 : 1 : g_clear_object (&stream);
1045 : :
1046 : : /* At this point, there should be a regular file, `target`, containing
1047 : : * @new_contents; and a symlink `source` which points to `target`. */
1048 : 1 : g_assert_cmpint (g_file_query_file_type (source_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_SYMBOLIC_LINK);
1049 : 1 : g_assert_cmpint (g_file_query_file_type (target_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL), ==, G_FILE_TYPE_REGULAR);
1050 : :
1051 : : /* Check the content of `target`. */
1052 : 1 : g_file_load_contents (target_file,
1053 : : NULL,
1054 : : &contents,
1055 : : &length,
1056 : : NULL,
1057 : : &local_error);
1058 : 1 : g_assert_no_error (local_error);
1059 : 1 : g_assert_cmpstr (contents, ==, new_contents);
1060 : 1 : g_assert_cmpuint (length, ==, strlen (new_contents));
1061 : 1 : g_free (contents);
1062 : :
1063 : : /* And check its ETag value has changed. */
1064 : 1 : info = g_file_query_info (target_file, G_FILE_ATTRIBUTE_ETAG_VALUE,
1065 : : G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1066 : 1 : g_assert_no_error (local_error);
1067 : 1 : g_assert_cmpstr (g_file_info_get_etag (info), !=, old_etag);
1068 : :
1069 : 1 : g_clear_object (&info);
1070 : 1 : g_free (old_etag);
1071 : :
1072 : : /* Tidy up. */
1073 : 1 : g_file_delete (target_file, NULL, &local_error);
1074 : 1 : g_assert_no_error (local_error);
1075 : :
1076 : 1 : g_file_delete (source_file, NULL, &local_error);
1077 : 1 : g_assert_no_error (local_error);
1078 : :
1079 : 1 : g_file_delete (tmpdir, NULL, &local_error);
1080 : 1 : g_assert_no_error (local_error);
1081 : :
1082 : 1 : g_clear_object (&target_file);
1083 : 1 : g_clear_object (&source_file);
1084 : 1 : g_clear_object (&tmpdir);
1085 : : #else /* if !G_OS_UNIX */
1086 : : g_test_skip ("Symlink replacement tests can only be run on Unix")
1087 : : #endif
1088 : 1 : }
1089 : :
1090 : : /* FIXME: These tests have only been checked on Linux. Most of them are probably
1091 : : * applicable on Windows, too, but that has not been tested yet.
1092 : : * See https://gitlab.gnome.org/GNOME/glib/-/issues/2325 */
1093 : : #ifdef __linux__
1094 : :
1095 : : /* Different kinds of file which create_test_file() can create. */
1096 : : typedef enum
1097 : : {
1098 : : FILE_TEST_SETUP_TYPE_NONEXISTENT,
1099 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY,
1100 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY,
1101 : : FILE_TEST_SETUP_TYPE_DIRECTORY,
1102 : : FILE_TEST_SETUP_TYPE_SOCKET,
1103 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING,
1104 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID,
1105 : : } FileTestSetupType;
1106 : :
1107 : : /* Create file `tmpdir/basename`, of type @setup_type, and chmod it to
1108 : : * @setup_mode. Return the #GFile representing it. Abort on any errors. */
1109 : : static GFile *
1110 : 196 : create_test_file (GFile *tmpdir,
1111 : : const gchar *basename,
1112 : : FileTestSetupType setup_type,
1113 : : guint setup_mode)
1114 : : {
1115 : 196 : GFile *test_file = g_file_get_child (tmpdir, basename);
1116 : 196 : gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1117 : 196 : GFile *target_file = g_file_get_child (tmpdir, target_basename);
1118 : 196 : GError *local_error = NULL;
1119 : :
1120 : 196 : switch (setup_type)
1121 : : {
1122 : 34 : case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1123 : : /* Nothing to do here. */
1124 : 34 : g_assert (setup_mode == 0);
1125 : 34 : break;
1126 : 114 : case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1127 : : case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1128 : : {
1129 : 114 : gchar *contents = NULL;
1130 : :
1131 : 114 : if (setup_type == FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY)
1132 : 100 : contents = g_strdup_printf ("this is some test content in %s", basename);
1133 : : else
1134 : 14 : contents = g_strdup ("");
1135 : :
1136 : 114 : g_file_set_contents (g_file_peek_path (test_file), contents, -1, &local_error);
1137 : 114 : g_assert_no_error (local_error);
1138 : :
1139 : 114 : g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1140 : : setup_mode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1141 : : NULL, &local_error);
1142 : 114 : g_assert_no_error (local_error);
1143 : :
1144 : 114 : g_free (contents);
1145 : 114 : break;
1146 : : }
1147 : 12 : case FILE_TEST_SETUP_TYPE_DIRECTORY:
1148 : 12 : g_assert (setup_mode == 0);
1149 : :
1150 : 12 : g_file_make_directory (test_file, NULL, &local_error);
1151 : 12 : g_assert_no_error (local_error);
1152 : 12 : break;
1153 : 12 : case FILE_TEST_SETUP_TYPE_SOCKET:
1154 : 12 : g_assert_no_errno (mknod (g_file_peek_path (test_file), S_IFSOCK | setup_mode, 0));
1155 : 12 : break;
1156 : 12 : case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1157 : 12 : g_file_set_contents (g_file_peek_path (target_file), "target file", -1, &local_error);
1158 : 12 : g_assert_no_error (local_error);
1159 : : G_GNUC_FALLTHROUGH;
1160 : : case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1161 : : /* Permissions on a symlink are not used by the kernel, so are only
1162 : : * applicable if the symlink is valid (and are applied to the target) */
1163 : 24 : g_assert (setup_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || setup_mode == 0);
1164 : :
1165 : 24 : g_file_make_symbolic_link (test_file, target_basename, NULL, &local_error);
1166 : 24 : g_assert_no_error (local_error);
1167 : :
1168 : 24 : if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1169 : : {
1170 : 12 : g_file_set_attribute_uint32 (test_file, G_FILE_ATTRIBUTE_UNIX_MODE,
1171 : : setup_mode, G_FILE_QUERY_INFO_NONE,
1172 : : NULL, &local_error);
1173 : 12 : g_assert_no_error (local_error);
1174 : : }
1175 : :
1176 : 24 : if (setup_type == FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING)
1177 : : {
1178 : : /* Ensure that the target doesn’t exist */
1179 : 12 : g_assert_false (g_file_query_exists (target_file, NULL));
1180 : : }
1181 : 24 : break;
1182 : 0 : default:
1183 : : g_assert_not_reached ();
1184 : : }
1185 : :
1186 : 196 : g_clear_object (&target_file);
1187 : 196 : g_free (target_basename);
1188 : :
1189 : 196 : return g_steal_pointer (&test_file);
1190 : : }
1191 : :
1192 : : /* Check that @test_file is of the @expected_type, has the @expected_mode, and
1193 : : * (if it’s a regular file) has the @expected_contents or (if it’s a symlink)
1194 : : * has the symlink target given by @expected_contents.
1195 : : *
1196 : : * @test_file must point to the file `tmpdir/basename`.
1197 : : *
1198 : : * Aborts on any errors or mismatches against the expectations.
1199 : : */
1200 : : static void
1201 : 196 : check_test_file (GFile *test_file,
1202 : : GFile *tmpdir,
1203 : : const gchar *basename,
1204 : : FileTestSetupType expected_type,
1205 : : guint expected_mode,
1206 : : const gchar *expected_contents)
1207 : : {
1208 : 196 : gchar *target_basename = g_strdup_printf ("%s-target", basename); /* for symlinks */
1209 : 196 : GFile *target_file = g_file_get_child (tmpdir, target_basename);
1210 : 196 : GFileType test_file_type = g_file_query_file_type (test_file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL);
1211 : 196 : GFileInfo *info = NULL;
1212 : 196 : GError *local_error = NULL;
1213 : :
1214 : 196 : switch (expected_type)
1215 : : {
1216 : 18 : case FILE_TEST_SETUP_TYPE_NONEXISTENT:
1217 : 18 : g_assert (expected_mode == 0);
1218 : 18 : g_assert (expected_contents == NULL);
1219 : :
1220 : 18 : g_assert_false (g_file_query_exists (test_file, NULL));
1221 : 18 : g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_UNKNOWN);
1222 : 18 : break;
1223 : 146 : case FILE_TEST_SETUP_TYPE_REGULAR_EMPTY:
1224 : : case FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY:
1225 : 146 : g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_EMPTY || expected_contents == NULL);
1226 : 146 : g_assert (expected_type != FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY || expected_contents != NULL);
1227 : :
1228 : 146 : g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_REGULAR);
1229 : :
1230 : 146 : info = g_file_query_info (test_file,
1231 : : G_FILE_ATTRIBUTE_STANDARD_SIZE ","
1232 : : G_FILE_ATTRIBUTE_UNIX_MODE,
1233 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1234 : 146 : g_assert_no_error (local_error);
1235 : :
1236 : 146 : if (expected_type == FILE_TEST_SETUP_TYPE_REGULAR_EMPTY)
1237 : 8 : g_assert_cmpint (g_file_info_get_size (info), ==, 0);
1238 : : else
1239 : 138 : g_assert_cmpint (g_file_info_get_size (info), >, 0);
1240 : :
1241 : 146 : if (expected_contents != NULL)
1242 : : {
1243 : 138 : gchar *contents = NULL;
1244 : 138 : gsize length = 0;
1245 : :
1246 : 138 : g_file_get_contents (g_file_peek_path (test_file), &contents, &length, &local_error);
1247 : 138 : g_assert_no_error (local_error);
1248 : :
1249 : 138 : g_assert_cmpstr (contents, ==, expected_contents);
1250 : 138 : g_free (contents);
1251 : : }
1252 : :
1253 : 146 : g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1254 : :
1255 : 146 : break;
1256 : 12 : case FILE_TEST_SETUP_TYPE_DIRECTORY:
1257 : 12 : g_assert (expected_mode == 0);
1258 : 12 : g_assert (expected_contents == NULL);
1259 : :
1260 : 12 : g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_DIRECTORY);
1261 : 12 : break;
1262 : 8 : case FILE_TEST_SETUP_TYPE_SOCKET:
1263 : 8 : g_assert (expected_contents == NULL);
1264 : :
1265 : 8 : g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SPECIAL);
1266 : :
1267 : 8 : info = g_file_query_info (test_file,
1268 : : G_FILE_ATTRIBUTE_UNIX_MODE,
1269 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1270 : 8 : g_assert_no_error (local_error);
1271 : :
1272 : 8 : g_assert_cmpuint (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1273 : 8 : break;
1274 : 12 : case FILE_TEST_SETUP_TYPE_SYMLINK_VALID:
1275 : : case FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING:
1276 : : {
1277 : 12 : GFile *symlink_target_file = NULL;
1278 : :
1279 : : /* Permissions on a symlink are not used by the kernel, so are only
1280 : : * applicable if the symlink is valid (and are applied to the target) */
1281 : 12 : g_assert (expected_type != FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING || expected_mode == 0);
1282 : 12 : g_assert (expected_contents != NULL);
1283 : :
1284 : 12 : g_assert_cmpint (test_file_type, ==, G_FILE_TYPE_SYMBOLIC_LINK);
1285 : :
1286 : 12 : info = g_file_query_info (test_file,
1287 : : G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
1288 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
1289 : 12 : g_assert_no_error (local_error);
1290 : :
1291 : 12 : g_assert_cmpstr (g_file_info_get_symlink_target (info), ==, expected_contents);
1292 : :
1293 : 12 : symlink_target_file = g_file_get_child (tmpdir, g_file_info_get_symlink_target (info));
1294 : 12 : if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1295 : 10 : g_assert_true (g_file_query_exists (symlink_target_file, NULL));
1296 : : else
1297 : 2 : g_assert_false (g_file_query_exists (symlink_target_file, NULL));
1298 : :
1299 : 12 : if (expected_type == FILE_TEST_SETUP_TYPE_SYMLINK_VALID)
1300 : : {
1301 : 10 : GFileInfo *target_info = NULL;
1302 : :
1303 : : /* Need to re-query the info so we follow symlinks */
1304 : 10 : target_info = g_file_query_info (test_file,
1305 : : G_FILE_ATTRIBUTE_UNIX_MODE,
1306 : : G_FILE_QUERY_INFO_NONE, NULL, &local_error);
1307 : 10 : g_assert_no_error (local_error);
1308 : :
1309 : 10 : g_assert_cmpuint (g_file_info_get_attribute_uint32 (target_info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777, ==, expected_mode);
1310 : :
1311 : 10 : g_clear_object (&target_info);
1312 : : }
1313 : :
1314 : 12 : g_clear_object (&symlink_target_file);
1315 : 12 : break;
1316 : : }
1317 : 0 : default:
1318 : : g_assert_not_reached ();
1319 : : }
1320 : :
1321 : 196 : g_clear_object (&info);
1322 : 196 : g_clear_object (&target_file);
1323 : 196 : g_free (target_basename);
1324 : 196 : }
1325 : :
1326 : : #endif /* __linux__ */
1327 : :
1328 : : #ifdef __linux__
1329 : : /*
1330 : : * check_cap_dac_override:
1331 : : * @tmpdir: A temporary directory in which we can create and delete files
1332 : : *
1333 : : * Check whether the current process can bypass DAC permissions.
1334 : : *
1335 : : * Traditionally, "privileged" processes (those with effective uid 0)
1336 : : * could do this (and bypass many other checks), and "unprivileged"
1337 : : * processes could not.
1338 : : *
1339 : : * In Linux, the special powers of euid 0 are divided into many
1340 : : * capabilities: see `capabilities(7)`. The one we are interested in
1341 : : * here is `CAP_DAC_OVERRIDE`.
1342 : : *
1343 : : * We do this generically instead of actually looking at the capability
1344 : : * bits, so that the right thing will happen on non-Linux Unix
1345 : : * implementations, in particular if they have something equivalent to
1346 : : * but not identical to Linux permissions.
1347 : : *
1348 : : * Returns: %TRUE if we have Linux `CAP_DAC_OVERRIDE` or equivalent
1349 : : * privileges
1350 : : */
1351 : : static gboolean
1352 : 2 : check_cap_dac_override (const char *tmpdir)
1353 : : {
1354 : : gchar *dac_denies_write;
1355 : : gchar *inside;
1356 : : gboolean have_cap;
1357 : :
1358 : 2 : dac_denies_write = g_build_filename (tmpdir, "dac-denies-write", NULL);
1359 : 2 : inside = g_build_filename (dac_denies_write, "inside", NULL);
1360 : :
1361 : 2 : g_assert_no_errno (mkdir (dac_denies_write, S_IRWXU));
1362 : 2 : g_assert_no_errno (chmod (dac_denies_write, 0));
1363 : :
1364 : 2 : if (mkdir (inside, S_IRWXU) == 0)
1365 : : {
1366 : 0 : g_test_message ("Looks like we have CAP_DAC_OVERRIDE or equivalent");
1367 : 0 : g_assert_no_errno (rmdir (inside));
1368 : 0 : have_cap = TRUE;
1369 : : }
1370 : : else
1371 : : {
1372 : 2 : int saved_errno = errno;
1373 : :
1374 : 2 : g_test_message ("We do not have CAP_DAC_OVERRIDE or equivalent");
1375 : 2 : g_assert_cmpint (saved_errno, ==, EACCES);
1376 : 2 : have_cap = FALSE;
1377 : : }
1378 : :
1379 : 2 : g_assert_no_errno (chmod (dac_denies_write, S_IRWXU));
1380 : 2 : g_assert_no_errno (rmdir (dac_denies_write));
1381 : 2 : g_free (dac_denies_write);
1382 : 2 : g_free (inside);
1383 : 2 : return have_cap;
1384 : : }
1385 : : #endif
1386 : :
1387 : : /* A big test for g_file_replace() and g_file_replace_readwrite(). The
1388 : : * @test_data is a boolean: %TRUE to test g_file_replace_readwrite(), %FALSE to
1389 : : * test g_file_replace(). The test setup and checks are identical for both
1390 : : * functions; in the case of testing g_file_replace_readwrite(), only the output
1391 : : * stream side of the returned #GIOStream is tested. i.e. We test the write
1392 : : * behaviour of both functions is identical.
1393 : : *
1394 : : * This is intended to test all static behaviour of the function: for each test
1395 : : * scenario, a temporary directory is set up with a source file (and maybe some
1396 : : * other files) in a set configuration, g_file_replace{,_readwrite}() is called,
1397 : : * and the final state of the directory is checked.
1398 : : *
1399 : : * This test does not check dynamic behaviour or race conditions. For example,
1400 : : * it does not test what happens if the source file is deleted from another
1401 : : * process half-way through a call to g_file_replace().
1402 : : */
1403 : : static void
1404 : 2 : test_replace (gconstpointer test_data)
1405 : : {
1406 : : #ifdef __linux__
1407 : 2 : gboolean read_write = GPOINTER_TO_UINT (test_data);
1408 : 2 : const gchar *new_contents = "this is a new test message which should be written to source";
1409 : 2 : const gchar *original_source_contents = "this is some test content in source";
1410 : 2 : const gchar *original_backup_contents = "this is some test content in source~";
1411 : 2 : mode_t current_umask = umask (0);
1412 : 2 : guint32 default_public_mode = 0666 & ~current_umask;
1413 : 2 : guint32 default_private_mode = 0600;
1414 : :
1415 : : const struct
1416 : : {
1417 : : /* Arguments to pass to g_file_replace(). */
1418 : : gboolean replace_make_backup;
1419 : : GFileCreateFlags replace_flags;
1420 : : const gchar *replace_etag; /* (nullable) */
1421 : :
1422 : : /* File system setup. */
1423 : : FileTestSetupType setup_source_type;
1424 : : guint setup_source_mode;
1425 : : FileTestSetupType setup_backup_type;
1426 : : guint setup_backup_mode;
1427 : : gboolean skip_if_cap_dac_override;
1428 : :
1429 : : /* Expected results. */
1430 : : gboolean expected_success;
1431 : : GQuark expected_error_domain;
1432 : : gint expected_error_code;
1433 : :
1434 : : /* Expected final file system state. */
1435 : : guint expected_n_files;
1436 : : FileTestSetupType expected_source_type;
1437 : : guint expected_source_mode;
1438 : : const gchar *expected_source_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1439 : : FileTestSetupType expected_backup_type;
1440 : : guint expected_backup_mode;
1441 : : const gchar *expected_backup_contents; /* content for a regular file, or target for a symlink; NULL otherwise */
1442 : : }
1443 : 28 : tests[] =
1444 : : {
1445 : : /* replace_make_backup == FALSE, replace_flags == NONE, replace_etag == NULL,
1446 : : * all the different values of setup_source_type, mostly with a backup
1447 : : * file created to check it’s not modified */
1448 : : {
1449 : : FALSE, G_FILE_CREATE_NONE, NULL,
1450 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1451 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1452 : : TRUE, 0, 0,
1453 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1454 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1455 : : },
1456 : : {
1457 : : FALSE, G_FILE_CREATE_NONE, NULL,
1458 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1459 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1460 : : TRUE, 0, 0,
1461 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1462 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1463 : : },
1464 : : {
1465 : : FALSE, G_FILE_CREATE_NONE, NULL,
1466 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1467 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1468 : : TRUE, 0, 0,
1469 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1470 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1471 : : },
1472 : : {
1473 : : FALSE, G_FILE_CREATE_NONE, NULL,
1474 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1475 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1476 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1477 : : 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1478 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1479 : : },
1480 : : {
1481 : : FALSE, G_FILE_CREATE_NONE, NULL,
1482 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1483 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1484 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1485 : : 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1486 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1487 : : },
1488 : : {
1489 : : FALSE, G_FILE_CREATE_NONE, NULL,
1490 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1491 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1492 : : TRUE, 0, 0,
1493 : : 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1494 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1495 : : },
1496 : : {
1497 : : FALSE, G_FILE_CREATE_NONE, NULL,
1498 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1499 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1500 : : TRUE, 0, 0,
1501 : : 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1502 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1503 : : },
1504 : :
1505 : : /* replace_etag set to an invalid value, with setup_source_type as a
1506 : : * regular non-empty file; replacement should fail */
1507 : : {
1508 : : FALSE, G_FILE_CREATE_NONE, "incorrect etag",
1509 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1510 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1511 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1512 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1513 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1514 : : },
1515 : :
1516 : : /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1517 : : * all the different values of setup_source_type, with a backup
1518 : : * file created to check it’s either replaced or the operation fails */
1519 : : {
1520 : : TRUE, G_FILE_CREATE_NONE, NULL,
1521 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1522 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1523 : : TRUE, 0, 0,
1524 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1525 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1526 : : },
1527 : : {
1528 : : TRUE, G_FILE_CREATE_NONE, NULL,
1529 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1530 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1531 : : TRUE, 0, 0,
1532 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1533 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1534 : : },
1535 : : {
1536 : : TRUE, G_FILE_CREATE_NONE, NULL,
1537 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1538 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1539 : : TRUE, 0, 0,
1540 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1541 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1542 : : },
1543 : : {
1544 : : TRUE, G_FILE_CREATE_NONE, NULL,
1545 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1546 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1547 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1548 : : 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1549 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1550 : : },
1551 : : {
1552 : : TRUE, G_FILE_CREATE_NONE, NULL,
1553 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1554 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1555 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1556 : : 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1557 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1558 : : },
1559 : : {
1560 : : TRUE, G_FILE_CREATE_NONE, NULL,
1561 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1562 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1563 : : TRUE, 0, 0,
1564 : : /* The final situation here is a bit odd; the backup file is a bit
1565 : : * pointless as the original source file was a dangling symlink.
1566 : : * Theoretically the backup file should be that symlink, pointing to
1567 : : * `source-target`, and hence no longer dangling, as that file has now
1568 : : * been created as the new source content, since REPLACE_DESTINATION was
1569 : : * not specified. However, the code instead creates an empty regular
1570 : : * file as the backup. FIXME: This seems acceptable for now, but not
1571 : : * entirely ideal and would be good to fix at some point. */
1572 : : 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1573 : 2 : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0777 & ~current_umask, NULL,
1574 : : },
1575 : : {
1576 : : TRUE, G_FILE_CREATE_NONE, NULL,
1577 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1578 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1579 : : TRUE, 0, 0,
1580 : : /* FIXME: The permissions for the backup file are just the default umask,
1581 : : * but should probably be the same as the permissions for the source
1582 : : * file (`default_public_mode`). This probably arises from the fact that
1583 : : * symlinks don’t have permissions. */
1584 : : 3, FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1585 : 2 : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, 0777 & ~current_umask, "target file",
1586 : : },
1587 : :
1588 : : /* replace_make_backup == TRUE, replace_flags == NONE, replace_etag == NULL,
1589 : : * setup_source_type is a regular file, with a backup file of every type
1590 : : * created to check it’s either replaced or the operation fails */
1591 : : {
1592 : : TRUE, G_FILE_CREATE_NONE, NULL,
1593 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1594 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1595 : : TRUE, 0, 0,
1596 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1597 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1598 : : },
1599 : : {
1600 : : TRUE, G_FILE_CREATE_NONE, NULL,
1601 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1602 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
1603 : : TRUE, 0, 0,
1604 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1605 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1606 : : },
1607 : : {
1608 : : TRUE, G_FILE_CREATE_NONE, NULL,
1609 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1610 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1611 : : TRUE, 0, 0,
1612 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1613 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1614 : : },
1615 : : {
1616 : : TRUE, G_FILE_CREATE_NONE, NULL,
1617 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1618 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
1619 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1620 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1621 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1622 : : },
1623 : : {
1624 : : TRUE, G_FILE_CREATE_NONE, NULL,
1625 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1626 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
1627 : : TRUE, 0, 0,
1628 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1629 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1630 : : },
1631 : : {
1632 : : TRUE, G_FILE_CREATE_NONE, NULL,
1633 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1634 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
1635 : : TRUE, 0, 0,
1636 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1637 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1638 : : },
1639 : : {
1640 : : TRUE, G_FILE_CREATE_NONE, NULL,
1641 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1642 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
1643 : : TRUE, 0, 0,
1644 : : /* the third file is `source~-target`, the original target of the old
1645 : : * backup symlink */
1646 : : 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1647 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1648 : : },
1649 : :
1650 : : /* replace_make_backup == FALSE, replace_flags == REPLACE_DESTINATION,
1651 : : * replace_etag == NULL, all the different values of setup_source_type,
1652 : : * mostly with a backup file created to check it’s not modified */
1653 : : {
1654 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1655 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1656 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1657 : : TRUE, 0, 0,
1658 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1659 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1660 : : },
1661 : : {
1662 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1663 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1664 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1665 : : TRUE, 0, 0,
1666 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1667 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1668 : : },
1669 : : {
1670 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1671 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1672 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1673 : : TRUE, 0, 0,
1674 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1675 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1676 : : },
1677 : : {
1678 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1679 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1680 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1681 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1682 : : 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1683 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1684 : : },
1685 : : {
1686 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1687 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1688 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1689 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1690 : : 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1691 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1692 : : },
1693 : : {
1694 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1695 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1696 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1697 : : TRUE, 0, 0,
1698 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1699 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1700 : : },
1701 : : {
1702 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1703 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1704 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1705 : : TRUE, 0, 0,
1706 : : /* the third file is `source-target`, the original target of the old
1707 : : * source file */
1708 : : 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1709 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1710 : : },
1711 : :
1712 : : /* replace_flags == REPLACE_DESTINATION, replace_etag set to an invalid
1713 : : * value, with setup_source_type as a regular non-empty file; replacement
1714 : : * should fail */
1715 : : {
1716 : : FALSE, G_FILE_CREATE_REPLACE_DESTINATION, "incorrect etag",
1717 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1718 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1719 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_WRONG_ETAG,
1720 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1721 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1722 : : },
1723 : :
1724 : : /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1725 : : * replace_etag == NULL, all the different values of setup_source_type,
1726 : : * with a backup file created to check it’s either replaced or the
1727 : : * operation fails */
1728 : : {
1729 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1730 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1731 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1732 : : TRUE, 0, 0,
1733 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1734 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1735 : : },
1736 : : {
1737 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1738 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode,
1739 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1740 : : TRUE, 0, 0,
1741 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1742 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, NULL,
1743 : : },
1744 : : {
1745 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1746 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1747 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1748 : : TRUE, 0, 0,
1749 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1750 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1751 : : },
1752 : : {
1753 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1754 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0,
1755 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1756 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
1757 : : 2, FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1758 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1759 : : },
1760 : : {
1761 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1762 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode,
1763 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1764 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE,
1765 : : 2, FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, NULL,
1766 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_backup_contents,
1767 : : },
1768 : : {
1769 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1770 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0,
1771 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1772 : : TRUE, 0, 0,
1773 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1774 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, "source-target",
1775 : : },
1776 : : {
1777 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1778 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode,
1779 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1780 : : TRUE, 0, 0,
1781 : : /* the third file is `source-target`, the original target of the old
1782 : : * source file */
1783 : : 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1784 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, "source-target",
1785 : : },
1786 : :
1787 : : /* replace_make_backup == TRUE, replace_flags == REPLACE_DESTINATION,
1788 : : * replace_etag == NULL, setup_source_type is a regular file, with a
1789 : : * backup file of every type created to check it’s either replaced or the
1790 : : * operation fails */
1791 : : {
1792 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1793 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1794 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1795 : : TRUE, 0, 0,
1796 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1797 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1798 : : },
1799 : : {
1800 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1801 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1802 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, default_public_mode, FALSE,
1803 : : TRUE, 0, 0,
1804 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1805 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1806 : : },
1807 : : {
1808 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1809 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1810 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, FALSE,
1811 : : TRUE, 0, 0,
1812 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1813 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1814 : : },
1815 : : {
1816 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1817 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1818 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0, FALSE,
1819 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_CANT_CREATE_BACKUP,
1820 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1821 : : FILE_TEST_SETUP_TYPE_DIRECTORY, 0, NULL,
1822 : : },
1823 : : {
1824 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1825 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1826 : : FILE_TEST_SETUP_TYPE_SOCKET, default_public_mode, FALSE,
1827 : : TRUE, 0, 0,
1828 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1829 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1830 : : },
1831 : : {
1832 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1833 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1834 : : FILE_TEST_SETUP_TYPE_SYMLINK_DANGLING, 0, FALSE,
1835 : : TRUE, 0, 0,
1836 : : 2, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1837 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1838 : : },
1839 : : {
1840 : : TRUE, G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1841 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1842 : : FILE_TEST_SETUP_TYPE_SYMLINK_VALID, default_public_mode, FALSE,
1843 : : TRUE, 0, 0,
1844 : : /* the third file is `source~-target`, the original target of the old
1845 : : * backup symlink */
1846 : : 3, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1847 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, original_source_contents,
1848 : : },
1849 : :
1850 : : /* several different setups with replace_flags == PRIVATE */
1851 : : {
1852 : : FALSE, G_FILE_CREATE_PRIVATE, NULL,
1853 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1854 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1855 : : TRUE, 0, 0,
1856 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1857 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1858 : : },
1859 : : {
1860 : : FALSE, G_FILE_CREATE_PRIVATE, NULL,
1861 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1862 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1863 : : TRUE, 0, 0,
1864 : : /* the file isn’t being replaced, so it should keep its existing permissions */
1865 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode, new_contents,
1866 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1867 : : },
1868 : : {
1869 : : FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1870 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0,
1871 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1872 : : TRUE, 0, 0,
1873 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1874 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1875 : : },
1876 : : {
1877 : : FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, NULL,
1878 : : FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_public_mode,
1879 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, FALSE,
1880 : : TRUE, 0, 0,
1881 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_NONEMPTY, default_private_mode, new_contents,
1882 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1883 : : },
1884 : :
1885 : : /* make the initial source file unreadable, so the replace operation
1886 : : * should fail
1887 : : *
1888 : : * Permissions are ignored if we have CAP_DAC_OVERRIDE or equivalent,
1889 : : * and in particular if we're root. In this scenario,we need to skip it */
1890 : : {
1891 : : FALSE, G_FILE_CREATE_NONE, NULL,
1892 : : FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0 /* most restrictive permissions */,
1893 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, TRUE,
1894 : 2 : FALSE, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
1895 : : 1, FILE_TEST_SETUP_TYPE_REGULAR_EMPTY, 0, NULL,
1896 : : FILE_TEST_SETUP_TYPE_NONEXISTENT, 0, NULL,
1897 : : },
1898 : : };
1899 : : gsize i;
1900 : :
1901 : 2 : g_test_summary ("Test various situations for g_file_replace()");
1902 : :
1903 : : /* Reset the umask after querying it above. There’s no way to query it without
1904 : : * changing it. */
1905 : 2 : umask (current_umask);
1906 : 2 : g_test_message ("Current umask: %u", current_umask);
1907 : :
1908 : 100 : for (i = 0; i < G_N_ELEMENTS (tests); i++)
1909 : : {
1910 : 98 : gchar *tmpdir_path = NULL;
1911 : 98 : GFile *tmpdir = NULL, *source_file = NULL, *backup_file = NULL;
1912 : 98 : GFileOutputStream *output_stream = NULL;
1913 : 98 : GFileIOStream *io_stream = NULL;
1914 : 98 : GFileEnumerator *enumerator = NULL;
1915 : 98 : GFileInfo *info = NULL;
1916 : : guint n_files;
1917 : 98 : GError *local_error = NULL;
1918 : :
1919 : : /* Create a fresh, empty working directory. */
1920 : 98 : tmpdir_path = g_dir_make_tmp ("g_file_replace_XXXXXX", &local_error);
1921 : 98 : g_assert_no_error (local_error);
1922 : 98 : tmpdir = g_file_new_for_path (tmpdir_path);
1923 : :
1924 : 98 : g_test_message ("Test %" G_GSIZE_FORMAT ", using temporary directory %s", i, tmpdir_path);
1925 : :
1926 : 98 : if (tests[i].skip_if_cap_dac_override && check_cap_dac_override (tmpdir_path))
1927 : : {
1928 : 0 : g_test_message ("Skipping test as process has CAP_DAC_OVERRIDE capability and the test checks permissions");
1929 : :
1930 : 0 : g_file_delete (tmpdir, NULL, &local_error);
1931 : 0 : g_assert_no_error (local_error);
1932 : 0 : g_clear_object (&tmpdir);
1933 : 0 : g_free (tmpdir_path);
1934 : :
1935 : 0 : continue;
1936 : : }
1937 : :
1938 : 98 : g_free (tmpdir_path);
1939 : :
1940 : : /* Set up the test directory. */
1941 : 98 : source_file = create_test_file (tmpdir, "source", tests[i].setup_source_type, tests[i].setup_source_mode);
1942 : 98 : backup_file = create_test_file (tmpdir, "source~", tests[i].setup_backup_type, tests[i].setup_backup_mode);
1943 : :
1944 : : /* Replace the source file. Check the error state only after finishing
1945 : : * writing, as the replace operation is split across g_file_replace() and
1946 : : * g_output_stream_close(). */
1947 : 98 : if (read_write)
1948 : 49 : io_stream = g_file_replace_readwrite (source_file,
1949 : 49 : tests[i].replace_etag,
1950 : 49 : tests[i].replace_make_backup,
1951 : 49 : tests[i].replace_flags,
1952 : : NULL,
1953 : : &local_error);
1954 : : else
1955 : 49 : output_stream = g_file_replace (source_file,
1956 : 49 : tests[i].replace_etag,
1957 : 49 : tests[i].replace_make_backup,
1958 : 49 : tests[i].replace_flags,
1959 : : NULL,
1960 : : &local_error);
1961 : :
1962 : 98 : if (tests[i].expected_success)
1963 : : {
1964 : 72 : g_assert_no_error (local_error);
1965 : 72 : if (read_write)
1966 : 36 : g_assert_nonnull (io_stream);
1967 : : else
1968 : 36 : g_assert_nonnull (output_stream);
1969 : : }
1970 : :
1971 : : /* Write new content to it. */
1972 : 98 : if (io_stream != NULL)
1973 : : {
1974 : 38 : GOutputStream *io_output_stream = g_io_stream_get_output_stream (G_IO_STREAM (io_stream));
1975 : : gsize n_written;
1976 : :
1977 : 38 : g_output_stream_write_all (G_OUTPUT_STREAM (io_output_stream), new_contents, strlen (new_contents),
1978 : : &n_written, NULL, &local_error);
1979 : :
1980 : 38 : if (tests[i].expected_success)
1981 : : {
1982 : 36 : g_assert_no_error (local_error);
1983 : 36 : g_assert_cmpint (n_written, ==, strlen (new_contents));
1984 : : }
1985 : :
1986 : 38 : g_io_stream_close (G_IO_STREAM (io_stream), NULL, (local_error == NULL) ? &local_error : NULL);
1987 : :
1988 : 38 : if (tests[i].expected_success)
1989 : 36 : g_assert_no_error (local_error);
1990 : : }
1991 : 60 : else if (output_stream != NULL)
1992 : : {
1993 : : gsize n_written;
1994 : :
1995 : 38 : g_output_stream_write_all (G_OUTPUT_STREAM (output_stream), new_contents, strlen (new_contents),
1996 : : &n_written, NULL, &local_error);
1997 : :
1998 : 38 : if (tests[i].expected_success)
1999 : : {
2000 : 36 : g_assert_no_error (local_error);
2001 : 36 : g_assert_cmpint (n_written, ==, strlen (new_contents));
2002 : : }
2003 : :
2004 : 38 : g_output_stream_close (G_OUTPUT_STREAM (output_stream), NULL, (local_error == NULL) ? &local_error : NULL);
2005 : :
2006 : 38 : if (tests[i].expected_success)
2007 : 36 : g_assert_no_error (local_error);
2008 : : }
2009 : :
2010 : 98 : if (tests[i].expected_success)
2011 : 72 : g_assert_no_error (local_error);
2012 : : else
2013 : 26 : g_assert_error (local_error, tests[i].expected_error_domain, tests[i].expected_error_code);
2014 : :
2015 : 98 : g_clear_error (&local_error);
2016 : 98 : g_clear_object (&io_stream);
2017 : 98 : g_clear_object (&output_stream);
2018 : :
2019 : : /* Verify the final state of the directory. */
2020 : 98 : enumerator = g_file_enumerate_children (tmpdir,
2021 : : G_FILE_ATTRIBUTE_STANDARD_NAME,
2022 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
2023 : 98 : g_assert_no_error (local_error);
2024 : :
2025 : 98 : n_files = 0;
2026 : : do
2027 : : {
2028 : 292 : g_file_enumerator_iterate (enumerator, &info, NULL, NULL, &local_error);
2029 : 292 : g_assert_no_error (local_error);
2030 : :
2031 : 292 : if (info != NULL)
2032 : 194 : n_files++;
2033 : : }
2034 : 292 : while (info != NULL);
2035 : :
2036 : 98 : g_clear_object (&enumerator);
2037 : :
2038 : 98 : g_assert_cmpuint (n_files, ==, tests[i].expected_n_files);
2039 : :
2040 : 98 : check_test_file (source_file, tmpdir, "source", tests[i].expected_source_type, tests[i].expected_source_mode, tests[i].expected_source_contents);
2041 : 98 : check_test_file (backup_file, tmpdir, "source~", tests[i].expected_backup_type, tests[i].expected_backup_mode, tests[i].expected_backup_contents);
2042 : :
2043 : : /* Tidy up. Ignore failure apart from when deleting the directory, which
2044 : : * should be empty. */
2045 : 98 : g_file_delete (source_file, NULL, NULL);
2046 : 98 : g_file_delete (backup_file, NULL, NULL);
2047 : :
2048 : : /* Other files which are occasionally generated by the tests. */
2049 : : {
2050 : 98 : GFile *backup_target_file = g_file_get_child (tmpdir, "source~-target");
2051 : 98 : g_file_delete (backup_target_file, NULL, NULL);
2052 : 98 : g_clear_object (&backup_target_file);
2053 : : }
2054 : : {
2055 : 98 : GFile *backup_target_file = g_file_get_child (tmpdir, "source-target");
2056 : 98 : g_file_delete (backup_target_file, NULL, NULL);
2057 : 98 : g_clear_object (&backup_target_file);
2058 : : }
2059 : :
2060 : 98 : g_file_delete (tmpdir, NULL, &local_error);
2061 : 98 : g_assert_no_error (local_error);
2062 : :
2063 : 98 : g_clear_object (&backup_file);
2064 : 98 : g_clear_object (&source_file);
2065 : 98 : g_clear_object (&tmpdir);
2066 : : }
2067 : : #else /* if !__linux__ */
2068 : : g_test_skip ("File replacement tests can only be run on Linux");
2069 : : #endif
2070 : 2 : }
2071 : :
2072 : : static void
2073 : 1 : on_new_tmp_done (GObject *object,
2074 : : GAsyncResult *result,
2075 : : gpointer user_data)
2076 : : {
2077 : : GFile *file;
2078 : : GFile *parent;
2079 : : GFileInfo *info;
2080 : : GFileIOStream *iostream;
2081 : 1 : GError *error = NULL;
2082 : 1 : GMainLoop *loop = user_data;
2083 : : gchar *basename;
2084 : 1 : GFile *tmpdir = NULL;
2085 : :
2086 : 1 : g_assert_null (object);
2087 : :
2088 : 1 : file = g_file_new_tmp_finish (result, &iostream, &error);
2089 : 1 : g_assert_no_error (error);
2090 : :
2091 : 1 : g_assert_true (g_file_query_exists (file, NULL));
2092 : :
2093 : 1 : basename = g_file_get_basename (file);
2094 : 1 : g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_async_"));
2095 : :
2096 : 1 : info = g_file_io_stream_query_info (iostream, G_FILE_ATTRIBUTE_STANDARD_TYPE,
2097 : : NULL, &error);
2098 : 1 : g_assert_no_error (error);
2099 : :
2100 : 1 : g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
2101 : 1 : g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2102 : 1 : g_assert_no_error (error);
2103 : :
2104 : 1 : parent = g_file_get_parent (file);
2105 : 1 : tmpdir = g_file_new_for_path (g_get_tmp_dir ());
2106 : :
2107 : 1 : g_assert_true (g_file_equal (tmpdir, parent));
2108 : :
2109 : 1 : g_main_loop_quit (loop);
2110 : :
2111 : 1 : g_object_unref (file);
2112 : 1 : g_object_unref (parent);
2113 : 1 : g_object_unref (iostream);
2114 : 1 : g_object_unref (info);
2115 : 1 : g_free (basename);
2116 : 1 : g_object_unref (tmpdir);
2117 : 1 : }
2118 : :
2119 : : static void
2120 : 2 : on_new_tmp_error (GObject *object,
2121 : : GAsyncResult *result,
2122 : : gpointer user_data)
2123 : : {
2124 : 2 : GFileIOStream *iostream = (GFileIOStream*) &on_new_tmp_error;
2125 : 2 : AsyncErrorData *error_data = user_data;
2126 : :
2127 : 2 : g_assert_null (object);
2128 : :
2129 : 2 : g_assert_null (g_file_new_tmp_finish (result, &iostream, error_data->error));
2130 : 2 : g_assert_nonnull (error_data->error);
2131 : 2 : g_assert_null (iostream);
2132 : :
2133 : 2 : g_main_loop_quit (error_data->loop);
2134 : 2 : }
2135 : :
2136 : : static void
2137 : 1 : test_async_new_tmp (void)
2138 : : {
2139 : : GMainLoop *loop;
2140 : 1 : GError *error = NULL;
2141 : : GCancellable *cancellable;
2142 : 1 : AsyncErrorData error_data = { .error = &error };
2143 : :
2144 : 1 : loop = g_main_loop_new (NULL, TRUE);
2145 : 1 : error_data.loop = loop;
2146 : :
2147 : 1 : g_file_new_tmp_async ("g_file_new_tmp_async_XXXXXX",
2148 : : G_PRIORITY_DEFAULT, NULL,
2149 : : on_new_tmp_done, loop);
2150 : 1 : g_main_loop_run (loop);
2151 : :
2152 : 1 : g_file_new_tmp_async ("g_file_new_tmp_async_invalid_template",
2153 : : G_PRIORITY_DEFAULT, NULL,
2154 : : on_new_tmp_error, &error_data);
2155 : 1 : g_main_loop_run (loop);
2156 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
2157 : 1 : g_clear_error (&error);
2158 : :
2159 : 1 : cancellable = g_cancellable_new ();
2160 : 1 : g_file_new_tmp_async ("g_file_new_tmp_async_cancelled_XXXXXX",
2161 : : G_PRIORITY_DEFAULT, cancellable,
2162 : : on_new_tmp_error, &error_data);
2163 : 1 : g_cancellable_cancel (cancellable);
2164 : 1 : g_main_loop_run (loop);
2165 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2166 : 1 : g_clear_object (&cancellable);
2167 : 1 : g_clear_error (&error);
2168 : :
2169 : 1 : g_main_loop_unref (loop);
2170 : 1 : }
2171 : :
2172 : : static void
2173 : 1 : on_new_tmp_dir_done (GObject *object,
2174 : : GAsyncResult *result,
2175 : : gpointer user_data)
2176 : : {
2177 : : GFile *file;
2178 : : GFile *parent;
2179 : : GFileInfo *info;
2180 : 1 : GError *error = NULL;
2181 : 1 : GMainLoop *loop = user_data;
2182 : : gchar *basename;
2183 : 1 : GFile *tmpdir = NULL;
2184 : :
2185 : 1 : g_assert_null (object);
2186 : :
2187 : 1 : file = g_file_new_tmp_dir_finish (result, &error);
2188 : 1 : g_assert_no_error (error);
2189 : :
2190 : 1 : g_assert_true (g_file_query_exists (file, NULL));
2191 : :
2192 : 1 : basename = g_file_get_basename (file);
2193 : 1 : g_assert_true (g_str_has_prefix (basename, "g_file_new_tmp_dir_async_"));
2194 : :
2195 : 1 : info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE,
2196 : : G_FILE_QUERY_INFO_NONE, NULL, &error);
2197 : 1 : g_assert_no_error (error);
2198 : :
2199 : 1 : g_assert_cmpuint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_DIRECTORY);
2200 : :
2201 : 1 : parent = g_file_get_parent (file);
2202 : 1 : tmpdir = g_file_new_for_path (g_get_tmp_dir ());
2203 : :
2204 : 1 : g_assert_true (g_file_equal (tmpdir, parent));
2205 : :
2206 : 1 : g_main_loop_quit (loop);
2207 : :
2208 : 1 : g_object_unref (file);
2209 : 1 : g_object_unref (parent);
2210 : 1 : g_object_unref (info);
2211 : 1 : g_free (basename);
2212 : 1 : g_object_unref (tmpdir);
2213 : 1 : }
2214 : :
2215 : : static void
2216 : 2 : on_new_tmp_dir_error (GObject *object,
2217 : : GAsyncResult *result,
2218 : : gpointer user_data)
2219 : : {
2220 : 2 : AsyncErrorData *error_data = user_data;
2221 : :
2222 : 2 : g_assert_null (object);
2223 : :
2224 : 2 : g_assert_null (g_file_new_tmp_dir_finish (result, error_data->error));
2225 : 2 : g_assert_nonnull (error_data->error);
2226 : :
2227 : 2 : g_main_loop_quit (error_data->loop);
2228 : 2 : }
2229 : :
2230 : : static void
2231 : 1 : test_async_new_tmp_dir (void)
2232 : : {
2233 : : GMainLoop *loop;
2234 : 1 : GError *error = NULL;
2235 : : GCancellable *cancellable;
2236 : 1 : AsyncErrorData error_data = { .error = &error };
2237 : :
2238 : 1 : loop = g_main_loop_new (NULL, TRUE);
2239 : 1 : error_data.loop = loop;
2240 : :
2241 : 1 : g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_XXXXXX",
2242 : : G_PRIORITY_DEFAULT, NULL,
2243 : : on_new_tmp_dir_done, loop);
2244 : 1 : g_main_loop_run (loop);
2245 : :
2246 : 1 : g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async",
2247 : : G_PRIORITY_DEFAULT, NULL,
2248 : : on_new_tmp_dir_error, &error_data);
2249 : 1 : g_main_loop_run (loop);
2250 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
2251 : 1 : g_clear_error (&error);
2252 : :
2253 : 1 : cancellable = g_cancellable_new ();
2254 : 1 : g_file_new_tmp_dir_async ("g_file_new_tmp_dir_async_cancelled_XXXXXX",
2255 : : G_PRIORITY_DEFAULT, cancellable,
2256 : : on_new_tmp_dir_error, &error_data);
2257 : 1 : g_cancellable_cancel (cancellable);
2258 : 1 : g_main_loop_run (loop);
2259 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2260 : 1 : g_clear_object (&cancellable);
2261 : 1 : g_clear_error (&error);
2262 : :
2263 : 1 : g_main_loop_unref (loop);
2264 : 1 : }
2265 : :
2266 : : static void
2267 : 1 : on_file_deleted (GObject *object,
2268 : : GAsyncResult *result,
2269 : : gpointer user_data)
2270 : : {
2271 : 1 : GError *local_error = NULL;
2272 : 1 : GMainLoop *loop = user_data;
2273 : :
2274 : 1 : (void) g_file_delete_finish ((GFile*)object, result, &local_error);
2275 : 1 : g_assert_no_error (local_error);
2276 : :
2277 : 1 : g_main_loop_quit (loop);
2278 : 1 : }
2279 : :
2280 : : static void
2281 : 1 : test_async_delete (void)
2282 : : {
2283 : : GFile *file;
2284 : : GFileIOStream *iostream;
2285 : 1 : GError *local_error = NULL;
2286 : 1 : GError **error = &local_error;
2287 : : GMainLoop *loop;
2288 : :
2289 : 1 : file = g_file_new_tmp ("g_file_delete_XXXXXX",
2290 : : &iostream, error);
2291 : 1 : g_assert_no_error (local_error);
2292 : 1 : g_object_unref (iostream);
2293 : :
2294 : 1 : g_assert_true (g_file_query_exists (file, NULL));
2295 : :
2296 : 1 : loop = g_main_loop_new (NULL, TRUE);
2297 : :
2298 : 1 : g_file_delete_async (file, G_PRIORITY_DEFAULT, NULL, on_file_deleted, loop);
2299 : :
2300 : 1 : g_main_loop_run (loop);
2301 : :
2302 : 1 : g_assert_false (g_file_query_exists (file, NULL));
2303 : :
2304 : 1 : g_main_loop_unref (loop);
2305 : 1 : g_object_unref (file);
2306 : 1 : }
2307 : :
2308 : : static void
2309 : 1 : on_symlink_done (GObject *object,
2310 : : GAsyncResult *result,
2311 : : gpointer user_data)
2312 : : {
2313 : 1 : GFile *file = (GFile *) object;
2314 : 1 : GError *error = NULL;
2315 : 1 : GMainLoop *loop = user_data;
2316 : :
2317 : 1 : g_assert_true (g_file_make_symbolic_link_finish (file, result, &error));
2318 : 1 : g_assert_no_error (error);
2319 : :
2320 : 1 : g_main_loop_quit (loop);
2321 : 1 : }
2322 : :
2323 : : static void
2324 : 3 : on_symlink_error (GObject *object,
2325 : : GAsyncResult *result,
2326 : : gpointer user_data)
2327 : : {
2328 : 3 : GFile *file = (GFile *) object;
2329 : 3 : GError *error = NULL;
2330 : 3 : AsyncErrorData *data = user_data;
2331 : :
2332 : 3 : g_assert_false (g_file_make_symbolic_link_finish (file, result, &error));
2333 : 3 : g_assert_nonnull (error);
2334 : 3 : g_propagate_error (data->error, g_steal_pointer (&error));
2335 : :
2336 : 3 : g_main_loop_quit (data->loop);
2337 : 3 : }
2338 : :
2339 : : static void
2340 : 1 : test_async_make_symlink (void)
2341 : : {
2342 : : GFile *link;
2343 : : GFile *parent_dir;
2344 : : GFile *target;
2345 : : GFileInfo *link_info;
2346 : : GFileIOStream *iostream;
2347 : 1 : GError *error = NULL;
2348 : : GCancellable *cancellable;
2349 : : GMainLoop *loop;
2350 : 1 : AsyncErrorData error_data = {0};
2351 : : gchar *tmpdir_path;
2352 : : gchar *target_path;
2353 : :
2354 : 1 : target = g_file_new_tmp ("g_file_symlink_target_XXXXXX", &iostream, &error);
2355 : 1 : g_assert_no_error (error);
2356 : :
2357 : 1 : g_io_stream_close ((GIOStream *) iostream, NULL, &error);
2358 : 1 : g_assert_no_error (error);
2359 : 1 : g_object_unref (iostream);
2360 : :
2361 : 1 : g_assert_true (g_file_query_exists (target, NULL));
2362 : :
2363 : 1 : loop = g_main_loop_new (NULL, TRUE);
2364 : 1 : error_data.loop = loop;
2365 : 1 : error_data.error = &error;
2366 : :
2367 : 1 : tmpdir_path = g_dir_make_tmp ("g_file_symlink_XXXXXX", &error);
2368 : 1 : g_assert_no_error (error);
2369 : :
2370 : 1 : parent_dir = g_file_new_for_path (tmpdir_path);
2371 : 1 : g_assert_true (g_file_query_exists (parent_dir, NULL));
2372 : :
2373 : 1 : link = g_file_get_child (parent_dir, "symlink");
2374 : 1 : g_assert_false (g_file_query_exists (link, NULL));
2375 : :
2376 : 1 : g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
2377 : : "*assertion*symlink_value*failed*");
2378 : 1 : g_file_make_symbolic_link_async (link, NULL,
2379 : : G_PRIORITY_DEFAULT, NULL,
2380 : : on_symlink_done, loop);
2381 : 1 : g_test_assert_expected_messages ();
2382 : :
2383 : 1 : g_file_make_symbolic_link_async (link, "",
2384 : : G_PRIORITY_DEFAULT, NULL,
2385 : : on_symlink_error, &error_data);
2386 : 1 : g_main_loop_run (loop);
2387 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
2388 : 1 : g_clear_error (&error);
2389 : :
2390 : 1 : target_path = g_file_get_path (target);
2391 : 1 : g_file_make_symbolic_link_async (link, target_path,
2392 : : G_PRIORITY_DEFAULT, NULL,
2393 : : on_symlink_done, loop);
2394 : 1 : g_main_loop_run (loop);
2395 : :
2396 : 1 : g_assert_true (g_file_query_exists (link, NULL));
2397 : 1 : link_info = g_file_query_info (link,
2398 : : G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
2399 : : G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
2400 : : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2401 : : NULL,
2402 : : &error);
2403 : 1 : g_assert_no_error (error);
2404 : :
2405 : 1 : g_assert_true (g_file_info_get_is_symlink (link_info));
2406 : 1 : g_assert_cmpstr (target_path, ==, g_file_info_get_symlink_target (link_info));
2407 : :
2408 : : /* Try creating it again, it fails */
2409 : 1 : g_file_make_symbolic_link_async (link, target_path,
2410 : : G_PRIORITY_DEFAULT, NULL,
2411 : : on_symlink_error, &error_data);
2412 : 1 : g_main_loop_run (loop);
2413 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
2414 : 1 : g_clear_error (&error);
2415 : :
2416 : 1 : cancellable = g_cancellable_new ();
2417 : 1 : g_file_make_symbolic_link_async (link, target_path,
2418 : : G_PRIORITY_DEFAULT, cancellable,
2419 : : on_symlink_error, &error_data);
2420 : 1 : g_cancellable_cancel (cancellable);
2421 : 1 : g_main_loop_run (loop);
2422 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
2423 : 1 : g_clear_error (&error);
2424 : 1 : g_clear_object (&cancellable);
2425 : :
2426 : 1 : g_main_loop_unref (loop);
2427 : 1 : g_object_unref (target);
2428 : 1 : g_object_unref (parent_dir);
2429 : 1 : g_object_unref (link);
2430 : 1 : g_object_unref (link_info);
2431 : 1 : g_free (tmpdir_path);
2432 : 1 : g_free (target_path);
2433 : 1 : }
2434 : :
2435 : : static void
2436 : 1 : test_copy_preserve_mode (void)
2437 : : {
2438 : : #ifdef G_OS_UNIX
2439 : 1 : mode_t current_umask = umask (0);
2440 : : const struct
2441 : : {
2442 : : guint32 source_mode;
2443 : : guint32 expected_destination_mode;
2444 : : gboolean create_destination_before_copy;
2445 : : GFileCopyFlags copy_flags;
2446 : : }
2447 : 1 : vectors[] =
2448 : : {
2449 : : /* Overwriting the destination file should copy the permissions from the
2450 : : * source file, even if %G_FILE_COPY_ALL_METADATA is set: */
2451 : : { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2452 : : { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2453 : : /* The same behaviour should hold if the destination file is not being
2454 : : * overwritten because it doesn’t already exist: */
2455 : : { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_ALL_METADATA },
2456 : : { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2457 : : { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS },
2458 : : /* Anything with %G_FILE_COPY_TARGET_DEFAULT_PERMS should use the current
2459 : : * umask for the destination file: */
2460 : 1 : { 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 },
2461 : 1 : { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2462 : 1 : { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_ALL_METADATA },
2463 : 1 : { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME },
2464 : 1 : { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA },
2465 : 1 : { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS },
2466 : : };
2467 : : gsize i;
2468 : :
2469 : : /* Reset the umask after querying it above. There’s no way to query it without
2470 : : * changing it. */
2471 : 1 : umask (current_umask);
2472 : 1 : g_test_message ("Current umask: %u", (unsigned int) current_umask);
2473 : :
2474 : 12 : for (i = 0; i < G_N_ELEMENTS (vectors); i++)
2475 : : {
2476 : : GFile *tmpfile;
2477 : : GFile *dest_tmpfile;
2478 : : GFileInfo *dest_info;
2479 : : GFileIOStream *iostream;
2480 : 11 : GError *local_error = NULL;
2481 : 11 : guint32 romode = vectors[i].source_mode;
2482 : : guint32 dest_mode;
2483 : :
2484 : 11 : g_test_message ("Vector %" G_GSIZE_FORMAT, i);
2485 : :
2486 : 11 : tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2487 : : &iostream, &local_error);
2488 : 11 : g_assert_no_error (local_error);
2489 : 11 : g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2490 : 11 : g_assert_no_error (local_error);
2491 : 11 : g_clear_object (&iostream);
2492 : :
2493 : 11 : g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
2494 : : &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2495 : : NULL, &local_error);
2496 : 11 : g_assert_no_error (local_error);
2497 : :
2498 : 11 : dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
2499 : : &iostream, &local_error);
2500 : 11 : g_assert_no_error (local_error);
2501 : 11 : g_io_stream_close ((GIOStream*)iostream, NULL, &local_error);
2502 : 11 : g_assert_no_error (local_error);
2503 : 11 : g_clear_object (&iostream);
2504 : :
2505 : 11 : if (!vectors[i].create_destination_before_copy)
2506 : : {
2507 : 7 : g_file_delete (dest_tmpfile, NULL, &local_error);
2508 : 7 : g_assert_no_error (local_error);
2509 : : }
2510 : :
2511 : 11 : g_file_copy (tmpfile, dest_tmpfile, vectors[i].copy_flags,
2512 : : NULL, NULL, NULL, &local_error);
2513 : 11 : g_assert_no_error (local_error);
2514 : :
2515 : 11 : dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2516 : : NULL, &local_error);
2517 : 11 : g_assert_no_error (local_error);
2518 : :
2519 : 11 : dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
2520 : :
2521 : 11 : g_assert_cmpint (dest_mode & ~S_IFMT, ==, vectors[i].expected_destination_mode);
2522 : 11 : g_assert_cmpint (dest_mode & S_IFMT, ==, S_IFREG);
2523 : :
2524 : 11 : (void) g_file_delete (tmpfile, NULL, NULL);
2525 : 11 : (void) g_file_delete (dest_tmpfile, NULL, NULL);
2526 : :
2527 : 11 : g_clear_object (&tmpfile);
2528 : 11 : g_clear_object (&dest_tmpfile);
2529 : 11 : g_clear_object (&dest_info);
2530 : : }
2531 : : #else /* if !G_OS_UNIX */
2532 : : g_test_skip ("File permissions tests can only be run on Unix")
2533 : : #endif
2534 : 1 : }
2535 : :
2536 : : typedef struct
2537 : : {
2538 : : goffset current_num_bytes;
2539 : : goffset total_num_bytes;
2540 : : } CopyProgressData;
2541 : :
2542 : : static void
2543 : 1 : file_copy_progress_cb (goffset current_num_bytes,
2544 : : goffset total_num_bytes,
2545 : : gpointer user_data)
2546 : : {
2547 : 1 : CopyProgressData *prev_data = user_data;
2548 : :
2549 : 1 : g_assert_cmpuint (total_num_bytes, ==, prev_data->total_num_bytes);
2550 : 1 : g_assert_cmpuint (current_num_bytes, >=, prev_data->current_num_bytes);
2551 : :
2552 : : /* Update it for the next callback. */
2553 : 1 : prev_data->current_num_bytes = current_num_bytes;
2554 : 1 : }
2555 : :
2556 : : static void
2557 : 1 : test_copy_progress (void)
2558 : : {
2559 : 1 : GFile *src_tmpfile = NULL;
2560 : 1 : GFile *dest_tmpfile = NULL;
2561 : : GFileIOStream *iostream;
2562 : : GOutputStream *ostream;
2563 : 1 : GError *local_error = NULL;
2564 : 1 : const guint8 buffer[] = { 1, 2, 3, 4, 5 };
2565 : : CopyProgressData progress_data;
2566 : :
2567 : 1 : src_tmpfile = g_file_new_tmp ("tmp-copy-progressXXXXXX",
2568 : : &iostream, &local_error);
2569 : 1 : g_assert_no_error (local_error);
2570 : :
2571 : : /* Write some content to the file for testing. */
2572 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2573 : 1 : g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &local_error);
2574 : 1 : g_assert_no_error (local_error);
2575 : :
2576 : 1 : g_io_stream_close ((GIOStream *) iostream, NULL, &local_error);
2577 : 1 : g_assert_no_error (local_error);
2578 : 1 : g_clear_object (&iostream);
2579 : :
2580 : : /* Grab a unique destination filename. */
2581 : 1 : dest_tmpfile = g_file_new_tmp ("tmp-copy-progressXXXXXX",
2582 : : &iostream, &local_error);
2583 : 1 : g_assert_no_error (local_error);
2584 : 1 : g_io_stream_close ((GIOStream *) iostream, NULL, &local_error);
2585 : 1 : g_assert_no_error (local_error);
2586 : 1 : g_clear_object (&iostream);
2587 : :
2588 : : /* Set the progress data to an initial offset of zero. The callback will
2589 : : * assert that progress is non-decreasing and reaches the total length of
2590 : : * the file. */
2591 : 1 : progress_data.current_num_bytes = 0;
2592 : 1 : progress_data.total_num_bytes = sizeof (buffer);
2593 : :
2594 : : /* Copy the file with progress reporting. */
2595 : 1 : g_file_copy (src_tmpfile, dest_tmpfile, G_FILE_COPY_OVERWRITE,
2596 : : NULL, file_copy_progress_cb, &progress_data, &local_error);
2597 : 1 : g_assert_no_error (local_error);
2598 : :
2599 : 1 : g_assert_cmpuint (progress_data.current_num_bytes, ==, progress_data.total_num_bytes);
2600 : 1 : g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
2601 : :
2602 : : /* Clean up. */
2603 : 1 : (void) g_file_delete (src_tmpfile, NULL, NULL);
2604 : 1 : (void) g_file_delete (dest_tmpfile, NULL, NULL);
2605 : :
2606 : 1 : g_clear_object (&src_tmpfile);
2607 : 1 : g_clear_object (&dest_tmpfile);
2608 : 1 : }
2609 : :
2610 : : typedef struct
2611 : : {
2612 : : GError *error;
2613 : : gboolean done;
2614 : : gboolean res;
2615 : : } CopyAsyncData;
2616 : :
2617 : : static void
2618 : 1 : test_copy_async_cb (GObject *object,
2619 : : GAsyncResult *result,
2620 : : void *user_data)
2621 : : {
2622 : 1 : GFile *file = G_FILE (object);
2623 : 1 : CopyAsyncData *data = user_data;
2624 : 1 : GError *error = NULL;
2625 : :
2626 : 1 : data->res = g_file_move_finish (file, result, &error);
2627 : 1 : data->error = g_steal_pointer (&error);
2628 : 1 : data->done = TRUE;
2629 : 1 : }
2630 : :
2631 : : typedef struct
2632 : : {
2633 : : goffset total_num_bytes;
2634 : : } CopyAsyncProgressData;
2635 : :
2636 : : static void
2637 : 1 : test_copy_async_progress_cb (goffset current_num_bytes,
2638 : : goffset total_num_bytes,
2639 : : void *user_data)
2640 : : {
2641 : 1 : CopyAsyncProgressData *data = user_data;
2642 : 1 : data->total_num_bytes = total_num_bytes;
2643 : 1 : }
2644 : :
2645 : : /* Exercise copy_async_with_closures() */
2646 : : static void
2647 : 1 : test_copy_async_with_closures (void)
2648 : : {
2649 : 1 : CopyAsyncData data = { 0 };
2650 : 1 : CopyAsyncProgressData progress_data = { 0 };
2651 : : GFile *source;
2652 : : GFileIOStream *iostream;
2653 : : GOutputStream *ostream;
2654 : : GFile *destination;
2655 : : gchar *destination_path;
2656 : 1 : GError *error = NULL;
2657 : : gboolean res;
2658 : 1 : const guint8 buffer[] = { 1, 2, 3, 4, 5 };
2659 : : GClosure *progress_closure;
2660 : : GClosure *ready_closure;
2661 : :
2662 : 1 : source = g_file_new_tmp ("g_file_copy_async_with_closures_XXXXXX", &iostream, NULL);
2663 : :
2664 : 1 : destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_copy_async_with_closures_target", NULL);
2665 : 1 : destination = g_file_new_for_path (destination_path);
2666 : :
2667 : 1 : g_assert_nonnull (source);
2668 : 1 : g_assert_nonnull (iostream);
2669 : :
2670 : 1 : res = g_file_query_exists (source, NULL);
2671 : 1 : g_assert_true (res);
2672 : 1 : res = g_file_query_exists (destination, NULL);
2673 : 1 : g_assert_false (res);
2674 : :
2675 : : /* Write a known number of bytes to the file, so we can test the progress
2676 : : * callback against it */
2677 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
2678 : 1 : g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
2679 : 1 : g_assert_no_error (error);
2680 : :
2681 : 1 : progress_closure = g_cclosure_new (G_CALLBACK (test_copy_async_progress_cb), &progress_data, NULL);
2682 : 1 : ready_closure = g_cclosure_new (G_CALLBACK (test_copy_async_cb), &data, NULL);
2683 : :
2684 : 1 : g_file_copy_async_with_closures (source,
2685 : : destination,
2686 : : G_FILE_COPY_NONE,
2687 : : 0,
2688 : : NULL,
2689 : : progress_closure,
2690 : : ready_closure);
2691 : :
2692 : 4 : while (!data.done)
2693 : 3 : g_main_context_iteration (NULL, TRUE);
2694 : :
2695 : 1 : g_assert_no_error (data.error);
2696 : 1 : g_assert_true (data.res);
2697 : 1 : g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
2698 : :
2699 : 1 : res = g_file_query_exists (source, NULL);
2700 : 1 : g_assert_true (res);
2701 : 1 : res = g_file_query_exists (destination, NULL);
2702 : 1 : g_assert_true (res);
2703 : :
2704 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
2705 : 1 : g_assert_no_error (error);
2706 : 1 : g_assert_true (res);
2707 : 1 : g_object_unref (iostream);
2708 : :
2709 : 1 : res = g_file_delete (source, NULL, &error);
2710 : 1 : g_assert_no_error (error);
2711 : 1 : g_assert_true (res);
2712 : :
2713 : 1 : res = g_file_delete (destination, NULL, &error);
2714 : 1 : g_assert_no_error (error);
2715 : 1 : g_assert_true (res);
2716 : :
2717 : 1 : g_object_unref (source);
2718 : 1 : g_object_unref (destination);
2719 : :
2720 : 1 : g_free (destination_path);
2721 : 1 : }
2722 : :
2723 : : static void
2724 : 1 : test_measure (void)
2725 : : {
2726 : : GFile *file;
2727 : : guint64 num_bytes;
2728 : : guint64 num_dirs;
2729 : : guint64 num_files;
2730 : 1 : GError *error = NULL;
2731 : : gboolean ok;
2732 : : gchar *path;
2733 : :
2734 : 1 : path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2735 : 1 : file = g_file_new_for_path (path);
2736 : :
2737 : 1 : ok = g_file_measure_disk_usage (file,
2738 : : G_FILE_MEASURE_APPARENT_SIZE,
2739 : : NULL,
2740 : : NULL,
2741 : : NULL,
2742 : : &num_bytes,
2743 : : &num_dirs,
2744 : : &num_files,
2745 : : &error);
2746 : 1 : g_assert_true (ok);
2747 : 1 : g_assert_no_error (error);
2748 : :
2749 : 1 : g_assert_cmpuint (num_bytes, ==, 74469);
2750 : 1 : g_assert_cmpuint (num_dirs, ==, 6);
2751 : 1 : g_assert_cmpuint (num_files, ==, 32);
2752 : :
2753 : 1 : g_object_unref (file);
2754 : 1 : g_free (path);
2755 : 1 : }
2756 : :
2757 : : typedef struct {
2758 : : guint64 expected_bytes;
2759 : : guint64 expected_dirs;
2760 : : guint64 expected_files;
2761 : : gint progress_count;
2762 : : guint64 progress_bytes;
2763 : : guint64 progress_dirs;
2764 : : guint64 progress_files;
2765 : : } MeasureData;
2766 : :
2767 : : static void
2768 : 1 : measure_progress (gboolean reporting,
2769 : : guint64 current_size,
2770 : : guint64 num_dirs,
2771 : : guint64 num_files,
2772 : : gpointer user_data)
2773 : : {
2774 : 1 : MeasureData *data = user_data;
2775 : :
2776 : 1 : data->progress_count += 1;
2777 : :
2778 : 1 : g_assert_cmpuint (current_size, >=, data->progress_bytes);
2779 : 1 : g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2780 : 1 : g_assert_cmpuint (num_files, >=, data->progress_files);
2781 : :
2782 : 1 : data->progress_bytes = current_size;
2783 : 1 : data->progress_dirs = num_dirs;
2784 : 1 : data->progress_files = num_files;
2785 : 1 : }
2786 : :
2787 : : static void
2788 : 1 : measure_done (GObject *source,
2789 : : GAsyncResult *res,
2790 : : gpointer user_data)
2791 : : {
2792 : 1 : MeasureData *data = user_data;
2793 : : guint64 num_bytes, num_dirs, num_files;
2794 : 1 : GError *error = NULL;
2795 : : gboolean ok;
2796 : :
2797 : 1 : ok = g_file_measure_disk_usage_finish (G_FILE (source), res, &num_bytes, &num_dirs, &num_files, &error);
2798 : 1 : g_assert_true (ok);
2799 : 1 : g_assert_no_error (error);
2800 : :
2801 : 1 : g_assert_cmpuint (data->expected_bytes, ==, num_bytes);
2802 : 1 : g_assert_cmpuint (data->expected_dirs, ==, num_dirs);
2803 : 1 : g_assert_cmpuint (data->expected_files, ==, num_files);
2804 : :
2805 : 1 : g_assert_cmpuint (data->progress_count, >, 0);
2806 : 1 : g_assert_cmpuint (num_bytes, >=, data->progress_bytes);
2807 : 1 : g_assert_cmpuint (num_dirs, >=, data->progress_dirs);
2808 : 1 : g_assert_cmpuint (num_files, >=, data->progress_files);
2809 : :
2810 : 1 : g_free (data);
2811 : 1 : g_object_unref (source);
2812 : 1 : }
2813 : :
2814 : : static void
2815 : 1 : test_measure_async (void)
2816 : : {
2817 : : gchar *path;
2818 : : GFile *file;
2819 : : MeasureData *data;
2820 : :
2821 : 1 : data = g_new (MeasureData, 1);
2822 : :
2823 : 1 : data->progress_count = 0;
2824 : 1 : data->progress_bytes = 0;
2825 : 1 : data->progress_files = 0;
2826 : 1 : data->progress_dirs = 0;
2827 : :
2828 : 1 : path = g_test_build_filename (G_TEST_DIST, "desktop-files", NULL);
2829 : 1 : file = g_file_new_for_path (path);
2830 : 1 : g_free (path);
2831 : :
2832 : 1 : data->expected_bytes = 74469;
2833 : 1 : data->expected_dirs = 6;
2834 : 1 : data->expected_files = 32;
2835 : :
2836 : 1 : g_file_measure_disk_usage_async (file,
2837 : : G_FILE_MEASURE_APPARENT_SIZE,
2838 : : 0, NULL,
2839 : : measure_progress, data,
2840 : : measure_done, data);
2841 : 1 : }
2842 : :
2843 : : static void
2844 : 1 : test_load_bytes (void)
2845 : : {
2846 : 1 : gchar filename[] = "g_file_load_bytes_XXXXXX";
2847 : 1 : GError *error = NULL;
2848 : : GBytes *bytes;
2849 : : GFile *file;
2850 : : int len;
2851 : : int fd;
2852 : : int ret;
2853 : :
2854 : 1 : fd = g_mkstemp (filename);
2855 : 1 : g_assert_cmpint (fd, !=, -1);
2856 : 1 : len = strlen ("test_load_bytes");
2857 : 1 : ret = write (fd, "test_load_bytes", len);
2858 : 1 : g_assert_cmpint (ret, ==, len);
2859 : 1 : g_clear_fd (&fd, &error);
2860 : 1 : g_assert_no_error (error);
2861 : :
2862 : 1 : file = g_file_new_for_path (filename);
2863 : 1 : bytes = g_file_load_bytes (file, NULL, NULL, &error);
2864 : 1 : g_assert_no_error (error);
2865 : 1 : g_assert_nonnull (bytes);
2866 : 1 : g_assert_cmpint (len, ==, g_bytes_get_size (bytes));
2867 : 1 : g_assert_cmpstr ("test_load_bytes", ==, (gchar *)g_bytes_get_data (bytes, NULL));
2868 : :
2869 : 1 : g_file_delete (file, NULL, NULL);
2870 : :
2871 : 1 : g_bytes_unref (bytes);
2872 : 1 : g_object_unref (file);
2873 : 1 : }
2874 : :
2875 : : typedef struct
2876 : : {
2877 : : GMainLoop *main_loop;
2878 : : GFile *file;
2879 : : GBytes *bytes;
2880 : : } LoadBytesAsyncData;
2881 : :
2882 : : static void
2883 : 1 : test_load_bytes_cb (GObject *object,
2884 : : GAsyncResult *result,
2885 : : gpointer user_data)
2886 : : {
2887 : 1 : GFile *file = G_FILE (object);
2888 : 1 : LoadBytesAsyncData *data = user_data;
2889 : 1 : GError *error = NULL;
2890 : :
2891 : 1 : data->bytes = g_file_load_bytes_finish (file, result, NULL, &error);
2892 : 1 : g_assert_no_error (error);
2893 : 1 : g_assert_nonnull (data->bytes);
2894 : :
2895 : 1 : g_main_loop_quit (data->main_loop);
2896 : 1 : }
2897 : :
2898 : : static void
2899 : 1 : test_load_bytes_async (void)
2900 : : {
2901 : 1 : LoadBytesAsyncData data = { 0 };
2902 : 1 : gchar filename[] = "g_file_load_bytes_XXXXXX";
2903 : 1 : GError *error = NULL;
2904 : : int len;
2905 : : int fd;
2906 : : int ret;
2907 : :
2908 : 1 : fd = g_mkstemp (filename);
2909 : 1 : g_assert_cmpint (fd, !=, -1);
2910 : 1 : len = strlen ("test_load_bytes_async");
2911 : 1 : ret = write (fd, "test_load_bytes_async", len);
2912 : 1 : g_assert_cmpint (ret, ==, len);
2913 : 1 : g_clear_fd (&fd, &error);
2914 : 1 : g_assert_no_error (error);
2915 : :
2916 : 1 : data.main_loop = g_main_loop_new (NULL, FALSE);
2917 : 1 : data.file = g_file_new_for_path (filename);
2918 : :
2919 : 1 : g_file_load_bytes_async (data.file, NULL, test_load_bytes_cb, &data);
2920 : 1 : g_main_loop_run (data.main_loop);
2921 : :
2922 : 1 : g_assert_cmpint (len, ==, g_bytes_get_size (data.bytes));
2923 : 1 : g_assert_cmpstr ("test_load_bytes_async", ==, (gchar *)g_bytes_get_data (data.bytes, NULL));
2924 : :
2925 : 1 : g_file_delete (data.file, NULL, NULL);
2926 : 1 : g_object_unref (data.file);
2927 : 1 : g_bytes_unref (data.bytes);
2928 : 1 : g_main_loop_unref (data.main_loop);
2929 : 1 : }
2930 : :
2931 : : #if GLIB_SIZEOF_SIZE_T > 4
2932 : : static const gsize testfile_4gb_size = ((gsize) 1 << 32) + (1 << 16); /* 4GB + a bit */
2933 : : #else
2934 : : /* Have to make do with something smaller on 32-bit platforms */
2935 : : static const gsize testfile_4gb_size = G_MAXSIZE;
2936 : : #endif
2937 : :
2938 : : /* @filename will be modified as per g_mkstemp() */
2939 : : static gboolean
2940 : 3 : create_testfile_4gb_or_skip (char *filename)
2941 : : {
2942 : 3 : GError *error = NULL;
2943 : : int fd;
2944 : : int ret;
2945 : :
2946 : : /* Reading each 4GB test file takes about 5s on a fast machine, and another 7s
2947 : : * to compare its contents once it’s been read. That’s too slow for a normal
2948 : : * test run, and there’s no way to speed it up. */
2949 : 3 : if (!g_test_slow ())
2950 : : {
2951 : 3 : g_test_skip ("Skipping slow >4GB file test");
2952 : 3 : return FALSE;
2953 : : }
2954 : :
2955 : 0 : fd = g_mkstemp (filename);
2956 : 0 : g_assert_cmpint (fd, !=, -1);
2957 : 0 : ret = ftruncate (fd, testfile_4gb_size);
2958 : 0 : g_clear_fd (&fd, &error);
2959 : 0 : g_assert_no_error (error);
2960 : 0 : if (ret == 1)
2961 : : {
2962 : 0 : g_test_skip ("Could not create testfile >4GB");
2963 : 0 : g_assert_no_errno (g_unlink (filename));
2964 : 0 : return FALSE;
2965 : : }
2966 : :
2967 : 0 : return TRUE;
2968 : : }
2969 : :
2970 : : static void
2971 : 0 : check_testfile_4gb_contents (const char *data,
2972 : : gsize len)
2973 : : {
2974 : : gsize i;
2975 : :
2976 : 0 : g_assert_nonnull (data);
2977 : 0 : g_assert_cmpuint (testfile_4gb_size, ==, len);
2978 : :
2979 : 0 : for (i = 0; i < testfile_4gb_size; i++)
2980 : : {
2981 : 0 : if (data[i] != 0)
2982 : 0 : break;
2983 : : }
2984 : 0 : g_assert_cmpint (i, ==, testfile_4gb_size);
2985 : 0 : }
2986 : :
2987 : : static void
2988 : 1 : test_load_contents_4gb (void)
2989 : : {
2990 : 1 : char filename[] = "g_file_load_contents_4gb_XXXXXX";
2991 : 1 : GError *error = NULL;
2992 : : gboolean result;
2993 : : char *data;
2994 : : gsize len;
2995 : : GFile *file;
2996 : :
2997 : 1 : if (!create_testfile_4gb_or_skip (filename))
2998 : 1 : return;
2999 : :
3000 : 0 : file = g_file_new_for_path (filename);
3001 : 0 : result = g_file_load_contents (file, NULL, &data, &len, NULL, &error);
3002 : 0 : g_assert_no_error (error);
3003 : 0 : g_assert_true (result);
3004 : :
3005 : 0 : check_testfile_4gb_contents (data, len);
3006 : :
3007 : 0 : g_file_delete (file, NULL, NULL);
3008 : :
3009 : 0 : g_free (data);
3010 : 0 : g_object_unref (file);
3011 : : }
3012 : :
3013 : : static void
3014 : 0 : load_contents_4gb_cb (GObject *object,
3015 : : GAsyncResult *result,
3016 : : gpointer user_data)
3017 : : {
3018 : 0 : GAsyncResult **result_out = user_data;
3019 : :
3020 : 0 : g_assert (*result_out == NULL);
3021 : 0 : *result_out = g_object_ref (result);
3022 : :
3023 : 0 : g_main_context_wakeup (NULL);
3024 : 0 : }
3025 : :
3026 : : static void
3027 : 1 : test_load_contents_4gb_async (void)
3028 : : {
3029 : 1 : char filename[] = "g_file_load_contents_4gb_async_XXXXXX";
3030 : : GFile *file;
3031 : 1 : GAsyncResult *async_result = NULL;
3032 : 1 : GError *error = NULL;
3033 : : char *data;
3034 : : gsize len;
3035 : : gboolean ret;
3036 : :
3037 : 1 : if (!create_testfile_4gb_or_skip (filename))
3038 : 1 : return;
3039 : :
3040 : 0 : file = g_file_new_for_path (filename);
3041 : 0 : g_file_load_contents_async (file, NULL, load_contents_4gb_cb, &async_result);
3042 : :
3043 : 0 : while (async_result == NULL)
3044 : 0 : g_main_context_iteration (NULL, TRUE);
3045 : :
3046 : 0 : ret = g_file_load_contents_finish (file, async_result, &data, &len, NULL, &error);
3047 : 0 : g_assert_no_error (error);
3048 : 0 : g_assert_true (ret);
3049 : :
3050 : 0 : check_testfile_4gb_contents (data, len);
3051 : :
3052 : 0 : g_file_delete (file, NULL, NULL);
3053 : :
3054 : 0 : g_free (data);
3055 : 0 : g_object_unref (async_result);
3056 : 0 : g_object_unref (file);
3057 : : }
3058 : :
3059 : : static void
3060 : 1 : test_load_bytes_4gb (void)
3061 : : {
3062 : 1 : char filename[] = "g_file_load_bytes_4gb_XXXXXX";
3063 : 1 : GError *error = NULL;
3064 : : GBytes *bytes;
3065 : : GFile *file;
3066 : :
3067 : 1 : if (!create_testfile_4gb_or_skip (filename))
3068 : 1 : return;
3069 : :
3070 : 0 : file = g_file_new_for_path (filename);
3071 : 0 : bytes = g_file_load_bytes (file, NULL, NULL, &error);
3072 : 0 : g_assert_no_error (error);
3073 : 0 : g_assert_true (bytes);
3074 : :
3075 : 0 : check_testfile_4gb_contents (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
3076 : :
3077 : 0 : g_file_delete (file, NULL, NULL);
3078 : :
3079 : 0 : g_bytes_unref (bytes);
3080 : 0 : g_object_unref (file);
3081 : : }
3082 : :
3083 : : static void
3084 : 4 : test_writev_helper (GOutputVector *vectors,
3085 : : gsize n_vectors,
3086 : : gboolean use_bytes_written,
3087 : : const guint8 *expected_contents,
3088 : : gsize expected_length)
3089 : : {
3090 : : GFile *file;
3091 : 4 : GFileIOStream *iostream = NULL;
3092 : : GOutputStream *ostream;
3093 : 4 : GError *error = NULL;
3094 : 4 : gsize bytes_written = 0;
3095 : : gboolean res;
3096 : : guint8 *contents;
3097 : : gsize length;
3098 : :
3099 : 4 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3100 : : &iostream, NULL);
3101 : 4 : g_assert_nonnull (file);
3102 : 4 : g_assert_nonnull (iostream);
3103 : :
3104 : 4 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3105 : :
3106 : 4 : res = g_output_stream_writev_all (ostream, vectors, n_vectors, use_bytes_written ? &bytes_written : NULL, NULL, &error);
3107 : 4 : g_assert_no_error (error);
3108 : 4 : g_assert_true (res);
3109 : 4 : if (use_bytes_written)
3110 : 3 : g_assert_cmpuint (bytes_written, ==, expected_length);
3111 : :
3112 : 4 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3113 : 4 : g_assert_no_error (error);
3114 : 4 : g_assert_true (res);
3115 : 4 : g_object_unref (iostream);
3116 : :
3117 : 4 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3118 : 4 : g_assert_no_error (error);
3119 : 4 : g_assert_true (res);
3120 : :
3121 : 4 : g_assert_cmpmem (contents, length, expected_contents, expected_length);
3122 : :
3123 : 4 : g_free (contents);
3124 : :
3125 : 4 : g_file_delete (file, NULL, NULL);
3126 : 4 : g_object_unref (file);
3127 : 4 : }
3128 : :
3129 : : /* Test that writev() on local file output streams works on a non-empty vector */
3130 : : static void
3131 : 1 : test_writev (void)
3132 : : {
3133 : : GOutputVector vectors[3];
3134 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5,
3135 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3136 : : 1, 2, 3};
3137 : :
3138 : 1 : vectors[0].buffer = buffer;
3139 : 1 : vectors[0].size = 5;
3140 : :
3141 : 1 : vectors[1].buffer = buffer + 5;
3142 : 1 : vectors[1].size = 12;
3143 : :
3144 : 1 : vectors[2].buffer = buffer + 5 + 12;
3145 : 1 : vectors[2].size = 3;
3146 : :
3147 : 1 : test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, buffer, sizeof buffer);
3148 : 1 : }
3149 : :
3150 : : /* Test that writev() on local file output streams works on a non-empty vector without returning bytes_written */
3151 : : static void
3152 : 1 : test_writev_no_bytes_written (void)
3153 : : {
3154 : : GOutputVector vectors[3];
3155 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5,
3156 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3157 : : 1, 2, 3};
3158 : :
3159 : 1 : vectors[0].buffer = buffer;
3160 : 1 : vectors[0].size = 5;
3161 : :
3162 : 1 : vectors[1].buffer = buffer + 5;
3163 : 1 : vectors[1].size = 12;
3164 : :
3165 : 1 : vectors[2].buffer = buffer + 5 + 12;
3166 : 1 : vectors[2].size = 3;
3167 : :
3168 : 1 : test_writev_helper (vectors, G_N_ELEMENTS (vectors), FALSE, buffer, sizeof buffer);
3169 : 1 : }
3170 : :
3171 : : /* Test that writev() on local file output streams works on 0 vectors */
3172 : : static void
3173 : 1 : test_writev_no_vectors (void)
3174 : : {
3175 : 1 : test_writev_helper (NULL, 0, TRUE, NULL, 0);
3176 : 1 : }
3177 : :
3178 : : /* Test that writev() on local file output streams works on empty vectors */
3179 : : static void
3180 : 1 : test_writev_empty_vectors (void)
3181 : : {
3182 : : GOutputVector vectors[3];
3183 : :
3184 : 1 : vectors[0].buffer = NULL;
3185 : 1 : vectors[0].size = 0;
3186 : 1 : vectors[1].buffer = NULL;
3187 : 1 : vectors[1].size = 0;
3188 : 1 : vectors[2].buffer = NULL;
3189 : 1 : vectors[2].size = 0;
3190 : :
3191 : 1 : test_writev_helper (vectors, G_N_ELEMENTS (vectors), TRUE, NULL, 0);
3192 : 1 : }
3193 : :
3194 : : /* Test that writev() fails if the sum of sizes in the vector is too big */
3195 : : static void
3196 : 1 : test_writev_too_big_vectors (void)
3197 : : {
3198 : : GFile *file;
3199 : 1 : GFileIOStream *iostream = NULL;
3200 : : GOutputStream *ostream;
3201 : 1 : GError *error = NULL;
3202 : 1 : gsize bytes_written = 0;
3203 : : gboolean res;
3204 : : guint8 *contents;
3205 : : gsize length;
3206 : : GOutputVector vectors[3];
3207 : :
3208 : 1 : vectors[0].buffer = (void*) 1;
3209 : 1 : vectors[0].size = G_MAXSIZE / 2;
3210 : :
3211 : 1 : vectors[1].buffer = (void*) 1;
3212 : 1 : vectors[1].size = G_MAXSIZE / 2;
3213 : :
3214 : 1 : vectors[2].buffer = (void*) 1;
3215 : 1 : vectors[2].size = G_MAXSIZE / 2;
3216 : :
3217 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3218 : : &iostream, NULL);
3219 : 1 : g_assert_nonnull (file);
3220 : 1 : g_assert_nonnull (iostream);
3221 : :
3222 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3223 : :
3224 : 1 : res = g_output_stream_writev_all (ostream, vectors, G_N_ELEMENTS (vectors), &bytes_written, NULL, &error);
3225 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
3226 : 1 : g_assert_cmpuint (bytes_written, ==, 0);
3227 : 1 : g_assert_false (res);
3228 : 1 : g_clear_error (&error);
3229 : :
3230 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3231 : 1 : g_assert_no_error (error);
3232 : 1 : g_assert_true (res);
3233 : 1 : g_object_unref (iostream);
3234 : :
3235 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3236 : 1 : g_assert_no_error (error);
3237 : 1 : g_assert_true (res);
3238 : :
3239 : 1 : g_assert_cmpmem (contents, length, NULL, 0);
3240 : :
3241 : 1 : g_free (contents);
3242 : :
3243 : 1 : g_file_delete (file, NULL, NULL);
3244 : 1 : g_object_unref (file);
3245 : 1 : }
3246 : :
3247 : : typedef struct
3248 : : {
3249 : : gsize bytes_written;
3250 : : GOutputVector *vectors;
3251 : : gsize n_vectors;
3252 : : GError *error;
3253 : : gboolean done;
3254 : : } WritevAsyncData;
3255 : :
3256 : : static void
3257 : 1 : test_writev_async_cb (GObject *object,
3258 : : GAsyncResult *result,
3259 : : gpointer user_data)
3260 : : {
3261 : 1 : GOutputStream *ostream = G_OUTPUT_STREAM (object);
3262 : 1 : WritevAsyncData *data = user_data;
3263 : 1 : GError *error = NULL;
3264 : : gsize bytes_written;
3265 : : gboolean res;
3266 : :
3267 : 1 : res = g_output_stream_writev_finish (ostream, result, &bytes_written, &error);
3268 : 1 : g_assert_true (res);
3269 : 1 : g_assert_no_error (error);
3270 : 1 : data->bytes_written += bytes_written;
3271 : :
3272 : : /* skip vectors that have been written in full */
3273 : 4 : while (data->n_vectors > 0 && bytes_written >= data->vectors[0].size)
3274 : : {
3275 : 3 : bytes_written -= data->vectors[0].size;
3276 : 3 : ++data->vectors;
3277 : 3 : --data->n_vectors;
3278 : : }
3279 : : /* skip partially written vector data */
3280 : 1 : if (bytes_written > 0 && data->n_vectors > 0)
3281 : : {
3282 : 0 : data->vectors[0].size -= bytes_written;
3283 : 0 : data->vectors[0].buffer = ((guint8 *) data->vectors[0].buffer) + bytes_written;
3284 : : }
3285 : :
3286 : 1 : if (data->n_vectors > 0)
3287 : 0 : g_output_stream_writev_async (ostream, data->vectors, data->n_vectors, 0, NULL, test_writev_async_cb, &data);
3288 : 1 : }
3289 : :
3290 : : /* Test that writev_async() on local file output streams works on a non-empty vector */
3291 : : static void
3292 : 1 : test_writev_async (void)
3293 : : {
3294 : 1 : WritevAsyncData data = { 0 };
3295 : : GFile *file;
3296 : 1 : GFileIOStream *iostream = NULL;
3297 : : GOutputVector vectors[3];
3298 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5,
3299 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3300 : : 1, 2, 3};
3301 : : GOutputStream *ostream;
3302 : 1 : GError *error = NULL;
3303 : : gboolean res;
3304 : : guint8 *contents;
3305 : : gsize length;
3306 : :
3307 : 1 : vectors[0].buffer = buffer;
3308 : 1 : vectors[0].size = 5;
3309 : :
3310 : 1 : vectors[1].buffer = buffer + 5;
3311 : 1 : vectors[1].size = 12;
3312 : :
3313 : 1 : vectors[2].buffer = buffer + 5 + 12;
3314 : 1 : vectors[2].size = 3;
3315 : :
3316 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3317 : : &iostream, NULL);
3318 : 1 : g_assert_nonnull (file);
3319 : 1 : g_assert_nonnull (iostream);
3320 : :
3321 : 1 : data.vectors = vectors;
3322 : 1 : data.n_vectors = G_N_ELEMENTS (vectors);
3323 : :
3324 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3325 : :
3326 : 1 : g_output_stream_writev_async (ostream, data.vectors, data.n_vectors, 0, NULL, test_writev_async_cb, &data);
3327 : :
3328 : 3 : while (data.n_vectors > 0)
3329 : 2 : g_main_context_iteration (NULL, TRUE);
3330 : :
3331 : 1 : g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
3332 : :
3333 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3334 : 1 : g_assert_no_error (error);
3335 : 1 : g_assert_true (res);
3336 : 1 : g_object_unref (iostream);
3337 : :
3338 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3339 : 1 : g_assert_no_error (error);
3340 : 1 : g_assert_true (res);
3341 : :
3342 : 1 : g_assert_cmpmem (contents, length, buffer, sizeof buffer);
3343 : :
3344 : 1 : g_free (contents);
3345 : :
3346 : 1 : g_file_delete (file, NULL, NULL);
3347 : 1 : g_object_unref (file);
3348 : 1 : }
3349 : :
3350 : : static void
3351 : 5 : test_writev_all_cb (GObject *object,
3352 : : GAsyncResult *result,
3353 : : gpointer user_data)
3354 : : {
3355 : 5 : GOutputStream *ostream = G_OUTPUT_STREAM (object);
3356 : 5 : WritevAsyncData *data = user_data;
3357 : :
3358 : 5 : g_output_stream_writev_all_finish (ostream, result, &data->bytes_written, &data->error);
3359 : 5 : data->done = TRUE;
3360 : 5 : }
3361 : :
3362 : : /* Test that writev_async_all() on local file output streams works on a non-empty vector */
3363 : : static void
3364 : 1 : test_writev_async_all (void)
3365 : : {
3366 : 1 : WritevAsyncData data = { 0 };
3367 : : GFile *file;
3368 : 1 : GFileIOStream *iostream = NULL;
3369 : : GOutputStream *ostream;
3370 : : GOutputVector vectors[3];
3371 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5,
3372 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3373 : : 1, 2, 3};
3374 : 1 : GError *error = NULL;
3375 : : gboolean res;
3376 : : guint8 *contents;
3377 : : gsize length;
3378 : :
3379 : 1 : vectors[0].buffer = buffer;
3380 : 1 : vectors[0].size = 5;
3381 : :
3382 : 1 : vectors[1].buffer = buffer + 5;
3383 : 1 : vectors[1].size = 12;
3384 : :
3385 : 1 : vectors[2].buffer = buffer + 5 + 12;
3386 : 1 : vectors[2].size = 3;
3387 : :
3388 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3389 : : &iostream, NULL);
3390 : 1 : g_assert_nonnull (file);
3391 : 1 : g_assert_nonnull (iostream);
3392 : :
3393 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3394 : :
3395 : 1 : g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3396 : :
3397 : 2 : while (!data.done)
3398 : 1 : g_main_context_iteration (NULL, TRUE);
3399 : :
3400 : 1 : g_assert_cmpuint (data.bytes_written, ==, sizeof buffer);
3401 : 1 : g_assert_no_error (data.error);
3402 : :
3403 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3404 : 1 : g_assert_no_error (error);
3405 : 1 : g_assert_true (res);
3406 : 1 : g_object_unref (iostream);
3407 : :
3408 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3409 : 1 : g_assert_no_error (error);
3410 : 1 : g_assert_true (res);
3411 : :
3412 : 1 : g_assert_cmpmem (contents, length, buffer, sizeof buffer);
3413 : :
3414 : 1 : g_free (contents);
3415 : :
3416 : 1 : g_file_delete (file, NULL, NULL);
3417 : 1 : g_object_unref (file);
3418 : 1 : }
3419 : :
3420 : : /* Test that writev_async_all() on local file output streams handles cancellation correctly */
3421 : : static void
3422 : 1 : test_writev_async_all_cancellation (void)
3423 : : {
3424 : 1 : WritevAsyncData data = { 0 };
3425 : : GFile *file;
3426 : 1 : GFileIOStream *iostream = NULL;
3427 : : GOutputVector vectors[3];
3428 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5,
3429 : : 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
3430 : : 1, 2, 3};
3431 : : GOutputStream *ostream;
3432 : 1 : GError *error = NULL;
3433 : : gboolean res;
3434 : : guint8 *contents;
3435 : : gsize length;
3436 : : GCancellable *cancellable;
3437 : :
3438 : 1 : vectors[0].buffer = buffer;
3439 : 1 : vectors[0].size = 5;
3440 : :
3441 : 1 : vectors[1].buffer = buffer + 5;
3442 : 1 : vectors[1].size = 12;
3443 : :
3444 : 1 : vectors[2].buffer = buffer + 5 + 12;
3445 : 1 : vectors[2].size = 3;
3446 : :
3447 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3448 : : &iostream, NULL);
3449 : 1 : g_assert_nonnull (file);
3450 : 1 : g_assert_nonnull (iostream);
3451 : :
3452 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3453 : :
3454 : 1 : cancellable = g_cancellable_new ();
3455 : 1 : g_cancellable_cancel (cancellable);
3456 : :
3457 : 1 : g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, cancellable, test_writev_all_cb, &data);
3458 : :
3459 : 2 : while (!data.done)
3460 : 1 : g_main_context_iteration (NULL, TRUE);
3461 : :
3462 : 1 : g_assert_cmpuint (data.bytes_written, ==, 0);
3463 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
3464 : 1 : g_clear_error (&data.error);
3465 : :
3466 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3467 : 1 : g_assert_no_error (error);
3468 : 1 : g_assert_true (res);
3469 : 1 : g_object_unref (iostream);
3470 : :
3471 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3472 : 1 : g_assert_no_error (error);
3473 : 1 : g_assert_true (res);
3474 : 1 : g_assert_cmpuint (length, ==, 0);
3475 : :
3476 : 1 : g_free (contents);
3477 : :
3478 : 1 : g_file_delete (file, NULL, NULL);
3479 : 1 : g_object_unref (file);
3480 : 1 : g_object_unref (cancellable);
3481 : 1 : }
3482 : :
3483 : : /* Test that writev_async_all() with empty vectors is handled correctly */
3484 : : static void
3485 : 1 : test_writev_async_all_empty_vectors (void)
3486 : : {
3487 : 1 : WritevAsyncData data = { 0 };
3488 : : GFile *file;
3489 : 1 : GFileIOStream *iostream = NULL;
3490 : : GOutputVector vectors[3];
3491 : : GOutputStream *ostream;
3492 : 1 : GError *error = NULL;
3493 : : gboolean res;
3494 : : guint8 *contents;
3495 : : gsize length;
3496 : :
3497 : 1 : vectors[0].buffer = NULL;
3498 : 1 : vectors[0].size = 0;
3499 : :
3500 : 1 : vectors[1].buffer = NULL;
3501 : 1 : vectors[1].size = 0;
3502 : :
3503 : 1 : vectors[2].buffer = NULL;
3504 : 1 : vectors[2].size = 0;
3505 : :
3506 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3507 : : &iostream, NULL);
3508 : 1 : g_assert_nonnull (file);
3509 : 1 : g_assert_nonnull (iostream);
3510 : :
3511 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3512 : :
3513 : 1 : g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3514 : :
3515 : 2 : while (!data.done)
3516 : 1 : g_main_context_iteration (NULL, TRUE);
3517 : :
3518 : 1 : g_assert_cmpuint (data.bytes_written, ==, 0);
3519 : 1 : g_assert_no_error (data.error);
3520 : 1 : g_clear_error (&data.error);
3521 : :
3522 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3523 : 1 : g_assert_no_error (error);
3524 : 1 : g_assert_true (res);
3525 : 1 : g_object_unref (iostream);
3526 : :
3527 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3528 : 1 : g_assert_no_error (error);
3529 : 1 : g_assert_true (res);
3530 : 1 : g_assert_cmpuint (length, ==, 0);
3531 : :
3532 : 1 : g_free (contents);
3533 : :
3534 : 1 : g_file_delete (file, NULL, NULL);
3535 : 1 : g_object_unref (file);
3536 : 1 : }
3537 : :
3538 : : /* Test that writev_async_all() with no vectors is handled correctly */
3539 : : static void
3540 : 1 : test_writev_async_all_no_vectors (void)
3541 : : {
3542 : 1 : WritevAsyncData data = { 0 };
3543 : : GFile *file;
3544 : 1 : GFileIOStream *iostream = NULL;
3545 : : GOutputStream *ostream;
3546 : 1 : GError *error = NULL;
3547 : : gboolean res;
3548 : : guint8 *contents;
3549 : : gsize length;
3550 : :
3551 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3552 : : &iostream, NULL);
3553 : 1 : g_assert_nonnull (file);
3554 : 1 : g_assert_nonnull (iostream);
3555 : :
3556 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3557 : :
3558 : 1 : g_output_stream_writev_all_async (ostream, NULL, 0, 0, NULL, test_writev_all_cb, &data);
3559 : :
3560 : 2 : while (!data.done)
3561 : 1 : g_main_context_iteration (NULL, TRUE);
3562 : :
3563 : 1 : g_assert_cmpuint (data.bytes_written, ==, 0);
3564 : 1 : g_assert_no_error (data.error);
3565 : 1 : g_clear_error (&data.error);
3566 : :
3567 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3568 : 1 : g_assert_no_error (error);
3569 : 1 : g_assert_true (res);
3570 : 1 : g_object_unref (iostream);
3571 : :
3572 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3573 : 1 : g_assert_no_error (error);
3574 : 1 : g_assert_true (res);
3575 : 1 : g_assert_cmpuint (length, ==, 0);
3576 : :
3577 : 1 : g_free (contents);
3578 : :
3579 : 1 : g_file_delete (file, NULL, NULL);
3580 : 1 : g_object_unref (file);
3581 : 1 : }
3582 : :
3583 : : /* Test that writev_async_all() with too big vectors is handled correctly */
3584 : : static void
3585 : 1 : test_writev_async_all_too_big_vectors (void)
3586 : : {
3587 : 1 : WritevAsyncData data = { 0 };
3588 : : GFile *file;
3589 : 1 : GFileIOStream *iostream = NULL;
3590 : : GOutputVector vectors[3];
3591 : : GOutputStream *ostream;
3592 : 1 : GError *error = NULL;
3593 : : gboolean res;
3594 : : guint8 *contents;
3595 : : gsize length;
3596 : :
3597 : 1 : vectors[0].buffer = (void*) 1;
3598 : 1 : vectors[0].size = G_MAXSIZE / 2;
3599 : :
3600 : 1 : vectors[1].buffer = (void*) 1;
3601 : 1 : vectors[1].size = G_MAXSIZE / 2;
3602 : :
3603 : 1 : vectors[2].buffer = (void*) 1;
3604 : 1 : vectors[2].size = G_MAXSIZE / 2;
3605 : :
3606 : 1 : file = g_file_new_tmp ("g_file_writev_XXXXXX",
3607 : : &iostream, NULL);
3608 : 1 : g_assert_nonnull (file);
3609 : 1 : g_assert_nonnull (iostream);
3610 : :
3611 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3612 : :
3613 : 1 : g_output_stream_writev_all_async (ostream, vectors, G_N_ELEMENTS (vectors), 0, NULL, test_writev_all_cb, &data);
3614 : :
3615 : 2 : while (!data.done)
3616 : 1 : g_main_context_iteration (NULL, TRUE);
3617 : :
3618 : 1 : g_assert_cmpuint (data.bytes_written, ==, 0);
3619 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
3620 : 1 : g_clear_error (&data.error);
3621 : :
3622 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3623 : 1 : g_assert_no_error (error);
3624 : 1 : g_assert_true (res);
3625 : 1 : g_object_unref (iostream);
3626 : :
3627 : 1 : res = g_file_load_contents (file, NULL, (gchar **) &contents, &length, NULL, &error);
3628 : 1 : g_assert_no_error (error);
3629 : 1 : g_assert_true (res);
3630 : 1 : g_assert_cmpuint (length, ==, 0);
3631 : :
3632 : 1 : g_free (contents);
3633 : :
3634 : 1 : g_file_delete (file, NULL, NULL);
3635 : 1 : g_object_unref (file);
3636 : 1 : }
3637 : :
3638 : : static void
3639 : 1 : test_build_attribute_list_for_copy (void)
3640 : : {
3641 : : GFile *tmpfile;
3642 : : GFileIOStream *iostream;
3643 : 1 : GError *error = NULL;
3644 : 1 : const GFileCopyFlags test_flags[] =
3645 : : {
3646 : : G_FILE_COPY_NONE,
3647 : : G_FILE_COPY_TARGET_DEFAULT_PERMS,
3648 : : G_FILE_COPY_ALL_METADATA,
3649 : : G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_PERMS,
3650 : : G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME,
3651 : : G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_TARGET_DEFAULT_PERMS,
3652 : : G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME,
3653 : : };
3654 : : gsize i;
3655 : : char *attrs;
3656 : : gchar *attrs_with_commas;
3657 : :
3658 : 1 : tmpfile = g_file_new_tmp ("tmp-build-attribute-list-for-copyXXXXXX",
3659 : : &iostream, &error);
3660 : 1 : g_assert_no_error (error);
3661 : 1 : g_io_stream_close ((GIOStream*)iostream, NULL, &error);
3662 : 1 : g_assert_no_error (error);
3663 : 1 : g_clear_object (&iostream);
3664 : :
3665 : 8 : for (i = 0; i < G_N_ELEMENTS (test_flags); i++)
3666 : : {
3667 : 7 : GFileCopyFlags flags = test_flags[i];
3668 : :
3669 : 7 : attrs = g_file_build_attribute_list_for_copy (tmpfile, flags, NULL, &error);
3670 : 7 : g_test_message ("Attributes for copy: %s", attrs);
3671 : 7 : g_assert_no_error (error);
3672 : 7 : g_assert_nonnull (attrs);
3673 : 7 : attrs_with_commas = g_strconcat (",", attrs, ",", NULL);
3674 : 7 : g_free (attrs);
3675 : :
3676 : : /* See g_local_file_class_init for reference. */
3677 : 7 : if (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
3678 : 3 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
3679 : : else
3680 : 4 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
3681 : : #ifdef G_OS_UNIX
3682 : 7 : if (flags & G_FILE_COPY_ALL_METADATA)
3683 : : {
3684 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
3685 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
3686 : : }
3687 : : else
3688 : : {
3689 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
3690 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
3691 : : }
3692 : : #endif
3693 : : #ifdef HAVE_UTIMES
3694 : 7 : if (flags & G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME)
3695 : : {
3696 : 3 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3697 : 3 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ","));
3698 : : }
3699 : : else
3700 : : {
3701 : 4 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3702 : 4 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ","));
3703 : : }
3704 : 7 : if (flags & G_FILE_COPY_ALL_METADATA)
3705 : : {
3706 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3707 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
3708 : : }
3709 : : else
3710 : : {
3711 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3712 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
3713 : : }
3714 : : #endif
3715 : : #ifdef HAVE_UTIMENSAT
3716 : 7 : if (flags & G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME)
3717 : : {
3718 : 3 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3719 : 3 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ","));
3720 : : }
3721 : : else
3722 : : {
3723 : 4 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
3724 : 4 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ","));
3725 : : }
3726 : 7 : if (flags & G_FILE_COPY_ALL_METADATA)
3727 : : {
3728 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3729 : 3 : g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
3730 : : }
3731 : : else
3732 : : {
3733 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
3734 : 4 : g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC ","));
3735 : : }
3736 : : #endif
3737 : 7 : g_free (attrs_with_commas);
3738 : : }
3739 : :
3740 : 1 : (void) g_file_delete (tmpfile, NULL, NULL);
3741 : 1 : g_clear_object (&tmpfile);
3742 : 1 : }
3743 : :
3744 : : typedef struct
3745 : : {
3746 : : GError *error;
3747 : : gboolean done;
3748 : : gboolean res;
3749 : : } MoveAsyncData;
3750 : :
3751 : : static void
3752 : 2 : test_move_async_cb (GObject *object,
3753 : : GAsyncResult *result,
3754 : : gpointer user_data)
3755 : : {
3756 : 2 : GFile *file = G_FILE (object);
3757 : 2 : MoveAsyncData *data = user_data;
3758 : 2 : GError *error = NULL;
3759 : :
3760 : 2 : data->res = g_file_move_finish (file, result, &error);
3761 : 2 : data->error = error;
3762 : 2 : data->done = TRUE;
3763 : 2 : }
3764 : :
3765 : : typedef struct
3766 : : {
3767 : : goffset total_num_bytes;
3768 : : } MoveAsyncProgressData;
3769 : :
3770 : : static void
3771 : 2 : test_move_async_progress_cb (goffset current_num_bytes,
3772 : : goffset total_num_bytes,
3773 : : gpointer user_data)
3774 : : {
3775 : 2 : MoveAsyncProgressData *data = user_data;
3776 : 2 : data->total_num_bytes = total_num_bytes;
3777 : 2 : }
3778 : :
3779 : : /* Test that move_async() moves the file correctly */
3780 : : static void
3781 : 1 : test_move_async (void)
3782 : : {
3783 : 1 : MoveAsyncData data = { 0 };
3784 : 1 : MoveAsyncProgressData progress_data = { 0 };
3785 : : GFile *source;
3786 : : GFileIOStream *iostream;
3787 : : GOutputStream *ostream;
3788 : : GFile *destination;
3789 : : gchar *destination_path;
3790 : 1 : GError *error = NULL;
3791 : : gboolean res;
3792 : 1 : const guint8 buffer[] = {1, 2, 3, 4, 5};
3793 : :
3794 : 1 : source = g_file_new_tmp ("g_file_move_XXXXXX", &iostream, NULL);
3795 : :
3796 : 1 : destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_move_target", NULL);
3797 : 1 : destination = g_file_new_for_path (destination_path);
3798 : :
3799 : 1 : g_assert_nonnull (source);
3800 : 1 : g_assert_nonnull (iostream);
3801 : :
3802 : 1 : res = g_file_query_exists (source, NULL);
3803 : 1 : g_assert_true (res);
3804 : 1 : res = g_file_query_exists (destination, NULL);
3805 : 1 : g_assert_false (res);
3806 : :
3807 : : // Write a known amount of bytes to the file, so we can test the progress callback against it
3808 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3809 : 1 : g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
3810 : 1 : g_assert_no_error (error);
3811 : :
3812 : 1 : g_file_move_async (source,
3813 : : destination,
3814 : : G_FILE_COPY_NONE,
3815 : : 0,
3816 : : NULL,
3817 : : test_move_async_progress_cb,
3818 : : &progress_data,
3819 : : test_move_async_cb,
3820 : : &data);
3821 : :
3822 : 3 : while (!data.done)
3823 : 2 : g_main_context_iteration (NULL, TRUE);
3824 : :
3825 : 1 : g_assert_no_error (data.error);
3826 : 1 : g_assert_true (data.res);
3827 : 1 : g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
3828 : :
3829 : 1 : res = g_file_query_exists (source, NULL);
3830 : 1 : g_assert_false (res);
3831 : 1 : res = g_file_query_exists (destination, NULL);
3832 : 1 : g_assert_true (res);
3833 : :
3834 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3835 : 1 : g_assert_no_error (error);
3836 : 1 : g_assert_true (res);
3837 : 1 : g_object_unref (iostream);
3838 : :
3839 : 1 : res = g_file_delete (destination, NULL, &error);
3840 : 1 : g_assert_no_error (error);
3841 : 1 : g_assert_true (res);
3842 : :
3843 : 1 : g_object_unref (source);
3844 : 1 : g_object_unref (destination);
3845 : :
3846 : 1 : g_free (destination_path);
3847 : 1 : }
3848 : :
3849 : : /* Same test as for move_async(), but for move_async_with_closures() */
3850 : : static void
3851 : 1 : test_move_async_with_closures (void)
3852 : : {
3853 : 1 : MoveAsyncData data = { 0 };
3854 : 1 : MoveAsyncProgressData progress_data = { 0 };
3855 : : GFile *source;
3856 : : GFileIOStream *iostream;
3857 : : GOutputStream *ostream;
3858 : : GFile *destination;
3859 : : gchar *destination_path;
3860 : 1 : GError *error = NULL;
3861 : : gboolean res;
3862 : 1 : const guint8 buffer[] = { 1, 2, 3, 4, 5 };
3863 : : GClosure *progress_closure;
3864 : : GClosure *ready_closure;
3865 : :
3866 : 1 : source = g_file_new_tmp ("g_file_move_async_with_closures_XXXXXX", &iostream, NULL);
3867 : :
3868 : 1 : destination_path = g_build_path (G_DIR_SEPARATOR_S, g_get_tmp_dir (), "g_file_move_async_with_closures_target", NULL);
3869 : 1 : destination = g_file_new_for_path (destination_path);
3870 : :
3871 : 1 : g_assert_nonnull (source);
3872 : 1 : g_assert_nonnull (iostream);
3873 : :
3874 : 1 : res = g_file_query_exists (source, NULL);
3875 : 1 : g_assert_true (res);
3876 : 1 : res = g_file_query_exists (destination, NULL);
3877 : 1 : g_assert_false (res);
3878 : :
3879 : : /* Write a known number of bytes to the file, so we can test the progress
3880 : : * callback against it */
3881 : 1 : ostream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
3882 : 1 : g_output_stream_write (ostream, buffer, sizeof (buffer), NULL, &error);
3883 : 1 : g_assert_no_error (error);
3884 : :
3885 : 1 : progress_closure = g_cclosure_new (G_CALLBACK (test_move_async_progress_cb), &progress_data, NULL);
3886 : 1 : ready_closure = g_cclosure_new (G_CALLBACK (test_move_async_cb), &data, NULL);
3887 : :
3888 : 1 : g_file_move_async_with_closures (source,
3889 : : destination,
3890 : : G_FILE_COPY_NONE,
3891 : : 0,
3892 : : NULL,
3893 : : progress_closure,
3894 : : ready_closure);
3895 : :
3896 : 3 : while (!data.done)
3897 : 2 : g_main_context_iteration (NULL, TRUE);
3898 : :
3899 : 1 : g_assert_no_error (data.error);
3900 : 1 : g_assert_true (data.res);
3901 : 1 : g_assert_cmpuint (progress_data.total_num_bytes, ==, sizeof (buffer));
3902 : :
3903 : 1 : res = g_file_query_exists (source, NULL);
3904 : 1 : g_assert_false (res);
3905 : 1 : res = g_file_query_exists (destination, NULL);
3906 : 1 : g_assert_true (res);
3907 : :
3908 : 1 : res = g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
3909 : 1 : g_assert_no_error (error);
3910 : 1 : g_assert_true (res);
3911 : 1 : g_object_unref (iostream);
3912 : :
3913 : 1 : res = g_file_delete (destination, NULL, &error);
3914 : 1 : g_assert_no_error (error);
3915 : 1 : g_assert_true (res);
3916 : :
3917 : 1 : g_object_unref (source);
3918 : 1 : g_object_unref (destination);
3919 : :
3920 : 1 : g_free (destination_path);
3921 : 1 : }
3922 : :
3923 : : static GAppInfo *
3924 : 4 : create_command_line_app_info (const char *name,
3925 : : const char *command_line,
3926 : : const char *default_for_type)
3927 : : {
3928 : : GAppInfo *info;
3929 : 4 : GError *error = NULL;
3930 : :
3931 : 4 : info = g_app_info_create_from_commandline (command_line,
3932 : : name,
3933 : : G_APP_INFO_CREATE_NONE,
3934 : : &error);
3935 : 4 : g_assert_no_error (error);
3936 : :
3937 : 4 : g_app_info_set_as_default_for_type (info, default_for_type, &error);
3938 : 4 : g_assert_no_error (error);
3939 : :
3940 : 4 : return g_steal_pointer (&info);
3941 : : }
3942 : :
3943 : : static gboolean
3944 : 4 : skip_missing_update_desktop_database (void)
3945 : : {
3946 : 4 : gchar *path = g_find_program_in_path ("update-desktop-database");
3947 : :
3948 : 4 : if (path == NULL)
3949 : : {
3950 : 0 : g_test_skip ("update-desktop-database is required to run this test");
3951 : 0 : return TRUE;
3952 : : }
3953 : 4 : g_free (path);
3954 : 4 : return FALSE;
3955 : : }
3956 : :
3957 : : static void
3958 : 1 : test_query_default_handler_uri (void)
3959 : : {
3960 : 1 : GError *error = NULL;
3961 : : GAppInfo *info;
3962 : : GAppInfo *default_info;
3963 : : GFile *file;
3964 : : GFile *invalid_file;
3965 : :
3966 : 1 : if (skip_missing_update_desktop_database ())
3967 : 0 : return;
3968 : :
3969 : 1 : info = create_command_line_app_info ("Gio File Handler", "true",
3970 : : "x-scheme-handler/gio-file");
3971 : 1 : g_assert_true (G_IS_APP_INFO (info));
3972 : :
3973 : 1 : file = g_file_new_for_uri ("gio-file://hello-gio!");
3974 : 1 : default_info = g_file_query_default_handler (file, NULL, &error);
3975 : 1 : g_assert_no_error (error);
3976 : 1 : g_assert_true (g_app_info_equal (default_info, info));
3977 : :
3978 : 1 : invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
3979 : 1 : g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
3980 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
3981 : 1 : g_clear_error (&error);
3982 : :
3983 : 1 : g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &error);
3984 : 1 : g_assert_no_error (error);
3985 : 1 : g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
3986 : :
3987 : 1 : g_object_unref (default_info);
3988 : 1 : g_object_unref (info);
3989 : 1 : g_object_unref (file);
3990 : 1 : g_object_unref (invalid_file);
3991 : : }
3992 : :
3993 : : static void
3994 : 1 : test_query_zero_length_content_type (void)
3995 : : {
3996 : : GFile *empty_file;
3997 : : GFileInfo *file_info;
3998 : 1 : GError *error = NULL;
3999 : : GFileIOStream *iostream;
4000 : :
4001 : 1 : g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=755795");
4002 : : /* Historically, GLib used to explicitly consider zero-size files as text/plain,
4003 : : * so they opened in a text editor. In 2.76, we changed that to application/x-zerosize,
4004 : : * because that’s what xdgmime uses:
4005 : : * - https://gitlab.gnome.org/GNOME/glib/-/blob/2.74.0/gio/glocalfileinfo.c#L1360-1369
4006 : : * - https://bugzilla.gnome.org/show_bug.cgi?id=755795
4007 : : * - https://gitlab.gnome.org/GNOME/glib/-/issues/2777
4008 : : */
4009 : 1 : g_test_summary ("empty files should always be considered application/x-zerosize");
4010 : :
4011 : 1 : empty_file = g_file_new_tmp ("empty-file-XXXXXX", &iostream, &error);
4012 : 1 : g_assert_no_error (error);
4013 : :
4014 : 1 : g_io_stream_close (G_IO_STREAM (iostream), NULL, &error);
4015 : 1 : g_assert_no_error (error);
4016 : 1 : g_clear_object (&iostream);
4017 : :
4018 : 1 : file_info =
4019 : 1 : g_file_query_info (empty_file,
4020 : : G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
4021 : : G_FILE_QUERY_INFO_NONE,
4022 : : NULL, &error);
4023 : 1 : g_assert_no_error (error);
4024 : :
4025 : : #ifndef __APPLE__
4026 : 1 : g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "application/x-zerosize");
4027 : : #else
4028 : : g_assert_cmpstr (g_file_info_get_content_type (file_info), ==, "public.text");
4029 : : #endif
4030 : :
4031 : 1 : g_clear_object (&file_info);
4032 : 1 : g_clear_object (&empty_file);
4033 : 1 : }
4034 : :
4035 : : static void
4036 : 1 : test_query_default_handler_file (void)
4037 : : {
4038 : 1 : GError *error = NULL;
4039 : : GAppInfo *info;
4040 : : GAppInfo *default_info;
4041 : : GFile *text_file;
4042 : : GFile *binary_file;
4043 : : GFile *invalid_file;
4044 : : GFileIOStream *iostream;
4045 : : GOutputStream *output_stream;
4046 : 1 : const char buffer[] = "Text file!\n";
4047 : 1 : const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
4048 : :
4049 : 1 : if (skip_missing_update_desktop_database ())
4050 : 0 : return;
4051 : :
4052 : 1 : text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
4053 : 1 : g_assert_no_error (error);
4054 : :
4055 : 1 : output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
4056 : 1 : g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
4057 : : NULL, NULL, &error);
4058 : 1 : g_assert_no_error (error);
4059 : :
4060 : 1 : g_output_stream_flush (output_stream, NULL, &error);
4061 : 1 : g_assert_no_error (error);
4062 : :
4063 : 1 : g_output_stream_close (output_stream, NULL, &error);
4064 : 1 : g_assert_no_error (error);
4065 : 1 : g_clear_object (&iostream);
4066 : :
4067 : 1 : info = create_command_line_app_info ("Text handler", "true", "text/plain");
4068 : 1 : g_assert_true (G_IS_APP_INFO (info));
4069 : :
4070 : 1 : default_info = g_file_query_default_handler (text_file, NULL, &error);
4071 : 1 : g_assert_no_error (error);
4072 : 1 : g_assert_true (g_app_info_equal (default_info, info));
4073 : :
4074 : 1 : invalid_file = g_file_new_for_path ("/hopefully/this-does-not-exists");
4075 : 1 : g_assert_null (g_file_query_default_handler (invalid_file, NULL, &error));
4076 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
4077 : 1 : g_clear_error (&error);
4078 : :
4079 : 1 : binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
4080 : 1 : g_assert_no_error (error);
4081 : :
4082 : 1 : output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
4083 : 1 : g_output_stream_write_all (output_stream, binary_buffer,
4084 : : G_N_ELEMENTS (binary_buffer),
4085 : : NULL, NULL, &error);
4086 : 1 : g_assert_no_error (error);
4087 : :
4088 : 1 : g_output_stream_flush (output_stream, NULL, &error);
4089 : 1 : g_assert_no_error (error);
4090 : :
4091 : 1 : g_output_stream_close (output_stream, NULL, &error);
4092 : 1 : g_assert_no_error (error);
4093 : 1 : g_clear_object (&iostream);
4094 : :
4095 : 1 : g_assert_null (g_file_query_default_handler (binary_file, NULL, &error));
4096 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
4097 : 1 : g_clear_error (&error);
4098 : :
4099 : 1 : g_app_info_remove_supports_type (info, "text/plain", &error);
4100 : 1 : g_assert_no_error (error);
4101 : 1 : g_app_info_reset_type_associations ("text/plain");
4102 : :
4103 : 1 : g_object_unref (default_info);
4104 : 1 : g_object_unref (info);
4105 : 1 : g_object_unref (text_file);
4106 : 1 : g_object_unref (binary_file);
4107 : 1 : g_object_unref (invalid_file);
4108 : : }
4109 : :
4110 : : typedef struct {
4111 : : GMainLoop *loop;
4112 : : GAppInfo *info;
4113 : : GError *error;
4114 : : } QueryDefaultHandlerData;
4115 : :
4116 : : static void
4117 : 7 : on_query_default (GObject *source,
4118 : : GAsyncResult *result,
4119 : : gpointer user_data)
4120 : : {
4121 : 7 : QueryDefaultHandlerData *data = user_data;
4122 : :
4123 : 7 : data->info = g_file_query_default_handler_finish (G_FILE (source), result,
4124 : : &data->error);
4125 : 7 : g_main_loop_quit (data->loop);
4126 : 7 : }
4127 : :
4128 : : static void
4129 : 1 : test_query_default_handler_file_async (void)
4130 : : {
4131 : 1 : QueryDefaultHandlerData data = {0};
4132 : : GCancellable *cancellable;
4133 : : GAppInfo *info;
4134 : : GFile *text_file;
4135 : : GFile *binary_file;
4136 : : GFile *invalid_file;
4137 : : GFileIOStream *iostream;
4138 : : GOutputStream *output_stream;
4139 : 1 : const char buffer[] = "Text file!\n";
4140 : 1 : const guint8 binary_buffer[] = "\xde\xad\xbe\xff";
4141 : 1 : GError *error = NULL;
4142 : :
4143 : 1 : if (skip_missing_update_desktop_database ())
4144 : 0 : return;
4145 : :
4146 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
4147 : :
4148 : 1 : text_file = g_file_new_tmp ("query-default-handler-XXXXXX", &iostream, &error);
4149 : 1 : g_assert_no_error (error);
4150 : :
4151 : 1 : output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
4152 : 1 : g_output_stream_write_all (output_stream, buffer, G_N_ELEMENTS (buffer) - 1,
4153 : : NULL, NULL, &error);
4154 : 1 : g_assert_no_error (error);
4155 : :
4156 : 1 : g_output_stream_close (output_stream, NULL, &error);
4157 : 1 : g_assert_no_error (error);
4158 : 1 : g_clear_object (&iostream);
4159 : :
4160 : 1 : info = create_command_line_app_info ("Text handler", "true", "text/plain");
4161 : 1 : g_assert_true (G_IS_APP_INFO (info));
4162 : :
4163 : 1 : g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
4164 : : NULL, on_query_default,
4165 : : &data);
4166 : 1 : g_main_loop_run (data.loop);
4167 : 1 : g_assert_no_error (data.error);
4168 : 1 : g_assert_true (g_app_info_equal (data.info, info));
4169 : 1 : g_clear_object (&data.info);
4170 : :
4171 : 1 : invalid_file = g_file_new_for_path ("/hopefully/this/.file/does-not-exists");
4172 : 1 : g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
4173 : : NULL, on_query_default,
4174 : : &data);
4175 : 1 : g_main_loop_run (data.loop);
4176 : 1 : g_assert_null (data.info);
4177 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND);
4178 : 1 : g_clear_error (&data.error);
4179 : :
4180 : 1 : cancellable = g_cancellable_new ();
4181 : 1 : g_file_query_default_handler_async (text_file, G_PRIORITY_DEFAULT,
4182 : : cancellable, on_query_default,
4183 : : &data);
4184 : 1 : g_cancellable_cancel (cancellable);
4185 : 1 : g_main_loop_run (data.loop);
4186 : 1 : g_assert_null (data.info);
4187 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
4188 : 1 : g_clear_error (&data.error);
4189 : :
4190 : 1 : binary_file = g_file_new_tmp ("query-default-handler-bin-XXXXXX", &iostream, &error);
4191 : 1 : g_assert_no_error (error);
4192 : :
4193 : 1 : output_stream = g_io_stream_get_output_stream (G_IO_STREAM (iostream));
4194 : 1 : g_output_stream_write_all (output_stream, binary_buffer,
4195 : : G_N_ELEMENTS (binary_buffer),
4196 : : NULL, NULL, &error);
4197 : 1 : g_assert_no_error (error);
4198 : :
4199 : 1 : g_output_stream_close (output_stream, NULL, &error);
4200 : 1 : g_assert_no_error (error);
4201 : 1 : g_clear_object (&iostream);
4202 : :
4203 : 1 : g_file_query_default_handler_async (binary_file, G_PRIORITY_DEFAULT,
4204 : : NULL, on_query_default,
4205 : : &data);
4206 : 1 : g_main_loop_run (data.loop);
4207 : 1 : g_assert_null (data.info);
4208 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
4209 : 1 : g_clear_error (&data.error);
4210 : :
4211 : 1 : g_app_info_remove_supports_type (info, "text/plain", &error);
4212 : 1 : g_assert_no_error (error);
4213 : 1 : g_app_info_reset_type_associations ("text/plain");
4214 : :
4215 : 1 : g_main_loop_unref (data.loop);
4216 : 1 : g_object_unref (info);
4217 : 1 : g_object_unref (text_file);
4218 : 1 : g_object_unref (binary_file);
4219 : 1 : g_object_unref (invalid_file);
4220 : : }
4221 : :
4222 : : static void
4223 : 1 : test_query_default_handler_uri_async (void)
4224 : : {
4225 : 1 : QueryDefaultHandlerData data = {0};
4226 : : GCancellable *cancellable;
4227 : : GAppInfo *info;
4228 : : GFile *file;
4229 : : GFile *invalid_file;
4230 : :
4231 : 1 : if (skip_missing_update_desktop_database ())
4232 : 0 : return;
4233 : :
4234 : 1 : info = create_command_line_app_info ("Gio File Handler", "true",
4235 : : "x-scheme-handler/gio-file");
4236 : 1 : g_assert_true (G_IS_APP_INFO (info));
4237 : :
4238 : 1 : data.loop = g_main_loop_new (NULL, FALSE);
4239 : :
4240 : 1 : file = g_file_new_for_uri ("gio-file://hello-gio!");
4241 : 1 : g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
4242 : : NULL, on_query_default,
4243 : : &data);
4244 : 1 : g_main_loop_run (data.loop);
4245 : 1 : g_assert_no_error (data.error);
4246 : 1 : g_assert_true (g_app_info_equal (data.info, info));
4247 : 1 : g_clear_object (&data.info);
4248 : :
4249 : 1 : invalid_file = g_file_new_for_uri ("gio-file-INVALID://goodbye-gio!");
4250 : 1 : g_file_query_default_handler_async (invalid_file, G_PRIORITY_DEFAULT,
4251 : : NULL, on_query_default,
4252 : : &data);
4253 : 1 : g_main_loop_run (data.loop);
4254 : 1 : g_assert_null (data.info);
4255 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
4256 : 1 : g_clear_error (&data.error);
4257 : :
4258 : 1 : cancellable = g_cancellable_new ();
4259 : 1 : g_file_query_default_handler_async (file, G_PRIORITY_DEFAULT,
4260 : : cancellable, on_query_default,
4261 : : &data);
4262 : 1 : g_cancellable_cancel (cancellable);
4263 : 1 : g_main_loop_run (data.loop);
4264 : 1 : g_assert_null (data.info);
4265 : 1 : g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
4266 : 1 : g_clear_error (&data.error);
4267 : :
4268 : 1 : g_app_info_remove_supports_type (info, "x-scheme-handler/gio-file", &data.error);
4269 : 1 : g_assert_no_error (data.error);
4270 : 1 : g_app_info_reset_type_associations ("x-scheme-handler/gio-file");
4271 : :
4272 : 1 : g_main_loop_unref (data.loop);
4273 : 1 : g_object_unref (info);
4274 : 1 : g_object_unref (file);
4275 : 1 : g_object_unref (invalid_file);
4276 : : }
4277 : :
4278 : : static void
4279 : 1 : test_enumerator_cancellation (void)
4280 : : {
4281 : : GCancellable *cancellable;
4282 : : GFileEnumerator *enumerator;
4283 : : GFileInfo *info;
4284 : : GFile *dir;
4285 : 1 : GError *error = NULL;
4286 : :
4287 : 1 : dir = g_file_new_for_path (g_get_tmp_dir ());
4288 : 1 : g_assert_nonnull (dir);
4289 : :
4290 : 1 : enumerator = g_file_enumerate_children (dir,
4291 : : G_FILE_ATTRIBUTE_STANDARD_NAME,
4292 : : G_FILE_QUERY_INFO_NONE,
4293 : : NULL,
4294 : : &error);
4295 : 1 : g_assert_nonnull (enumerator);
4296 : :
4297 : 1 : cancellable = g_cancellable_new ();
4298 : 1 : g_cancellable_cancel (cancellable);
4299 : 1 : info = g_file_enumerator_next_file (enumerator, cancellable, &error);
4300 : 1 : g_assert_null (info);
4301 : 1 : g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
4302 : :
4303 : 1 : g_error_free (error);
4304 : 1 : g_object_unref (cancellable);
4305 : 1 : g_object_unref (enumerator);
4306 : 1 : g_object_unref (dir);
4307 : 1 : }
4308 : :
4309 : : static void
4310 : 4 : test_path_from_uri_helper (const gchar *uri,
4311 : : const gchar *expected_path)
4312 : : {
4313 : : GFile *file;
4314 : : gchar *path;
4315 : : gchar *expected_platform_path;
4316 : :
4317 : 4 : expected_platform_path = g_strdup (expected_path);
4318 : : #ifdef G_OS_WIN32
4319 : : for (gchar *p = expected_platform_path; *p; p++)
4320 : : {
4321 : : if (*p == '/')
4322 : : *p = '\\';
4323 : : }
4324 : : #endif
4325 : :
4326 : 4 : file = g_file_new_for_uri (uri);
4327 : 4 : path = g_file_get_path (file);
4328 : 4 : g_assert_cmpstr (path, ==, expected_platform_path);
4329 : 4 : g_free (path);
4330 : 4 : g_object_unref (file);
4331 : 4 : g_free (expected_platform_path);
4332 : 4 : }
4333 : :
4334 : : static void
4335 : 1 : test_from_uri_ignores_fragment (void)
4336 : : {
4337 : 1 : test_path_from_uri_helper ("file:///tmp/foo#bar", "/tmp/foo");
4338 : 1 : test_path_from_uri_helper ("file:///tmp/foo#bar?baz", "/tmp/foo");
4339 : 1 : }
4340 : :
4341 : : static void
4342 : 1 : test_from_uri_ignores_query_string (void)
4343 : : {
4344 : 1 : test_path_from_uri_helper ("file:///tmp/foo?bar", "/tmp/foo");
4345 : 1 : test_path_from_uri_helper ("file:///tmp/foo?bar#baz", "/tmp/foo");
4346 : 1 : }
4347 : :
4348 : : int
4349 : 1 : main (int argc, char *argv[])
4350 : : {
4351 : 1 : setlocale (LC_ALL, "");
4352 : :
4353 : 1 : g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
4354 : :
4355 : 1 : g_test_add_func ("/file/basic", test_basic);
4356 : 1 : g_test_add_func ("/file/build-filename", test_build_filename);
4357 : 1 : g_test_add_func ("/file/build-filenamev", test_build_filenamev);
4358 : 1 : g_test_add_func ("/file/parent", test_parent);
4359 : 1 : g_test_add_func ("/file/child", test_child);
4360 : 1 : g_test_add_func ("/file/empty-path", test_empty_path);
4361 : 1 : g_test_add_func ("/file/type", test_type);
4362 : 1 : g_test_add_func ("/file/parse-name", test_parse_name);
4363 : 1 : g_test_add_data_func ("/file/async-create-delete/0", GINT_TO_POINTER (0), test_create_delete);
4364 : 1 : g_test_add_data_func ("/file/async-create-delete/1", GINT_TO_POINTER (1), test_create_delete);
4365 : 1 : g_test_add_data_func ("/file/async-create-delete/10", GINT_TO_POINTER (10), test_create_delete);
4366 : 1 : g_test_add_data_func ("/file/async-create-delete/25", GINT_TO_POINTER (25), test_create_delete);
4367 : 1 : g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
4368 : 1 : g_test_add_func ("/file/replace-load", test_replace_load);
4369 : 1 : g_test_add_func ("/file/replace-cancel", test_replace_cancel);
4370 : 1 : g_test_add_func ("/file/replace-symlink", test_replace_symlink);
4371 : 1 : g_test_add_func ("/file/replace-symlink/using-etag", test_replace_symlink_using_etag);
4372 : 1 : g_test_add_data_func ("/file/replace/write-only", GUINT_TO_POINTER (FALSE), test_replace);
4373 : 1 : g_test_add_data_func ("/file/replace/read-write", GUINT_TO_POINTER (TRUE), test_replace);
4374 : 1 : g_test_add_func ("/file/async-new-tmp", test_async_new_tmp);
4375 : 1 : g_test_add_func ("/file/async-new-tmp-dir", test_async_new_tmp_dir);
4376 : 1 : g_test_add_func ("/file/async-delete", test_async_delete);
4377 : 1 : g_test_add_func ("/file/async-make-symlink", test_async_make_symlink);
4378 : 1 : g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
4379 : 1 : g_test_add_func ("/file/copy/progress", test_copy_progress);
4380 : 1 : g_test_add_func ("/file/copy-async-with-closures", test_copy_async_with_closures);
4381 : 1 : g_test_add_func ("/file/measure", test_measure);
4382 : 1 : g_test_add_func ("/file/measure-async", test_measure_async);
4383 : 1 : g_test_add_func ("/file/load-bytes", test_load_bytes);
4384 : 1 : g_test_add_func ("/file/load-bytes-async", test_load_bytes_async);
4385 : 1 : g_test_add_func ("/file/load-bytes-4gb", test_load_bytes_4gb);
4386 : 1 : g_test_add_func ("/file/load-contents-4gb", test_load_contents_4gb);
4387 : 1 : g_test_add_func ("/file/load-contents-4gb-async", test_load_contents_4gb_async);
4388 : 1 : g_test_add_func ("/file/writev", test_writev);
4389 : 1 : g_test_add_func ("/file/writev/no-bytes-written", test_writev_no_bytes_written);
4390 : 1 : g_test_add_func ("/file/writev/no-vectors", test_writev_no_vectors);
4391 : 1 : g_test_add_func ("/file/writev/empty-vectors", test_writev_empty_vectors);
4392 : 1 : g_test_add_func ("/file/writev/too-big-vectors", test_writev_too_big_vectors);
4393 : 1 : g_test_add_func ("/file/writev/async", test_writev_async);
4394 : 1 : g_test_add_func ("/file/writev/async_all", test_writev_async_all);
4395 : 1 : g_test_add_func ("/file/writev/async_all-empty-vectors", test_writev_async_all_empty_vectors);
4396 : 1 : g_test_add_func ("/file/writev/async_all-no-vectors", test_writev_async_all_no_vectors);
4397 : 1 : g_test_add_func ("/file/writev/async_all-to-big-vectors", test_writev_async_all_too_big_vectors);
4398 : 1 : g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
4399 : 1 : g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
4400 : 1 : g_test_add_func ("/file/move_async", test_move_async);
4401 : 1 : g_test_add_func ("/file/move-async-with-closures", test_move_async_with_closures);
4402 : 1 : g_test_add_func ("/file/query-zero-length-content-type", test_query_zero_length_content_type);
4403 : 1 : g_test_add_func ("/file/query-default-handler-file", test_query_default_handler_file);
4404 : 1 : g_test_add_func ("/file/query-default-handler-file-async", test_query_default_handler_file_async);
4405 : 1 : g_test_add_func ("/file/query-default-handler-uri", test_query_default_handler_uri);
4406 : 1 : g_test_add_func ("/file/query-default-handler-uri-async", test_query_default_handler_uri_async);
4407 : 1 : g_test_add_func ("/file/enumerator-cancellation", test_enumerator_cancellation);
4408 : 1 : g_test_add_func ("/file/from-uri/ignores-query-string", test_from_uri_ignores_query_string);
4409 : 1 : g_test_add_func ("/file/from-uri/ignores-fragment", test_from_uri_ignores_fragment);
4410 : :
4411 : 1 : return g_test_run ();
4412 : : }
4413 : :
|