From 14d58d51a325797aee3b53fb4e0ba76ca0adc3f5 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Wed, 13 May 2009 13:03:47 +0200 Subject: [PATCH] Local file implementation of GFileIOStream and ops This implements all the GIOStream file ops for local files. We use the "fallback to output stream" for all GFileIOStream ops. Some helpers stuff was added to the local input and output streams so they could be reused. --- gio/Makefile.am | 2 + gio/glocalfile.c | 67 +++++++++++++++++++++++ gio/glocalfileinputstream.c | 12 ++++ gio/glocalfileinputstream.h | 5 +- gio/glocalfileiostream.c | 114 ++++++++++++++++++++++++++++++++++++++ gio/glocalfileiostream.h | 60 ++++++++++++++++++++ gio/glocalfileoutputstream.c | 127 ++++++++++++++++++++++++++++++++++++++----- gio/glocalfileoutputstream.h | 14 +++++ 8 files changed, 385 insertions(+), 16 deletions(-) create mode 100644 gio/glocalfileiostream.c create mode 100644 gio/glocalfileiostream.h diff --git a/gio/Makefile.am b/gio/Makefile.am index 76e402d..8481a7a 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -89,6 +89,8 @@ local_sources = \ glocalfilemonitor.h \ glocalfileoutputstream.c \ glocalfileoutputstream.h \ + glocalfileiostream.c \ + glocalfileiostream.h \ glocalvfs.c \ glocalvfs.h \ $(NULL) diff --git a/gio/glocalfile.c b/gio/glocalfile.c index efb8417..8ac6014 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -78,6 +78,7 @@ #include "glocalfileenumerator.h" #include "glocalfileinputstream.h" #include "glocalfileoutputstream.h" +#include "glocalfileiostream.h" #include "glocaldirectorymonitor.h" #include "glocalfilemonitor.h" #include "gmountprivate.h" @@ -1322,6 +1323,7 @@ g_local_file_create (GFile *file, GError **error) { return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename, + FALSE, flags, cancellable, error); } @@ -1334,10 +1336,72 @@ g_local_file_replace (GFile *file, GError **error) { return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename, + FALSE, etag, make_backup, flags, cancellable, error); } +static GFileIOStream * +g_local_file_open_readwrite (GFile *file, + GCancellable *cancellable, + GError **error) +{ + GFileOutputStream *output; + GFileIOStream *res; + + output = _g_local_file_output_stream_open (G_LOCAL_FILE (file)->filename, + TRUE, + cancellable, error); + if (output == NULL) + return NULL; + + res = _g_local_file_io_stream_new (G_LOCAL_FILE_OUTPUT_STREAM (output)); + g_object_unref (output); + return res; +} + +static GFileIOStream * +g_local_file_create_readwrite (GFile *file, + GFileCreateFlags flags, + GCancellable *cancellable, + GError **error) +{ + GFileOutputStream *output; + GFileIOStream *res; + + output = _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename, + TRUE, flags, + cancellable, error); + if (output == NULL) + return NULL; + + res = _g_local_file_io_stream_new (G_LOCAL_FILE_OUTPUT_STREAM (output)); + g_object_unref (output); + return res; +} + +static GFileIOStream * +g_local_file_replace_readwrite (GFile *file, + const char *etag, + gboolean make_backup, + GFileCreateFlags flags, + GCancellable *cancellable, + GError **error) +{ + GFileOutputStream *output; + GFileIOStream *res; + + output = _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename, + TRUE, + etag, make_backup, flags, + cancellable, error); + if (output == NULL) + return NULL; + + res = _g_local_file_io_stream_new (G_LOCAL_FILE_OUTPUT_STREAM (output)); + g_object_unref (output); + return res; +} static gboolean g_local_file_delete (GFile *file, @@ -2288,6 +2352,9 @@ g_local_file_file_iface_init (GFileIface *iface) iface->append_to = g_local_file_append_to; iface->create = g_local_file_create; iface->replace = g_local_file_replace; + iface->open_readwrite = g_local_file_open_readwrite; + iface->create_readwrite = g_local_file_create_readwrite; + iface->replace_readwrite = g_local_file_replace_readwrite; iface->delete_file = g_local_file_delete; iface->trash = g_local_file_trash; iface->make_directory = g_local_file_make_directory; diff --git a/gio/glocalfileinputstream.c b/gio/glocalfileinputstream.c index a8d0104..544c568 100644 --- a/gio/glocalfileinputstream.c +++ b/gio/glocalfileinputstream.c @@ -49,6 +49,7 @@ G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INP struct _GLocalFileInputStreamPrivate { int fd; + guint do_close : 1; }; static gssize g_local_file_input_stream_read (GInputStream *stream, @@ -85,6 +86,13 @@ g_local_file_input_stream_finalize (GObject *object) G_OBJECT_CLASS (g_local_file_input_stream_parent_class)->finalize (object); } +void +_g_local_file_input_stream_set_do_close (GLocalFileInputStream *in, + gboolean do_close) +{ + in->priv->do_close = do_close; +} + static void g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass) { @@ -111,6 +119,7 @@ g_local_file_input_stream_init (GLocalFileInputStream *info) info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info, G_TYPE_LOCAL_FILE_INPUT_STREAM, GLocalFileInputStreamPrivate); + info->priv->do_close = TRUE; } /** @@ -218,6 +227,9 @@ g_local_file_input_stream_close (GInputStream *stream, file = G_LOCAL_FILE_INPUT_STREAM (stream); + if (!file->priv->do_close) + return TRUE; + if (file->priv->fd == -1) return TRUE; diff --git a/gio/glocalfileinputstream.h b/gio/glocalfileinputstream.h index 29740d6..28f28bf 100644 --- a/gio/glocalfileinputstream.h +++ b/gio/glocalfileinputstream.h @@ -53,7 +53,10 @@ struct _GLocalFileInputStreamClass GType _g_local_file_input_stream_get_type (void) G_GNUC_CONST; -GFileInputStream * _g_local_file_input_stream_new (int fd); +GFileInputStream *_g_local_file_input_stream_new (int fd); +void _g_local_file_input_stream_set_do_close (GLocalFileInputStream *in, + gboolean do_close); + G_END_DECLS diff --git a/gio/glocalfileiostream.c b/gio/glocalfileiostream.c new file mode 100644 index 0000000..cb08061 --- /dev/null +++ b/gio/glocalfileiostream.c @@ -0,0 +1,114 @@ +/* GIO - GLib Input, IO and Streaming Library + * + * Copyright (C) 2006-2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#include "config.h" + +#include +#include +#include "glibintl.h" +#include "gioerror.h" +#include "gcancellable.h" +#include "glocalfileiostream.h" +#include "glocalfileinputstream.h" +#include "glocalfileinfo.h" + +#include "gioalias.h" + +#define g_local_file_io_stream_get_type _g_local_file_io_stream_get_type +G_DEFINE_TYPE (GLocalFileIOStream, g_local_file_io_stream, G_TYPE_FILE_IO_STREAM); + +static void +g_local_file_io_stream_finalize (GObject *object) +{ + GLocalFileIOStream *file; + + file = G_LOCAL_FILE_IO_STREAM (object); + + g_object_unref (file->input_stream); + g_object_unref (file->output_stream); + + G_OBJECT_CLASS (g_local_file_io_stream_parent_class)->finalize (object); +} + +GFileIOStream * +_g_local_file_io_stream_new (GLocalFileOutputStream *output_stream) +{ + GLocalFileIOStream *stream; + int fd; + + stream = g_object_new (G_TYPE_LOCAL_FILE_IO_STREAM, NULL); + stream->output_stream = g_object_ref (output_stream); + _g_local_file_output_stream_set_do_close (output_stream, FALSE); + fd = _g_local_file_output_stream_get_fd (output_stream); + stream->input_stream = (GInputStream *)_g_local_file_input_stream_new (fd); + _g_local_file_input_stream_set_do_close (G_LOCAL_FILE_INPUT_STREAM (stream->input_stream), + FALSE); + + return G_FILE_IO_STREAM (stream); +} + +static GInputStream * +g_local_file_io_stream_get_input_stream (GIOStream *stream) +{ + return G_LOCAL_FILE_IO_STREAM (stream)->input_stream; +} + +static GOutputStream * +g_local_file_io_stream_get_output_stream (GIOStream *stream) +{ + return G_LOCAL_FILE_IO_STREAM (stream)->output_stream; +} + + +static gboolean +g_local_file_io_stream_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + GLocalFileIOStream *file = G_LOCAL_FILE_IO_STREAM (stream); + + /* There are shortcutted and can't fail */ + g_output_stream_close (file->output_stream, cancellable, NULL); + g_input_stream_close (file->input_stream, cancellable, NULL); + + return + _g_local_file_output_stream_really_close (G_LOCAL_FILE_OUTPUT_STREAM (file->output_stream), + cancellable, error); +} + +static void +g_local_file_io_stream_class_init (GLocalFileIOStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass); + + gobject_class->finalize = g_local_file_io_stream_finalize; + + stream_class->get_input_stream = g_local_file_io_stream_get_input_stream; + stream_class->get_output_stream = g_local_file_io_stream_get_output_stream; + stream_class->close_fn = g_local_file_io_stream_close; +} + +static void +g_local_file_io_stream_init (GLocalFileIOStream *stream) +{ +} diff --git a/gio/glocalfileiostream.h b/gio/glocalfileiostream.h new file mode 100644 index 0000000..be7c786 --- /dev/null +++ b/gio/glocalfileiostream.h @@ -0,0 +1,60 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Alexander Larsson + */ + +#ifndef __G_LOCAL_FILE_IO_STREAM_H__ +#define __G_LOCAL_FILE_IO_STREAM_H__ + +#include +#include "glocalfileoutputstream.h" + +G_BEGIN_DECLS + +#define G_TYPE_LOCAL_FILE_IO_STREAM (_g_local_file_io_stream_get_type ()) +#define G_LOCAL_FILE_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_LOCAL_FILE_IO_STREAM, GLocalFileIOStream)) +#define G_LOCAL_FILE_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_LOCAL_FILE_IO_STREAM, GLocalFileIOStreamClass)) +#define G_IS_LOCAL_FILE_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_LOCAL_FILE_IO_STREAM)) +#define G_IS_LOCAL_FILE_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_LOCAL_FILE_IO_STREAM)) +#define G_LOCAL_FILE_IO_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_LOCAL_FILE_IO_STREAM, GLocalFileIOStreamClass)) + +typedef struct _GLocalFileIOStream GLocalFileIOStream; +typedef struct _GLocalFileIOStreamClass GLocalFileIOStreamClass; +typedef struct _GLocalFileIOStreamPrivate GLocalFileIOStreamPrivate; + +struct _GLocalFileIOStream +{ + GFileIOStream parent_instance; + + GInputStream *input_stream; + GOutputStream *output_stream; +}; + +struct _GLocalFileIOStreamClass +{ + GFileIOStreamClass parent_class; +}; + +GType _g_local_file_io_stream_get_type (void) G_GNUC_CONST; +GFileIOStream * _g_local_file_io_stream_new (GLocalFileOutputStream *output_stream); + +G_END_DECLS + +#endif /* __G_LOCAL_FILE_IO_STREAM_H__ */ diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c index 7c73da4..cb97831 100644 --- a/gio/glocalfileoutputstream.c +++ b/gio/glocalfileoutputstream.c @@ -69,7 +69,8 @@ struct _GLocalFileOutputStreamPrivate { char *original_filename; char *backup_filename; char *etag; - gboolean sync_on_close; + guint sync_on_close : 1; + guint do_close : 1; int fd; }; @@ -142,6 +143,13 @@ g_local_file_output_stream_init (GLocalFileOutputStream *stream) stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_LOCAL_FILE_OUTPUT_STREAM, GLocalFileOutputStreamPrivate); + stream->priv->do_close = TRUE; +} + +int +_g_local_file_output_stream_get_fd (GLocalFileOutputStream *out) +{ + return out->priv->fd; } static gssize @@ -180,17 +188,21 @@ g_local_file_output_stream_write (GOutputStream *stream, return res; } -static gboolean -g_local_file_output_stream_close (GOutputStream *stream, - GCancellable *cancellable, - GError **error) +void +_g_local_file_output_stream_set_do_close (GLocalFileOutputStream *out, + gboolean do_close) +{ + out->priv->do_close = do_close; +} + +gboolean +_g_local_file_output_stream_really_close (GLocalFileOutputStream *file, + GCancellable *cancellable, + GError **error) { - GLocalFileOutputStream *file; GLocalFileStat final_stat; int res; - file = G_LOCAL_FILE_OUTPUT_STREAM (stream); - #ifdef HAVE_FSYNC if (file->priv->sync_on_close && fsync (file->priv->fd) != 0) @@ -338,6 +350,23 @@ g_local_file_output_stream_close (GOutputStream *stream, return FALSE; } + +static gboolean +g_local_file_output_stream_close (GOutputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GLocalFileOutputStream *file; + + file = G_LOCAL_FILE_OUTPUT_STREAM (stream); + + if (file->priv->do_close) + return _g_local_file_output_stream_really_close (file, + cancellable, + error); + return TRUE; +} + static char * g_local_file_output_stream_get_etag (GFileOutputStream *stream) { @@ -491,7 +520,55 @@ g_local_file_output_stream_query_info (GFileOutputStream *stream, } GFileOutputStream * +_g_local_file_output_stream_open (const char *filename, + gboolean readable, + GCancellable *cancellable, + GError **error) +{ + GLocalFileOutputStream *stream; + int mode; + int fd; + int open_flags; + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return NULL; + + open_flags = O_BINARY; + if (readable) + open_flags |= O_RDWR; + else + open_flags |= O_WRONLY; + + fd = g_open (filename, open_flags, 0666); + if (fd == -1) + { + int errsv = errno; + + if (errsv == EINVAL) + /* This must be an invalid filename, on e.g. FAT */ + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_INVALID_FILENAME, + _("Invalid filename")); + else + { + char *display_name = g_filename_display_name (filename); + g_set_error (error, G_IO_ERROR, + g_io_error_from_errno (errsv), + _("Error opening file '%s': %s"), + display_name, g_strerror (errsv)); + g_free (display_name); + } + return NULL; + } + + stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL); + stream->priv->fd = fd; + return G_FILE_OUTPUT_STREAM (stream); +} + +GFileOutputStream * _g_local_file_output_stream_create (const char *filename, + gboolean readable, GFileCreateFlags flags, GCancellable *cancellable, GError **error) @@ -499,6 +576,7 @@ _g_local_file_output_stream_create (const char *filename, GLocalFileOutputStream *stream; int mode; int fd; + int open_flags; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; @@ -507,8 +585,14 @@ _g_local_file_output_stream_create (const char *filename, mode = 0600; else mode = 0666; - - fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode); + + open_flags = O_CREAT | O_EXCL | O_BINARY; + if (readable) + open_flags |= O_RDWR; + else + open_flags |= O_WRONLY; + + fd = g_open (filename, open_flags, mode); if (fd == -1) { int errsv = errno; @@ -656,6 +740,7 @@ copy_file_data (gint sfd, static int handle_overwrite_open (const char *filename, + gboolean readable, const char *etag, gboolean create_backup, char **temp_filename, @@ -678,7 +763,7 @@ handle_overwrite_open (const char *filename, /* We only need read access to the original file if we are creating a backup. * We also add O_CREATE to avoid a race if the file was just removed */ - if (create_backup) + if (create_backup || readable) open_flags = O_RDWR | O_CREAT | O_BINARY; else open_flags = O_WRONLY | O_CREAT | O_BINARY; @@ -938,8 +1023,12 @@ handle_overwrite_open (const char *filename, g_strerror (errsv)); goto err_out2; } - - fd = g_open (filename, O_WRONLY | O_CREAT | O_BINARY, mode); + + if (readable) + open_flags = O_RDWR | O_CREAT | O_BINARY; + else + open_flags = O_WRONLY | O_CREAT | O_BINARY; + fd = g_open (filename, open_flags, mode); if (fd == -1) { int errsv = errno; @@ -981,6 +1070,7 @@ handle_overwrite_open (const char *filename, GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, + gboolean readable, const char *etag, gboolean create_backup, GFileCreateFlags flags, @@ -992,6 +1082,7 @@ _g_local_file_output_stream_replace (const char *filename, int fd; char *temp_file; gboolean sync_on_close; + int open_flags; if (g_cancellable_set_error_if_cancelled (cancellable, error)) return NULL; @@ -1005,12 +1096,18 @@ _g_local_file_output_stream_replace (const char *filename, sync_on_close = FALSE; /* If the file doesn't exist, create it */ - fd = g_open (filename, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode); + open_flags = O_CREAT | O_EXCL | O_BINARY; + if (readable) + open_flags |= O_RDWR; + else + open_flags |= O_WRONLY; + fd = g_open (filename, open_flags, mode); if (fd == -1 && errno == EEXIST) { /* The file already exists */ - fd = handle_overwrite_open (filename, etag, create_backup, &temp_file, + fd = handle_overwrite_open (filename, readable, etag, + create_backup, &temp_file, flags, cancellable, error); if (fd == -1) return NULL; diff --git a/gio/glocalfileoutputstream.h b/gio/glocalfileoutputstream.h index 3606f65..5f08d13 100644 --- a/gio/glocalfileoutputstream.h +++ b/gio/glocalfileoutputstream.h @@ -52,7 +52,20 @@ struct _GLocalFileOutputStreamClass }; GType _g_local_file_output_stream_get_type (void) G_GNUC_CONST; + +int _g_local_file_output_stream_get_fd (GLocalFileOutputStream *out); +void _g_local_file_output_stream_set_do_close (GLocalFileOutputStream *out, + gboolean do_close); +gboolean _g_local_file_output_stream_really_close (GLocalFileOutputStream *out, + GCancellable *cancellable, + GError **error); + +GFileOutputStream * _g_local_file_output_stream_open (const char *filename, + gboolean readable, + GCancellable *cancellable, + GError **error); GFileOutputStream * _g_local_file_output_stream_create (const char *filename, + gboolean readable, GFileCreateFlags flags, GCancellable *cancellable, GError **error); @@ -61,6 +74,7 @@ GFileOutputStream * _g_local_file_output_stream_append (const char *file GCancellable *cancellable, GError **error); GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, + gboolean readable, const char *etag, gboolean create_backup, GFileCreateFlags flags, -- 2.7.4