gio/ docs/reference/gio Merged gio-standalone into glib.
[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 #include <unistd.h>
29 #include <errno.h>
30 #include <string.h>
31
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include "glibintl.h"
35 #include "gioerror.h"
36 #include "glocalfileoutputstream.h"
37 #include "glocalfileinfo.h"
38
39 G_DEFINE_TYPE (GLocalFileOutputStream, g_local_file_output_stream, G_TYPE_FILE_OUTPUT_STREAM);
40
41 /* Some of the file replacement code was based on the code from gedit,
42  * relicenced to LGPL with permissions from the authors.
43  */
44
45 #define BACKUP_EXTENSION "~"
46
47 struct _GLocalFileOutputStreamPrivate {
48   char *tmp_filename;
49   char *original_filename;
50   char *backup_filename;
51   char *etag;
52   int fd;
53 };
54
55 static gssize     g_local_file_output_stream_write        (GOutputStream      *stream,
56                                                            const void         *buffer,
57                                                            gsize               count,
58                                                            GCancellable       *cancellable,
59                                                            GError            **error);
60 static gboolean   g_local_file_output_stream_close        (GOutputStream      *stream,
61                                                            GCancellable       *cancellable,
62                                                            GError            **error);
63 static GFileInfo *g_local_file_output_stream_query_info   (GFileOutputStream  *stream,
64                                                            char               *attributes,
65                                                            GCancellable       *cancellable,
66                                                            GError            **error);
67 static char *     g_local_file_output_stream_get_etag     (GFileOutputStream  *stream);
68 static goffset    g_local_file_output_stream_tell         (GFileOutputStream  *stream);
69 static gboolean   g_local_file_output_stream_can_seek     (GFileOutputStream  *stream);
70 static gboolean   g_local_file_output_stream_seek         (GFileOutputStream  *stream,
71                                                            goffset             offset,
72                                                            GSeekType           type,
73                                                            GCancellable       *cancellable,
74                                                            GError            **error);
75 static gboolean   g_local_file_output_stream_can_truncate (GFileOutputStream  *stream);
76 static gboolean   g_local_file_output_stream_truncate     (GFileOutputStream  *stream,
77                                                            goffset             size,
78                                                            GCancellable       *cancellable,
79                                                            GError            **error);
80
81 static void
82 g_local_file_output_stream_finalize (GObject *object)
83 {
84   GLocalFileOutputStream *file;
85   
86   file = G_LOCAL_FILE_OUTPUT_STREAM (object);
87   
88   g_free (file->priv->tmp_filename);
89   g_free (file->priv->original_filename);
90   g_free (file->priv->backup_filename);
91   g_free (file->priv->etag);
92   
93   if (G_OBJECT_CLASS (g_local_file_output_stream_parent_class)->finalize)
94     (*G_OBJECT_CLASS (g_local_file_output_stream_parent_class)->finalize) (object);
95 }
96
97 static void
98 g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass)
99 {
100   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
101   GOutputStreamClass *stream_class = G_OUTPUT_STREAM_CLASS (klass);
102   GFileOutputStreamClass *file_stream_class = G_FILE_OUTPUT_STREAM_CLASS (klass);
103   
104   g_type_class_add_private (klass, sizeof (GLocalFileOutputStreamPrivate));
105   
106   gobject_class->finalize = g_local_file_output_stream_finalize;
107
108   stream_class->write = g_local_file_output_stream_write;
109   stream_class->close = g_local_file_output_stream_close;
110   file_stream_class->query_info = g_local_file_output_stream_query_info;
111   file_stream_class->get_etag = g_local_file_output_stream_get_etag;
112   file_stream_class->tell = g_local_file_output_stream_tell;
113   file_stream_class->can_seek = g_local_file_output_stream_can_seek;
114   file_stream_class->seek = g_local_file_output_stream_seek;
115   file_stream_class->can_truncate = g_local_file_output_stream_can_truncate;
116   file_stream_class->truncate = g_local_file_output_stream_truncate;
117 }
118
119 static void
120 g_local_file_output_stream_init (GLocalFileOutputStream *stream)
121 {
122   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
123                                               G_TYPE_LOCAL_FILE_OUTPUT_STREAM,
124                                               GLocalFileOutputStreamPrivate);
125 }
126
127 static gssize
128 g_local_file_output_stream_write (GOutputStream *stream,
129                                   const void   *buffer,
130                                   gsize         count,
131                                   GCancellable *cancellable,
132                                   GError      **error)
133 {
134   GLocalFileOutputStream *file;
135   gssize res;
136
137   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
138
139   while (1)
140     {
141       if (g_cancellable_set_error_if_cancelled (cancellable, error))
142         return -1;
143       res = write (file->priv->fd, buffer, count);
144       if (res == -1)
145         {
146           if (errno == EINTR)
147             continue;
148           
149           g_set_error (error, G_IO_ERROR,
150                        g_io_error_from_errno (errno),
151                        _("Error writing to file: %s"),
152                        g_strerror (errno));
153         }
154       
155       break;
156     }
157   
158   return res;
159 }
160
161 static gboolean
162 g_local_file_output_stream_close (GOutputStream *stream,
163                                   GCancellable *cancellable,
164                                   GError      **error)
165 {
166   GLocalFileOutputStream *file;
167   struct stat final_stat;
168   int res;
169
170   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
171
172   if (file->priv->tmp_filename)
173     {
174       /* We need to move the temp file to its final place,
175        * and possibly create the backup file
176        */
177
178       if (file->priv->backup_filename)
179         {
180           if (g_cancellable_set_error_if_cancelled (cancellable, error))
181             goto err_out;
182           
183 #ifdef HAVE_LINK
184           /* create original -> backup link, the original is then renamed over */
185           if (unlink (file->priv->backup_filename) != 0 &&
186               errno != ENOENT)
187             {
188               g_set_error (error, G_IO_ERROR,
189                            G_IO_ERROR_CANT_CREATE_BACKUP,
190                            _("Error removing old backup link: %s"),
191                            g_strerror (errno));
192               goto err_out;
193             }
194
195           if (link (file->priv->original_filename, file->priv->backup_filename) != 0)
196             {
197               g_set_error (error, G_IO_ERROR,
198                            G_IO_ERROR_CANT_CREATE_BACKUP,
199                            _("Error creating backup link: %s"),
200                            g_strerror (errno));
201               goto err_out;
202             }
203 #else
204             /* If link not supported, just rename... */
205           if (!rename (file->priv->original_filename, file->priv->backup_filename) != 0)
206             {
207               g_set_error (error, G_IO_ERROR,
208                            G_IO_ERROR_CANT_CREATE_BACKUP,
209                            _("Error creating backup copy: %s"),
210                            g_strerror (errno));
211               goto err_out;
212             }
213 #endif
214         }
215       
216
217       if (g_cancellable_set_error_if_cancelled (cancellable, error))
218         goto err_out;
219
220       /* tmp -> original */
221       if (rename (file->priv->tmp_filename, file->priv->original_filename) != 0)
222         {
223           g_set_error (error, G_IO_ERROR,
224                        g_io_error_from_errno (errno),
225                        _("Error renamining temporary file: %s"),
226                        g_strerror (errno));
227           goto err_out;
228         }
229     }
230   
231   if (g_cancellable_set_error_if_cancelled (cancellable, error))
232     goto err_out;
233       
234   if (fstat (file->priv->fd, &final_stat) == 0)
235     file->priv->etag = _g_local_file_info_create_etag (&final_stat);
236
237   while (1)
238     {
239       res = close (file->priv->fd);
240       if (res == -1)
241         {
242           g_set_error (error, G_IO_ERROR,
243                        g_io_error_from_errno (errno),
244                        _("Error closing file: %s"),
245                        g_strerror (errno));
246         }
247       break;
248     }
249   
250   return res != -1;
251
252  err_out:
253   /* A simple try to close the fd in case we fail before the actual close */
254   close (file->priv->fd);
255   return FALSE;
256 }
257
258 static char *
259 g_local_file_output_stream_get_etag (GFileOutputStream      *stream)
260 {
261   GLocalFileOutputStream *file;
262
263   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
264   
265   return g_strdup (file->priv->etag);
266 }
267
268 static goffset
269 g_local_file_output_stream_tell (GFileOutputStream *stream)
270 {
271   GLocalFileOutputStream *file;
272   off_t pos;
273
274   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
275   
276   pos = lseek (file->priv->fd, 0, SEEK_CUR);
277
278   if (pos == (off_t)-1)
279     return 0;
280   
281   return pos;
282 }
283
284 static gboolean
285 g_local_file_output_stream_can_seek (GFileOutputStream *stream)
286 {
287   GLocalFileOutputStream *file;
288   off_t pos;
289
290   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
291   
292   pos = lseek (file->priv->fd, 0, SEEK_CUR);
293
294   if (pos == (off_t)-1 &&
295       errno == ESPIPE)
296     return FALSE;
297   
298   return TRUE;
299 }
300
301 static int
302 seek_type_to_lseek (GSeekType type)
303 {
304   switch (type)
305     {
306     default:
307     case G_SEEK_CUR:
308       return SEEK_CUR;
309       
310     case G_SEEK_SET:
311       return SEEK_SET;
312       
313     case G_SEEK_END:
314       return SEEK_END;
315     }
316 }
317
318 static gboolean
319 g_local_file_output_stream_seek (GFileOutputStream     *stream,
320                                  goffset               offset,
321                                  GSeekType             type,
322                                  GCancellable         *cancellable,
323                                  GError              **error)
324 {
325   GLocalFileOutputStream *file;
326   off_t pos;
327
328   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
329
330   pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
331
332   if (pos == (off_t)-1)
333     {
334       g_set_error (error, G_IO_ERROR,
335                    g_io_error_from_errno (errno),
336                    _("Error seeking in file: %s"),
337                    g_strerror (errno));
338       return FALSE;
339     }
340   
341   return TRUE;
342 }
343
344 static gboolean
345 g_local_file_output_stream_can_truncate (GFileOutputStream    *stream)
346 {
347   /* We can't truncate pipes and stuff where we can't seek */
348   return g_local_file_output_stream_can_seek (stream);
349 }
350
351 static gboolean
352 g_local_file_output_stream_truncate (GFileOutputStream    *stream,
353                                      goffset               size,
354                                      GCancellable         *cancellable,
355                                      GError              **error)
356 {
357   GLocalFileOutputStream *file;
358   int res;
359
360   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
361
362  restart:
363   res = ftruncate(file->priv->fd, size);
364   
365   if (res == -1)
366     {
367       if (errno == EINTR)
368         {
369           if (g_cancellable_set_error_if_cancelled (cancellable, error))
370             return FALSE;
371           goto restart;
372         }
373
374       g_set_error (error, G_IO_ERROR,
375                    g_io_error_from_errno (errno),
376                    _("Error truncating file: %s"),
377                    g_strerror (errno));
378       return FALSE;
379     }
380   
381   return TRUE;
382 }
383
384
385 static GFileInfo *
386 g_local_file_output_stream_query_info (GFileOutputStream     *stream,
387                                        char                 *attributes,
388                                        GCancellable         *cancellable,
389                                        GError              **error)
390 {
391   GLocalFileOutputStream *file;
392
393   file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
394
395   if (g_cancellable_set_error_if_cancelled (cancellable, error))
396     return NULL;
397   
398   return _g_local_file_info_get_from_fd (file->priv->fd,
399                                          attributes,
400                                          error);
401 }
402
403 /**
404  * g_local_file_output_stream_create:
405  * @filename:
406  * @flags:
407  * @cancellable: optional #GCancellable object, %NULL to ignore. 
408  * @error: a #GError location to store the error occuring, or %NULL to 
409  * ignore.
410  * Returns: #GFileOutputStream.
411  **/
412 GFileOutputStream *
413 g_local_file_output_stream_create  (const char       *filename,
414                                     GFileCreateFlags  flags,
415                                     GCancellable     *cancellable,
416                                     GError          **error)
417 {
418   GLocalFileOutputStream *stream;
419   int mode;
420   int fd;
421
422   if (g_cancellable_set_error_if_cancelled (cancellable, error))
423     return NULL;
424
425   if (flags & G_FILE_CREATE_FLAGS_PRIVATE)
426     mode = 0600;
427   else
428     mode = 0666;
429   
430   fd = g_open (filename,
431                O_CREAT | O_EXCL | O_WRONLY,
432                0666);
433   if (fd == -1)
434     {
435       int errsv = errno;
436
437       if (errsv == EINVAL)
438         /* This must be an invalid filename, on e.g. FAT */
439         g_set_error (error, G_IO_ERROR,
440                      G_IO_ERROR_INVALID_FILENAME,
441                      _("Invalid filename"));
442       else
443         g_set_error (error, G_IO_ERROR,
444                      g_io_error_from_errno (errsv),
445                      _("Error opening file '%s': %s"),
446                      filename, g_strerror (errsv));
447       return NULL;
448     }
449   
450   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
451   stream->priv->fd = fd;
452   return G_FILE_OUTPUT_STREAM (stream);
453 }
454
455 /**
456  * g_local_file_output_stream_append:
457  * @filename:
458  * @flags:
459  * @cancellable: optional #GCancellable object, %NULL to ignore. 
460  * @error: a #GError location to store the error occuring, or %NULL to 
461  * ignore.
462  * Returns: 
463  **/
464 GFileOutputStream *
465 g_local_file_output_stream_append  (const char       *filename,
466                                     GFileCreateFlags  flags,
467                                     GCancellable     *cancellable,
468                                     GError          **error)
469 {
470   GLocalFileOutputStream *stream;
471   int mode;
472   int fd;
473
474   if (g_cancellable_set_error_if_cancelled (cancellable, error))
475     return NULL;
476
477   if (flags & G_FILE_CREATE_FLAGS_PRIVATE)
478     mode = 0600;
479   else
480     mode = 0666;
481
482   fd = g_open (filename,
483                O_CREAT | O_APPEND | O_WRONLY,
484                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   ssize_t bytes_read;
525   ssize_t bytes_to_write;
526   ssize_t 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   if (ftruncate (fd, 0) == -1)
822     {
823       g_set_error (error, G_IO_ERROR,
824                    g_io_error_from_errno (errno),
825                    _("Error truncating file: %s"),
826                    g_strerror (errno));
827       goto err_out;
828     }
829     
830   return fd;
831
832  err_out:
833   close (fd);
834   return -1;
835 }
836
837 /**
838  * g_local_file_output_stream_replace:
839  * @filename: the file name.
840  * @etag:
841  * @create_backup: if set, create a backup of the file.
842  * @flags:
843  * @cancellable: optional #GCancellable object, %NULL to ignore. 
844  * @error: a #GError location to store the error occuring, or %NULL to 
845  * ignore.
846  * Returns: #GFileOutputStream
847  **/
848 GFileOutputStream *
849 g_local_file_output_stream_replace (const char        *filename,
850                                     const char        *etag,
851                                     gboolean           create_backup,
852                                     GFileCreateFlags   flags,
853                                     GCancellable      *cancellable,
854                                     GError           **error)
855 {
856   GLocalFileOutputStream *stream;
857   int mode;
858   int fd;
859   char *temp_file;
860
861   if (g_cancellable_set_error_if_cancelled (cancellable, error))
862     return NULL;
863
864   temp_file = NULL;
865
866   if (flags & G_FILE_CREATE_FLAGS_PRIVATE)
867     mode = 0600;
868   else
869     mode = 0666;
870
871   /* If the file doesn't exist, create it */
872   fd = g_open (filename,
873                O_CREAT | O_EXCL | O_WRONLY,
874                mode);
875
876   if (fd == -1 && errno == EEXIST)
877     {
878       /* The file already exists */
879       fd = handle_overwrite_open (filename, etag, create_backup, &temp_file,
880                                   cancellable, error);
881       if (fd == -1)
882         return NULL;
883     }
884   else if (fd == -1)
885     {
886       int errsv = errno;
887
888       if (errsv == EINVAL)
889         /* This must be an invalid filename, on e.g. FAT */
890         g_set_error (error, G_IO_ERROR,
891                      G_IO_ERROR_INVALID_FILENAME,
892                      _("Invalid filename"));
893       else
894         g_set_error (error, G_IO_ERROR,
895                      g_io_error_from_errno (errsv),
896                      _("Error opening file '%s': %s"),
897                      filename, g_strerror (errsv));
898       return NULL;
899     }
900   
901  
902   stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
903   stream->priv->fd = fd;
904   stream->priv->tmp_filename = temp_file;
905   if (create_backup)
906     stream->priv->backup_filename = create_backup_filename (filename);
907   stream->priv->original_filename =  g_strdup (filename);
908   
909   return G_FILE_OUTPUT_STREAM (stream);
910 }