diff options
-rw-r--r-- | client/gdaemonfile.c | 21 | ||||
-rw-r--r-- | client/gdaemonfileoutputstream.c | 35 | ||||
-rw-r--r-- | daemon/gvfsbackend.h | 4 | ||||
-rw-r--r-- | daemon/gvfsbackendsmb.c | 32 | ||||
-rw-r--r-- | daemon/gvfsjobclosewrite.c | 9 | ||||
-rw-r--r-- | daemon/gvfsjobclosewrite.h | 4 | ||||
-rw-r--r-- | daemon/gvfsjobopenforwrite.c | 11 | ||||
-rw-r--r-- | daemon/gvfsjobopenforwrite.h | 2 | ||||
-rw-r--r-- | daemon/gvfswritechannel.c | 7 | ||||
-rw-r--r-- | daemon/gvfswritechannel.h | 3 |
10 files changed, 92 insertions, 36 deletions
diff --git a/client/gdaemonfile.c b/client/gdaemonfile.c index 477cef64..4eba1b5d 100644 --- a/client/gdaemonfile.c +++ b/client/gdaemonfile.c @@ -805,18 +805,19 @@ g_daemon_file_append_to (GFile *file, guint32 fd_id; dbus_bool_t can_seek; guint16 mode; - guint64 mtime, initial_offset; + guint64 initial_offset; dbus_bool_t make_backup; + char *etag; mode = 1; - mtime = 0; + etag = ""; make_backup = FALSE; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, - DBUS_TYPE_UINT64, &mtime, + DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &make_backup, 0); if (reply == NULL) @@ -858,18 +859,19 @@ g_daemon_file_create (GFile *file, guint32 fd_id; dbus_bool_t can_seek; guint16 mode; - guint64 mtime, initial_offset; + guint64 initial_offset; dbus_bool_t make_backup; + char *etag; mode = 0; - mtime = 0; + etag = ""; make_backup = FALSE; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, - DBUS_TYPE_UINT64, &mtime, + DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &make_backup, 0); if (reply == NULL) @@ -902,7 +904,7 @@ g_daemon_file_create (GFile *file, static GFileOutputStream * g_daemon_file_replace (GFile *file, - time_t mtime, + const char *etag, gboolean make_backup, GCancellable *cancellable, GError **error) @@ -913,18 +915,17 @@ g_daemon_file_replace (GFile *file, guint32 fd_id; dbus_bool_t can_seek; guint16 mode; - guint64 dbus_mtime, initial_offset; + guint64 initial_offset; dbus_bool_t dbus_make_backup; mode = 2; - dbus_mtime = mtime; dbus_make_backup = make_backup; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, - DBUS_TYPE_UINT64, &dbus_mtime, + DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &dbus_make_backup, 0); if (reply == NULL) diff --git a/client/gdaemonfileoutputstream.c b/client/gdaemonfileoutputstream.c index 51e21ac1..8ba48777 100644 --- a/client/gdaemonfileoutputstream.c +++ b/client/gdaemonfileoutputstream.c @@ -125,6 +125,9 @@ struct _GDaemonFileOutputStream { GString *input_buffer; GString *output_buffer; + + char *etag; + }; static gssize g_daemon_file_output_stream_write (GOutputStream *stream, @@ -139,6 +142,9 @@ static GFileInfo *g_daemon_file_output_stream_get_file_info (GFileOutputStream char *attributes, GCancellable *cancellable, GError **error); +static char *g_daemon_file_output_stream_get_etag (GFileOutputStream *stream, + GCancellable *cancellable, + GError **error); static goffset g_daemon_file_output_stream_tell (GFileOutputStream *stream); static gboolean g_daemon_file_output_stream_can_seek (GFileOutputStream *stream); static gboolean g_daemon_file_output_stream_seek (GFileOutputStream *stream, @@ -182,6 +188,8 @@ g_daemon_file_output_stream_finalize (GObject *object) g_string_free (file->input_buffer, TRUE); g_string_free (file->output_buffer, TRUE); + + g_free (file->etag); if (G_OBJECT_CLASS (g_daemon_file_output_stream_parent_class)->finalize) (*G_OBJECT_CLASS (g_daemon_file_output_stream_parent_class)->finalize) (object); @@ -208,7 +216,7 @@ g_daemon_file_output_stream_class_init (GDaemonFileOutputStreamClass *klass) file_stream_class->can_seek = g_daemon_file_output_stream_can_seek; file_stream_class->seek = g_daemon_file_output_stream_seek; file_stream_class->get_file_info = g_daemon_file_output_stream_get_file_info; - + file_stream_class->get_etag = g_daemon_file_output_stream_get_etag; } static void @@ -278,8 +286,10 @@ get_reply_header_missing_bytes (GString *buffer) type = g_ntohl (reply->type); arg2 = g_ntohl (reply->arg2); - - if (type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_ERROR) + + /* ERROR and CLOSED has extra data w/ len in arg2 */ + if (type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_ERROR || + type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_CLOSED) return G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SIZE + arg2 - buffer->len; return 0; } @@ -679,6 +689,8 @@ iterate_close_state_machine (GDaemonFileOutputStream *file, IOOperationData *io_ else if (reply.type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_CLOSED) { op->ret_val = TRUE; + if (reply.arg2 > 0) + file->etag = g_strndup (data, reply.arg2); g_string_truncate (file->input_buffer, 0); return STATE_OP_DONE; } @@ -941,6 +953,23 @@ g_daemon_file_output_stream_seek (GFileOutputStream *stream, return op.ret_val; } +static char * +g_daemon_file_output_stream_get_etag (GFileOutputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GDaemonFileOutputStream *file; + + file = G_DAEMON_FILE_OUTPUT_STREAM (stream); + + if (file->etag) + return file->etag; + + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("etag not supported on stream")); + return NULL; +} + static GFileInfo * g_daemon_file_output_stream_get_file_info (GFileOutputStream *stream, char *attributes, diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h index 95034abf..14b105f0 100644 --- a/daemon/gvfsbackend.h +++ b/daemon/gvfsbackend.h @@ -134,12 +134,12 @@ struct _GVfsBackendClass gboolean (*try_replace) (GVfsBackend *backend, GVfsJobOpenForWrite *job, const char *filename, - time_t mtime, + const char *etag, gboolean make_backup); void (*replace) (GVfsBackend *backend, GVfsJobOpenForWrite *job, const char *filename, - time_t mtime, + const char *etag, gboolean make_backup); void (*close_write) (GVfsBackend *backend, GVfsJobCloseWrite *job, diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c index 98df5ee4..5746d8e6 100644 --- a/daemon/gvfsbackendsmb.c +++ b/daemon/gvfsbackendsmb.c @@ -837,17 +837,23 @@ copy_file (GVfsBackendSmb *backend, return succeeded; } +static char * +create_etag (struct stat *statbuf) +{ + return g_strdup_printf ("%ld", statbuf->st_mtime); +} + static void do_replace (GVfsBackend *backend, GVfsJobOpenForWrite *job, const char *filename, - time_t mtime, + const char *etag, gboolean make_backup) { GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend); struct stat original_stat; int res; - char *uri, *tmp_uri, *backup_uri; + char *uri, *tmp_uri, *backup_uri, *current_etag; SMBCFILE *file; GError *error = NULL; SmbWriteHandle *handle; @@ -870,17 +876,23 @@ do_replace (GVfsBackend *backend, } else if (file == NULL && errno == EEXIST) { - if (mtime != 0) + if (etag != NULL) { res = op_backend->smb_context->stat (op_backend->smb_context, uri, &original_stat); - if (res == 0 && - original_stat.st_mtime != mtime) + + if (res == 0) { - g_set_error (&error, - G_IO_ERROR, - G_IO_ERROR_WRONG_ETAG, - _("The file was externally modified")); - goto error; + current_etag = create_etag (&original_stat); + if (strcmp (etag, current_etag) != 0) + { + g_free (current_etag); + g_set_error (&error, + G_IO_ERROR, + G_IO_ERROR_WRONG_ETAG, + _("The file was externally modified")); + goto error; + } + g_free (current_etag); } } diff --git a/daemon/gvfsjobclosewrite.c b/daemon/gvfsjobclosewrite.c index 94156179..d8e9e7fc 100644 --- a/daemon/gvfsjobclosewrite.c +++ b/daemon/gvfsjobclosewrite.c @@ -64,6 +64,13 @@ g_vfs_job_close_write_new (GVfsWriteChannel *channel, return G_VFS_JOB (job); } +void +g_vfs_job_close_write_set_etag (GVfsJobCloseWrite *job, + const char *etag) +{ + job->etag = g_strdup (etag); +} + /* Might be called on an i/o thwrite */ static void send_reply (GVfsJob *job) @@ -75,7 +82,7 @@ send_reply (GVfsJob *job) if (job->failed) g_vfs_channel_send_error (G_VFS_CHANNEL (op_job->channel), job->error); else - g_vfs_write_channel_send_closed (op_job->channel); + g_vfs_write_channel_send_closed (op_job->channel, op_job->etag ? op_job->etag : ""); } static void diff --git a/daemon/gvfsjobclosewrite.h b/daemon/gvfsjobclosewrite.h index 14005cd5..0b5fa768 100644 --- a/daemon/gvfsjobclosewrite.h +++ b/daemon/gvfsjobclosewrite.h @@ -20,6 +20,7 @@ struct _GVfsJobCloseWrite { GVfsJob parent_instance; + char *etag; GVfsWriteChannel *channel; GVfsBackend *backend; GVfsBackendHandle handle; @@ -36,6 +37,9 @@ GVfsJob *g_vfs_job_close_write_new (GVfsWriteChannel *channel, GVfsBackendHandle handle, GVfsBackend *backend); +void g_vfs_job_close_write_set_etag (GVfsJobCloseWrite *job, + const char *etag); + G_END_DECLS #endif /* __G_VFS_JOB_CLOSE_WRITE_H__ */ diff --git a/daemon/gvfsjobopenforwrite.c b/daemon/gvfsjobopenforwrite.c index b05566bc..c8a2d691 100644 --- a/daemon/gvfsjobopenforwrite.c +++ b/daemon/gvfsjobopenforwrite.c @@ -35,6 +35,7 @@ g_vfs_job_open_for_write_finalize (GObject *object) g_object_unref (job->write_channel); g_free (job->filename); + g_free (job->etag); if (G_OBJECT_CLASS (g_vfs_job_open_for_write_parent_class)->finalize) (*G_OBJECT_CLASS (g_vfs_job_open_for_write_parent_class)->finalize) (object); @@ -71,7 +72,7 @@ g_vfs_job_open_for_write_new (DBusConnection *connection, char *path; guint16 mode; dbus_bool_t make_backup; - guint64 mtime; + const char *etag; path = NULL; dbus_error_init (&derror); @@ -79,7 +80,7 @@ g_vfs_job_open_for_write_new (DBusConnection *connection, if (!_g_dbus_message_iter_get_args (&iter, &derror, G_DBUS_TYPE_CSTRING, &path, DBUS_TYPE_UINT16, &mode, - DBUS_TYPE_UINT64, &mtime, + DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &make_backup, 0)) { @@ -100,7 +101,7 @@ g_vfs_job_open_for_write_new (DBusConnection *connection, job->filename = path; job->mode = mode; - job->mtime = (time_t)mtime; + job->etag = g_strdup (etag); job->make_backup = make_backup; job->backend = backend; @@ -151,7 +152,7 @@ run (GVfsJob *job) class->replace (op_job->backend, op_job, op_job->filename, - op_job->mtime, + op_job->etag, op_job->make_backup); } else @@ -187,7 +188,7 @@ try (GVfsJob *job) return class->try_replace (op_job->backend, op_job, op_job->filename, - op_job->mtime, + op_job->etag, op_job->make_backup); } else diff --git a/daemon/gvfsjobopenforwrite.h b/daemon/gvfsjobopenforwrite.h index a0abc593..cc873052 100644 --- a/daemon/gvfsjobopenforwrite.h +++ b/daemon/gvfsjobopenforwrite.h @@ -29,7 +29,7 @@ struct _GVfsJobOpenForWrite GVfsJobOpenForWriteMode mode; char *filename; - time_t mtime; + char *etag; gboolean make_backup; GVfsBackend *backend; diff --git a/daemon/gvfswritechannel.c b/daemon/gvfswritechannel.c index d45f6a65..48b9c551 100644 --- a/daemon/gvfswritechannel.c +++ b/daemon/gvfswritechannel.c @@ -156,7 +156,8 @@ g_vfs_write_channel_send_seek_offset (GVfsWriteChannel *write_channel, /* Might be called on an i/o thread */ void -g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel) +g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel, + const char *etag) { GVfsDaemonSocketProtocolReply reply; GVfsChannel *channel; @@ -166,9 +167,9 @@ g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel) reply.type = g_htonl (G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_CLOSED); reply.seq_nr = g_htonl (g_vfs_channel_get_current_seq_nr (channel)); reply.arg1 = g_htonl (0); - reply.arg2 = g_htonl (0); + reply.arg2 = g_htonl (strlen (etag)); - g_vfs_channel_send_reply (channel, &reply, NULL, 0); + g_vfs_channel_send_reply (channel, &reply, etag, strlen (etag)); } /* Might be called on an i/o thread diff --git a/daemon/gvfswritechannel.h b/daemon/gvfswritechannel.h index b1af7341..d45feb7f 100644 --- a/daemon/gvfswritechannel.h +++ b/daemon/gvfswritechannel.h @@ -28,7 +28,8 @@ GType g_vfs_write_channel_get_type (void) G_GNUC_CONST; GVfsWriteChannel *g_vfs_write_channel_new (GVfsBackend *backend); void g_vfs_write_channel_send_written (GVfsWriteChannel *write_channel, gsize bytes_written); -void g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel); +void g_vfs_write_channel_send_closed (GVfsWriteChannel *write_channel, + const char *etag); void g_vfs_write_channel_send_seek_offset (GVfsWriteChannel *write_channel, goffset offset); |