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