glib r7880 - trunk/gio



Author: alexl
Date: Wed Feb 18 14:49:25 2009
New Revision: 7880
URL: http://svn.gnome.org/viewvc/glib?rev=7880&view=rev

Log:
2009-02-18  Alexander Larsson  <alexl redhat com>

	Bug 560564 â Replacing a symlink with its linked file truncates the original file

        * gioenums.h:
	Add G_FILE_CREATE_REPLACE_DESTINATION

        * glocalfileoutputstream.c:
        (handle_overwrite_open):
        (_g_local_file_output_stream_replace):
	Handle G_FILE_CREATE_REPLACE_DESTINATION when overwriting files.

        * gfile.c:
        (file_copy_fallback):
	Pass G_FILE_CREATE_REPLACE_DESTINATION to g_file_replace when copying
	with overwrite.



Modified:
   trunk/gio/ChangeLog
   trunk/gio/gfile.c
   trunk/gio/gioenums.h
   trunk/gio/glocalfileoutputstream.c

Modified: trunk/gio/gfile.c
==============================================================================
--- trunk/gio/gfile.c	(original)
+++ trunk/gio/gfile.c	Wed Feb 18 14:49:25 2009
@@ -2342,7 +2342,7 @@
       out = (GOutputStream *)g_file_replace (destination,
 					     NULL,
 					     flags & G_FILE_COPY_BACKUP,
-                                             0,
+                                             G_FILE_CREATE_REPLACE_DESTINATION,
 					     cancellable, error);
     }
   else

Modified: trunk/gio/gioenums.h
==============================================================================
--- trunk/gio/gioenums.h	(original)
+++ trunk/gio/gioenums.h	Wed Feb 18 14:49:25 2009
@@ -156,12 +156,21 @@
  * @G_FILE_CREATE_NONE: No flags set.
  * @G_FILE_CREATE_PRIVATE: Create a file that can only be
  *    accessed by the current user.
+ * @G_FILE_CREATE_REPLACE_DESTINATION: Replace the destination
+ *    as if it didn't exist before. Don't try to keep any old
+ *    permissions, replace instead of following links. This
+ *    is generally useful if you're doing a "copy over" 
+ *    rather than a "save new version of" replace operation.
+ *    You can think of it as "unlink destination" before
+ *    writing to it, although the implementation may not
+ *    be exactly like that.
  *
  * Flags used when an operation may create a file.
  */
 typedef enum {
   G_FILE_CREATE_NONE    = 0,
-  G_FILE_CREATE_PRIVATE = (1 << 0)
+  G_FILE_CREATE_PRIVATE = (1 << 0),
+  G_FILE_CREATE_REPLACE_DESTINATION = (1 << 1)
 } GFileCreateFlags;
 
 

Modified: trunk/gio/glocalfileoutputstream.c
==============================================================================
--- trunk/gio/glocalfileoutputstream.c	(original)
+++ trunk/gio/glocalfileoutputstream.c	Wed Feb 18 14:49:25 2009
@@ -644,6 +644,7 @@
 		       const char    *etag,
 		       gboolean       create_backup,
 		       char         **temp_filename,
+		       GFileCreateFlags flags,
 		       GCancellable  *cancellable,
 		       GError       **error)
 {
@@ -653,6 +654,12 @@
   gboolean is_symlink;
   int open_flags;
   int res;
+  int mode;
+
+  if (flags & G_FILE_CREATE_PRIVATE)
+    mode = 0600;
+  else
+    mode = 0666;
 
   /* We only need read access to the original file if we are creating a backup.
    * We also add O_CREATE to avoid a race if the file was just removed */
@@ -665,16 +672,16 @@
    * when finding out if the file we opened was a symlink */
 #ifdef O_NOFOLLOW
   is_symlink = FALSE;
-  fd = g_open (filename, open_flags | O_NOFOLLOW, 0666);
+  fd = g_open (filename, open_flags | O_NOFOLLOW, mode);
   if (fd == -1 && errno == ELOOP)
     {
       /* Could be a symlink, or it could be a regular ELOOP error,
        * but then the next open will fail too. */
       is_symlink = TRUE;
-      fd = g_open (filename, open_flags, 0666);
+      fd = g_open (filename, open_flags, mode);
     }
 #else
-  fd = g_open (filename, open_flags, 0666);
+  fd = g_open (filename, open_flags, mode);
   /* This is racy, but we do it as soon as possible to minimize the race */
   is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
 #endif
@@ -751,7 +758,8 @@
    * to a backup file and rewrite the contents of the file.
    */
   
-  if (!(original_stat.st_nlink > 1) && !is_symlink)
+  if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
+      (!(original_stat.st_nlink > 1) && !is_symlink))
     {
       char *dirname, *tmp_filename;
       int tmpfd;
@@ -767,16 +775,18 @@
 	  goto fallback_strategy;
 	}
       
-      /* try to keep permissions */
+      /* try to keep permissions (unless replacing) */
 
-      if (
+      if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
+	   (
 #ifdef HAVE_FCHOWN
-	  fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
+	    fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
 #endif
 #ifdef HAVE_FCHMOD
-	  fchmod (tmpfd, original_stat.st_mode) == -1 ||
+	    fchmod (tmpfd, original_stat.st_mode) == -1 ||
 #endif
-	  0
+	    0
+	    )
 	  )
 	{
 	  struct stat tmp_statbuf;
@@ -899,26 +909,58 @@
 	}
     }
 
-  /* Truncate the file at the start */
+  if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
+    {
+      close (fd);
+      
+      if (g_unlink (filename) != 0)
+	{
+	  int errsv = errno;
+	  
+	  g_set_error (error, G_IO_ERROR,
+		       g_io_error_from_errno (errsv),
+		       _("Error removing old file: %s"),
+		       g_strerror (errsv));
+	  goto err_out2;
+	}
+      
+      fd = g_open (filename, O_WRONLY | O_CREAT | O_BINARY, mode);
+      if (fd == -1)
+	{
+	  int errsv = errno;
+	  char *display_name = g_filename_display_name (filename);
+	  g_set_error (error, G_IO_ERROR,
+		       g_io_error_from_errno (errsv),
+		       _("Error opening file '%s': %s"),
+		       display_name, g_strerror (errsv));
+	  g_free (display_name);
+	  goto err_out2;
+	}
+    }
+  else
+    {
+      /* Truncate the file at the start */
 #ifdef G_OS_WIN32
-  if (g_win32_ftruncate (fd, 0) == -1)
+      if (g_win32_ftruncate (fd, 0) == -1)
 #else
-  if (ftruncate (fd, 0) == -1)
+	if (ftruncate (fd, 0) == -1)
 #endif
-    {
-      int errsv = errno;
-
-      g_set_error (error, G_IO_ERROR,
-		   g_io_error_from_errno (errsv),
-		   _("Error truncating file: %s"),
-		   g_strerror (errsv));
-      goto err_out;
+	  {
+	    int errsv = errno;
+	    
+	    g_set_error (error, G_IO_ERROR,
+			 g_io_error_from_errno (errsv),
+			 _("Error truncating file: %s"),
+			 g_strerror (errsv));
+	    goto err_out;
+	  }
     }
     
   return fd;
 
  err_out:
   close (fd);
+ err_out2:
   return -1;
 }
 
@@ -952,7 +994,7 @@
     {
       /* The file already exists */
       fd = handle_overwrite_open (filename, etag, create_backup, &temp_file,
-				  cancellable, error);
+				  flags, cancellable, error);
       if (fd == -1)
 	return NULL;
     }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]