diff options
-rw-r--r-- | daemon/gvfsbackendsftp.c | 112 |
1 files changed, 89 insertions, 23 deletions
diff --git a/daemon/gvfsbackendsftp.c b/daemon/gvfsbackendsftp.c index cde9cd85..1bb4a673 100644 --- a/daemon/gvfsbackendsftp.c +++ b/daemon/gvfsbackendsftp.c @@ -5491,6 +5491,8 @@ typedef struct { /* fstat information */ goffset size; guint32 permissions; + guint64 mtime; + guint64 atime; /* state */ goffset offset; @@ -5640,8 +5642,15 @@ push_close_deleted_file (GVfsBackendSftp *backend, } static void -push_close_delete_or_succeed (SftpPushHandle *handle) +push_close_delete_or_succeed (GVfsBackendSftp *backend, + int reply_type, + GDataInputStream *reply, + guint32 len, + GVfsJob *job, + gpointer user_data) { + SftpPushHandle *handle = user_data; + if (handle->tempname) { /* If we wrote to a temp file, do delete then rename. */ @@ -5662,15 +5671,52 @@ push_close_delete_or_succeed (SftpPushHandle *handle) } static void -push_close_restore_permissions (GVfsBackendSftp *backend, - int reply_type, - GDataInputStream *reply, - guint32 len, - GVfsJob *job, - gpointer user_data) +push_close_restore_permissions (SftpPushHandle *handle) +{ + gboolean default_perms = (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS); + guint32 flags = SSH_FILEXFER_ATTR_ACMODTIME; + + if (!default_perms) + flags |= SSH_FILEXFER_ATTR_PERMISSIONS; + + /* Restore the source file's permissions and timestamps. */ + GDataOutputStream *command = new_command_stream (handle->backend, SSH_FXP_SETSTAT); + put_string (command, handle->tempname ? handle->tempname : handle->op_job->destination); + g_data_output_stream_put_uint32 (command, flags, NULL, NULL); + if (!default_perms) + g_data_output_stream_put_uint32 (command, handle->permissions, NULL, NULL); + g_data_output_stream_put_uint32 (command, handle->atime, NULL, NULL); + g_data_output_stream_put_uint32 (command, handle->mtime, NULL, NULL); + queue_command_stream_and_free (&handle->backend->command_connection, command, + push_close_delete_or_succeed, + handle->job, handle); +} + +static void +push_close_stat_reply (GVfsBackendSftp *backend, + int reply_type, + GDataInputStream *reply, + guint32 len, + GVfsJob *job, + gpointer user_data) { - /* We don't care if setting the permissions succeeded or not. */ - push_close_delete_or_succeed (user_data); + SftpPushHandle *handle = user_data; + + if (reply_type == SSH_FXP_ATTRS) + { + GFileInfo *info = g_file_info_new (); + + parse_attributes (backend, info, NULL, reply, NULL); + + /* Don't fail on error, but fall back to the local atime + * (assigned in push_source_fstat_cb). */ + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_ACCESS)) + handle->atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS); + + g_object_unref (info); + } + + push_close_restore_permissions (handle); } static void @@ -5688,19 +5734,19 @@ push_close_write_reply (GVfsBackendSftp *backend, guint32 code = read_status_code (reply); if (code == SSH_FX_OK) { - if (handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) - push_close_delete_or_succeed (handle); - else + /* Atime is COPY_WHEN_MOVED, but not COPY_WITH_FILE. */ + if (!handle->op_job->remove_source && + !(handle->op_job->flags & G_FILE_COPY_ALL_METADATA)) { - /* Restore the source file's permissions. */ - GDataOutputStream *command = new_command_stream (backend, SSH_FXP_SETSTAT); - put_string (command, handle->tempname ? handle->tempname : handle->op_job->destination); - g_data_output_stream_put_uint32 (command, SSH_FILEXFER_ATTR_PERMISSIONS, NULL, NULL); - g_data_output_stream_put_uint32 (command, handle->permissions, NULL, NULL); + GDataOutputStream *command = new_command_stream (backend, SSH_FXP_LSTAT); + put_string (command, handle->op_job->destination); queue_command_stream_and_free (&backend->command_connection, command, - push_close_restore_permissions, + push_close_stat_reply, job, handle); + return; } + + push_close_restore_permissions (handle); return; } else @@ -6070,6 +6116,8 @@ push_source_fstat_cb (GObject *source, GAsyncResult *res, gpointer user_data) { handle->permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE) & 0777; handle->size = g_file_info_get_size (info); + handle->mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); + handle->atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS); command = new_command_stream (handle->backend, SSH_FXP_OPEN); put_string (command, handle->op_job->destination); @@ -6102,7 +6150,9 @@ push_source_open_cb (GObject *source, GAsyncResult *res, gpointer user_data) g_file_input_stream_query_info_async (fin, G_FILE_ATTRIBUTE_STANDARD_SIZE "," - G_FILE_ATTRIBUTE_UNIX_MODE, + G_FILE_ATTRIBUTE_UNIX_MODE "," + G_FILE_ATTRIBUTE_TIME_MODIFIED "," + G_FILE_ATTRIBUTE_TIME_ACCESS, 0, NULL, push_source_fstat_cb, handle); } @@ -6211,6 +6261,8 @@ typedef struct { /* fstat information */ goffset size; guint32 mode; + guint64 mtime; + guint64 atime; /* state */ goffset offset; @@ -6317,12 +6369,22 @@ pull_close_cb (GObject *source, GAsyncResult *res, gpointer user_data) { g_vfs_job_progress_callback (handle->n_written, handle->n_written, handle->job); - if (handle->size >= 0 && !(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)) + if (handle->size >= 0) { GFileInfo *info = g_file_info_new (); - g_file_info_set_attribute_uint32 (info, - G_FILE_ATTRIBUTE_UNIX_MODE, - handle->mode); + if (!(handle->op_job->flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)) + g_file_info_set_attribute_uint32 (info, + G_FILE_ATTRIBUTE_UNIX_MODE, + handle->mode); + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED, + handle->mtime); + /* Atime is COPY_WHEN_MOVED, but not COPY_WITH_FILE. */ + if (handle->op_job->remove_source || + (handle->op_job->flags & G_FILE_COPY_ALL_METADATA)) + g_file_info_set_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_ACCESS, + handle->atime); g_file_set_attributes_async (handle->dest, info, G_FILE_QUERY_INFO_NONE, @@ -6573,6 +6635,10 @@ pull_fstat_reply (GVfsBackendSftp *backend, handle->size = g_file_info_get_size (info); handle->mode = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE); + handle->mtime = g_file_info_get_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + handle->atime = g_file_info_get_attribute_uint64 (info, + G_FILE_ATTRIBUTE_TIME_ACCESS); g_object_unref (info); } else |