Bug 560564 – Replacing a symlink with its linked file truncates the
[platform/upstream/glib.git] / gio / glocalfileoutputstream.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #include <errno.h>
32 #include <string.h>
33
34 #include <glib.h>
35 #include <glib/gstdio.h>
36 #include "glibintl.h"
37 #include "gioerror.h"
38 #include "gcancellable.h"
39 #include "glocalfileoutputstream.h"
40 #include "glocalfileinfo.h"
41
42 #ifdef G_OS_WIN32
43 #include <io.h>
44 #ifndef S_ISDIR
45 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
46 #endif
47 #ifndef S_ISREG
48 #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
49 #endif
50 #endif
51
52 #ifndef O_BINARY
53 #define O_BINARY 0
54 #endif
55
56 #include "gioalias.h"
57
58 #define g_local_file_output_stream_get_type _g_local_file_output_stream_get_type
59 G_DEFINE_TYPE (GLocalFileOutputStream, g_local_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM);
60
61 /* Some of the file replacement code was based on the code from gedit,
62  * relicenced to LGPL with permissions from the authors.
63  */
64
65 #define BACKUP_EXTENSION "~"
66
67 struct _GLocalFileOutputStreamPrivate {
68   char *tmp_filename;
69   char *original_filename;
70   char *backup_filename;
71   char *etag;
72   int fd;
73 };
74
75 static gssize     g_local_file_output_stream_write        (GOutputStream      *stream,
76                                                            const void         *buffer,
77                                                            gsize               count,
78                                                            GCancellable       *cancellable,
79                                                            GError            **error);
80 static gboolean   g_local_file_output_stream_close        (GOutputStream      *stream,
81                                                            GCancellable       *cancellable,
82                                                            GError            **error);
83 static GFileInfo *g_local_file_output_stream_query_info   (GFileOutputStream  *stream,
84                                                            char               *attributes,
85                                                            GCancellable       *cancellable,
86                                                            GError            **error);
87 static char *     g_local_file_output_stream_get_etag     (GFileOutputStream  *stream);
88 static goffset    g_local_file_output_stream_tell         (GFileOutputStream  *stream);
89 static gboolean   g_local_file_output_stream_can_seek     (GFileOutputStream  *stream);
90 static gboolean   g_local_file_output_stream_seek         (GFileOutputStream  *stream,
91                                                            goffset             offset,
92                                                            GSeekType           type,
93                                                            GCancellable       *cancellable,
94                                                            GError            **error);
95 static gboolean   g_local_file_output_stream_can_truncate (GFileOutputStream  *stream);
96 static gboolean   g_local_file_output_stream_truncate     (GFileOutputStream  *stream,
97                                                            goffset             size,
98                                                            GCancellable       *cancellable,
99                                                            GError            **error);
100
101 static void
102 g_local_file_output_stream_finalize (GObject *object)
103 {
104   GLocalFileOutputStream *file;
105   
106   file = G_LOCAL_FILE_OUTPUT_STREAM (object);
107   
108   g_free (file->priv->tmp_filename);
109   g_free (file->priv->original_filename);
110   g_free (file->priv->backup_filename);
111   g_free (file->priv->etag);
112
113   G_OBJECT_CLASS (g_local_file_output_stream_parent_class)->finalize (object);
114 }
115
116 static void
117 g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass)
118 {
119   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
120   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
121   GFileOutputStreamClass *file_stream_class = G_FILE_OUTPUT_STREAM_CLASS (klass);
122   
123   g_type_class_add_private (klass, sizeof (GLocalFileOutputStreamPrivate));
124   
125   gobject_class->finalize = g_local_file_output_stream_finalize;
126
127   stream_class->write_fn = g_local_file_output_stream_write;
128   stream_class->close_fn = g_local_file_output_stream_close;
129   file_stream_class->query_info = g_local_file_output_stream_query_info;
130   file_stream_class->get_etag = g_local_file_output_stream_get_etag;
131   file_stream_class->tell = g_local_file_output_stream_tell;
132   file_stream_class->can_seek = g_local_file_output_stream_can_seek;
133   file_stream_class->seek = g_local_file_output_stream_seek;
134   file_stream_class->can_truncate = g_local_file_output_stream_can_truncate;
135   file_stream_class->truncate_fn = g_local_file_output_stream_truncate;
136 }
137
138 static void
139 g_local_file_output_stream_init (GLocalFileOutputStream *stream)
140 {
141   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
142                                               G_TYPE_LOCAL_FILE_OUTPUT_STREAM,
143                                               GLocalFileOutputStreamPrivate);
144 }
145
146 static gssize
147 g_local_file_output_stream_write (GOutputStream  *stream,
148                                   const void     *buffer,
149                                   gsize           count,
150                                   GCancellable   *cancellable,
151                                   GError        **error)
152 {
153   GLocalFileOutputStream *file;
154   gssize res;
155
156   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
157
158   while (1)
159     {
160       if (g_cancellable_set_error_if_cancelled (cancellable, error))
161         return -1;
162       res = write (file->priv->fd, buffer, count);
163       if (res == -1)
164         {
165           int errsv = errno;
166
167           if (errsv == EINTR)
168             continue;
169           
170           g_set_error (error, G_IO_ERROR,
171                        g_io_error_from_errno (errsv),
172                        _("Error writing to file: %s"),
173                        g_strerror (errsv));
174         }
175       
176       break;
177     }
178   
179   return res;
180 }
181
182 static gboolean
183 g_local_file_output_stream_close (GOutputStream  *stream,
184                                   GCancellable   *cancellable,
185                                   GError        **error)
186 {
187   GLocalFileOutputStream *file;
188   GLocalFileStat final_stat;
189   int res;
190
191   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
192
193 #ifdef G_OS_WIN32
194
195   /* Must close before renaming on Windows, so just do the close first
196    * in all cases for now.
197    */
198   if (_fstati64 (file->priv->fd, &final_stat) == 0)
199     file->priv->etag = _g_local_file_info_create_etag (&final_stat);
200
201   res = close (file->priv->fd);
202   if (res == -1)
203     {
204       int errsv = errno;
205       
206       g_set_error (error, G_IO_ERROR,
207                    g_io_error_from_errno (errsv),
208                    _("Error closing file: %s"),
209                    g_strerror (errsv));
210       return FALSE;
211     }
212
213 #endif
214
215   if (file->priv->tmp_filename)
216     {
217       /* We need to move the temp file to its final place,
218        * and possibly create the backup file
219        */
220
221       if (file->priv->backup_filename)
222         {
223           if (g_cancellable_set_error_if_cancelled (cancellable, error))
224             goto err_out;
225           
226 #ifdef HAVE_LINK
227           /* create original -> backup link, the original is then renamed over */
228           if (g_unlink (file->priv->backup_filename) != 0 &&
229               errno != ENOENT)
230             {
231               int errsv = errno;
232
233               g_set_error (error, G_IO_ERROR,
234                            G_IO_ERROR_CANT_CREATE_BACKUP,
235                            _("Error removing old backup link: %s"),
236                            g_strerror (errsv));
237               goto err_out;
238             }
239
240           if (link (file->priv->original_filename, file->priv->backup_filename) != 0)
241             {
242               /*  link failed or is not supported, try rename  */
243               if (g_rename (file->priv->original_filename, file->priv->backup_filename) != 0)
244                 {
245                   int errsv = errno;
246
247                   g_set_error (error, G_IO_ERROR,
248                                G_IO_ERROR_CANT_CREATE_BACKUP,
249                                _("Error creating backup copy: %s"),
250                                g_strerror (errsv));
251                   goto err_out;
252                 }
253             }
254 #else
255             /* If link not supported, just rename... */
256           if (g_rename (file->priv->original_filename, file->priv->backup_filename) != 0)
257             {
258               int errsv = errno;
259
260               g_set_error (error, G_IO_ERROR,
261                            G_IO_ERROR_CANT_CREATE_BACKUP,
262                            _("Error creating backup copy: %s"),
263                            g_strerror (errsv));
264               goto err_out;
265             }
266 #endif
267         }
268       
269
270       if (g_cancellable_set_error_if_cancelled (cancellable, error))
271         goto err_out;
272
273       /* tmp -> original */
274       if (g_rename (file->priv->tmp_filename, file->priv->original_filename) != 0)
275         {
276           int errsv = errno;
277
278           g_set_error (error, G_IO_ERROR,
279                        g_io_error_from_errno (errno),
280                        _("Error renaming temporary file: %s"),
281                        g_strerror (errsv));
282           goto err_out;
283         }
284     }
285   
286   if (g_cancellable_set_error_if_cancelled (cancellable, error))
287     goto err_out;
288       
289 #ifndef G_OS_WIN32              /* Already did the fstat() and close() above on Win32 */
290
291   if (fstat (file->priv->fd, &final_stat) == 0)
292     file->priv->etag = _g_local_file_info_create_etag (&final_stat);
293
294   while (1)
295     {
296       res = close (file->priv->fd);
297       if (res == -1)
298         {
299           int errsv = errno;
300
301           g_set_error (error, G_IO_ERROR,
302                        g_io_error_from_errno (errsv),
303                        _("Error closing file: %s"),
304                        g_strerror (errsv));
305         }
306       break;
307     }
308   
309   return res != -1;
310
311 #else
312
313   return TRUE;
314
315 #endif
316
317  err_out:
318
319 #ifndef G_OS_WIN32
320   /* A simple try to close the fd in case we fail before the actual close */
321   close (file->priv->fd);
322 #endif
323   return FALSE;
324 }
325
326 static char *
327 g_local_file_output_stream_get_etag (GFileOutputStream *stream)
328 {
329   GLocalFileOutputStream *file;
330
331   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
332   
333   return g_strdup (file->priv->etag);
334 }
335
336 static goffset
337 g_local_file_output_stream_tell (GFileOutputStream *stream)
338 {
339   GLocalFileOutputStream *file;
340   off_t pos;
341
342   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
343   
344   pos = lseek (file->priv->fd, 0, SEEK_CUR);
345
346   if (pos == (off_t)-1)
347     return 0;
348   
349   return pos;
350 }
351
352 static gboolean
353 g_local_file_output_stream_can_seek (GFileOutputStream *stream)
354 {
355   GLocalFileOutputStream *file;
356   off_t pos;
357
358   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
359   
360   pos = lseek (file->priv->fd, 0, SEEK_CUR);
361
362   if (pos == (off_t)-1 && errno == ESPIPE)
363     return FALSE;
364   
365   return TRUE;
366 }
367
368 static int
369 seek_type_to_lseek (GSeekType type)
370 {
371   switch (type)
372     {
373     default:
374     case G_SEEK_CUR:
375       return SEEK_CUR;
376       
377     case G_SEEK_SET:
378       return SEEK_SET;
379       
380     case G_SEEK_END:
381       return SEEK_END;
382     }
383 }
384
385 static gboolean
386 g_local_file_output_stream_seek (GFileOutputStream  *stream,
387                                  goffset             offset,
388                                  GSeekType           type,
389                                  GCancellable       *cancellable,
390                                  GError            **error)
391 {
392   GLocalFileOutputStream *file;
393   off_t pos;
394
395   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
396
397   pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
398
399   if (pos == (off_t)-1)
400     {
401       int errsv = errno;
402
403       g_set_error (error, G_IO_ERROR,
404                    g_io_error_from_errno (errsv),
405                    _("Error seeking in file: %s"),
406                    g_strerror (errsv));
407       return FALSE;
408     }
409   
410   return TRUE;
411 }
412
413 static gboolean
414 g_local_file_output_stream_can_truncate (GFileOutputStream *stream)
415 {
416   /* We can't truncate pipes and stuff where we can't seek */
417   return g_local_file_output_stream_can_seek (stream);
418 }
419
420 static gboolean
421 g_local_file_output_stream_truncate (GFileOutputStream  *stream,
422                                      goffset             size,
423                                      GCancellable       *cancellable,
424                                      GError            **error)
425 {
426   GLocalFileOutputStream *file;
427   int res;
428
429   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
430
431  restart:
432 #ifdef G_OS_WIN32
433   res = g_win32_ftruncate (file->priv->fd, size);
434 #else
435   res = ftruncate (file->priv->fd, size);
436 #endif
437   
438   if (res == -1)
439     {
440       int errsv = errno;
441
442       if (errsv == EINTR)
443         {
444           if (g_cancellable_set_error_if_cancelled (cancellable, error))
445             return FALSE;
446           goto restart;
447         }
448
449       g_set_error (error, G_IO_ERROR,
450                    g_io_error_from_errno (errsv),
451                    _("Error truncating file: %s"),
452                    g_strerror (errsv));
453       return FALSE;
454     }
455   
456   return TRUE;
457 }
458
459
460 static GFileInfo *
461 g_local_file_output_stream_query_info (GFileOutputStream  *stream,
462                                        char               *attributes,
463                                        GCancellable       *cancellable,
464                                        GError            **error)
465 {
466   GLocalFileOutputStream *file;
467
468   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
469
470   if (g_cancellable_set_error_if_cancelled (cancellable, error))
471     return NULL;
472   
473   return _g_local_file_info_get_from_fd (file->priv->fd,
474                                          attributes,
475                                          error);
476 }
477
478 GFileOutputStream *
479 _g_local_file_output_stream_create  (const char        *filename,
480                                      GFileCreateFlags   flags,
481                                      GCancellable      *cancellable,
482                                      GError           **error)
483 {
484   GLocalFileOutputStream *stream;
485   int mode;
486   int fd;
487
488   if (g_cancellable_set_error_if_cancelled (cancellable, error))
489     return NULL;
490
491   if (flags & G_FILE_CREATE_PRIVATE)
492     mode = 0600;
493   else
494     mode = 0666;
495   
496   fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
497   if (fd == -1)
498     {
499       int errsv = errno;
500
501       if (errsv == EINVAL)
502         /* This must be an invalid filename, on e.g. FAT */
503         g_set_error_literal (error, G_IO_ERROR,
504                              G_IO_ERROR_INVALID_FILENAME,
505                              _("Invalid filename"));
506       else
507         {
508           char *display_name = g_filename_display_name (filename);
509           g_set_error (error, G_IO_ERROR,
510                        g_io_error_from_errno (errsv),
511                        _("Error opening file '%s': %s"),
512                        display_name, g_strerror (errsv));
513           g_free (display_name);
514         }
515       return NULL;
516     }
517   
518   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
519   stream->priv->fd = fd;
520   return G_FILE_OUTPUT_STREAM (stream);
521 }
522
523 GFileOutputStream *
524 _g_local_file_output_stream_append  (const char        *filename,
525                                      GFileCreateFlags   flags,
526                                      GCancellable      *cancellable,
527                                      GError           **error)
528 {
529   GLocalFileOutputStream *stream;
530   int mode;
531   int fd;
532
533   if (g_cancellable_set_error_if_cancelled (cancellable, error))
534     return NULL;
535
536   if (flags & G_FILE_CREATE_PRIVATE)
537     mode = 0600;
538   else
539     mode = 0666;
540
541   fd = g_open (filename, O_CREAT | O_APPEND | O_WRONLY | O_BINARY, mode);
542   if (fd == -1)
543     {
544       int errsv = errno;
545
546       if (errsv == EINVAL)
547         /* This must be an invalid filename, on e.g. FAT */
548         g_set_error_literal (error, G_IO_ERROR,
549                              G_IO_ERROR_INVALID_FILENAME,
550                              _("Invalid filename"));
551       else
552         {
553           char *display_name = g_filename_display_name (filename);
554           g_set_error (error, G_IO_ERROR,
555                        g_io_error_from_errno (errsv),
556                        _("Error opening file '%s': %s"),
557                        display_name, g_strerror (errsv));
558           g_free (display_name);
559         }
560       return NULL;
561     }
562   
563   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
564   stream->priv->fd = fd;
565   
566   return G_FILE_OUTPUT_STREAM (stream);
567 }
568
569 static char *
570 create_backup_filename (const char *filename)
571 {
572   return g_strconcat (filename, BACKUP_EXTENSION, NULL);
573 }
574
575 #define BUFSIZE 8192 /* size of normal write buffer */
576
577 static gboolean
578 copy_file_data (gint     sfd,
579                 gint     dfd,
580                 GError **error)
581 {
582   gboolean ret = TRUE;
583   gpointer buffer;
584   const gchar *write_buffer;
585   gssize bytes_read;
586   gssize bytes_to_write;
587   gssize bytes_written;
588   
589   buffer = g_malloc (BUFSIZE);
590   
591   do
592     {
593       bytes_read = read (sfd, buffer, BUFSIZE);
594       if (bytes_read == -1)
595         {
596           int errsv = errno;
597
598           if (errsv == EINTR)
599             continue;
600           
601           g_set_error (error, G_IO_ERROR,
602                        g_io_error_from_errno (errsv),
603                        _("Error reading from file: %s"),
604                        g_strerror (errsv));
605           ret = FALSE;
606           break;
607         }
608       
609       bytes_to_write = bytes_read;
610       write_buffer = buffer;
611       
612       do
613         {
614           bytes_written = write (dfd, write_buffer, bytes_to_write);
615           if (bytes_written == -1)
616             {
617               int errsv = errno;
618
619               if (errsv == EINTR)
620                 continue;
621               
622               g_set_error (error, G_IO_ERROR,
623                            g_io_error_from_errno (errsv),
624                            _("Error writing to file: %s"),
625                            g_strerror (errsv));
626               ret = FALSE;
627               break;
628             }
629           
630           bytes_to_write -= bytes_written;
631           write_buffer += bytes_written;
632         }
633       while (bytes_to_write > 0);
634       
635     } while ((bytes_read != 0) && (ret == TRUE));
636
637   g_free (buffer);
638   
639   return ret;
640 }
641
642 static int
643 handle_overwrite_open (const char    *filename,
644                        const char    *etag,
645                        gboolean       create_backup,
646                        char         **temp_filename,
647                        GFileCreateFlags flags,
648                        GCancellable  *cancellable,
649                        GError       **error)
650 {
651   int fd = -1;
652   GLocalFileStat original_stat;
653   char *current_etag;
654   gboolean is_symlink;
655   int open_flags;
656   int res;
657   int mode;
658
659   if (flags & G_FILE_CREATE_PRIVATE)
660     mode = 0600;
661   else
662     mode = 0666;
663
664   /* We only need read access to the original file if we are creating a backup.
665    * We also add O_CREATE to avoid a race if the file was just removed */
666   if (create_backup)
667     open_flags = O_RDWR | O_CREAT | O_BINARY;
668   else
669     open_flags = O_WRONLY | O_CREAT | O_BINARY;
670   
671   /* Some systems have O_NOFOLLOW, which lets us avoid some races
672    * when finding out if the file we opened was a symlink */
673 #ifdef O_NOFOLLOW
674   is_symlink = FALSE;
675   fd = g_open (filename, open_flags | O_NOFOLLOW, mode);
676   if (fd == -1 && errno == ELOOP)
677     {
678       /* Could be a symlink, or it could be a regular ELOOP error,
679        * but then the next open will fail too. */
680       is_symlink = TRUE;
681       fd = g_open (filename, open_flags, mode);
682     }
683 #else
684   fd = g_open (filename, open_flags, mode);
685   /* This is racy, but we do it as soon as possible to minimize the race */
686   is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
687 #endif
688     
689   if (fd == -1)
690     {
691       int errsv = errno;
692       char *display_name = g_filename_display_name (filename);
693       g_set_error (error, G_IO_ERROR,
694                    g_io_error_from_errno (errsv),
695                    _("Error opening file '%s': %s"),
696                    display_name, g_strerror (errsv));
697       g_free (display_name);
698       return -1;
699     }
700   
701 #ifdef G_OS_WIN32
702   res = _fstati64 (fd, &original_stat);
703 #else
704   res = fstat (fd, &original_stat);
705 #endif
706
707   if (res != 0) 
708     {
709       int errsv = errno;
710       char *display_name = g_filename_display_name (filename);
711       g_set_error (error, G_IO_ERROR,
712                    g_io_error_from_errno (errsv),
713                    _("Error stating file '%s': %s"),
714                    display_name, g_strerror (errsv));
715       g_free (display_name);
716       goto err_out;
717     }
718   
719   /* not a regular file */
720   if (!S_ISREG (original_stat.st_mode))
721     {
722       if (S_ISDIR (original_stat.st_mode))
723         g_set_error_literal (error,
724                              G_IO_ERROR,
725                              G_IO_ERROR_IS_DIRECTORY,
726                              _("Target file is a directory"));
727       else
728         g_set_error_literal (error,
729                              G_IO_ERROR,
730                              G_IO_ERROR_NOT_REGULAR_FILE,
731                              _("Target file is not a regular file"));
732       goto err_out;
733     }
734   
735   if (etag != NULL)
736     {
737       current_etag = _g_local_file_info_create_etag (&original_stat);
738       if (strcmp (etag, current_etag) != 0)
739         {
740           g_set_error_literal (error,
741                                G_IO_ERROR,
742                                G_IO_ERROR_WRONG_ETAG,
743                                _("The file was externally modified"));
744           g_free (current_etag);
745           goto err_out;
746         }
747       g_free (current_etag);
748     }
749
750   /* We use two backup strategies.
751    * The first one (which is faster) consist in saving to a
752    * tmp file then rename the original file to the backup and the
753    * tmp file to the original name. This is fast but doesn't work
754    * when the file is a link (hard or symbolic) or when we can't
755    * write to the current dir or can't set the permissions on the
756    * new file. 
757    * The second strategy consist simply in copying the old file
758    * to a backup file and rewrite the contents of the file.
759    */
760   
761   if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
762       (!(original_stat.st_nlink > 1) && !is_symlink))
763     {
764       char *dirname, *tmp_filename;
765       int tmpfd;
766       
767       dirname = g_path_get_dirname (filename);
768       tmp_filename = g_build_filename (dirname, ".goutputstream-XXXXXX", NULL);
769       g_free (dirname);
770
771       tmpfd = g_mkstemp (tmp_filename);
772       if (tmpfd == -1)
773         {
774           g_free (tmp_filename);
775           goto fallback_strategy;
776         }
777       
778       /* try to keep permissions (unless replacing) */
779
780       if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
781            (
782 #ifdef HAVE_FCHOWN
783             fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
784 #endif
785 #ifdef HAVE_FCHMOD
786             fchmod (tmpfd, original_stat.st_mode) == -1 ||
787 #endif
788             0
789             )
790           )
791         {
792           struct stat tmp_statbuf;
793           
794           /* Check that we really needed to change something */
795           if (fstat (tmpfd, &tmp_statbuf) != 0 ||
796               original_stat.st_uid != tmp_statbuf.st_uid ||
797               original_stat.st_gid != tmp_statbuf.st_gid ||
798               original_stat.st_mode != tmp_statbuf.st_mode)
799             {
800               close (tmpfd);
801               g_unlink (tmp_filename);
802               g_free (tmp_filename);
803               goto fallback_strategy;
804             }
805         }
806
807       close (fd);
808       *temp_filename = tmp_filename;
809       return tmpfd;
810     }
811
812  fallback_strategy:
813
814   if (create_backup)
815     {
816 #if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
817       struct stat tmp_statbuf;      
818 #endif
819       char *backup_filename;
820       int bfd;
821       
822       backup_filename = create_backup_filename (filename);
823
824       if (g_unlink (backup_filename) == -1 && errno != ENOENT)
825         {
826           g_set_error_literal (error,
827                                G_IO_ERROR,
828                                G_IO_ERROR_CANT_CREATE_BACKUP,
829                                _("Backup file creation failed"));
830           g_free (backup_filename);
831           goto err_out;
832         }
833
834       bfd = g_open (backup_filename,
835                     O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
836                     original_stat.st_mode & 0777);
837
838       if (bfd == -1)
839         {
840           g_set_error_literal (error,
841                                G_IO_ERROR,
842                                G_IO_ERROR_CANT_CREATE_BACKUP,
843                                _("Backup file creation failed"));
844           g_free (backup_filename);
845           goto err_out;
846         }
847
848       /* If needed, Try to set the group of the backup same as the
849        * original file. If this fails, set the protection
850        * bits for the group same as the protection bits for
851        * others. */
852 #if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
853       if (fstat (bfd, &tmp_statbuf) != 0)
854         {
855           g_set_error_literal (error,
856                                G_IO_ERROR,
857                                G_IO_ERROR_CANT_CREATE_BACKUP,
858                                _("Backup file creation failed"));
859           g_unlink (backup_filename);
860           g_free (backup_filename);
861           goto err_out;
862         }
863       
864       if ((original_stat.st_gid != tmp_statbuf.st_gid)  &&
865           fchown (bfd, (uid_t) -1, original_stat.st_gid) != 0)
866         {
867           if (fchmod (bfd,
868                       (original_stat.st_mode & 0707) |
869                       ((original_stat.st_mode & 07) << 3)) != 0)
870             {
871               g_set_error_literal (error,
872                                    G_IO_ERROR,
873                                    G_IO_ERROR_CANT_CREATE_BACKUP,
874                                    _("Backup file creation failed"));
875               g_unlink (backup_filename);
876               close (bfd);
877               g_free (backup_filename);
878               goto err_out;
879             }
880         }
881 #endif
882
883       if (!copy_file_data (fd, bfd, NULL))
884         {
885           g_set_error_literal (error,
886                                G_IO_ERROR,
887                                G_IO_ERROR_CANT_CREATE_BACKUP,
888                                _("Backup file creation failed"));
889           g_unlink (backup_filename);
890           close (bfd);
891           g_free (backup_filename);
892           
893           goto err_out;
894         }
895       
896       close (bfd);
897       g_free (backup_filename);
898
899       /* Seek back to the start of the file after the backup copy */
900       if (lseek (fd, 0, SEEK_SET) == -1)
901         {
902           int errsv = errno;
903
904           g_set_error (error, G_IO_ERROR,
905                        g_io_error_from_errno (errsv),
906                        _("Error seeking in file: %s"),
907                        g_strerror (errsv));
908           goto err_out;
909         }
910     }
911
912   if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
913     {
914       close (fd);
915       
916       if (g_unlink (filename) != 0)
917         {
918           int errsv = errno;
919           
920           g_set_error (error, G_IO_ERROR,
921                        g_io_error_from_errno (errsv),
922                        _("Error removing old file: %s"),
923                        g_strerror (errsv));
924           goto err_out2;
925         }
926       
927       fd = g_open (filename, O_WRONLY | O_CREAT | O_BINARY, mode);
928       if (fd == -1)
929         {
930           int errsv = errno;
931           char *display_name = g_filename_display_name (filename);
932           g_set_error (error, G_IO_ERROR,
933                        g_io_error_from_errno (errsv),
934                        _("Error opening file '%s': %s"),
935                        display_name, g_strerror (errsv));
936           g_free (display_name);
937           goto err_out2;
938         }
939     }
940   else
941     {
942       /* Truncate the file at the start */
943 #ifdef G_OS_WIN32
944       if (g_win32_ftruncate (fd, 0) == -1)
945 #else
946         if (ftruncate (fd, 0) == -1)
947 #endif
948           {
949             int errsv = errno;
950             
951             g_set_error (error, G_IO_ERROR,
952                          g_io_error_from_errno (errsv),
953                          _("Error truncating file: %s"),
954                          g_strerror (errsv));
955             goto err_out;
956           }
957     }
958     
959   return fd;
960
961  err_out:
962   close (fd);
963  err_out2:
964   return -1;
965 }
966
967 GFileOutputStream *
968 _g_local_file_output_stream_replace (const char        *filename,
969                                      const char        *etag,
970                                      gboolean           create_backup,
971                                      GFileCreateFlags   flags,
972                                      GCancellable      *cancellable,
973                                      GError           **error)
974 {
975   GLocalFileOutputStream *stream;
976   int mode;
977   int fd;
978   char *temp_file;
979
980   if (g_cancellable_set_error_if_cancelled (cancellable, error))
981     return NULL;
982
983   temp_file = NULL;
984
985   if (flags & G_FILE_CREATE_PRIVATE)
986     mode = 0600;
987   else
988     mode = 0666;
989
990   /* If the file doesn't exist, create it */
991   fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode);
992
993   if (fd == -1 && errno == EEXIST)
994     {
995       /* The file already exists */
996       fd = handle_overwrite_open (filename, etag, create_backup, &temp_file,
997                                   flags, cancellable, error);
998       if (fd == -1)
999         return NULL;
1000     }
1001   else if (fd == -1)
1002     {
1003       int errsv = errno;
1004
1005       if (errsv == EINVAL)
1006         /* This must be an invalid filename, on e.g. FAT */
1007         g_set_error_literal (error, G_IO_ERROR,
1008                              G_IO_ERROR_INVALID_FILENAME,
1009                              _("Invalid filename"));
1010       else
1011         {
1012           char *display_name = g_filename_display_name (filename);
1013           g_set_error (error, G_IO_ERROR,
1014                        g_io_error_from_errno (errsv),
1015                        _("Error opening file '%s': %s"),
1016                        display_name, g_strerror (errsv));
1017           g_free (display_name);
1018         }
1019       return NULL;
1020     }
1021   
1022  
1023   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
1024   stream->priv->fd = fd;
1025   stream->priv->tmp_filename = temp_file;
1026   if (create_backup)
1027     stream->priv->backup_filename = create_backup_filename (filename);
1028   stream->priv->original_filename =  g_strdup (filename);
1029   
1030   return G_FILE_OUTPUT_STREAM (stream);
1031 }