Close the file descriptor. (#75507, Matthias Clasen)
[platform/upstream/glib.git] / glib / gfileutils.c
1 /* gfileutils.c - File utility functions
2  *
3  *  Copyright 2000 Red Hat, Inc.
4  *
5  * GLib is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * GLib is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with GLib; see the file COPYING.LIB.  If not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  *   Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22
23 #include "glib.h"
24
25 #include <sys/stat.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38
39 #ifdef G_OS_WIN32
40 #include <io.h>
41 #ifndef F_OK
42 #define F_OK 0
43 #define X_OK 1
44 #define W_OK 2
45 #define R_OK 4
46 #endif /* !F_OK */
47
48 #ifndef S_ISREG
49 #define S_ISREG(mode) ((mode)&_S_IFREG)
50 #endif
51
52 #ifndef S_ISDIR
53 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
54 #endif
55
56 #endif /* G_OS_WIN32 */
57
58 #ifndef S_ISLNK
59 #define S_ISLNK(x) 0
60 #endif
61
62 #ifndef O_BINARY
63 #define O_BINARY 0
64 #endif
65
66 #include "glibintl.h"
67
68 /**
69  * g_file_test:
70  * @filename: a filename to test
71  * @test: bitfield of #GFileTest flags
72  * 
73  * Returns %TRUE if any of the tests in the bitfield @test are
74  * %TRUE. For example, <literal>(G_FILE_TEST_EXISTS | 
75  * G_FILE_TEST_IS_DIR)</literal> will return %TRUE if the file exists; 
76  * the check whether it's a directory doesn't matter since the existence 
77  * test is %TRUE. With the current set of available tests, there's no point
78  * passing in more than one test at a time.
79  * 
80  * Apart from #G_FILE_TEST_IS_SYMLINK all tests follow symbolic links,
81  * so for a symbolic link to a regular file g_file_test() will return
82  * %TRUE for both #G_FILE_TEST_IS_SYMLINK and #G_FILE_TEST_IS_REGULAR.
83  *
84  * Note, that for a dangling symbolic link g_file_test() will return
85  * %TRUE for #G_FILE_TEST_IS_SYMLINK and %FALSE for all other flags.
86  *
87  * Return value: whether a test was %TRUE
88  **/
89 gboolean
90 g_file_test (const gchar *filename,
91              GFileTest    test)
92 {
93   if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0))
94     return TRUE;
95   
96   if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access (filename, X_OK) == 0))
97     return TRUE;
98
99   if (test & G_FILE_TEST_IS_SYMLINK)
100     {
101 #ifdef G_OS_WIN32
102       /* no sym links on win32, no lstat in msvcrt */
103 #else
104       struct stat s;
105
106       if ((lstat (filename, &s) == 0) && S_ISLNK (s.st_mode))
107         return TRUE;
108 #endif
109     }
110   
111   if (test & (G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR))
112     {
113       struct stat s;
114       
115       if (stat (filename, &s) == 0)
116         {
117           if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
118             return TRUE;
119           
120           if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
121             return TRUE;
122         }
123     }
124
125   return FALSE;
126 }
127
128 GQuark
129 g_file_error_quark (void)
130 {
131   static GQuark q = 0;
132   if (q == 0)
133     q = g_quark_from_static_string ("g-file-error-quark");
134
135   return q;
136 }
137
138 /**
139  * g_file_error_from_errno:
140  * @err_no: an "errno" value
141  * 
142  * Gets a #GFileError constant based on the passed-in @errno.
143  * For example, if you pass in %EEXIST this function returns
144  * #G_FILE_ERROR_EXIST. Unlike @errno values, you can portably
145  * assume that all #GFileError values will exist.
146  *
147  * Normally a #GFileError value goes into a #GError returned
148  * from a function that manipulates files. So you would use
149  * g_file_error_from_errno() when constructing a #GError.
150  * 
151  * Return value: #GFileError corresponding to the given @errno
152  **/
153 GFileError
154 g_file_error_from_errno (gint err_no)
155 {
156   switch (err_no)
157     {
158 #ifdef EEXIST
159     case EEXIST:
160       return G_FILE_ERROR_EXIST;
161       break;
162 #endif
163
164 #ifdef EISDIR
165     case EISDIR:
166       return G_FILE_ERROR_ISDIR;
167       break;
168 #endif
169
170 #ifdef EACCES
171     case EACCES:
172       return G_FILE_ERROR_ACCES;
173       break;
174 #endif
175
176 #ifdef ENAMETOOLONG
177     case ENAMETOOLONG:
178       return G_FILE_ERROR_NAMETOOLONG;
179       break;
180 #endif
181
182 #ifdef ENOENT
183     case ENOENT:
184       return G_FILE_ERROR_NOENT;
185       break;
186 #endif
187
188 #ifdef ENOTDIR
189     case ENOTDIR:
190       return G_FILE_ERROR_NOTDIR;
191       break;
192 #endif
193
194 #ifdef ENXIO
195     case ENXIO:
196       return G_FILE_ERROR_NXIO;
197       break;
198 #endif
199
200 #ifdef ENODEV
201     case ENODEV:
202       return G_FILE_ERROR_NODEV;
203       break;
204 #endif
205
206 #ifdef EROFS
207     case EROFS:
208       return G_FILE_ERROR_ROFS;
209       break;
210 #endif
211
212 #ifdef ETXTBSY
213     case ETXTBSY:
214       return G_FILE_ERROR_TXTBSY;
215       break;
216 #endif
217
218 #ifdef EFAULT
219     case EFAULT:
220       return G_FILE_ERROR_FAULT;
221       break;
222 #endif
223
224 #ifdef ELOOP
225     case ELOOP:
226       return G_FILE_ERROR_LOOP;
227       break;
228 #endif
229
230 #ifdef ENOSPC
231     case ENOSPC:
232       return G_FILE_ERROR_NOSPC;
233       break;
234 #endif
235
236 #ifdef ENOMEM
237     case ENOMEM:
238       return G_FILE_ERROR_NOMEM;
239       break;
240 #endif
241
242 #ifdef EMFILE
243     case EMFILE:
244       return G_FILE_ERROR_MFILE;
245       break;
246 #endif
247
248 #ifdef ENFILE
249     case ENFILE:
250       return G_FILE_ERROR_NFILE;
251       break;
252 #endif
253
254 #ifdef EBADF
255     case EBADF:
256       return G_FILE_ERROR_BADF;
257       break;
258 #endif
259
260 #ifdef EINVAL
261     case EINVAL:
262       return G_FILE_ERROR_INVAL;
263       break;
264 #endif
265
266 #ifdef EPIPE
267     case EPIPE:
268       return G_FILE_ERROR_PIPE;
269       break;
270 #endif
271
272 #ifdef EAGAIN
273     case EAGAIN:
274       return G_FILE_ERROR_AGAIN;
275       break;
276 #endif
277
278 #ifdef EINTR
279     case EINTR:
280       return G_FILE_ERROR_INTR;
281       break;
282 #endif
283
284 #ifdef EIO
285     case EIO:
286       return G_FILE_ERROR_IO;
287       break;
288 #endif
289
290 #ifdef EPERM
291     case EPERM:
292       return G_FILE_ERROR_PERM;
293       break;
294 #endif
295       
296     default:
297       return G_FILE_ERROR_FAILED;
298       break;
299     }
300 }
301
302 static gboolean
303 get_contents_stdio (const gchar *filename,
304                     FILE        *f,
305                     gchar      **contents,
306                     gsize       *length, 
307                     GError     **error)
308 {
309   gchar buf[2048];
310   size_t bytes;
311   char *str;
312   size_t total_bytes;
313   size_t total_allocated;
314   
315   g_assert (f != NULL);
316
317 #define STARTING_ALLOC 64
318   
319   total_bytes = 0;
320   total_allocated = STARTING_ALLOC;
321   str = g_malloc (STARTING_ALLOC);
322   
323   while (!feof (f))
324     {
325       bytes = fread (buf, 1, 2048, f);
326
327       while ((total_bytes + bytes + 1) > total_allocated)
328         {
329           total_allocated *= 2;
330           str = g_try_realloc (str, total_allocated);
331
332           if (str == NULL)
333             {
334               g_set_error (error,
335                            G_FILE_ERROR,
336                            G_FILE_ERROR_NOMEM,
337                            _("Could not allocate %lu bytes to read file \"%s\""),
338                            (gulong) total_allocated, filename);
339               goto error;
340             }
341         }
342       
343       if (ferror (f))
344         {
345           g_set_error (error,
346                        G_FILE_ERROR,
347                        g_file_error_from_errno (errno),
348                        _("Error reading file '%s': %s"),
349                        filename, g_strerror (errno));
350
351           goto error;
352         }
353
354       memcpy (str + total_bytes, buf, bytes);
355       total_bytes += bytes;
356     }
357
358   fclose (f);
359
360   str[total_bytes] = '\0';
361   
362   if (length)
363     *length = total_bytes;
364   
365   *contents = str;
366   
367   return TRUE;
368
369  error:
370
371   g_free (str);
372   fclose (f);
373   
374   return FALSE;  
375 }
376
377 #ifndef G_OS_WIN32
378
379 static gboolean
380 get_contents_regfile (const gchar *filename,
381                       struct stat *stat_buf,
382                       gint         fd,
383                       gchar      **contents,
384                       gsize       *length,
385                       GError     **error)
386 {
387   gchar *buf;
388   size_t bytes_read;
389   size_t size;
390   size_t alloc_size;
391   
392   size = stat_buf->st_size;
393
394   alloc_size = size + 1;
395   buf = g_try_malloc (alloc_size);
396
397   if (buf == NULL)
398     {
399       g_set_error (error,
400                    G_FILE_ERROR,
401                    G_FILE_ERROR_NOMEM,
402                    _("Could not allocate %lu bytes to read file \"%s\""),
403                    (gulong) alloc_size, filename);
404
405       goto error;
406     }
407   
408   bytes_read = 0;
409   while (bytes_read < size)
410     {
411       gssize rc;
412           
413       rc = read (fd, buf + bytes_read, size - bytes_read);
414
415       if (rc < 0)
416         {
417           if (errno != EINTR) 
418             {
419               close (fd);
420
421               g_free (buf);
422                   
423               g_set_error (error,
424                            G_FILE_ERROR,
425                            g_file_error_from_errno (errno),
426                            _("Failed to read from file '%s': %s"),
427                            filename, g_strerror (errno));
428
429               goto error;
430             }
431         }
432       else if (rc == 0)
433         break;
434       else
435         bytes_read += rc;
436     }
437       
438   buf[bytes_read] = '\0';
439
440   if (length)
441     *length = bytes_read;
442   
443   *contents = buf;
444
445   close (fd);
446
447   return TRUE;
448
449  error:
450
451   close (fd);
452   
453   return FALSE;
454 }
455
456 static gboolean
457 get_contents_posix (const gchar *filename,
458                     gchar      **contents,
459                     gsize       *length,
460                     GError     **error)
461 {
462   struct stat stat_buf;
463   gint fd;
464   
465   /* O_BINARY useful on Cygwin */
466   fd = open (filename, O_RDONLY|O_BINARY);
467
468   if (fd < 0)
469     {
470       g_set_error (error,
471                    G_FILE_ERROR,
472                    g_file_error_from_errno (errno),
473                    _("Failed to open file '%s': %s"),
474                    filename, g_strerror (errno));
475
476       return FALSE;
477     }
478
479   /* I don't think this will ever fail, aside from ENOMEM, but. */
480   if (fstat (fd, &stat_buf) < 0)
481     {
482       close (fd);
483       
484       g_set_error (error,
485                    G_FILE_ERROR,
486                    g_file_error_from_errno (errno),
487                    _("Failed to get attributes of file '%s': fstat() failed: %s"),
488                    filename, g_strerror (errno));
489
490       return FALSE;
491     }
492
493   if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
494     {
495       return get_contents_regfile (filename,
496                                    &stat_buf,
497                                    fd,
498                                    contents,
499                                    length,
500                                    error);
501     }
502   else
503     {
504       FILE *f;
505
506       f = fdopen (fd, "r");
507       
508       if (f == NULL)
509         {
510           g_set_error (error,
511                        G_FILE_ERROR,
512                        g_file_error_from_errno (errno),
513                        _("Failed to open file '%s': fdopen() failed: %s"),
514                        filename, g_strerror (errno));
515           
516           return FALSE;
517         }
518   
519       return get_contents_stdio (filename, f, contents, length, error);
520     }
521 }
522
523 #else  /* G_OS_WIN32 */
524
525 static gboolean
526 get_contents_win32 (const gchar *filename,
527                     gchar      **contents,
528                     gsize       *length,
529                     GError     **error)
530 {
531   FILE *f;
532
533   /* I guess you want binary mode; maybe you want text sometimes? */
534   f = fopen (filename, "rb");
535
536   if (f == NULL)
537     {
538       g_set_error (error,
539                    G_FILE_ERROR,
540                    g_file_error_from_errno (errno),
541                    _("Failed to open file '%s': %s"),
542                    filename, g_strerror (errno));
543       
544       return FALSE;
545     }
546   
547   return get_contents_stdio (filename, f, contents, length, error);
548 }
549
550 #endif
551
552 /**
553  * g_file_get_contents:
554  * @filename: a file to read contents from
555  * @contents: location to store an allocated string
556  * @length: location to store length in bytes of the contents
557  * @error: return location for a #GError
558  * 
559  * Reads an entire file into allocated memory, with good error
560  * checking. If @error is set, %FALSE is returned, and @contents is set
561  * to %NULL. If %TRUE is returned, @error will not be set, and @contents
562  * will be set to the file contents.  The string stored in @contents
563  * will be nul-terminated, so for text files you can pass %NULL for the
564  * @length argument.  The error domain is #G_FILE_ERROR. Possible
565  * error codes are those in the #GFileError enumeration.
566  *
567  * Return value: %TRUE on success, %FALSE if error is set
568  **/
569 gboolean
570 g_file_get_contents (const gchar *filename,
571                      gchar      **contents,
572                      gsize       *length,
573                      GError     **error)
574 {  
575   g_return_val_if_fail (filename != NULL, FALSE);
576   g_return_val_if_fail (contents != NULL, FALSE);
577
578   *contents = NULL;
579   if (length)
580     *length = 0;
581
582 #ifdef G_OS_WIN32
583   return get_contents_win32 (filename, contents, length, error);
584 #else
585   return get_contents_posix (filename, contents, length, error);
586 #endif
587 }
588
589 /*
590  * mkstemp() implementation is from the GNU C library.
591  * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
592  */
593 /**
594  * g_mkstemp:
595  * @tmpl: template filename
596  *
597  * Opens a temporary file. See the <function>mkstemp()</function> documentation
598  * on most UNIX-like systems. This is a portability wrapper, which simply calls 
599  * <function>mkstemp()</function> on systems that have it, and implements 
600  * it in GLib otherwise.
601  *
602  * The parameter is a string that should match the rules for
603  * <function>mkstemp()</function>, i.e. end in "XXXXXX". The X string will 
604  * be modified to form the name of a file that didn't exist.
605  *
606  * Return value: A file handle (as from <function>open()</function>) to the file
607  * opened for reading and writing. The file is opened in binary mode
608  * on platforms where there is a difference. The file handle should be
609  * closed with <function>close()</function>. In case of errors, -1 is returned.
610  */
611 int
612 g_mkstemp (char *tmpl)
613 {
614 #ifdef HAVE_MKSTEMP
615   return mkstemp (tmpl);
616 #else
617   int len;
618   char *XXXXXX;
619   int count, fd;
620   static const char letters[] =
621     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
622   static const int NLETTERS = sizeof (letters) - 1;
623   glong value;
624   GTimeVal tv;
625   static int counter = 0;
626
627   len = strlen (tmpl);
628   if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
629     return -1;
630
631   /* This is where the Xs start.  */
632   XXXXXX = &tmpl[len - 6];
633
634   /* Get some more or less random data.  */
635   g_get_current_time (&tv);
636   value = (tv.tv_usec ^ tv.tv_sec) + counter++;
637
638   for (count = 0; count < 100; value += 7777, ++count)
639     {
640       glong v = value;
641
642       /* Fill in the random bits.  */
643       XXXXXX[0] = letters[v % NLETTERS];
644       v /= NLETTERS;
645       XXXXXX[1] = letters[v % NLETTERS];
646       v /= NLETTERS;
647       XXXXXX[2] = letters[v % NLETTERS];
648       v /= NLETTERS;
649       XXXXXX[3] = letters[v % NLETTERS];
650       v /= NLETTERS;
651       XXXXXX[4] = letters[v % NLETTERS];
652       v /= NLETTERS;
653       XXXXXX[5] = letters[v % NLETTERS];
654
655       fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
656
657       if (fd >= 0)
658         return fd;
659       else if (errno != EEXIST)
660         /* Any other error will apply also to other names we might
661          *  try, and there are 2^32 or so of them, so give up now.
662          */
663         return -1;
664     }
665
666   /* We got out of the loop because we ran out of combinations to try.  */
667   return -1;
668 #endif
669 }
670
671 /**
672  * g_file_open_tmp:
673  * @tmpl: Template for file name, as in g_mkstemp(), basename only
674  * @name_used: location to store actual name used
675  * @error: return location for a #GError
676  *
677  * Opens a file for writing in the preferred directory for temporary
678  * files (as returned by g_get_tmp_dir()). 
679  *
680  * @tmpl should be a string ending with six 'X' characters, as the
681  * parameter to g_mkstemp() (or <function>mkstemp()</function>). 
682  * However, unlike these functions, the template should only be a 
683  * basename, no directory components are allowed. If template is %NULL, 
684  * a default template is used.
685  *
686  * Note that in contrast to g_mkstemp() (and <function>mkstemp()</function>) 
687  * @tmpl is not modified, and might thus be a read-only literal string.
688  *
689  * The actual name used is returned in @name_used if non-%NULL. This
690  * string should be freed with g_free() when not needed any longer.
691  *
692  * Return value: A file handle (as from <function>open()</function>) to 
693  * the file opened for reading and writing. The file is opened in binary 
694  * mode on platforms where there is a difference. The file handle should be
695  * closed with <function>close()</function>. In case of errors, -1 is returned 
696  * and @error will be set.
697  **/
698 int
699 g_file_open_tmp (const char *tmpl,
700                  char      **name_used,
701                  GError    **error)
702 {
703   int retval;
704   const char *tmpdir;
705   char *sep;
706   char *fulltemplate;
707
708   if (tmpl == NULL)
709     tmpl = ".XXXXXX";
710
711   if (strchr (tmpl, G_DIR_SEPARATOR)
712 #ifdef G_OS_WIN32
713       || strchr (tmpl, '/')
714 #endif
715                                     )
716     {
717       g_set_error (error,
718                    G_FILE_ERROR,
719                    G_FILE_ERROR_FAILED,
720                    _("Template '%s' invalid, should not contain a '%s'"),
721                    tmpl, G_DIR_SEPARATOR_S);
722
723       return -1;
724     }
725   
726   if (strlen (tmpl) < 6 ||
727       strcmp (tmpl + strlen (tmpl) - 6, "XXXXXX") != 0)
728     {
729       g_set_error (error,
730                    G_FILE_ERROR,
731                    G_FILE_ERROR_FAILED,
732                    _("Template '%s' doesn't end with XXXXXX"),
733                    tmpl);
734       return -1;
735     }
736
737   tmpdir = g_get_tmp_dir ();
738
739   if (tmpdir [strlen (tmpdir) - 1] == G_DIR_SEPARATOR)
740     sep = "";
741   else
742     sep = G_DIR_SEPARATOR_S;
743
744   fulltemplate = g_strconcat (tmpdir, sep, tmpl, NULL);
745
746   retval = g_mkstemp (fulltemplate);
747
748   if (retval == -1)
749     {
750       g_set_error (error,
751                    G_FILE_ERROR,
752                    g_file_error_from_errno (errno),
753                    _("Failed to create file '%s': %s"),
754                    fulltemplate, g_strerror (errno));
755       g_free (fulltemplate);
756       return -1;
757     }
758
759   if (name_used)
760     *name_used = fulltemplate;
761   else
762     g_free (fulltemplate);
763
764   return retval;
765 }
766
767 static gchar *
768 g_build_pathv (const gchar *separator,
769                const gchar *first_element,
770                va_list      args)
771 {
772   GString *result;
773   gint separator_len = strlen (separator);
774   gboolean is_first = TRUE;
775   const gchar *next_element;
776
777   result = g_string_new (NULL);
778
779   next_element = first_element;
780
781   while (TRUE)
782     {
783       const gchar *element;
784       const gchar *start;
785       const gchar *end;
786
787       if (next_element)
788         {
789           element = next_element;
790           next_element = va_arg (args, gchar *);
791         }
792       else
793         break;
794
795       start = element;
796       
797       if (is_first)
798         is_first = FALSE;
799       else if (separator_len)
800         {
801           while (start &&
802                  strncmp (start, separator, separator_len) == 0)
803             start += separator_len;
804         }
805
806       end = start + strlen (start);
807       
808       if (next_element && separator_len)
809         {
810           while (end > start + separator_len &&
811                  strncmp (end - separator_len, separator, separator_len) == 0)
812             end -= separator_len;
813         }
814
815       if (end > start)
816         {
817           if (result->len > 0)
818             g_string_append (result, separator);
819
820           g_string_append_len (result, start, end - start);
821         }
822     }
823   
824   return g_string_free (result, FALSE);
825 }
826
827 /**
828  * g_build_path:
829  * @separator: a string used to separator the elements of the path.
830  * @first_element: the first element in the path
831  * @Varargs: remaining elements in path
832  * 
833  * Creates a path from a series of elements using @separator as the
834  * separator between elements. At the boundary between two elements,
835  * any trailing occurrences of separator in the first element, or
836  * leading occurrences of separator in the second element are removed
837  * and exactly one copy of the separator is inserted.
838  * 
839  * Return value: a newly-allocated string that must be freed with g_free().
840  **/
841 gchar *
842 g_build_path (const gchar *separator,
843               const gchar *first_element,
844               ...)
845 {
846   gchar *str;
847   va_list args;
848
849   g_return_val_if_fail (separator != NULL, NULL);
850
851   va_start (args, first_element);
852   str = g_build_pathv (separator, first_element, args);
853   va_end (args);
854
855   return str;
856 }
857
858 /**
859  * g_build_filename:
860  * @first_element: the first element in the path
861  * @Varargs: remaining elements in path
862  * 
863  * Creates a filename from a series of elements using the correct
864  * separator for filenames. This function behaves identically
865  * to <literal>g_build_path (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
866  *
867  * No attempt is made to force the resulting filename to be an absolute
868  * path. If the first element is a relative path, the result will
869  * be a relative path. 
870  * 
871  * Return value: a newly-allocated string that must be freed with g_free().
872  **/
873 gchar *
874 g_build_filename (const gchar *first_element, 
875                   ...)
876 {
877   gchar *str;
878   va_list args;
879
880   va_start (args, first_element);
881   str = g_build_pathv (G_DIR_SEPARATOR_S, first_element, args);
882   va_end (args);
883
884   return str;
885 }