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