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