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.
This commit is contained in:
Alexander Larsson 2009-05-13 13:03:47 +02:00
parent 7a2d4889b5
commit 14d58d51a3
8 changed files with 385 additions and 16 deletions

View File

@ -89,6 +89,8 @@ local_sources = \
glocalfilemonitor.h \ glocalfilemonitor.h \
glocalfileoutputstream.c \ glocalfileoutputstream.c \
glocalfileoutputstream.h \ glocalfileoutputstream.h \
glocalfileiostream.c \
glocalfileiostream.h \
glocalvfs.c \ glocalvfs.c \
glocalvfs.h \ glocalvfs.h \
$(NULL) $(NULL)

View File

@ -78,6 +78,7 @@
#include "glocalfileenumerator.h" #include "glocalfileenumerator.h"
#include "glocalfileinputstream.h" #include "glocalfileinputstream.h"
#include "glocalfileoutputstream.h" #include "glocalfileoutputstream.h"
#include "glocalfileiostream.h"
#include "glocaldirectorymonitor.h" #include "glocaldirectorymonitor.h"
#include "glocalfilemonitor.h" #include "glocalfilemonitor.h"
#include "gmountprivate.h" #include "gmountprivate.h"
@ -1322,6 +1323,7 @@ g_local_file_create (GFile *file,
GError **error) GError **error)
{ {
return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename, return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename,
FALSE,
flags, cancellable, error); flags, cancellable, error);
} }
@ -1334,10 +1336,72 @@ g_local_file_replace (GFile *file,
GError **error) GError **error)
{ {
return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename, return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename,
FALSE,
etag, make_backup, flags, etag, make_backup, flags,
cancellable, error); 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 static gboolean
g_local_file_delete (GFile *file, 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->append_to = g_local_file_append_to;
iface->create = g_local_file_create; iface->create = g_local_file_create;
iface->replace = g_local_file_replace; 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->delete_file = g_local_file_delete;
iface->trash = g_local_file_trash; iface->trash = g_local_file_trash;
iface->make_directory = g_local_file_make_directory; iface->make_directory = g_local_file_make_directory;

View File

@ -49,6 +49,7 @@ G_DEFINE_TYPE (GLocalFileInputStream, g_local_file_input_stream, G_TYPE_FILE_INP
struct _GLocalFileInputStreamPrivate { struct _GLocalFileInputStreamPrivate {
int fd; int fd;
guint do_close : 1;
}; };
static gssize g_local_file_input_stream_read (GInputStream *stream, 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); 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 static void
g_local_file_input_stream_class_init (GLocalFileInputStreamClass *klass) 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, info->priv = G_TYPE_INSTANCE_GET_PRIVATE (info,
G_TYPE_LOCAL_FILE_INPUT_STREAM, G_TYPE_LOCAL_FILE_INPUT_STREAM,
GLocalFileInputStreamPrivate); 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); file = G_LOCAL_FILE_INPUT_STREAM (stream);
if (!file->priv->do_close)
return TRUE;
if (file->priv->fd == -1) if (file->priv->fd == -1)
return TRUE; return TRUE;

View File

@ -54,6 +54,9 @@ struct _GLocalFileInputStreamClass
GType _g_local_file_input_stream_get_type (void) G_GNUC_CONST; 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 G_END_DECLS

114
gio/glocalfileiostream.c Normal file
View File

@ -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 <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)
{
}

60
gio/glocalfileiostream.h Normal file
View File

@ -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 <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__ */

View File

@ -69,7 +69,8 @@ struct _GLocalFileOutputStreamPrivate {
char *original_filename; char *original_filename;
char *backup_filename; char *backup_filename;
char *etag; char *etag;
gboolean sync_on_close; guint sync_on_close : 1;
guint do_close : 1;
int fd; int fd;
}; };
@ -142,6 +143,13 @@ g_local_file_output_stream_init (GLocalFileOutputStream *stream)
stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
G_TYPE_LOCAL_FILE_OUTPUT_STREAM, G_TYPE_LOCAL_FILE_OUTPUT_STREAM,
GLocalFileOutputStreamPrivate); GLocalFileOutputStreamPrivate);
stream->priv->do_close = TRUE;
}
int
_g_local_file_output_stream_get_fd (GLocalFileOutputStream *out)
{
return out->priv->fd;
} }
static gssize static gssize
@ -180,17 +188,21 @@ g_local_file_output_stream_write (GOutputStream *stream,
return res; return res;
} }
static gboolean void
g_local_file_output_stream_close (GOutputStream *stream, _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, GCancellable *cancellable,
GError **error) GError **error)
{ {
GLocalFileOutputStream *file;
GLocalFileStat final_stat; GLocalFileStat final_stat;
int res; int res;
file = G_LOCAL_FILE_OUTPUT_STREAM (stream);
#ifdef HAVE_FSYNC #ifdef HAVE_FSYNC
if (file->priv->sync_on_close && if (file->priv->sync_on_close &&
fsync (file->priv->fd) != 0) fsync (file->priv->fd) != 0)
@ -338,6 +350,23 @@ g_local_file_output_stream_close (GOutputStream *stream,
return FALSE; 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 * static char *
g_local_file_output_stream_get_etag (GFileOutputStream *stream) g_local_file_output_stream_get_etag (GFileOutputStream *stream)
{ {
@ -490,8 +519,56 @@ g_local_file_output_stream_query_info (GFileOutputStream *stream,
error); error);
} }
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 * GFileOutputStream *
_g_local_file_output_stream_create (const char *filename, _g_local_file_output_stream_create (const char *filename,
gboolean readable,
GFileCreateFlags flags, GFileCreateFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GError **error) GError **error)
@ -499,6 +576,7 @@ _g_local_file_output_stream_create (const char *filename,
GLocalFileOutputStream *stream; GLocalFileOutputStream *stream;
int mode; int mode;
int fd; int fd;
int open_flags;
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL; return NULL;
@ -508,7 +586,13 @@ _g_local_file_output_stream_create (const char *filename,
else else
mode = 0666; 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) if (fd == -1)
{ {
int errsv = errno; int errsv = errno;
@ -656,6 +740,7 @@ copy_file_data (gint sfd,
static int static int
handle_overwrite_open (const char *filename, handle_overwrite_open (const char *filename,
gboolean readable,
const char *etag, const char *etag,
gboolean create_backup, gboolean create_backup,
char **temp_filename, 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 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 */ * 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; open_flags = O_RDWR | O_CREAT | O_BINARY;
else else
open_flags = O_WRONLY | O_CREAT | O_BINARY; open_flags = O_WRONLY | O_CREAT | O_BINARY;
@ -939,7 +1024,11 @@ handle_overwrite_open (const char *filename,
goto err_out2; 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) if (fd == -1)
{ {
int errsv = errno; int errsv = errno;
@ -981,6 +1070,7 @@ handle_overwrite_open (const char *filename,
GFileOutputStream * GFileOutputStream *
_g_local_file_output_stream_replace (const char *filename, _g_local_file_output_stream_replace (const char *filename,
gboolean readable,
const char *etag, const char *etag,
gboolean create_backup, gboolean create_backup,
GFileCreateFlags flags, GFileCreateFlags flags,
@ -992,6 +1082,7 @@ _g_local_file_output_stream_replace (const char *filename,
int fd; int fd;
char *temp_file; char *temp_file;
gboolean sync_on_close; gboolean sync_on_close;
int open_flags;
if (g_cancellable_set_error_if_cancelled (cancellable, error)) if (g_cancellable_set_error_if_cancelled (cancellable, error))
return NULL; return NULL;
@ -1005,12 +1096,18 @@ _g_local_file_output_stream_replace (const char *filename,
sync_on_close = FALSE; sync_on_close = FALSE;
/* If the file doesn't exist, create it */ /* 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) if (fd == -1 && errno == EEXIST)
{ {
/* The file already exists */ /* 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); flags, cancellable, error);
if (fd == -1) if (fd == -1)
return NULL; return NULL;

View File

@ -52,7 +52,20 @@ struct _GLocalFileOutputStreamClass
}; };
GType _g_local_file_output_stream_get_type (void) G_GNUC_CONST; 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, GFileOutputStream * _g_local_file_output_stream_create (const char *filename,
gboolean readable,
GFileCreateFlags flags, GFileCreateFlags flags,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
@ -61,6 +74,7 @@ GFileOutputStream * _g_local_file_output_stream_append (const char *file
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
GFileOutputStream * _g_local_file_output_stream_replace (const char *filename, GFileOutputStream * _g_local_file_output_stream_replace (const char *filename,
gboolean readable,
const char *etag, const char *etag,
gboolean create_backup, gboolean create_backup,
GFileCreateFlags flags, GFileCreateFlags flags,