Save the errno in various places
authorSoeren Sandmann <sandmann@redhat.com>
Sun, 17 Apr 2005 00:16:51 +0000 (00:16 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Sun, 17 Apr 2005 00:16:51 +0000 (00:16 +0000)
Sat Apr 16 20:15:44 2005  Soeren Sandmann  <sandmann@redhat.com>

* glib/gfileutils.c (g_file_replace): Save the errno in various
places

* glib/gfileutils.c (set_umask_permissions): Fork a child and do
chmod() to the umask() permissions there.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-8
glib/gfileutils.c

index a69d097..610b1f9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sat Apr 16 20:15:44 2005  Soeren Sandmann  <sandmann@redhat.com>
+
+       * glib/gfileutils.c (g_file_replace): Save the errno in various
+       places
+
+       * glib/gfileutils.c (set_umask_permissions): Fork a child and do
+       chmod() to the umask() permissions there.
+
 2005-04-10  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/gmessages.h (g_debug): Use G_LOG_LEVEL_DEBUG in
index a69d097..610b1f9 100644 (file)
@@ -1,3 +1,11 @@
+Sat Apr 16 20:15:44 2005  Soeren Sandmann  <sandmann@redhat.com>
+
+       * glib/gfileutils.c (g_file_replace): Save the errno in various
+       places
+
+       * glib/gfileutils.c (set_umask_permissions): Fork a child and do
+       chmod() to the umask() permissions there.
+
 2005-04-10  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/gmessages.h (g_debug): Use G_LOG_LEVEL_DEBUG in
index a69d097..610b1f9 100644 (file)
@@ -1,3 +1,11 @@
+Sat Apr 16 20:15:44 2005  Soeren Sandmann  <sandmann@redhat.com>
+
+       * glib/gfileutils.c (g_file_replace): Save the errno in various
+       places
+
+       * glib/gfileutils.c (set_umask_permissions): Fork a child and do
+       chmod() to the umask() permissions there.
+
 2005-04-10  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/gmessages.h (g_debug): Use G_LOG_LEVEL_DEBUG in
index a69d097..610b1f9 100644 (file)
@@ -1,3 +1,11 @@
+Sat Apr 16 20:15:44 2005  Soeren Sandmann  <sandmann@redhat.com>
+
+       * glib/gfileutils.c (g_file_replace): Save the errno in various
+       places
+
+       * glib/gfileutils.c (set_umask_permissions): Fork a child and do
+       chmod() to the umask() permissions there.
+
 2005-04-10  Matthias Clasen  <mclasen@redhat.com>
 
        * glib/gmessages.h (g_debug): Use G_LOG_LEVEL_DEBUG in
index d2263ea..b3c1565 100644 (file)
@@ -33,6 +33,7 @@
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 #include <stdlib.h>
 
@@ -816,7 +817,6 @@ g_file_get_contents (const gchar *filename,
 
 #endif
 
-
 static gboolean
 rename_file (const char *old_name,
             const char *new_name,
@@ -828,7 +828,7 @@ rename_file (const char *old_name,
       int save_errno = errno;
       gchar *display_old_name = g_filename_display_name (old_name);
       gchar *display_new_name = g_filename_display_name (new_name);
-      
+
       g_set_error (err,
                   G_FILE_ERROR,
                   g_file_error_from_errno (save_errno),
@@ -846,6 +846,114 @@ 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,
@@ -865,11 +973,11 @@ write_to_temp_file (const gchar *contents,
 
   errno = 0;
   fd = g_mkstemp (tmp_name);
-  save_errno = errno;
   display_name = g_filename_display_name (tmp_name);
       
   if (fd == -1)
     {
+      save_errno = errno;
       g_set_error (err,
                   G_FILE_ERROR,
                   g_file_error_from_errno (save_errno),
@@ -879,16 +987,25 @@ 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)
     {
+      save_errno = errno;
       g_set_error (err,
                   G_FILE_ERROR,
-                  g_file_error_from_errno (errno),
+                  g_file_error_from_errno (save_errno),
                   _("Failed to open file '%s' for writing: fdopen() failed: %s"),
                   display_name,
-                  g_strerror (errno));
+                  g_strerror (save_errno));
 
       close (fd);
       g_unlink (tmp_name);
@@ -903,15 +1020,17 @@ write_to_temp_file (const gchar *contents,
       errno = 0;
 
       n_written = fwrite (contents, 1, length, file);
-      
+
       if (n_written < length)
        {
+         save_errno = errno;
+      
          g_set_error (err,
                       G_FILE_ERROR,
-                      g_file_error_from_errno (errno),
+                      g_file_error_from_errno (save_errno),
                       _("Failed to write file '%s': fwrite() failed: %s"),
                       display_name,
-                      g_strerror (errno));
+                      g_strerror (save_errno));
 
          fclose (file);
          g_unlink (tmp_name);
@@ -922,21 +1041,23 @@ write_to_temp_file (const gchar *contents,
    
   errno = 0;
   if (fclose (file) == EOF)
-    {
+    { 
+      save_errno = 0;
+      
       g_set_error (err,
                   G_FILE_ERROR,
-                  g_file_error_from_errno (errno),
+                  g_file_error_from_errno (save_errno),
                   _("Failed to close file '%s': fclose() failed: %s"),
                   display_name, 
-                  g_strerror (errno));
+                  g_strerror (save_errno));
 
       g_unlink (tmp_name);
       
       goto out;
     }
-  
-  retval = g_strdup (tmp_name);
 
+  retval = g_strdup (tmp_name);
+  
  out:
   g_free (tmp_name);
   g_free (display_name);
@@ -1039,12 +1160,14 @@ g_file_replace (const gchar *filename,
        {
           gchar *display_filename = g_filename_display_name (filename);
 
+         save_errno = errno;
+         
          g_set_error (error,
                       G_FILE_ERROR,
-                      g_file_error_from_errno (errno),
+                      g_file_error_from_errno (save_errno),
                       _("Existing file '%s' could not be removed: g_unlink() failed: %s"),
                       display_filename,
-                      g_strerror (errno));
+                      g_strerror (save_errno));
 
          g_free (display_filename);
          g_unlink (tmp_filename);