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