Add a note about casting the results of g_new() and g_new0().
[platform/upstream/glib.git] / glib / gfileutils.c
index a236a54..382564d 100644 (file)
@@ -33,9 +33,6 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#ifndef G_OS_WIN32
-#include <sys/wait.h>
-#endif
 #include <fcntl.h>
 #include <stdlib.h>
 
 
 #include "galias.h"
 
+static gint create_temp_file (gchar *tmpl, 
+                             int    permissions);
+
 /**
- * g_makepath:
+ * g_mkdir_with_parents:
  * @pathname: a pathname in the GLib file name encoding
  * @mode: permissions to use for newly created directories
  *
  * Create a directory if it doesn't already exist. Create intermediate
  * parent directories as needed, too.
  *
- * Returns: 0 if the directoty already exists, or was successfully
+ * Returns: 0 if the directory already exists, or was successfully
  * created. Returns -1 if an error occurred, with errno set.
  *
  * Since: 2.8
  */
 int
-g_makepath (const gchar *pathname,
-           int          mode)
+g_mkdir_with_parents (const gchar *pathname,
+                     int          mode)
 {
   gchar *fn, *p;
 
-  if (pathname == NULL)
+  if (pathname == NULL || *pathname == '\0')
     {
       errno = EINVAL;
       return -1;
@@ -920,114 +920,6 @@ rename_file (const char *old_name,
   return TRUE;
 }
 
-static gboolean
-set_umask_permissions (int          fd,
-                      GError      **err)
-{
-#ifdef G_OS_WIN32
-
-  return TRUE;
-
-#else
-  /* All of this function is just to work around the fact that
-   * there is no way to get the umask without changing it.
-   *
-   * We can't just change-and-reset the umask because that would
-   * lead to a race condition if another thread tried to change
-   * the umask in between the getting and the setting of the umask.
-   * So we have to do the whole thing in a child process.
-   */
-
-  int save_errno;
-  pid_t pid;
-
-  pid = fork ();
-  
-  if (pid == -1)
-    {
-      save_errno = errno;
-      g_set_error (err,
-                  G_FILE_ERROR,
-                  g_file_error_from_errno (save_errno),
-                  _("Could not change file mode: fork() failed: %s"),
-                  g_strerror (save_errno));
-      
-      return FALSE;
-    }
-  else if (pid == 0)
-    {
-      /* child */
-      mode_t mask = umask (0666);
-
-      errno = 0;
-      if (fchmod (fd, 0666 & ~mask) == -1)
-       _exit (errno);
-      else
-       _exit (0);
-
-      return TRUE; /* To quiet gcc */
-    }
-  else
-    { 
-      /* parent */
-      int status;
-
-      errno = 0;
-      if (waitpid (pid, &status, 0) == -1)
-       {
-         save_errno = errno;
-
-         g_set_error (err,
-                      G_FILE_ERROR,
-                      g_file_error_from_errno (save_errno),
-                      _("Could not change file mode: waitpid() failed: %s"),
-                      g_strerror (save_errno));
-
-         return FALSE;
-       }
-
-      if (WIFEXITED (status))
-       {
-         save_errno = WEXITSTATUS (status);
-
-         if (save_errno == 0)
-           {
-             return TRUE;
-           }
-         else
-           {
-             g_set_error (err,
-                          G_FILE_ERROR,
-                          g_file_error_from_errno (save_errno),
-                          _("Could not change file mode: chmod() failed: %s"),
-                          g_strerror (save_errno));
-      
-             return FALSE;
-           }
-       }
-      else if (WIFSIGNALED (status))
-       {
-         g_set_error (err,
-                      G_FILE_ERROR,
-                      G_FILE_ERROR_FAILED,
-                      _("Could not change file mode: Child terminated by signal: %s"),
-                      g_strsignal (WTERMSIG (status)));
-                      
-         return FALSE;
-       }
-      else
-       {
-         /* This shouldn't happen */
-         g_set_error (err,
-                      G_FILE_ERROR,
-                      G_FILE_ERROR_FAILED,
-                      _("Could not change file mode: Child terminated abnormally"));
-         return FALSE;
-       }
-    }
-#endif
-}
-
 static gchar *
 write_to_temp_file (const gchar *contents,
                    gssize length,
@@ -1046,7 +938,7 @@ write_to_temp_file (const gchar *contents,
   tmp_name = g_strdup_printf ("%s.XXXXXX", template);
 
   errno = 0;
-  fd = g_mkstemp (tmp_name);
+  fd = create_temp_file (tmp_name, 0666);
   display_name = g_filename_display_name (tmp_name);
       
   if (fd == -1)
@@ -1061,14 +953,6 @@ write_to_temp_file (const gchar *contents,
       goto out;
     }
 
-  if (!set_umask_permissions (fd, err))
-    {
-      close (fd);
-      g_unlink (tmp_name);
-
-      goto out;
-    }
-  
   errno = 0;
   file = fdopen (fd, "wb");
   if (!file)
@@ -1267,35 +1151,13 @@ g_file_set_contents (const gchar *filename,
 }
 
 /*
- * mkstemp() implementation is from the GNU C library.
+ * create_temp_file based on the mkstemp implementation from the GNU C library.
  * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
  */
-/**
- * g_mkstemp:
- * @tmpl: template filename
- *
- * Opens a temporary file. See the mkstemp() documentation
- * on most UNIX-like systems. This is a portability wrapper, which simply calls 
- * mkstemp() on systems that have it, and implements 
- * it in GLib otherwise.
- *
- * The parameter is a string that should match the rules for
- * mkstemp(), i.e. end in "XXXXXX". The X string will 
- * be modified to form the name of a file that didn't exist.
- * The string should be in the GLib file name encoding. Most importantly, 
- * on Windows it should be in UTF-8.
- *
- * Return value: A file handle (as from open()) to the file
- * opened for reading and writing. The file is opened in binary mode
- * on platforms where there is a difference. The file handle should be
- * closed with close(). In case of errors, -1 is returned.
- */
-gint
-g_mkstemp (gchar *tmpl)
+static gint
+create_temp_file (gchar *tmpl, 
+                 int    permissions)
 {
-#ifdef HAVE_MKSTEMP
-  return mkstemp (tmpl);
-#else
   int len;
   char *XXXXXX;
   int count, fd;
@@ -1338,7 +1200,7 @@ g_mkstemp (gchar *tmpl)
       XXXXXX[5] = letters[v % NLETTERS];
 
       /* tmpl is in UTF-8 on Windows, thus use g_open() */
-      fd = g_open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+      fd = g_open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, permissions);
 
       if (fd >= 0)
        return fd;
@@ -1352,6 +1214,35 @@ g_mkstemp (gchar *tmpl)
   /* We got out of the loop because we ran out of combinations to try.  */
   errno = EEXIST;
   return -1;
+}
+
+/**
+ * g_mkstemp:
+ * @tmpl: template filename
+ *
+ * Opens a temporary file. See the mkstemp() documentation
+ * on most UNIX-like systems. This is a portability wrapper, which simply calls 
+ * mkstemp() on systems that have it, and implements 
+ * it in GLib otherwise.
+ *
+ * The parameter is a string that should match the rules for
+ * mkstemp(), i.e. end in "XXXXXX". The X string will 
+ * be modified to form the name of a file that didn't exist.
+ * The string should be in the GLib file name encoding. Most importantly, 
+ * on Windows it should be in UTF-8.
+ *
+ * Return value: A file handle (as from open()) to the file
+ * opened for reading and writing. The file is opened in binary mode
+ * on platforms where there is a difference. The file handle should be
+ * closed with close(). In case of errors, -1 is returned.
+ */
+gint
+g_mkstemp (gchar *tmpl)
+{
+#ifdef HAVE_MKSTEMP
+  return mkstemp (tmpl);
+#else
+  return create_temp_file (tmpl, 0600);
 #endif
 }
 
@@ -1570,9 +1461,10 @@ g_file_open_tmp (const gchar *tmpl,
 #endif
 
 static gchar *
-g_build_pathv (const gchar *separator,
-              const gchar *first_element,
-              va_list      args)
+g_build_path_va (const gchar  *separator,
+                const gchar  *first_element,
+                va_list      *args,
+                gchar       **str_array)
 {
   GString *result;
   gint separator_len = strlen (separator);
@@ -1581,10 +1473,14 @@ g_build_pathv (const gchar *separator,
   const gchar *single_element = NULL;
   const gchar *next_element;
   const gchar *last_trailing = NULL;
+  gint i = 0;
 
   result = g_string_new (NULL);
 
-  next_element = first_element;
+  if (str_array)
+    next_element = str_array[i++];
+  else
+    next_element = first_element;
 
   while (TRUE)
     {
@@ -1595,7 +1491,10 @@ g_build_pathv (const gchar *separator,
       if (next_element)
        {
          element = next_element;
-         next_element = va_arg (args, gchar *);
+         if (str_array)
+           next_element = str_array[i++];
+         else
+           next_element = va_arg (*args, gchar *);
        }
       else
        break;
@@ -1666,6 +1565,30 @@ g_build_pathv (const gchar *separator,
 }
 
 /**
+ * g_build_pathv:
+ * @separator: a string used to separator the elements of the path.
+ * @args: %NULL-terminated array of strings containing the path elements.
+ * 
+ * Behaves exactly like g_build_path(), but takes the path elements 
+ * as a string array, instead of varargs. This function is mainly
+ * meant for language bindings.
+ *
+ * Return value: a newly-allocated string that must be freed with g_free().
+ *
+ * Since: 2.8
+ */
+gchar *
+g_build_pathv (const gchar  *separator,
+              gchar       **args)
+{
+  if (!args)
+    return NULL;
+
+  return g_build_path_va (separator, NULL, NULL, args);
+}
+
+
+/**
  * g_build_path:
  * @separator: a string used to separator the elements of the path.
  * @first_element: the first element in the path
@@ -1712,54 +1635,22 @@ g_build_path (const gchar *separator,
   g_return_val_if_fail (separator != NULL, NULL);
 
   va_start (args, first_element);
-  str = g_build_pathv (separator, first_element, args);
+  str = g_build_path_va (separator, first_element, &args, NULL);
   va_end (args);
 
   return str;
 }
 
-/**
- * g_build_filename:
- * @first_element: the first element in the path
- * @Varargs: remaining elements in path, terminated by %NULL
- * 
- * Creates a filename from a series of elements using the correct
- * separator for filenames.
- *
- * On Unix, this function behaves identically to <literal>g_build_path
- * (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
- *
- * On Windows, it takes into account that either the backslash
- * (<literal>\</literal> or slash (<literal>/</literal>) can be used
- * as separator in filenames, but otherwise behaves as on Unix. When
- * file pathname separators need to be inserted, the one that last
- * previously occurred in the parameters (reading from left to right)
- * is used.
- *
- * No attempt is made to force the resulting filename to be an absolute
- * path. If the first element is a relative path, the result will
- * be a relative path. 
- * 
- * Return value: a newly-allocated string that must be freed with g_free().
- **/
-gchar *
-g_build_filename (const gchar *first_element, 
-                 ...)
-{
-#ifndef G_OS_WIN32
-  gchar *str;
-  va_list args;
-
-  va_start (args, first_element);
-  str = g_build_pathv (G_DIR_SEPARATOR_S, first_element, args);
-  va_end (args);
+#ifdef G_OS_WIN32
 
-  return str;
-#else
-  /* Code copied from g_build_pathv(), and modifed to use two
+static gchar *
+g_build_pathname_va (const gchar  *first_element,
+                    va_list      *args,
+                    gchar       **str_array)
+{
+  /* Code copied from g_build_pathv(), and modified to use two
    * alternative single-character separators.
    */
-  va_list args;
   GString *result;
   gboolean is_first = TRUE;
   gboolean have_leading = FALSE;
@@ -1767,13 +1658,15 @@ g_build_filename (const gchar *first_element,
   const gchar *next_element;
   const gchar *last_trailing = NULL;
   gchar current_separator = '\\';
-
-  va_start (args, first_element);
+  gint i = 0;
 
   result = g_string_new (NULL);
 
-  next_element = first_element;
-
+  if (str_array)
+    next_element = str_array[i++];
+  else
+    next_element = first_element;
+  
   while (TRUE)
     {
       const gchar *element;
@@ -1783,7 +1676,10 @@ g_build_filename (const gchar *first_element,
       if (next_element)
        {
          element = next_element;
-         next_element = va_arg (args, gchar *);
+         if (str_array)
+           next_element = str_array[i++];
+         else
+           next_element = va_arg (*args, gchar *);
        }
       else
        break;
@@ -1845,8 +1741,6 @@ g_build_filename (const gchar *first_element,
       is_first = FALSE;
     }
 
-  va_end (args);
-
   if (single_element)
     {
       g_string_free (result, TRUE);
@@ -1859,7 +1753,76 @@ g_build_filename (const gchar *first_element,
   
       return g_string_free (result, FALSE);
     }
+}
+
+#endif
+
+/**
+ * g_build_filenamev:
+ * @args: %NULL-terminated array of strings containing the path elements.
+ * 
+ * Behaves exactly like g_build_filename(), but takes the path elements 
+ * as a string array, instead of varargs. This function is mainly
+ * meant for language bindings.
+ *
+ * Return value: a newly-allocated string that must be freed with g_free().
+ * 
+ * Since: 2.8
+ */
+gchar *
+g_build_filenamev (gchar **args)
+{
+  gchar *str;
+
+#ifndef G_OS_WIN32
+  str = g_build_path_va (G_DIR_SEPARATOR_S, NULL, NULL, args);
+#else
+  str = g_build_pathname_va (NULL, NULL, args);
+#endif
+
+  return str;
+}
+
+/**
+ * g_build_filename:
+ * @first_element: the first element in the path
+ * @Varargs: remaining elements in path, terminated by %NULL
+ * 
+ * Creates a filename from a series of elements using the correct
+ * separator for filenames.
+ *
+ * On Unix, this function behaves identically to <literal>g_build_path
+ * (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
+ *
+ * On Windows, it takes into account that either the backslash
+ * (<literal>\</literal> or slash (<literal>/</literal>) can be used
+ * as separator in filenames, but otherwise behaves as on Unix. When
+ * file pathname separators need to be inserted, the one that last
+ * previously occurred in the parameters (reading from left to right)
+ * is used.
+ *
+ * No attempt is made to force the resulting filename to be an absolute
+ * path. If the first element is a relative path, the result will
+ * be a relative path. 
+ * 
+ * Return value: a newly-allocated string that must be freed with g_free().
+ **/
+gchar *
+g_build_filename (const gchar *first_element, 
+                 ...)
+{
+  gchar *str;
+  va_list args;
+
+  va_start (args, first_element);
+#ifndef G_OS_WIN32
+  str = g_build_path_va (G_DIR_SEPARATOR_S, first_element, &args, NULL);
+#else
+  str = g_build_pathname_va (first_element, &args, NULL);
 #endif
+  va_end (args);
+
+  return str;
 }
 
 /**