1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 *
3 * Copyright (C) 2012 William Jon McCann <mccann@redhat.com>
4 * Copyright (C) 2012 Colin Walters <walters@verbum.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "config.h"
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE
26 #endif
27
28 #include <string.h>
29
30 #define _GSYSTEM_NO_LOCAL_ALLOC
31 #include "libgsystem.h"
32 #include "gsystem-glib-compat.h"
33 #include <glib/gstdio.h>
34 #include <gio/gunixinputstream.h>
35 #include <gio/gfiledescriptorbased.h>
36 #include <gio/gunixoutputstream.h>
37 #include <glib-unix.h>
38 #include <limits.h>
39 #include <dirent.h>
40
41 static int
42 close_nointr (int fd)
43 {
44 int res;
45 /* Note this is NOT actually a retry loop.
46 * See: https://bugzilla.gnome.org/show_bug.cgi?id=682819
47 */
48 res = close (fd);
49 /* Just ignore EINTR...on Linux, retrying is wrong. */
50 if (res == EINTR)
51 res = 0;
52 return res;
53 }
54
55 static void
56 close_nointr_noerror (int fd)
57 {
58 (void) close_nointr (fd);
59 }
60
61 static int
62 open_nointr (const char *path, int flags, mode_t mode)
63 {
64 int res;
65 do
(1) Event open_fn: |
Returning handle opened by function "open(char const *, int, ...)". |
(2) Event var_assign: |
Assigning: "res" = "open(path, flags, mode)". |
Also see events: |
[return_handle] |
66 res = open (path, flags, mode);
(3) Event cond_true: |
Condition "res != 0", taking true branch |
(4) Event cond_true: |
Condition "*__errno_location() == 4", taking true branch |
(5) Event if_fallthrough: |
Falling through to end of if statement |
(6) Event if_end: |
End of if statement |
(7) Event cond_false: |
Condition "({...})", taking false branch |
67 while (G_UNLIKELY (res != 0 && errno == EINTR));
(8) Event return_handle: |
Returning opened handle "res". |
Also see events: |
[open_fn][var_assign] |
68 return res;
69 }
70
71 static int
72 _open_fd_noatime (const char *path)
73 {
74 int fd;
75
76 #ifdef O_NOATIME
77 fd = open_nointr (path, O_RDONLY | O_NOATIME, 0);
78 /* Only the owner or superuser may use O_NOATIME; so we may get
79 * EPERM. EINVAL may happen if the kernel is really old...
80 */
81 if (fd == -1 && (errno == EPERM || errno == EINVAL))
82 #endif
83 fd = open_nointr (path, O_RDONLY, 0);
84
85 return fd;
86 }
87
88 static inline void
89 _set_error_from_errno (GError **error)
90 {
91 int errsv = errno;
92 g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
93 g_strerror (errsv));
94 }
95
96 /**
97 * gs_file_read_noatime:
98 * @file: a #GFile
99 * @cancellable: a #GCancellable
100 * @error: a #GError
101 *
102 * Like g_file_read(), but try to avoid updating the file's
103 * access time. This should be used by background scanning
104 * components such as search indexers, antivirus programs, etc.
105 *
106 * Returns: (transfer full): A new input stream, or %NULL on error
107 */
108 GInputStream *
109 gs_file_read_noatime (GFile *file,
110 GCancellable *cancellable,
111 GError **error)
112 {
113 const char *path = NULL;
114 int fd;
115
116 if (g_cancellable_set_error_if_cancelled (cancellable, error))
117 return NULL;
118
119 path = gs_file_get_path_cached (file);
120 if (path == NULL)
121 return NULL;
122
123 fd = _open_fd_noatime (path);
124 if (fd < 0)
125 {
126 _set_error_from_errno (error);
127 return NULL;
128 }
129
130 return g_unix_input_stream_new (fd, TRUE);
131 }
132
133 /**
134 * gs_stream_fstat:
135 * @stream: A stream containing a Unix file descriptor
136 * @stbuf: Memory location to write stat buffer
137 * @cancellable:
138 * @error:
139 *
140 * Some streams created via libgsystem are #GUnixInputStream; these do
141 * not support e.g. g_file_input_stream_query_info(). This function
142 * allows dropping to the raw unix fstat() call for these types of
143 * streams, while still conveniently wrapped with the normal GLib
144 * handling of @cancellable and @error.
145 */
146 gboolean
147 gs_stream_fstat (GFileDescriptorBased *stream,
148 struct stat *stbuf,
149 GCancellable *cancellable,
150 GError **error)
151 {
152 gboolean ret = FALSE;
153 int fd;
154
155 if (g_cancellable_set_error_if_cancelled (cancellable, error))
156 goto out;
157
158 fd = g_file_descriptor_based_get_fd (stream);
159
160 if (fstat (fd, stbuf) == -1)
161 {
162 _set_error_from_errno (error);
163 goto out;
164 }
165
166 ret = TRUE;
167 out:
168 return ret;
169 }
170
171 /**
172 * gs_file_map_noatime: (skip)
173 * @file: a #GFile
174 * @cancellable: a #GCancellable
175 * @error: a #GError
176 *
177 * Like g_mapped_file_new(), but try to avoid updating the file's
178 * access time. This should be used by background scanning
179 * components such as search indexers, antivirus programs, etc.
180 *
181 * Returns: (transfer full): A new mapped file, or %NULL on error
182 */
183 GMappedFile *
184 gs_file_map_noatime (GFile *file,
185 GCancellable *cancellable,
186 GError **error)
187 {
188 const char *path;
189 int fd;
190 GMappedFile *ret;
191
192 if (g_cancellable_set_error_if_cancelled (cancellable, error))
193 return NULL;
194
195 path = gs_file_get_path_cached (file);
196 if (path == NULL)
197 return NULL;
198
199 fd = _open_fd_noatime (path);
200 if (fd < 0)
201 {
202 _set_error_from_errno (error);
203 return NULL;
204 }
205
206 ret = g_mapped_file_new_from_fd (fd, FALSE, error);
207 close_nointr_noerror (fd); /* Ignore errors - we always want to close */
208
209 return ret;
210 }
211
212 #if GLIB_CHECK_VERSION(2,34,0)
213 /**
214 * gs_file_map_readonly:
215 * @file: a #GFile
216 * @cancellable:
217 * @error:
218 *
219 * Return a #GBytes which references a readonly view of the contents of
220 * @file. This function uses #GMappedFile internally.
221 *
222 * Returns: (transfer full): a newly referenced #GBytes
223 */
224 GBytes *
225 gs_file_map_readonly (GFile *file,
226 GCancellable *cancellable,
227 GError **error)
228 {
229 GMappedFile *mfile;
230 GBytes *ret;
231
232 if (g_cancellable_set_error_if_cancelled (cancellable, error))
233 return NULL;
234
235 mfile = g_mapped_file_new (gs_file_get_path_cached (file), FALSE, error);
236 if (!mfile)
237 return NULL;
238
239 ret = g_mapped_file_get_bytes (mfile);
240 g_mapped_file_unref (mfile);
241 return ret;
242 }
243 #endif
244
245 /**
246 * gs_file_sync_data:
247 * @file: a #GFile
248 * @cancellable:
249 * @error:
250 *
251 * Wraps the UNIX fdatasync() function, which ensures that the data in
252 * @file is on non-volatile storage.
253 */
254 gboolean
255 gs_file_sync_data (GFile *file,
256 GCancellable *cancellable,
257 GError **error)
258 {
259 gboolean ret = FALSE;
260 int res;
261 int fd = -1;
262
263 fd = _open_fd_noatime (gs_file_get_path_cached (file));
264 if (fd < 0)
265 {
266 _set_error_from_errno (error);
267 goto out;
268 }
269
270 do
271 res = fdatasync (fd);
272 while (G_UNLIKELY (res != 0 && errno == EINTR));
273 if (res != 0)
274 {
275 _set_error_from_errno (error);
276 goto out;
277 }
278
279 res = close_nointr (fd);
280 if (res != 0)
281 {
282 _set_error_from_errno (error);
283 goto out;
284 }
285 fd = -1;
286
287 ret = TRUE;
288 out:
289 if (fd != -1)
290 close_nointr_noerror (fd);
291 return ret;
292 }
293
294 /**
295 * gs_file_create_with_uidgid:
296 * @file: Path of file to create
297 * @mode: Unix mode
298 * @uid: Unix uid
299 * @gid: Unix gid
300 * @out_stream: (out) (transfer full) (allow-none): Output stream connected to file descriptor
301 * @cancellable: a #GCancellable
302 * @error: a #GError
303 *
304 * Create @file exclusively; it must not exist already. Ensure the
305 * returned file has mode @mode and has Unix owners corresponding to
306 * the parameters @uid and @gid.
307 *
308 * The parameter @out_stream if provided, will be filled in with a
309 * #GOutputStream connected to the file.
310 *
311 * Returns: %TRUE on success, %FALSE on error.
312 */
313 gboolean
314 gs_file_create_with_uidgid (GFile *file,
315 int mode,
316 uid_t uid,
317 gid_t gid,
318 GOutputStream **out_stream,
319 GCancellable *cancellable,
320 GError **error)
321 {
322 gboolean ret = FALSE;
323 int fd;
324 GOutputStream *ret_stream = NULL;
325 static gsize uidgid_cached;
326 static uid_t myuid;
327 static uid_t mygid;
328
329 /* Ok yes this is lame, but calling these two over and over shows up
330 * in strace. I like my straces to be clean, shoot me.
331 */
332 if (g_once_init_enter (&uidgid_cached))
333 {
334 myuid = getuid ();
335 mygid = getgid ();
336 g_once_init_leave (&uidgid_cached, 1);
337 }
338
339 fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode);
340 if (fd < 0)
341 {
342 _set_error_from_errno (error);
343 goto out;
344 }
345
346 if (uid != myuid || gid != mygid)
347 {
348 if (fchown (fd, uid, gid) < 0)
349 {
350 _set_error_from_errno (error);
351 goto out;
352 }
353 }
354
355 if (fchmod (fd, mode) < 0)
356 {
357 _set_error_from_errno (error);
358 goto out;
359 }
360
361 ret_stream = g_unix_output_stream_new (fd, TRUE);
362
363 ret = TRUE;
364 gs_transfer_out_value (out_stream, &ret_stream);
365 out:
366 g_clear_object (&ret_stream);
367 return ret;
368 }
369
370 /**
371 * gs_file_create:
372 * @file: Path to non-existent file
373 * @mode: Unix access permissions
374 * @out_stream: (out) (transfer full) (allow-none): Newly created output, or %NULL
375 * @cancellable: a #GCancellable
376 * @error: a #GError
377 *
378 * Like g_file_create(), except this function allows specifying the
379 * access mode. This allows atomically creating private files.
380 */
381 gboolean
382 gs_file_create (GFile *file,
383 int mode,
384 GOutputStream **out_stream,
385 GCancellable *cancellable,
386 GError **error)
387 {
388 gboolean ret = FALSE;
389 int fd;
390 GOutputStream *ret_stream = NULL;
391
(1) Event open_fn: |
Returning handle opened by function "open_nointr(char const *, int, mode_t)". [details] |
(2) Event var_assign: |
Assigning: "fd" = handle returned from "open_nointr(gs_file_get_path_cached(file), 193, mode)". |
Also see events: |
[leaked_handle] |
392 fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode);
(3) Event cond_false: |
Condition "fd < 0", taking false branch |
393 if (fd < 0)
394 {
395 _set_error_from_errno (error);
396 goto out;
(4) Event if_end: |
End of if statement |
397 }
398
(5) Event cond_true: |
Condition "fchmod(fd, mode) < 0", taking true branch |
399 if (fchmod (fd, mode) < 0)
400 {
401 _set_error_from_errno (error);
(6) Event goto: |
Jumping to label "out" |
402 goto out;
403 }
404
405 ret_stream = g_unix_output_stream_new (fd, TRUE);
406
407 ret = TRUE;
408 gs_transfer_out_value (out_stream, &ret_stream);
(7) Event label: |
Reached label "out" |
409 out:
(8) Event cond_false: |
Condition "0", taking false branch |
(9) Event cond_false: |
Condition "0", taking false branch |
(10) Event cond_true: |
Condition "!({...})", taking true branch |
(11) Event if_fallthrough: |
Falling through to end of if statement |
(12) Event if_end: |
End of if statement |
(13) Event cond_false: |
Condition "({...})", taking false branch |
(14) Event cond_true: |
Condition "_p", taking true branch |
410 g_clear_object (&ret_stream);
(15) Event leaked_handle: |
Handle variable "fd" going out of scope leaks the handle. |
Also see events: |
[open_fn][var_assign] |
411 return ret;
412 }
413
414 static const char *
415 get_default_tmp_prefix (void)
416 {
417 static char *tmpprefix = NULL;
418
419 if (g_once_init_enter (&tmpprefix))
420 {
421 const char *prgname = g_get_prgname ();
422 const char *p;
423 char *prefix;
424
425 p = strrchr (prgname, '/');
426 if (p)
427 prgname = p + 1;
428
429 prefix = g_strdup_printf ("tmp-%s%u-", prgname, getuid ());
430
431 g_once_init_leave (&tmpprefix, prefix);
432 }
433
434 return tmpprefix;
435 }
436
437 /**
438 * gsystem_fileutil_gen_tmp_name:
439 * @prefix: (allow-none): String prepended to the result
440 * @suffix: (allow-none): String suffixed to the result
441 *
442 * Generate a name suitable for use as a temporary file. This
443 * function does no I/O; it is not guaranteed that a file with that
444 * name does not exist.
445 */
446 char *
447 gsystem_fileutil_gen_tmp_name (const char *prefix,
448 const char *suffix)
449 {
450 static const char table[] = "ABCEDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789";
451 GString *str = g_string_new ("");
452 guint i;
453
454 if (!prefix)
455 prefix = get_default_tmp_prefix ();
456 if (!suffix)
457 suffix = "tmp";
458
459 g_string_append (str, prefix);
460 for (i = 0; i < 8; i++)
461 {
462 int offset = g_random_int_range (0, sizeof (table) - 1);
463 g_string_append_c (str, (guint8)table[offset]);
464 }
465 g_string_append_c (str, '.');
466 g_string_append (str, suffix);
467
468 return g_string_free (str, FALSE);
469 }
470
471 /**
472 * gs_file_open_in_tmpdir:
473 * @tmpdir: Directory to place temporary file
474 * @mode: Default mode (will be affected by umask)
475 * @out_file: (out) (transfer full): Newly created file path
476 * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
477 * @cancellable:
478 * @error:
479 *
480 * Like g_file_open_tmp(), except the file will be created in the
481 * provided @tmpdir, and allows specification of the Unix @mode, which
482 * means private files may be created. Return values will be stored
483 * in @out_file, and optionally @out_stream.
484 */
485 gboolean
486 gs_file_open_in_tmpdir (GFile *tmpdir,
487 int mode,
488 GFile **out_file,
489 GOutputStream **out_stream,
490 GCancellable *cancellable,
491 GError **error)
492 {
493 gboolean ret = FALSE;
494 const int max_attempts = 128;
495 guint i;
496 DIR *d = NULL;
497 int dfd = -1;
498 char *tmp_name = NULL;
499 int fd;
500
501 d = opendir (gs_file_get_path_cached (tmpdir));
502 if (!d)
503 {
504 _set_error_from_errno (error);
505 goto out;
506 }
507 dfd = dirfd (d);
508
509 /* 128 attempts seems reasonable... */
510 for (i = 0; i < max_attempts; i++)
511 {
512 g_free (tmp_name);
513 tmp_name = gsystem_fileutil_gen_tmp_name (NULL, NULL);
514
515 do
516 fd = openat (dfd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode);
517 while (fd == -1 && errno == EINTR);
518 if (fd < 0 && errno != EEXIST)
519 {
520 _set_error_from_errno (error);
521 goto out;
522 }
523 break;
524 }
525 if (i == max_attempts)
526 {
527 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
528 "Exhausted attempts to open temporary file");
529 goto out;
530 }
531
532 ret = TRUE;
533 *out_file = g_file_get_child (tmpdir, tmp_name);
534 if (out_stream)
535 *out_stream = g_unix_output_stream_new (fd, TRUE);
536 out:
537 if (d) (void) closedir (d);
538 return ret;
539 }
540
541 static gboolean
542 linkcopy_internal_attempt (GFile *src,
543 GFile *dest,
544 GFile *dest_parent,
545 GFileCopyFlags flags,
546 gboolean sync_data,
547 gboolean enable_guestfs_fuse_workaround,
548 gboolean *out_try_again,
549 GCancellable *cancellable,
550 GError **error)
551 {
552 gboolean ret = FALSE;
553 int res;
554 char *tmp_name = NULL;
555 GFile *tmp_dest = NULL;
556
557 if (g_cancellable_set_error_if_cancelled (cancellable, error))
558 goto out;
559
560 tmp_name = gsystem_fileutil_gen_tmp_name (NULL, NULL);
561 tmp_dest = g_file_get_child (dest_parent, tmp_name);
562
563 res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest));
564 if (res == -1)
565 {
566 if (errno == EEXIST)
567 {
568 /* Nothing, fall through */
569 *out_try_again = TRUE;
570 ret = TRUE;
571 goto out;
572 }
573 else if (errno == EXDEV || errno == EMLINK || errno == EPERM
574 || (enable_guestfs_fuse_workaround && errno == ENOENT))
575 {
576 if (!g_file_copy (src, tmp_dest, flags,
577 cancellable, NULL, NULL, error))
578 goto out;
579 }
580 else
581 {
582 _set_error_from_errno (error);
583 goto out;
584 }
585 }
586
587 if (sync_data)
588 {
589 /* Now, we need to fdatasync */
590 if (!gs_file_sync_data (tmp_dest, cancellable, error))
591 goto out;
592 }
593
594 if (!gs_file_rename (tmp_dest, dest, cancellable, error))
595 goto out;
596
597 ret = TRUE;
598 *out_try_again = FALSE;
599 out:
600 g_clear_pointer (&tmp_name, g_free);
601 g_clear_object (&tmp_dest);
602 return ret;
603 }
604
605 static gboolean
606 linkcopy_internal (GFile *src,
607 GFile *dest,
608 GFileCopyFlags flags,
609 gboolean sync_data,
610 GCancellable *cancellable,
611 GError **error)
612 {
613 gboolean ret = FALSE;
614 gboolean dest_exists;
615 int i;
616 gboolean enable_guestfs_fuse_workaround;
617 struct stat src_stat;
618 struct stat dest_stat;
619 GFile *dest_parent = NULL;
620
621 flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS;
622
623 g_return_val_if_fail ((flags & (G_FILE_COPY_BACKUP | G_FILE_COPY_TARGET_DEFAULT_PERMS)) == 0, FALSE);
624
625 dest_parent = g_file_get_parent (dest);
626
627 if (lstat (gs_file_get_path_cached (src), &src_stat) == -1)
628 {
629 int errsv = errno;
630 g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
631 g_strerror (errsv));
632 goto out;
633 }
634
635 if (lstat (gs_file_get_path_cached (dest), &dest_stat) == -1)
636 dest_exists = FALSE;
637 else
638 dest_exists = TRUE;
639
640 if (((flags & G_FILE_COPY_OVERWRITE) == 0) && dest_exists)
641 {
642 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
643 "File exists");
644 goto out;
645 }
646
647 /* Work around the behavior of link() where it's a no-op if src and
648 * dest are the same.
649 */
650 if (dest_exists &&
651 src_stat.st_dev == dest_stat.st_dev &&
652 src_stat.st_ino == dest_stat.st_ino)
653 {
654 ret = TRUE;
655 goto out;
656 }
657
658 enable_guestfs_fuse_workaround = getenv ("LIBGSYSTEM_ENABLE_GUESTFS_FUSE_WORKAROUND") != NULL;
659
660 /* 128 attempts seems reasonable... */
661 for (i = 0; i < 128; i++)
662 {
663 gboolean tryagain = FALSE;
664
665 if (!linkcopy_internal_attempt (src, dest, dest_parent,
666 flags, sync_data,
667 enable_guestfs_fuse_workaround,
668 &tryagain,
669 cancellable, error))
670 goto out;
671
672 if (!tryagain)
673 break;
674 }
675
676 ret = TRUE;
677 out:
678 g_clear_object (&dest_parent);
679 return ret;
680
681 }
682
683 /**
684 * gs_file_linkcopy:
685 * @src: Source file
686 * @dest: Destination file
687 * @flags: flags
688 * @cancellable:
689 * @error:
690 *
691 * First tries to use the UNIX link() call, but if the files are on
692 * separate devices, fall back to copying via g_file_copy().
693 *
694 * The given @flags have different semantics than those documented
695 * when hardlinking is used. Specifically, both
696 * #G_FILE_COPY_TARGET_DEFAULT_PERMS and #G_FILE_COPY_BACKUP are not
697 * supported. #G_FILE_COPY_NOFOLLOW_SYMLINKS treated as if it was
698 * always given - if you want to follow symbolic links, you will need
699 * to resolve them manually.
700 *
701 * Beware - do not use this function if @src may be modified, and it's
702 * undesirable for the changes to also be reflected in @dest. The
703 * best use of this function is in the case where @src and @dest are
704 * read-only, or where @src is a temporary file, and you want to put
705 * it in the final place.
706 */
707 gboolean
708 gs_file_linkcopy (GFile *src,
709 GFile *dest,
710 GFileCopyFlags flags,
711 GCancellable *cancellable,
712 GError **error)
713 {
714 return linkcopy_internal (src, dest, flags, FALSE, cancellable, error);
715 }
716
717 /**
718 * gs_file_linkcopy_sync_data:
719 * @src: Source file
720 * @dest: Destination file
721 * @flags: flags
722 * @cancellable:
723 * @error:
724 *
725 * This function is similar to gs_file_linkcopy(), except it also uses
726 * gs_file_sync_data() to ensure that @dest is in stable storage
727 * before it is moved into place.
728 */
729 gboolean
730 gs_file_linkcopy_sync_data (GFile *src,
731 GFile *dest,
732 GFileCopyFlags flags,
733 GCancellable *cancellable,
734 GError **error)
735 {
736 return linkcopy_internal (src, dest, flags, TRUE, cancellable, error);
737 }
738
739 /**
740 * gs_file_get_path_cached:
741 *
742 * Like g_file_get_path(), but returns a constant copy so callers
743 * don't need to free the result.
744 */
745 const char *
746 gs_file_get_path_cached (GFile *file)
747 {
748 const char *path;
749 static GQuark _file_path_quark = 0;
750
751 if (G_UNLIKELY (_file_path_quark) == 0)
752 _file_path_quark = g_quark_from_static_string ("gsystem-file-path");
753
754 path = g_object_get_qdata ((GObject*)file, _file_path_quark);
755 if (!path)
756 {
757 path = g_file_get_path (file);
758 g_assert (path != NULL);
759 g_object_set_qdata_full ((GObject*)file, _file_path_quark, (char*)path, (GDestroyNotify)g_free);
760 }
761 return path;
762 }
763
764 /**
765 * gs_file_get_basename_cached:
766 *
767 * Like g_file_get_basename(), but returns a constant copy so callers
768 * don't need to free the result.
769 */
770 const char *
771 gs_file_get_basename_cached (GFile *file)
772 {
773 const char *name;
774 static GQuark _file_name_quark = 0;
775
776 if (G_UNLIKELY (_file_name_quark) == 0)
777 _file_name_quark = g_quark_from_static_string ("gsystem-file-name");
778
779 name = g_object_get_qdata ((GObject*)file, _file_name_quark);
780 if (!name)
781 {
782 name = g_file_get_basename (file);
783 g_object_set_qdata_full ((GObject*)file, _file_name_quark, (char*)name, (GDestroyNotify)g_free);
784 }
785 return name;
786 }
787
788 /**
789 * gs_file_enumerator_iterate:
790 * @direnum: an open #GFileEnumerator
791 * @out_info: (out) (transfer none) (allow-none): Output location for the next #GFileInfo
792 * @out_child: (out) (transfer none) (allow-none): Output location for the next #GFile, or %NULL
793 * @cancellable: a #GCancellable
794 * @error: a #GError
795 *
796 * This is a version of g_file_enumerator_next_file() that's easier to
797 * use correctly from C programs. With g_file_enumerator_next_file(),
798 * the gboolean return value signifies "end of iteration or error", which
799 * requires allocation of a temporary #GError.
800 *
801 * In contrast, with this function, a %FALSE return from
802 * gs_file_enumerator_iterate() <emphasis>always</emphasis> means
803 * "error". End of iteration is signaled by @out_info being %NULL.
804 *
805 * Another crucial difference is that the references for @out_info and
806 * @out_child are owned by @direnum (they are cached as hidden
807 * properties). You must not unref them in your own code. This makes
808 * memory management significantly easier for C code in combination
809 * with loops.
810 *
811 * Finally, this function optionally allows retrieving a #GFile as
812 * well.
813 *
814 * The code pattern for correctly using gs_file_enumerator_iterate() from C
815 * is:
816 *
817 * |[
818 * direnum = g_file_enumerate_children (file, ...);
819 * while (TRUE)
820 * {
821 * GFileInfo *info;
822 * if (!gs_file_enumerator_iterate (direnum, &info, NULL, cancellable, error))
823 * goto out;
824 * if (!info)
825 * break;
826 * ... do stuff with "info"; do not unref it! ...
827 * }
828 *
829 * out:
830 * g_object_unref (direnum); // Note: frees the last @info
831 * ]|
832 */
833 gboolean
834 gs_file_enumerator_iterate (GFileEnumerator *direnum,
835 GFileInfo **out_info,
836 GFile **out_child,
837 GCancellable *cancellable,
838 GError **error)
839 {
840 gboolean ret = FALSE;
841 GError *temp_error = NULL;
842
843 static GQuark cached_info_quark;
844 static GQuark cached_child_quark;
845 static gsize quarks_initialized;
846
847 g_return_val_if_fail (direnum != NULL, FALSE);
848 g_return_val_if_fail (out_info != NULL, FALSE);
849
850 if (g_once_init_enter (&quarks_initialized))
851 {
852 cached_info_quark = g_quark_from_static_string ("gsystem-cached-info");
853 cached_child_quark = g_quark_from_static_string ("gsystem-cached-child");
854 g_once_init_leave (&quarks_initialized, 1);
855 }
856
857
858 *out_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
859 if (out_child)
860 *out_child = NULL;
861 if (temp_error != NULL)
862 {
863 g_propagate_error (error, temp_error);
864 goto out;
865 }
866 else if (*out_info != NULL)
867 {
868 g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, *out_info, (GDestroyNotify)g_object_unref);
869 if (out_child != NULL)
870 {
871 const char *name = g_file_info_get_name (*out_info);
872 *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
873 g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
874 }
875 }
876
877 ret = TRUE;
878 out:
879 return ret;
880 }
881
882 /**
883 * gs_file_rename:
884 * @from: Current path
885 * @to: New path
886 * @cancellable: a #GCancellable
887 * @error: a #GError
888 *
889 * This function wraps the raw Unix function rename().
890 *
891 * Returns: %TRUE on success, %FALSE on error
892 */
893 gboolean
894 gs_file_rename (GFile *from,
895 GFile *to,
896 GCancellable *cancellable,
897 GError **error)
898 {
899 if (g_cancellable_set_error_if_cancelled (cancellable, error))
900 return FALSE;
901
902 if (rename (gs_file_get_path_cached (from),
903 gs_file_get_path_cached (to)) < 0)
904 {
905 _set_error_from_errno (error);
906 return FALSE;
907 }
908 return TRUE;
909 }
910
911 /**
912 * gs_file_unlink:
913 * @path: Path to file
914 * @cancellable: a #GCancellable
915 * @error: a #GError
916 *
917 * Like g_file_delete(), except this function does not follow Unix
918 * symbolic links, and will delete a symbolic link even if it's
919 * pointing to a nonexistent file. In other words, this function
920 * merely wraps the raw Unix function unlink().
921 *
922 * Returns: %TRUE on success, %FALSE on error
923 */
924 gboolean
925 gs_file_unlink (GFile *path,
926 GCancellable *cancellable,
927 GError **error)
928 {
929 if (g_cancellable_set_error_if_cancelled (cancellable, error))
930 return FALSE;
931
932 if (unlink (gs_file_get_path_cached (path)) < 0)
933 {
934 _set_error_from_errno (error);
935 return FALSE;
936 }
937 return TRUE;
938 }
939
940 /**
941 * gs_file_chown:
942 * @path: Path to file
943 * @owner: UNIX owner
944 * @group: UNIX group
945 * @cancellable: a #GCancellable
946 * @error: a #GError
947 *
948 * Merely wraps UNIX chown().
949 *
950 * Returns: %TRUE on success, %FALSE on error
951 */
952 gboolean
953 gs_file_chown (GFile *path,
954 guint32 owner,
955 guint32 group,
956 GCancellable *cancellable,
957 GError **error)
958 {
959 gboolean ret = FALSE;
960 int res;
961
962 if (g_cancellable_set_error_if_cancelled (cancellable, error))
963 return FALSE;
964
965 do
966 res = chown (gs_file_get_path_cached (path), owner, group);
967 while (G_UNLIKELY (res != 0 && errno == EINTR));
968
969 if (res < 0)
970 {
971 _set_error_from_errno (error);
972 goto out;
973 }
974
975 ret = TRUE;
976 out:
977 return ret;
978 }
979
980 /**
981 * gs_file_chmod:
982 * @path: Path to file
983 * @mode: UNIX mode
984 * @cancellable: a #GCancellable
985 * @error: a #GError
986 *
987 * Merely wraps UNIX chmod().
988 *
989 * Returns: %TRUE on success, %FALSE on error
990 */
991 gboolean
992 gs_file_chmod (GFile *path,
993 guint mode,
994 GCancellable *cancellable,
995 GError **error)
996 {
997 gboolean ret = FALSE;
998 int res;
999
1000 if (g_cancellable_set_error_if_cancelled (cancellable, error))
1001 return FALSE;
1002
1003 do
1004 res = chmod (gs_file_get_path_cached (path), mode);
1005 while (G_UNLIKELY (res != 0 && errno == EINTR));
1006
1007 if (res < 0)
1008 {
1009 _set_error_from_errno (error);
1010 goto out;
1011 }
1012
1013 ret = TRUE;
1014 out:
1015 return ret;
1016 }
1017
1018 /**
1019 * gs_file_ensure_directory:
1020 * @dir: Path to create as directory
1021 * @with_parents: Also create parent directories
1022 * @cancellable: a #GCancellable
1023 * @error: a #GError
1024 *
1025 * Like g_file_make_directory(), except does not throw an error if the
1026 * directory already exists.
1027 */
1028 gboolean
1029 gs_file_ensure_directory (GFile *dir,
1030 gboolean with_parents,
1031 GCancellable *cancellable,
1032 GError **error)
1033 {
1034 gboolean ret = FALSE;
1035 GError *temp_error = NULL;
1036 GFile *parent = NULL;
1037
1038 if (!g_file_make_directory (dir, cancellable, &temp_error))
1039 {
1040 if (with_parents &&
1041 g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
1042 {
1043 g_clear_error (&temp_error);
1044
1045 parent = g_file_get_parent (dir);
1046 if (parent)
1047 {
1048 if (!gs_file_ensure_directory (parent, TRUE, cancellable, error))
1049 goto out;
1050 }
1051 if (!gs_file_ensure_directory (dir, FALSE, cancellable, error))
1052 goto out;
1053 }
1054 else if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
1055 {
1056 g_propagate_error (error, temp_error);
1057 goto out;
1058 }
1059 else
1060 g_clear_error (&temp_error);
1061 }
1062
1063 ret = TRUE;
1064 out:
1065 g_clear_object (&parent);
1066 return ret;
1067 }
1068
1069 /**
1070 * gs_file_ensure_directory_mode:
1071 * @dir: Path to create as directory
1072 * @mode: Create directory with these permissions
1073 * @cancellable: a #GCancellable
1074 * @error: a #GError
1075 *
1076 * Wraps UNIX mkdir() function with support for @cancellable, and
1077 * uses @error instead of errno.
1078 */
1079 gboolean
1080 gs_file_ensure_directory_mode (GFile *dir,
1081 guint mode,
1082 GCancellable *cancellable,
1083 GError **error)
1084 {
1085 if (g_cancellable_set_error_if_cancelled (cancellable, error))
1086 return FALSE;
1087
1088 if (mkdir (gs_file_get_path_cached (dir), mode) == -1 && errno != EEXIST)
1089 {
1090 _set_error_from_errno (error);
1091 return FALSE;
1092 }
1093 return TRUE;
1094 }
1095
1096 /**
1097 * gs_file_load_contents_utf8:
1098 * @file: Path to file whose contents must be UTF-8
1099 * @cancellable:
1100 * @error:
1101 *
1102 * Like g_file_load_contents(), except validates the contents are
1103 * UTF-8.
1104 */
1105 gchar *
1106 gs_file_load_contents_utf8 (GFile *file,
1107 GCancellable *cancellable,
1108 GError **error)
1109 {
1110 gboolean ret = FALSE;
1111 gsize len;
1112 char *ret_contents = NULL;
1113
1114 if (!g_file_load_contents (file, cancellable, &ret_contents, &len,
1115 NULL, error))
1116 goto out;
1117 if (!g_utf8_validate (ret_contents, len, NULL))
1118 {
1119 g_set_error (error,
1120 G_IO_ERROR,
1121 G_IO_ERROR_INVALID_DATA,
1122 "Invalid UTF-8");
1123 goto out;
1124 }
1125
1126 ret = TRUE;
1127 out:
1128 if (!ret)
1129 {
1130 g_free (ret_contents);
1131 return NULL;
1132 }
1133 return ret_contents;
1134 }
1135
1136 static int
1137 path_common_directory (char *one,
1138 char *two)
1139 {
1140 int dir_index = 0;
1141 int i = 0;
1142
1143 while (*one && *two)
1144 {
1145 if (*one != *two)
1146 break;
1147 if (*one == '/')
1148 dir_index = i + 1;
1149
1150 one++;
1151 two++;
1152 i++;
1153 }
1154
1155 return dir_index;
1156 }
1157
1158 /**
1159 * gs_file_get_relpath:
1160 * @one: The first #GFile
1161 * @two: The second #GFile
1162 *
1163 * Like gs_file_get_relative_path(), but does not mandate that
1164 * the two files have any parent in common. This function will
1165 * instead insert "../" where appropriate.
1166 *
1167 * Returns: (transfer full): The relative path between the two.
1168 */
1169 gchar *
1170 gs_file_get_relpath (GFile *one,
1171 GFile *two)
1172 {
1173 gchar *simple_path;
1174 gchar *one_path, *one_suffix;
1175 gchar *two_path, *two_suffix;
1176 GString *path;
1177 int i;
1178
1179 simple_path = g_file_get_relative_path (one, two);
1180 if (simple_path)
1181 return simple_path;
1182
1183 one_path = g_file_get_path (one);
1184 two_path = g_file_get_path (two);
1185
1186 i = path_common_directory (one_path, two_path);
1187 one_suffix = one_path + i;
1188 two_suffix = two_path + i;
1189
1190 path = g_string_new ("");
1191
1192 /* For every leftover path segment one has, append "../" so
1193 * that we reach the same directory. */
1194 while (*one_suffix)
1195 {
1196 g_string_append (path, "../");
1197 one_suffix = strchr (one_suffix, '/');
1198 if (one_suffix == NULL)
1199 break;
1200 one_suffix++;
1201 }
1202
1203 /* And now append the leftover stuff on two's side. */
1204 g_string_append (path, two_suffix);
1205
1206 g_free (one_path);
1207 g_free (two_path);
1208
1209 return g_string_free (path, FALSE);
1210 }
1211
1212 /**
1213 * gs_file_realpath:
1214 * @file: A #GFile
1215 *
1216 * Return a #GFile that contains the same path with symlinks
1217 * followed. That is, it's a #GFile whose path is the result
1218 * of calling realpath() on @file.
1219 *
1220 * Returns: (allow-none) (transfer full): A new #GFile or %NULL if @file is invalid
1221 */
1222 GFile *
1223 gs_file_realpath (GFile *file)
1224 {
1225 gchar *path;
1226 gchar path_real[PATH_MAX];
1227
1228 path = g_file_get_path (file);
1229
1230 if (realpath ((const char *) path, path_real) == NULL)
1231 {
1232 g_free (path);
1233 return NULL;
1234 }
1235
1236 g_free (path);
1237 return g_file_new_for_path (path_real);
1238 }
1239