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.
glocalfilemonitor.h \
glocalfileoutputstream.c \
glocalfileoutputstream.h \
+ glocalfileiostream.c \
+ glocalfileiostream.h \
glocalvfs.c \
glocalvfs.h \
$(NULL)
#include "glocalfileenumerator.h"
#include "glocalfileinputstream.h"
#include "glocalfileoutputstream.h"
+#include "glocalfileiostream.h"
#include "glocaldirectorymonitor.h"
#include "glocalfilemonitor.h"
#include "gmountprivate.h"
GError **error)
{
return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename,
+ FALSE,
flags, cancellable, error);
}
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,
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;
struct _GLocalFileInputStreamPrivate {
int fd;
+ guint do_close : 1;
};
static gssize g_local_file_input_stream_read (GInputStream *stream,
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)
{
info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info,
G_TYPE_LOCAL_FILE_INPUT_STREAM,
GLocalFileInputStreamPrivate);
+ info->priv->do_close = TRUE;
}
/**
file = G_LOCAL_FILE_INPUT_STREAM (stream);
+ if (!file->priv->do_close)
+ return TRUE;
+
if (file->priv->fd == -1)
return TRUE;
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
--- /dev/null
+/* 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 <alexl@redhat.com>
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#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)
+{
+}
--- /dev/null
+/* 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 <alexl@redhat.com>
+ */
+
+#ifndef __G_LOCAL_FILE_IO_STREAM_H__
+#define __G_LOCAL_FILE_IO_STREAM_H__
+
+#include <gio/gfileiostream.h>
+#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__ */
char *original_filename;
char *backup_filename;
char *etag;
- gboolean sync_on_close;
+ guint sync_on_close : 1;
+ guint do_close : 1;
int fd;
};
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
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)
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)
{
}
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)
GLocalFileOutputStream *stream;
int mode;
int fd;
+ int open_flags;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL;
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;
static int
handle_overwrite_open (const char *filename,
+ gboolean readable,
const char *etag,
gboolean create_backup,
char **temp_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;
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;
GFileOutputStream *
_g_local_file_output_stream_replace (const char *filename,
+ gboolean readable,
const char *etag,
gboolean create_backup,
GFileCreateFlags flags,
int fd;
char *temp_file;
gboolean sync_on_close;
+ int open_flags;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL;
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;
};
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);
GCancellable *cancellable,
GError **error);
GFileOutputStream * _g_local_file_output_stream_replace (const char *filename,
+ gboolean readable,
const char *etag,
gboolean create_backup,
GFileCreateFlags flags,