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
72 struct _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
83 static 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
88 G_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
93 G_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
104 static 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
110 static 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
117 static gboolean g_local_file_output_stream_close (GOutputStream *stream,
118 GCancellable *cancellable,
119 GError **error);
120 static GFileInfo *g_local_file_output_stream_query_info (GFileOutputStream *stream,
121 const char *attributes,
122 GCancellable *cancellable,
123 GError **error);
124 static char * g_local_file_output_stream_get_etag (GFileOutputStream *stream);
125 static goffset g_local_file_output_stream_tell (GFileOutputStream *stream);
126 static gboolean g_local_file_output_stream_can_seek (GFileOutputStream *stream);
127 static gboolean g_local_file_output_stream_seek (GFileOutputStream *stream,
128 goffset offset,
129 GSeekType type,
130 GCancellable *cancellable,
131 GError **error);
132 static gboolean g_local_file_output_stream_can_truncate (GFileOutputStream *stream);
133 static gboolean g_local_file_output_stream_truncate (GFileOutputStream *stream,
134 goffset size,
135 GCancellable *cancellable,
136 GError **error);
137 #ifdef G_OS_UNIX
138 static int g_local_file_output_stream_get_fd (GFileDescriptorBased *stream);
139 #endif
140
141 static void
g_local_file_output_stream_finalize(GObject * object)142 g_local_file_output_stream_finalize (GObject *object)
143 {
144 GLocalFileOutputStream *file;
145
146 file = G_LOCAL_FILE_OUTPUT_STREAM (object);
147
148 g_free (file->priv->tmp_filename);
149 g_free (file->priv->original_filename);
150 g_free (file->priv->backup_filename);
151 g_free (file->priv->etag);
152
153 G_OBJECT_CLASS (g_local_file_output_stream_parent_class)->finalize (object);
154 }
155
156 static void
g_local_file_output_stream_class_init(GLocalFileOutputStreamClass * klass)157 g_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
180 static void
g_file_descriptor_based_iface_init(GFileDescriptorBasedIface * iface)181 g_file_descriptor_based_iface_init (GFileDescriptorBasedIface *iface)
182 {
183 iface->get_fd = g_local_file_output_stream_get_fd;
184 }
185 #endif
186
187 static void
g_local_file_output_stream_init(GLocalFileOutputStream * stream)188 g_local_file_output_stream_init (GLocalFileOutputStream *stream)
189 {
190 stream->priv = g_local_file_output_stream_get_instance_private (stream);
191 stream->priv->do_close = TRUE;
192 }
193
194 static gssize
g_local_file_output_stream_write(GOutputStream * stream,const void * buffer,gsize count,GCancellable * cancellable,GError ** error)195 g_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 (file->priv->fd, buffer, count);
211 if (res == -1)
212 {
213 int errsv = errno;
214
215 if (errsv == EINTR)
216 continue;
217
218 g_set_error (error, G_IO_ERROR,
219 g_io_error_from_errno (errsv),
220 _("Error writing to file: %s"),
221 g_strerror (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
243 static gboolean
g_local_file_output_stream_writev(GOutputStream * stream,const GOutputVector * vectors,gsize n_vectors,gsize * bytes_written,GCancellable * cancellable,GError ** error)244 g_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 (file->priv->fd, iov, n_vectors);
289 if (res == -1)
290 {
291 int errsv = errno;
292
293 if (errsv == EINTR)
294 continue;
295
296 g_set_error (error, G_IO_ERROR,
297 g_io_error_from_errno (errsv),
298 _("Error writing to file: %s"),
299 g_strerror (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
313 void
_g_local_file_output_stream_set_do_close(GLocalFileOutputStream * out,gboolean do_close)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
320 gboolean
_g_local_file_output_stream_really_close(GLocalFileOutputStream * file,GCancellable * cancellable,GError ** error)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 (file->priv->fd) != 0)
329 {
330 int errsv = errno;
331
332 g_set_error (error, G_IO_ERROR,
333 g_io_error_from_errno (errsv),
334 _("Error writing to file: %s"),
335 g_strerror (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 (file->priv->backup_filename) != 0 &&
374 errno != ENOENT)
375 {
376 int errsv = errno;
377
378 g_set_error (error, G_IO_ERROR,
379 G_IO_ERROR_CANT_CREATE_BACKUP,
380 _("Error removing old backup link: %s"),
381 g_strerror (errsv));
382 goto err_out;
383 }
384
385 if (link (file->priv->original_filename, file->priv->backup_filename) != 0)
386 {
387 /* link failed or is not supported, try rename */
388 if (g_rename (file->priv->original_filename, file->priv->backup_filename) != 0)
389 {
390 int errsv = errno;
391
392 g_set_error (error, G_IO_ERROR,
393 G_IO_ERROR_CANT_CREATE_BACKUP,
394 _("Error creating backup copy: %s"),
395 g_strerror (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 (file->priv->tmp_filename, file->priv->original_filename) != 0)
420 {
421 int errsv = errno;
422
423 g_set_error (error, G_IO_ERROR,
424 g_io_error_from_errno (errsv),
425 _("Error renaming temporary file: %s"),
426 g_strerror (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 (file->priv->fd, G_LOCAL_FILE_STAT_FIELD_MTIME, G_LOCAL_FILE_STAT_FIELD_ALL, &final_stat) == 0)
439 file->priv->etag = _g_local_file_info_create_etag (&final_stat);
440
441 if (!g_close (file->priv->fd, NULL))
442 {
443 int errsv = errno;
444
445 g_set_error (error, G_IO_ERROR,
446 g_io_error_from_errno (errsv),
447 _("Error closing file: %s"),
448 g_strerror (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 (file->priv->fd, NULL);
460 #endif
461 if (file->priv->tmp_filename)
462 g_unlink (file->priv->tmp_filename);
463
464 return FALSE;
465 }
466
467
468 static gboolean
g_local_file_output_stream_close(GOutputStream * stream,GCancellable * cancellable,GError ** error)469 g_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
484 static char *
g_local_file_output_stream_get_etag(GFileOutputStream * stream)485 g_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 (file->priv->etag);
492 }
493
494 static goffset
g_local_file_output_stream_tell(GFileOutputStream * stream)495 g_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 (file->priv->fd, 0, SEEK_CUR);
503
504 if (pos == (off_t)-1)
505 return 0;
506
507 return pos;
508 }
509
510 static gboolean
g_local_file_output_stream_can_seek(GFileOutputStream * stream)511 g_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 (file->priv->fd, 0, SEEK_CUR);
519
520 if (pos == (off_t)-1 && errno == ESPIPE)
521 return FALSE;
522
523 return TRUE;
524 }
525
526 static int
seek_type_to_lseek(GSeekType type)527 seek_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
543 static gboolean
g_local_file_output_stream_seek(GFileOutputStream * stream,goffset offset,GSeekType type,GCancellable * cancellable,GError ** error)544 g_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 (file->priv->fd, offset, seek_type_to_lseek (type));
556
557 if (pos == (off_t)-1)
558 {
559 int errsv = errno;
560
561 g_set_error (error, G_IO_ERROR,
562 g_io_error_from_errno (errsv),
563 _("Error seeking in file: %s"),
564 g_strerror (errsv));
565 return FALSE;
566 }
567
568 return TRUE;
569 }
570
571 static gboolean
g_local_file_output_stream_can_truncate(GFileOutputStream * stream)572 g_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
578 static gboolean
g_local_file_output_stream_truncate(GFileOutputStream * stream,goffset size,GCancellable * cancellable,GError ** error)579 g_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 (file->priv->fd, 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 (error, G_IO_ERROR,
608 g_io_error_from_errno (errsv),
609 _("Error truncating file: %s"),
610 g_strerror (errsv));
611 return FALSE;
612 }
613
614 return TRUE;
615 }
616
617
618 static GFileInfo *
g_local_file_output_stream_query_info(GFileOutputStream * stream,const char * attributes,GCancellable * cancellable,GError ** error)619 g_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 (file->priv->fd,
632 attributes,
633 error);
634 }
635
636 GFileOutputStream *
_g_local_file_output_stream_new(int fd)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
646 static void
set_error_from_open_errno(const char * filename,GError ** error)647 set_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 (error, G_IO_ERROR,
655 G_IO_ERROR_INVALID_FILENAME,
656 _("Invalid filename"));
657 else
658 {
659 char *display_name = g_filename_display_name (filename);
660 g_set_error (error, G_IO_ERROR,
661 g_io_error_from_errno (errsv),
662 _("Error opening file “%s”: %s"),
663 display_name, g_strerror (errsv));
664 g_free (display_name);
665 }
666 }
667
668 static GFileOutputStream *
output_stream_open(const char * filename,gint open_flags,guint mode,GCancellable * cancellable,GError ** error)669 output_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 (filename, 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
690 GFileOutputStream *
_g_local_file_output_stream_open(const char * filename,gboolean readable,GCancellable * cancellable,GError ** error)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, 0666, cancellable, error);
708 }
709
710 static gint
mode_from_flags_or_info(GFileCreateFlags flags,GFileInfo * reference_info)711 mode_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 (reference_info, "unix::mode"))
717 return g_file_info_get_attribute_uint32 (reference_info, "unix::mode") & (~S_IFMT);
718 else
719 return 0666;
720 }
721
722 GFileOutputStream *
_g_local_file_output_stream_create(const char * filename,gboolean readable,GFileCreateFlags flags,GFileInfo * reference_info,GCancellable * cancellable,GError ** error)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
747 GFileOutputStream *
_g_local_file_output_stream_append(const char * filename,GFileCreateFlags flags,GCancellable * cancellable,GError ** error)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
767 static char *
create_backup_filename(const char * filename)768 create_backup_filename (const char *filename)
769 {
770 return g_strconcat (filename, BACKUP_EXTENSION, NULL);
771 }
772
773 #define BUFSIZE 8192 /* size of normal write buffer */
774
775 static gboolean
copy_file_data(gint sfd,gint dfd,GError ** error)776 copy_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 (sfd, buffer, BUFSIZE);
792 if (bytes_read == -1)
793 {
794 int errsv = errno;
795
796 if (errsv == EINTR)
797 continue;
798
799 g_set_error (error, G_IO_ERROR,
800 g_io_error_from_errno (errsv),
801 _("Error reading from file: %s"),
802 g_strerror (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 (dfd, write_buffer, 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 (error, G_IO_ERROR,
821 g_io_error_from_errno (errsv),
822 _("Error writing to file: %s"),
823 g_strerror (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 (buffer);
836
837 return ret;
838 }
839
840 static int
handle_overwrite_open(const char * filename,gboolean readable,const char * etag,gboolean create_backup,char ** temp_filename,GFileCreateFlags flags,GFileInfo * reference_info,GCancellable * cancellable,GError ** error)841 handle_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 (filename, 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 (filename, 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 (error, G_IO_ERROR,
906 g_io_error_from_errno (errsv),
907 _("Error opening file “%s”: %s"),
908 display_name, g_strerror (errsv));
909 g_free (display_name);
910 return -1;
911 }
912
913 if (!is_symlink)
914 {
915 res = g_local_file_fstat (fd,
916 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, &original_stat);
923 errsv = errno;
924 }
925 else
926 {
927 res = g_local_file_lstat (filename,
928 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, &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 (error, G_IO_ERROR,
942 g_io_error_from_errno (errsv),
943 _("Error when getting information for file “%s”: %s"),
944 display_name, g_strerror (errsv));
945 g_free (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 (error,
955 G_IO_ERROR,
956 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 (error,
969 G_IO_ERROR,
970 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 (filename,
986 G_LOCAL_FILE_STAT_FIELD_MTIME,
987 G_LOCAL_FILE_STAT_FIELD_ALL, &etag_stat);
988 errsv = errno;
989
990 if (res != 0)
991 {
992 char *display_name = g_filename_display_name (filename);
993 g_set_error (error, G_IO_ERROR,
994 g_io_error_from_errno (errsv),
995 _("Error when getting information for file “%s”: %s"),
996 display_name, g_strerror (errsv));
997 g_free (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 (etag_stat_pointer);
1008 if (strcmp (etag, current_etag) != 0)
1009 {
1010 g_set_error_literal (error,
1011 G_IO_ERROR,
1012 G_IO_ERROR_WRONG_ETAG,
1013 _("The file was externally modified"));
1014 g_free (current_etag);
1015 goto error;
1016 }
1017 g_free (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 (&original_stat) > 1) && !is_symlink))
1033 {
1034 char *dirname, *tmp_filename;
1035 int tmpfd;
1036
1037 dirname = g_path_get_dirname (filename);
1038 tmp_filename = g_build_filename (dirname, ".goutputstream-XXXXXX", NULL);
1039 g_free (dirname);
1040
1041 tmpfd = g_mkstemp_full (tmp_filename, (readable ? O_RDWR : O_WRONLY) | O_BINARY, mode);
1042 if (tmpfd == -1)
1043 {
1044 g_free (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 (tmpfd, _g_stat_uid (&original_stat), _g_stat_gid (&original_stat)) == -1 ||
1054 #endif
1055 #ifdef HAVE_FCHMOD
1056 fchmod (tmpfd, _g_stat_mode (&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 (tmpfd,
1066 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, &tmp_statbuf);
1071
1072 /* Check that we really needed to change something */
1073 if (tres != 0 ||
1074 _g_stat_uid (&original_stat) != _g_stat_uid (&tmp_statbuf) ||
1075 _g_stat_gid (&original_stat) != _g_stat_gid (&tmp_statbuf) ||
1076 _g_stat_mode (&original_stat) != _g_stat_mode (&tmp_statbuf))
1077 {
1078 g_close (tmpfd, NULL);
1079 g_unlink (tmp_filename);
1080 g_free (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 (backup_filename) == -1 && errno != ENOENT)
1104 {
1105 g_set_error_literal (error,
1106 G_IO_ERROR,
1107 G_IO_ERROR_CANT_CREATE_BACKUP,
1108 _("Backup file creation failed"));
1109 g_free (backup_filename);
1110 goto error;
1111 }
1112
1113 bfd = g_open (backup_filename,
1114 O_WRONLY | O_CREAT | O_EXCL | O_BINARY,
1115 _g_stat_mode (&original_stat) & 0777);
1116
1117 if (bfd == -1)
1118 {
1119 g_set_error_literal (error,
1120 G_IO_ERROR,
1121 G_IO_ERROR_CANT_CREATE_BACKUP,
1122 _("Backup file creation failed"));
1123 g_free (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 (bfd, G_LOCAL_FILE_STAT_FIELD_GID, G_LOCAL_FILE_STAT_FIELD_ALL, &tmp_statbuf) != 0)
1133 {
1134 g_set_error_literal (error,
1135 G_IO_ERROR,
1136 G_IO_ERROR_CANT_CREATE_BACKUP,
1137 _("Backup file creation failed"));
1138 g_unlink (backup_filename);
1139 g_close (bfd, NULL);
1140 g_free (backup_filename);
1141 goto error;
1142 }
1143
1144 if ((_g_stat_gid (&original_stat) != _g_stat_gid (&tmp_statbuf)) &&
1145 fchown (bfd, (uid_t) -1, _g_stat_gid (&original_stat)) != 0)
1146 {
1147 if (fchmod (bfd,
1148 (_g_stat_mode (&original_stat) & 0707) |
1149 ((_g_stat_mode (&original_stat) & 07) << 3)) != 0)
1150 {
1151 g_set_error_literal (error,
1152 G_IO_ERROR,
1153 G_IO_ERROR_CANT_CREATE_BACKUP,
1154 _("Backup file creation failed"));
1155 g_unlink (backup_filename);
1156 g_close (bfd, NULL);
1157 g_free (backup_filename);
1158 goto error;
1159 }
1160 }
1161 #endif
1162
1163 if (!copy_file_data (fd, bfd, NULL))
1164 {
1165 g_set_error_literal (error,
1166 G_IO_ERROR,
1167 G_IO_ERROR_CANT_CREATE_BACKUP,
1168 _("Backup file creation failed"));
1169 g_unlink (backup_filename);
1170 g_close (bfd, NULL);
1171 g_free (backup_filename);
1172
1173 goto error;
1174 }
1175
1176 g_close (bfd, NULL);
1177 g_free (backup_filename);
1178
1179 /* Seek back to the start of the file after the backup copy */
1180 if (lseek (fd, 0, SEEK_SET) == -1)
1181 {
1182 int errsv = errno;
1183
1184 g_set_error (error, G_IO_ERROR,
1185 g_io_error_from_errno (errsv),
1186 _("Error seeking in file: %s"),
1187 g_strerror (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 (error, G_IO_ERROR,
1201 g_io_error_from_errno (errsv),
1202 _("Error removing old file: %s"),
1203 g_strerror (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 (filename, 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 (error, G_IO_ERROR,
1217 g_io_error_from_errno (errsv),
1218 _("Error opening file “%s”: %s"),
1219 display_name, g_strerror (errsv));
1220 g_free (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, 0) == -1)
1231 #endif
1232 {
1233 int errsv = errno;
1234
1235 g_set_error (error, G_IO_ERROR,
1236 g_io_error_from_errno (errsv),
1237 _("Error truncating file: %s"),
1238 g_strerror (errsv));
1239 goto error;
1240 }
1241 }
1242
1243 return fd;
1244
1245 error:
1246 if (fd >= 0)
1247 g_close (fd, NULL);
1248
1249 return -1;
1250 }
1251
1252 GFileOutputStream *
_g_local_file_output_stream_replace(const char * filename,gboolean readable,const char * etag,gboolean create_backup,GFileCreateFlags flags,GFileInfo * reference_info,GCancellable * cancellable,GError ** error)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 (filename, 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_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 (filename);
1320
1321 return G_FILE_OUTPUT_STREAM (stream);
1322 }
1323
1324 gint
_g_local_file_output_stream_get_fd(GLocalFileOutputStream * stream)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
1332 static int
g_local_file_output_stream_get_fd(GFileDescriptorBased * fd_based)1333 g_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