summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorRoss Lagerwall <rosslagerwall@gmail.com>2013-10-17 07:26:05 +0200
committerRoss Lagerwall <rosslagerwall@gmail.com>2013-12-05 23:51:30 +0000
commitc3b6615e95bd213beab32d90a8bf38f1b221a8b4 (patch)
treeb18ec470be6377b527e603d58ca274bb5c48074d /daemon
parent444a63d09fdaf4db8124801ec6f4ff26ca3c7c0e (diff)
downloadgvfs-c3b6615e95bd213beab32d90a8bf38f1b221a8b4.tar.gz
Implement truncate support for output streams
Backends receive a TRUNCATE message which contains a size parameter. Truncation is signaled with a TRUNCATED message (which contains no other useful information). In more detail: Add a new dbus method, OpenForWriteFlags, which has a flags parameter to implement can_seek and can_truncate. These flags are used in GDaemonFileOutputStream. Compatability with old clients is maintained. Implement the can_truncate and truncate_fn GDaemonFileOutputStream methods. Add two new message types to the daemon socket protocol: G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_TRUNCATE G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_TRUNCATED Add a new job type, GVfsJobTruncate. Add two new methods to GVfsBackend which backend classes can implement: truncate and try_truncate https://bugzilla.gnome.org/show_bug.cgi?id=573837
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gvfsbackend.c1
-rw-r--r--daemon/gvfsbackend.h9
-rw-r--r--daemon/gvfsjobopenforwrite.c107
-rw-r--r--daemon/gvfsjobopenforwrite.h22
-rw-r--r--daemon/gvfsjobtruncate.c128
-rw-r--r--daemon/gvfsjobtruncate.h63
-rw-r--r--daemon/gvfswritechannel.c26
-rw-r--r--daemon/gvfswritechannel.h1
9 files changed, 338 insertions, 20 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 020943ac..6a1b8378 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -178,6 +178,7 @@ libdaemon_la_SOURCES = \
gvfsjobopenforwrite.c gvfsjobopenforwrite.h \
gvfsjobwrite.c gvfsjobwrite.h \
gvfsjobseekwrite.c gvfsjobseekwrite.h \
+ gvfsjobtruncate.c gvfsjobtruncate.h \
gvfsjobclosewrite.c gvfsjobclosewrite.h \
gvfsjobqueryinfo.c gvfsjobqueryinfo.h \
gvfsjobqueryinforead.c gvfsjobqueryinforead.h \
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index f6eb77bc..26eba289 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -280,6 +280,7 @@ register_path_cb (GDBusConnection *conn,
g_signal_connect (skeleton, "handle-unmount", G_CALLBACK (g_vfs_job_unmount_new_handle), data);
g_signal_connect (skeleton, "handle-open-for-read", G_CALLBACK (g_vfs_job_open_for_read_new_handle), data);
g_signal_connect (skeleton, "handle-open-for-write", G_CALLBACK (g_vfs_job_open_for_write_new_handle), data);
+ g_signal_connect (skeleton, "handle-open-for-write-flags", G_CALLBACK (g_vfs_job_open_for_write_new_handle_with_flags), data);
g_signal_connect (skeleton, "handle-copy", G_CALLBACK (g_vfs_job_copy_new_handle), data);
g_signal_connect (skeleton, "handle-move", G_CALLBACK (g_vfs_job_move_new_handle), data);
g_signal_connect (skeleton, "handle-push", G_CALLBACK (g_vfs_job_push_new_handle), data);
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index 45ec4fb7..8e7ba551 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -55,6 +55,7 @@ typedef struct _GVfsJobRead GVfsJobRead;
typedef struct _GVfsJobOpenForWrite GVfsJobOpenForWrite;
typedef struct _GVfsJobWrite GVfsJobWrite;
typedef struct _GVfsJobSeekWrite GVfsJobSeekWrite;
+typedef struct _GVfsJobTruncate GVfsJobTruncate;
typedef struct _GVfsJobCloseWrite GVfsJobCloseWrite;
typedef struct _GVfsJobQueryInfo GVfsJobQueryInfo;
typedef struct _GVfsJobQueryInfoRead GVfsJobQueryInfoRead;
@@ -236,6 +237,14 @@ struct _GVfsBackendClass
GVfsBackendHandle handle,
goffset offset,
GSeekType type);
+ void (*truncate) (GVfsBackend *backend,
+ GVfsJobTruncate *job,
+ GVfsBackendHandle handle,
+ goffset size);
+ gboolean (*try_truncate) (GVfsBackend *backend,
+ GVfsJobTruncate *job,
+ GVfsBackendHandle handle,
+ goffset size);
void (*query_info) (GVfsBackend *backend,
GVfsJobQueryInfo *job,
const char *filename,
diff --git a/daemon/gvfsjobopenforwrite.c b/daemon/gvfsjobopenforwrite.c
index 429e2679..1388dabf 100644
--- a/daemon/gvfsjobopenforwrite.c
+++ b/daemon/gvfsjobopenforwrite.c
@@ -81,28 +81,29 @@ g_vfs_job_open_for_write_init (GVfsJobOpenForWrite *job)
{
}
-gboolean
-g_vfs_job_open_for_write_new_handle (GVfsDBusMount *object,
- GDBusMethodInvocation *invocation,
- GUnixFDList *fd_list,
- const gchar *arg_path_data,
- guint16 arg_mode,
- const gchar *arg_etag,
- gboolean arg_make_backup,
- guint arg_flags,
- guint arg_pid,
- GVfsBackend *backend)
+static gboolean
+open_for_write_new_handle_common (GVfsDBusMount *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ const gchar *arg_path_data,
+ guint16 arg_mode,
+ const gchar *arg_etag,
+ gboolean arg_make_backup,
+ guint arg_flags,
+ guint arg_pid,
+ GVfsBackend *backend,
+ GVfsJobOpenForWriteVersion version)
{
GVfsJobOpenForWrite *job;
-
+
if (g_vfs_backend_invocation_first_handler (object, invocation, backend))
return TRUE;
-
+
job = g_object_new (G_VFS_TYPE_JOB_OPEN_FOR_WRITE,
"object", object,
"invocation", invocation,
NULL);
-
+
job->filename = g_strdup (arg_path_data);
job->mode = arg_mode;
if (*arg_etag != 0)
@@ -111,6 +112,7 @@ g_vfs_job_open_for_write_new_handle (GVfsDBusMount *object,
job->flags = arg_flags;
job->backend = backend;
job->pid = arg_pid;
+ job->version = version;
g_vfs_job_source_new_job (G_VFS_JOB_SOURCE (backend), G_VFS_JOB (job));
g_object_unref (job);
@@ -118,6 +120,56 @@ g_vfs_job_open_for_write_new_handle (GVfsDBusMount *object,
return TRUE;
}
+gboolean
+g_vfs_job_open_for_write_new_handle (GVfsDBusMount *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ const gchar *arg_path_data,
+ guint16 arg_mode,
+ const gchar *arg_etag,
+ gboolean arg_make_backup,
+ guint arg_flags,
+ guint arg_pid,
+ GVfsBackend *backend)
+{
+ return open_for_write_new_handle_common(object,
+ invocation,
+ fd_list,
+ arg_path_data,
+ arg_mode,
+ arg_etag,
+ arg_make_backup,
+ arg_flags,
+ arg_pid,
+ backend,
+ OPEN_FOR_WRITE_VERSION_ORIGINAL);
+}
+
+gboolean
+g_vfs_job_open_for_write_new_handle_with_flags (GVfsDBusMount *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ const gchar *arg_path_data,
+ guint16 arg_mode,
+ const gchar *arg_etag,
+ gboolean arg_make_backup,
+ guint arg_flags,
+ guint arg_pid,
+ GVfsBackend *backend)
+{
+ return open_for_write_new_handle_common(object,
+ invocation,
+ fd_list,
+ arg_path_data,
+ arg_mode,
+ arg_etag,
+ arg_make_backup,
+ arg_flags,
+ arg_pid,
+ backend,
+ OPEN_FOR_WRITE_VERSION_WITH_FLAGS);
+}
+
static void
run (GVfsJob *job)
{
@@ -233,6 +285,13 @@ g_vfs_job_open_for_write_set_can_seek (GVfsJobOpenForWrite *job,
}
void
+g_vfs_job_open_for_write_set_can_truncate (GVfsJobOpenForWrite *job,
+ gboolean can_truncate)
+{
+ job->can_truncate = can_truncate;
+}
+
+void
g_vfs_job_open_for_write_set_initial_offset (GVfsJobOpenForWrite *job,
goffset initial_offset)
{
@@ -284,10 +343,22 @@ create_reply (GVfsJob *job,
g_signal_emit_by_name (job, "new-source", open_job->write_channel);
- gvfs_dbus_mount_complete_open_for_write (object, invocation,
- fd_list, g_variant_new_handle (fd_id),
- open_job->can_seek,
- open_job->initial_offset);
+ switch (open_job->version)
+ {
+ case OPEN_FOR_WRITE_VERSION_ORIGINAL:
+ gvfs_dbus_mount_complete_open_for_write (object, invocation,
+ fd_list, g_variant_new_handle (fd_id),
+ open_job->can_seek ? OPEN_FOR_WRITE_FLAG_CAN_SEEK : 0,
+ open_job->initial_offset);
+ break;
+ case OPEN_FOR_WRITE_VERSION_WITH_FLAGS:
+ gvfs_dbus_mount_complete_open_for_write_flags (object, invocation,
+ fd_list, g_variant_new_handle (fd_id),
+ (open_job->can_seek ? OPEN_FOR_WRITE_FLAG_CAN_SEEK : 0) |
+ (open_job->can_truncate ? OPEN_FOR_WRITE_FLAG_CAN_TRUNCATE : 0),
+ open_job->initial_offset);
+ break;
+ }
close (remote_fd);
g_object_unref (fd_list);
diff --git a/daemon/gvfsjobopenforwrite.h b/daemon/gvfsjobopenforwrite.h
index 79854d23..141189f3 100644
--- a/daemon/gvfsjobopenforwrite.h
+++ b/daemon/gvfsjobopenforwrite.h
@@ -44,6 +44,11 @@ typedef enum {
OPEN_FOR_WRITE_REPLACE = 2
} GVfsJobOpenForWriteMode;
+typedef enum {
+ OPEN_FOR_WRITE_VERSION_ORIGINAL,
+ OPEN_FOR_WRITE_VERSION_WITH_FLAGS,
+} GVfsJobOpenForWriteVersion;
+
struct _GVfsJobOpenForWrite
{
GVfsJobDBus parent_instance;
@@ -57,11 +62,14 @@ struct _GVfsJobOpenForWrite
GVfsBackend *backend;
GVfsBackendHandle backend_handle;
- gboolean can_seek;
+ guint can_seek : 1;
+ guint can_truncate : 1;
goffset initial_offset;
GVfsWriteChannel *write_channel;
GPid pid;
+
+ GVfsJobOpenForWriteVersion version;
};
struct _GVfsJobOpenForWriteClass
@@ -81,10 +89,22 @@ gboolean g_vfs_job_open_for_write_new_handle (GVfsDBusMount *obj
guint arg_flags,
guint arg_pid,
GVfsBackend *backend);
+gboolean g_vfs_job_open_for_write_new_handle_with_flags (GVfsDBusMount *object,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ const gchar *arg_path_data,
+ guint16 arg_mode,
+ const gchar *arg_etag,
+ gboolean arg_make_backup,
+ guint arg_flags,
+ guint arg_pid,
+ GVfsBackend *backend);
void g_vfs_job_open_for_write_set_handle (GVfsJobOpenForWrite *job,
GVfsBackendHandle handle);
void g_vfs_job_open_for_write_set_can_seek (GVfsJobOpenForWrite *job,
gboolean can_seek);
+void g_vfs_job_open_for_write_set_can_truncate (GVfsJobOpenForWrite *job,
+ gboolean can_truncate);
void g_vfs_job_open_for_write_set_initial_offset (GVfsJobOpenForWrite *job,
goffset initial_offset);
GPid g_vfs_job_open_for_write_get_pid (GVfsJobOpenForWrite *job);
diff --git a/daemon/gvfsjobtruncate.c b/daemon/gvfsjobtruncate.c
new file mode 100644
index 00000000..bac32483
--- /dev/null
+++ b/daemon/gvfsjobtruncate.c
@@ -0,0 +1,128 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2013 Ross Lagerwall
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include "gvfswritechannel.h"
+#include "gvfsjobtruncate.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobTruncate, g_vfs_job_truncate, G_VFS_TYPE_JOB)
+
+static void run (GVfsJob *job);
+static gboolean try (GVfsJob *job);
+static void send_reply (GVfsJob *job);
+
+static void
+g_vfs_job_truncate_finalize (GObject *object)
+{
+ GVfsJobTruncate *job;
+
+ job = G_VFS_JOB_TRUNCATE (object);
+ g_object_unref (job->channel);
+
+ if (G_OBJECT_CLASS (g_vfs_job_truncate_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_job_truncate_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_truncate_class_init (GVfsJobTruncateClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_job_truncate_finalize;
+
+ job_class->run = run;
+ job_class->try = try;
+ job_class->send_reply = send_reply;
+}
+
+static void
+g_vfs_job_truncate_init (GVfsJobTruncate *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_truncate_new (GVfsWriteChannel *channel,
+ GVfsBackendHandle handle,
+ goffset size,
+ GVfsBackend *backend)
+{
+ GVfsJobTruncate *job;
+
+ job = g_object_new (G_VFS_TYPE_JOB_TRUNCATE, NULL);
+
+ job->backend = backend;
+ job->channel = g_object_ref (channel);
+ job->handle = handle;
+ job->size = size;
+
+ return G_VFS_JOB (job);
+}
+
+/* Might be called on an i/o thread */
+static void
+send_reply (GVfsJob *job)
+{
+ GVfsJobTruncate *op_job = G_VFS_JOB_TRUNCATE (job);
+
+ g_debug ("job_truncate send reply\n");
+
+ if (job->failed)
+ g_vfs_channel_send_error (G_VFS_CHANNEL (op_job->channel), job->error);
+ else
+ g_vfs_write_channel_send_truncated (op_job->channel);
+}
+
+static void
+run (GVfsJob *job)
+{
+ GVfsJobTruncate *op_job = G_VFS_JOB_TRUNCATE (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+ if (class->truncate)
+ class->truncate (op_job->backend, op_job, op_job->handle, op_job->size);
+ else
+ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported by backend"));
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+ GVfsJobTruncate *op_job = G_VFS_JOB_TRUNCATE (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+ if (class->try_truncate)
+ return class->try_truncate (op_job->backend,
+ op_job,
+ op_job->handle,
+ op_job->size);
+ else
+ return FALSE;
+}
diff --git a/daemon/gvfsjobtruncate.h b/daemon/gvfsjobtruncate.h
new file mode 100644
index 00000000..9a3f0494
--- /dev/null
+++ b/daemon/gvfsjobtruncate.h
@@ -0,0 +1,63 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2013 Ross Lagerwall
+ *
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __G_VFS_JOB_TRUNCATE_H__
+#define __G_VFS_JOB_TRUNCATE_H__
+
+#include <gvfsjob.h>
+#include <gvfsbackend.h>
+#include <gvfswritechannel.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_TRUNCATE (g_vfs_job_truncate_get_type ())
+#define G_VFS_JOB_TRUNCATE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_TRUNCATE, GVfsJobTruncate))
+#define G_VFS_JOB_TRUNCATE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_TRUNCATE, GVfsJobTruncateClass))
+#define G_VFS_IS_JOB_TRUNCATE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_TRUNCATE))
+#define G_VFS_IS_JOB_TRUNCATE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_TRUNCATE))
+#define G_VFS_JOB_TRUNCATE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_TRUNCATE, GVfsJobTruncateClass))
+
+typedef struct _GVfsJobTruncateClass GVfsJobTruncateClass;
+
+struct _GVfsJobTruncate
+{
+ GVfsJob parent_instance;
+
+ GVfsWriteChannel *channel;
+ GVfsBackend *backend;
+ GVfsBackendHandle handle;
+ goffset size;
+};
+
+struct _GVfsJobTruncateClass
+{
+ GVfsJobClass parent_class;
+};
+
+GType g_vfs_job_truncate_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_truncate_new (GVfsWriteChannel *channel,
+ GVfsBackendHandle handle,
+ goffset size,
+ GVfsBackend *backend);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_TRUNCATE_H__ */
diff --git a/daemon/gvfswritechannel.c b/daemon/gvfswritechannel.c
index bc71f76f..c691deb6 100644
--- a/daemon/gvfswritechannel.c
+++ b/daemon/gvfswritechannel.c
@@ -38,6 +38,7 @@
#include <gvfsdaemonutils.h>
#include <gvfsjobwrite.h>
#include <gvfsjobseekwrite.h>
+#include <gvfsjobtruncate.h>
#include <gvfsjobclosewrite.h>
#include <gvfsjobqueryinfowrite.h>
@@ -137,7 +138,12 @@ write_channel_handle_request (GVfsChannel *channel,
((goffset)arg1) | (((goffset)arg2) << 32),
backend);
break;
-
+ case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_TRUNCATE:
+ job = g_vfs_job_truncate_new (write_channel,
+ backend_handle,
+ ((goffset)arg1) | (((goffset)arg2) << 32),
+ backend);
+ break;
case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_QUERY_INFO:
attrs = g_strndup (data, data_len);
job = g_vfs_job_query_info_write_new (write_channel,
@@ -181,6 +187,24 @@ g_vfs_write_channel_send_seek_offset (GVfsWriteChannel *write_channel,
/* Might be called on an i/o thread
*/
void
+g_vfs_write_channel_send_truncated (GVfsWriteChannel *write_channel)
+{
+ GVfsDaemonSocketProtocolReply reply;
+ GVfsChannel *channel;
+
+ channel = G_VFS_CHANNEL (write_channel);
+
+ reply.type = g_htonl (G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_TRUNCATED);
+ reply.seq_nr = g_htonl (g_vfs_channel_get_current_seq_nr (channel));
+ reply.arg1 = g_htonl (0);
+ reply.arg2 = g_htonl (0);
+
+ g_vfs_channel_send_reply (channel, &reply, NULL, 0);
+}
+
+/* Might be called on an i/o thread
+ */
+void
g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel,
const char *etag)
{
diff --git a/daemon/gvfswritechannel.h b/daemon/gvfswritechannel.h
index 4fba2589..d721f238 100644
--- a/daemon/gvfswritechannel.h
+++ b/daemon/gvfswritechannel.h
@@ -55,6 +55,7 @@ void g_vfs_write_channel_send_closed (GVfsWriteChannel *write_
const char *etag);
void g_vfs_write_channel_send_seek_offset (GVfsWriteChannel *write_channel,
goffset offset);
+void g_vfs_write_channel_send_truncated (GVfsWriteChannel *write_channel);
G_END_DECLS