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

source code of gtk/subprojects/glib/gio/glocalfileoutputstream.c