summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/gdaemonfile.c21
-rw-r--r--client/gdaemonfileoutputstream.c35
-rw-r--r--daemon/gvfsbackend.h4
-rw-r--r--daemon/gvfsbackendsmb.c32
-rw-r--r--daemon/gvfsjobclosewrite.c9
-rw-r--r--daemon/gvfsjobclosewrite.h4
-rw-r--r--daemon/gvfsjobopenforwrite.c11
-rw-r--r--daemon/gvfsjobopenforwrite.h2
-rw-r--r--daemon/gvfswritechannel.c7
-rw-r--r--daemon/gvfswritechannel.h3
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);