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