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