Merge branch 'test-ip_mreq_source-android-only' into 'master'
[glib.git] / gio / glocalfileoutputstream.c
blob57d2d5dfe350e67b002888c0dfd8645f99a78393
1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
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.1 of the License, or (at your option) any later version.
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.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Alexander Larsson <alexl@redhat.com>
21 #include "config.h"
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <string.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #include "glibintl.h"
32 #include "gioerror.h"
33 #include "gcancellable.h"
34 #include "glocalfileoutputstream.h"
35 #include "gfileinfo.h"
36 #include "glocalfileinfo.h"
38 #ifdef G_OS_UNIX
39 #include <unistd.h>
40 #include "gfiledescriptorbased.h"
41 #endif
43 #include "glib-private.h"
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
55 #ifndef O_BINARY
56 #define O_BINARY 0
57 #endif
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;
69 #ifdef G_OS_UNIX
70 static void g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface);
71 #endif
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
85 /* Some of the file replacement code was based on the code from gedit,
86 * relicenced to LGPL with permissions from the authors.
89 #define BACKUP_EXTENSION "~"
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
120 static void
121 g_local_file_output_stream_finalize (GObject *object)
123 GLocalFileOutputStream *file;
125 file = G_LOCAL_FILE_OUTPUT_STREAM (object);
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);
132 G_OBJECT_CLASS (g_local_file_output_stream_parent_class)->finalize (object);
135 static void
136 g_local_file_output_stream_class_init (GLocalFileOutputStreamClass *klass)
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);
142 gobject_class->finalize = g_local_file_output_stream_finalize;
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;
155 #ifdef G_OS_UNIX
156 static void
157 g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
159 iface->get_fd = g_local_file_output_stream_get_fd;
161 #endif
163 static void
164 g_local_file_output_stream_init (GLocalFileOutputStream *stream)
166 stream->priv = g_local_file_output_stream_get_instance_private (stream);
167 stream->priv->do_close = TRUE;
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)
177 GLocalFileOutputStream *file;
178 gssize res;
180 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
182 while (1)
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)
189 int errsv = errno;
191 if (errsv == EINTR)
192 continue;
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));
200 break;
203 return res;
206 void
207 _g_local_file_output_stream_set_do_close (GLocalFileOutputStream *out,
208 gboolean do_close)
210 out->priv->do_close = do_close;
213 gboolean
214 _g_local_file_output_stream_really_close (GLocalFileOutputStream *file,
215 GCancellable *cancellable,
216 GError **error)
218 GLocalFileStat final_stat;
220 #ifdef HAVE_FSYNC
221 if (file->priv->sync_on_close &&
222 fsync (file->priv->fd) != 0)
224 int errsv = errno;
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;
232 #endif
234 #ifdef G_OS_WIN32
236 /* Must close before renaming on Windows, so just do the close first
237 * in all cases for now.
239 if (GLIB_PRIVATE_CALL (g_win32_fstat) (file->priv->fd, &final_stat) == 0)
240 file->priv->etag = _g_local_file_info_create_etag (&final_stat);
242 if (!g_close (file->priv->fd, NULL))
244 int errsv = errno;
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;
253 #endif
255 if (file->priv->tmp_filename)
257 /* We need to move the temp file to its final place,
258 * and possibly create the backup file
261 if (file->priv->backup_filename)
263 if (g_cancellable_set_error_if_cancelled (cancellable, error))
264 goto err_out;
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)
271 int errsv = errno;
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;
280 if (link (file->priv->original_filename, file->priv->backup_filename) != 0)
282 /* link failed or is not supported, try rename */
283 if (g_rename (file->priv->original_filename, file->priv->backup_filename) != 0)
285 int errsv = errno;
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;
294 #else
295 /* If link not supported, just rename... */
296 if (g_rename (file->priv->original_filename, file->priv->backup_filename) != 0)
298 int errsv = errno;
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;
306 #endif
310 if (g_cancellable_set_error_if_cancelled (cancellable, error))
311 goto err_out;
313 /* tmp -> original */
314 if (g_rename (file->priv->tmp_filename, file->priv->original_filename) != 0)
316 int errsv = errno;
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;
325 g_clear_pointer (&file->priv->tmp_filename, g_free);
328 if (g_cancellable_set_error_if_cancelled (cancellable, error))
329 goto err_out;
331 #ifndef G_OS_WIN32 /* Already did the fstat() and close() above on Win32 */
333 if (fstat (file->priv->fd, &final_stat) == 0)
334 file->priv->etag = _g_local_file_info_create_etag (&final_stat);
336 if (!g_close (file->priv->fd, NULL))
338 int errsv = errno;
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;
347 #endif
349 return TRUE;
350 err_out:
352 #ifndef G_OS_WIN32
353 /* A simple try to close the fd in case we fail before the actual close */
354 g_close (file->priv->fd, NULL);
355 #endif
356 if (file->priv->tmp_filename)
357 g_unlink (file->priv->tmp_filename);
359 return FALSE;
363 static gboolean
364 g_local_file_output_stream_close (GOutputStream *stream,
365 GCancellable *cancellable,
366 GError **error)
368 GLocalFileOutputStream *file;
370 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
372 if (file->priv->do_close)
373 return _g_local_file_output_stream_really_close (file,
374 cancellable,
375 error);
376 return TRUE;
379 static char *
380 g_local_file_output_stream_get_etag (GFileOutputStream *stream)
382 GLocalFileOutputStream *file;
384 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
386 return g_strdup (file->priv->etag);
389 static goffset
390 g_local_file_output_stream_tell (GFileOutputStream *stream)
392 GLocalFileOutputStream *file;
393 off_t pos;
395 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
397 pos = lseek (file->priv->fd, 0, SEEK_CUR);
399 if (pos == (off_t)-1)
400 return 0;
402 return pos;
405 static gboolean
406 g_local_file_output_stream_can_seek (GFileOutputStream *stream)
408 GLocalFileOutputStream *file;
409 off_t pos;
411 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
413 pos = lseek (file->priv->fd, 0, SEEK_CUR);
415 if (pos == (off_t)-1 && errno == ESPIPE)
416 return FALSE;
418 return TRUE;
421 static int
422 seek_type_to_lseek (GSeekType type)
424 switch (type)
426 default:
427 case G_SEEK_CUR:
428 return SEEK_CUR;
430 case G_SEEK_SET:
431 return SEEK_SET;
433 case G_SEEK_END:
434 return SEEK_END;
438 static gboolean
439 g_local_file_output_stream_seek (GFileOutputStream *stream,
440 goffset offset,
441 GSeekType type,
442 GCancellable *cancellable,
443 GError **error)
445 GLocalFileOutputStream *file;
446 off_t pos;
448 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
450 pos = lseek (file->priv->fd, offset, seek_type_to_lseek (type));
452 if (pos == (off_t)-1)
454 int errsv = errno;
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;
463 return TRUE;
466 static gboolean
467 g_local_file_output_stream_can_truncate (GFileOutputStream *stream)
469 /* We can't truncate pipes and stuff where we can't seek */
470 return g_local_file_output_stream_can_seek (stream);
473 static gboolean
474 g_local_file_output_stream_truncate (GFileOutputStream *stream,
475 goffset size,
476 GCancellable *cancellable,
477 GError **error)
479 GLocalFileOutputStream *file;
480 int res;
482 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
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
491 if (res == -1)
493 int errsv = errno;
495 if (errsv == EINTR)
497 if (g_cancellable_set_error_if_cancelled (cancellable, error))
498 return FALSE;
499 goto restart;
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;
509 return TRUE;
513 static GFileInfo *
514 g_local_file_output_stream_query_info (GFileOutputStream *stream,
515 const char *attributes,
516 GCancellable *cancellable,
517 GError **error)
519 GLocalFileOutputStream *file;
521 file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
523 if (g_cancellable_set_error_if_cancelled (cancellable, error))
524 return NULL;
526 return _g_local_file_info_get_from_fd (file->priv->fd,
527 attributes,
528 error);
531 GFileOutputStream *
532 _g_local_file_output_stream_new (int fd)
534 GLocalFileOutputStream *stream;
536 stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
537 stream->priv->fd = fd;
538 return G_FILE_OUTPUT_STREAM (stream);
541 static void
542 set_error_from_open_errno (const char *filename,
543 GError **error)
545 int errsv = errno;
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
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);
563 static GFileOutputStream *
564 output_stream_open (const char *filename,
565 gint open_flags,
566 guint mode,
567 GCancellable *cancellable,
568 GError **error)
570 GLocalFileOutputStream *stream;
571 gint fd;
573 fd = g_open (filename, open_flags, mode);
574 if (fd == -1)
576 set_error_from_open_errno (filename, error);
577 return NULL;
580 stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
581 stream->priv->fd = fd;
582 return G_FILE_OUTPUT_STREAM (stream);
585 GFileOutputStream *
586 _g_local_file_output_stream_open (const char *filename,
587 gboolean readable,
588 GCancellable *cancellable,
589 GError **error)
591 int open_flags;
593 if (g_cancellable_set_error_if_cancelled (cancellable, error))
594 return NULL;
596 open_flags = O_BINARY;
597 if (readable)
598 open_flags |= O_RDWR;
599 else
600 open_flags |= O_WRONLY;
602 return output_stream_open (filename, open_flags, 0666, cancellable, error);
605 static gint
606 mode_from_flags_or_info (GFileCreateFlags flags,
607 GFileInfo *reference_info)
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;
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)
625 int mode;
626 int open_flags;
628 if (g_cancellable_set_error_if_cancelled (cancellable, error))
629 return NULL;
631 mode = mode_from_flags_or_info (flags, reference_info);
633 open_flags = O_CREAT | O_EXCL | O_BINARY;
634 if (readable)
635 open_flags |= O_RDWR;
636 else
637 open_flags |= O_WRONLY;
639 return output_stream_open (filename, open_flags, mode, cancellable, error);
642 GFileOutputStream *
643 _g_local_file_output_stream_append (const char *filename,
644 GFileCreateFlags flags,
645 GCancellable *cancellable,
646 GError **error)
648 int mode;
650 if (g_cancellable_set_error_if_cancelled (cancellable, error))
651 return NULL;
653 if (flags & G_FILE_CREATE_PRIVATE)
654 mode = 0600;
655 else
656 mode = 0666;
658 return output_stream_open (filename, O_CREAT | O_APPEND | O_WRONLY | O_BINARY, mode,
659 cancellable, error);
662 static char *
663 create_backup_filename (const char *filename)
665 return g_strconcat (filename, BACKUP_EXTENSION, NULL);
668 #define BUFSIZE 8192 /* size of normal write buffer */
670 static gboolean
671 copy_file_data (gint sfd,
672 gint dfd,
673 GError **error)
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;
682 buffer = g_malloc (BUFSIZE);
686 bytes_read = read (sfd, buffer, BUFSIZE);
687 if (bytes_read == -1)
689 int errsv = errno;
691 if (errsv == EINTR)
692 continue;
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;
702 bytes_to_write = bytes_read;
703 write_buffer = buffer;
707 bytes_written = write (dfd, write_buffer, bytes_to_write);
708 if (bytes_written == -1)
710 int errsv = errno;
712 if (errsv == EINTR)
713 continue;
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;
723 bytes_to_write -= bytes_written;
724 write_buffer += bytes_written;
726 while (bytes_to_write > 0);
728 } while ((bytes_read != 0) && (ret == TRUE));
730 g_free (buffer);
732 return ret;
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)
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 int errsv;
755 mode = mode_from_flags_or_info (flags, reference_info);
757 /* We only need read access to the original file if we are creating a backup.
758 * We also add O_CREATE to avoid a race if the file was just removed */
759 if (create_backup || readable)
760 open_flags = O_RDWR | O_CREAT | O_BINARY;
761 else
762 open_flags = O_WRONLY | O_CREAT | O_BINARY;
764 /* Some systems have O_NOFOLLOW, which lets us avoid some races
765 * when finding out if the file we opened was a symlink */
766 #ifdef O_NOFOLLOW
767 is_symlink = FALSE;
768 fd = g_open (filename, open_flags | O_NOFOLLOW, mode);
769 errsv = errno;
770 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
771 if (fd == -1 && errsv == EMLINK)
772 #elif defined(__NetBSD__)
773 if (fd == -1 && errsv == EFTYPE)
774 #else
775 if (fd == -1 && errsv == ELOOP)
776 #endif
778 /* Could be a symlink, or it could be a regular ELOOP error,
779 * but then the next open will fail too. */
780 is_symlink = TRUE;
781 fd = g_open (filename, open_flags, mode);
783 #else
784 fd = g_open (filename, open_flags, mode);
785 errsv = errno;
786 /* This is racy, but we do it as soon as possible to minimize the race */
787 is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
788 #endif
790 if (fd == -1)
792 char *display_name = g_filename_display_name (filename);
793 g_set_error (error, G_IO_ERROR,
794 g_io_error_from_errno (errsv),
795 _("Error opening file ā€œ%sā€: %s"),
796 display_name, g_strerror (errsv));
797 g_free (display_name);
798 return -1;
801 #ifdef G_OS_WIN32
802 res = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &original_stat);
803 #else
804 res = fstat (fd, &original_stat);
805 #endif
806 errsv = errno;
808 if (res != 0)
810 char *display_name = g_filename_display_name (filename);
811 g_set_error (error, G_IO_ERROR,
812 g_io_error_from_errno (errsv),
813 _("Error when getting information for file ā€œ%sā€: %s"),
814 display_name, g_strerror (errsv));
815 g_free (display_name);
816 goto err_out;
819 /* not a regular file */
820 if (!S_ISREG (original_stat.st_mode))
822 if (S_ISDIR (original_stat.st_mode))
823 g_set_error_literal (error,
824 G_IO_ERROR,
825 G_IO_ERROR_IS_DIRECTORY,
826 _("Target file is a directory"));
827 else
828 g_set_error_literal (error,
829 G_IO_ERROR,
830 G_IO_ERROR_NOT_REGULAR_FILE,
831 _("Target file is not a regular file"));
832 goto err_out;
835 if (etag != NULL)
837 current_etag = _g_local_file_info_create_etag (&original_stat);
838 if (strcmp (etag, current_etag) != 0)
840 g_set_error_literal (error,
841 G_IO_ERROR,
842 G_IO_ERROR_WRONG_ETAG,
843 _("The file was externally modified"));
844 g_free (current_etag);
845 goto err_out;
847 g_free (current_etag);
850 /* We use two backup strategies.
851 * The first one (which is faster) consist in saving to a
852 * tmp file then rename the original file to the backup and the
853 * tmp file to the original name. This is fast but doesn't work
854 * when the file is a link (hard or symbolic) or when we can't
855 * write to the current dir or can't set the permissions on the
856 * new file.
857 * The second strategy consist simply in copying the old file
858 * to a backup file and rewrite the contents of the file.
861 if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
862 (!(original_stat.st_nlink > 1) && !is_symlink))
864 char *dirname, *tmp_filename;
865 int tmpfd;
867 dirname = g_path_get_dirname (filename);
868 tmp_filename = g_build_filename (dirname, ".goutputstream-XXXXXX", NULL);
869 g_free (dirname);
871 tmpfd = g_mkstemp_full (tmp_filename, (readable ? O_RDWR : O_WRONLY) | O_BINARY, mode);
872 if (tmpfd == -1)
874 g_free (tmp_filename);
875 goto fallback_strategy;
878 /* try to keep permissions (unless replacing) */
880 if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
882 #ifdef HAVE_FCHOWN
883 fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
884 #endif
885 #ifdef HAVE_FCHMOD
886 fchmod (tmpfd, original_stat.st_mode) == -1 ||
887 #endif
892 GLocalFileStat tmp_statbuf;
893 int tres;
895 #ifdef G_OS_WIN32
896 tres = GLIB_PRIVATE_CALL (g_win32_fstat) (tmpfd, &tmp_statbuf);
897 #else
898 tres = fstat (tmpfd, &tmp_statbuf);
899 #endif
900 /* Check that we really needed to change something */
901 if (tres != 0 ||
902 original_stat.st_uid != tmp_statbuf.st_uid ||
903 original_stat.st_gid != tmp_statbuf.st_gid ||
904 original_stat.st_mode != tmp_statbuf.st_mode)
906 g_close (tmpfd, NULL);
907 g_unlink (tmp_filename);
908 g_free (tmp_filename);
909 goto fallback_strategy;
913 g_close (fd, NULL);
914 *temp_filename = tmp_filename;
915 return tmpfd;
918 fallback_strategy:
920 if (create_backup)
922 #if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
923 struct stat tmp_statbuf;
924 #endif
925 char *backup_filename;
926 int bfd;
928 backup_filename = create_backup_filename (filename);
930 if (g_unlink (backup_filename) == -1 && errno != ENOENT)
932 g_set_error_literal (error,
933 G_IO_ERROR,
934 G_IO_ERROR_CANT_CREATE_BACKUP,
935 _("Backup file creation failed"));
936 g_free (backup_filename);
937 goto err_out;
940 bfd = g_open (backup_filename,
941 O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
942 original_stat.st_mode & 0777);
944 if (bfd == -1)
946 g_set_error_literal (error,
947 G_IO_ERROR,
948 G_IO_ERROR_CANT_CREATE_BACKUP,
949 _("Backup file creation failed"));
950 g_free (backup_filename);
951 goto err_out;
954 /* If needed, Try to set the group of the backup same as the
955 * original file. If this fails, set the protection
956 * bits for the group same as the protection bits for
957 * others. */
958 #if defined(HAVE_FCHOWN) && defined(HAVE_FCHMOD)
959 if (fstat (bfd, &tmp_statbuf) != 0)
961 g_set_error_literal (error,
962 G_IO_ERROR,
963 G_IO_ERROR_CANT_CREATE_BACKUP,
964 _("Backup file creation failed"));
965 g_unlink (backup_filename);
966 g_close (bfd, NULL);
967 g_free (backup_filename);
968 goto err_out;
971 if ((original_stat.st_gid != tmp_statbuf.st_gid) &&
972 fchown (bfd, (uid_t) -1, original_stat.st_gid) != 0)
974 if (fchmod (bfd,
975 (original_stat.st_mode & 0707) |
976 ((original_stat.st_mode & 07) << 3)) != 0)
978 g_set_error_literal (error,
979 G_IO_ERROR,
980 G_IO_ERROR_CANT_CREATE_BACKUP,
981 _("Backup file creation failed"));
982 g_unlink (backup_filename);
983 g_close (bfd, NULL);
984 g_free (backup_filename);
985 goto err_out;
988 #endif
990 if (!copy_file_data (fd, bfd, NULL))
992 g_set_error_literal (error,
993 G_IO_ERROR,
994 G_IO_ERROR_CANT_CREATE_BACKUP,
995 _("Backup file creation failed"));
996 g_unlink (backup_filename);
997 g_close (bfd, NULL);
998 g_free (backup_filename);
1000 goto err_out;
1003 g_close (bfd, NULL);
1004 g_free (backup_filename);
1006 /* Seek back to the start of the file after the backup copy */
1007 if (lseek (fd, 0, SEEK_SET) == -1)
1009 int errsv = errno;
1011 g_set_error (error, G_IO_ERROR,
1012 g_io_error_from_errno (errsv),
1013 _("Error seeking in file: %s"),
1014 g_strerror (errsv));
1015 goto err_out;
1019 if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
1021 g_close (fd, NULL);
1023 if (g_unlink (filename) != 0)
1025 int errsv = errno;
1027 g_set_error (error, G_IO_ERROR,
1028 g_io_error_from_errno (errsv),
1029 _("Error removing old file: %s"),
1030 g_strerror (errsv));
1031 goto err_out2;
1034 if (readable)
1035 open_flags = O_RDWR | O_CREAT | O_BINARY;
1036 else
1037 open_flags = O_WRONLY | O_CREAT | O_BINARY;
1038 fd = g_open (filename, open_flags, mode);
1039 if (fd == -1)
1041 int errsv = errno;
1042 char *display_name = g_filename_display_name (filename);
1043 g_set_error (error, G_IO_ERROR,
1044 g_io_error_from_errno (errsv),
1045 _("Error opening file ā€œ%sā€: %s"),
1046 display_name, g_strerror (errsv));
1047 g_free (display_name);
1048 goto err_out2;
1051 else
1053 /* Truncate the file at the start */
1054 #ifdef G_OS_WIN32
1055 if (g_win32_ftruncate (fd, 0) == -1)
1056 #else
1057 if (ftruncate (fd, 0) == -1)
1058 #endif
1060 int errsv = errno;
1062 g_set_error (error, G_IO_ERROR,
1063 g_io_error_from_errno (errsv),
1064 _("Error truncating file: %s"),
1065 g_strerror (errsv));
1066 goto err_out;
1070 return fd;
1072 err_out:
1073 g_close (fd, NULL);
1074 err_out2:
1075 return -1;
1078 GFileOutputStream *
1079 _g_local_file_output_stream_replace (const char *filename,
1080 gboolean readable,
1081 const char *etag,
1082 gboolean create_backup,
1083 GFileCreateFlags flags,
1084 GFileInfo *reference_info,
1085 GCancellable *cancellable,
1086 GError **error)
1088 GLocalFileOutputStream *stream;
1089 int mode;
1090 int fd;
1091 char *temp_file;
1092 gboolean sync_on_close;
1093 int open_flags;
1095 if (g_cancellable_set_error_if_cancelled (cancellable, error))
1096 return NULL;
1098 temp_file = NULL;
1100 mode = mode_from_flags_or_info (flags, reference_info);
1101 sync_on_close = FALSE;
1103 /* If the file doesn't exist, create it */
1104 open_flags = O_CREAT | O_EXCL | O_BINARY;
1105 if (readable)
1106 open_flags |= O_RDWR;
1107 else
1108 open_flags |= O_WRONLY;
1109 fd = g_open (filename, open_flags, mode);
1111 if (fd == -1 && errno == EEXIST)
1113 /* The file already exists */
1114 fd = handle_overwrite_open (filename, readable, etag,
1115 create_backup, &temp_file,
1116 flags, reference_info,
1117 cancellable, error);
1118 if (fd == -1)
1119 return NULL;
1121 /* If the final destination exists, we want to sync the newly written
1122 * file to ensure the data is on disk when we rename over the destination.
1123 * otherwise if we get a system crash we can lose both the new and the
1124 * old file on some filesystems. (I.E. those that don't guarantee the
1125 * data is written to the disk before the metadata.)
1127 sync_on_close = TRUE;
1129 else if (fd == -1)
1131 set_error_from_open_errno (filename, error);
1132 return NULL;
1136 stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
1137 stream->priv->fd = fd;
1138 stream->priv->sync_on_close = sync_on_close;
1139 stream->priv->tmp_filename = temp_file;
1140 if (create_backup)
1141 stream->priv->backup_filename = create_backup_filename (filename);
1142 stream->priv->original_filename = g_strdup (filename);
1144 return G_FILE_OUTPUT_STREAM (stream);
1147 gint
1148 _g_local_file_output_stream_get_fd (GLocalFileOutputStream *stream)
1150 g_return_val_if_fail (G_IS_LOCAL_FILE_OUTPUT_STREAM (stream), -1);
1151 return stream->priv->fd;
1154 #ifdef G_OS_UNIX
1155 static int
1156 g_local_file_output_stream_get_fd (GFileDescriptorBased *fd_based)
1158 GLocalFileOutputStream *stream = G_LOCAL_FILE_OUTPUT_STREAM (fd_based);
1159 return _g_local_file_output_stream_get_fd (stream);
1161 #endif