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