After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 527339 - gvfs should set file attributes properly
gvfs should set file attributes properly
Status: RESOLVED OBSOLETE
Product: gvfs
Classification: Core
Component: general
0.2.x
Other Linux
: Normal normal
: ---
Assigned To: gvfs-maint
gvfs-maint
Depends on:
Blocks:
 
 
Reported: 2008-04-10 12:55 UTC by Alexandre Rostovtsev
Modified: 2018-09-21 16:21 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gvfs-0.2.3-set_attributes_from_info-v1.patch (21.46 KB, patch)
2008-04-11 22:20 UTC, Alexandre Rostovtsev
needs-work Details | Review
copy from http://git.pld-linux.org/?p=packages/gvfs.git;a=blob_plain;f=set_attributes_from_info-v1.patch;hb=a9b6d02cddc109818a0dd3736b6f630a642b8e31 (21.97 KB, patch)
2012-10-02 09:09 UTC, Elan Ruusamäe
needs-work Details | Review
Patch: Implemented setting atime and mtime in gvfs sftp backend (6.40 KB, patch)
2017-08-20 16:30 UTC, Max Maisel
none Details | Review
Patch: Implemented setting atime and mtime in gvfs sftp backend (correctly uploaded) (6.43 KB, patch)
2017-08-21 16:44 UTC, Max Maisel
none Details | Review
Implement set timestamps in gvfsbackend-sftp (v2) (7.12 KB, patch)
2017-08-24 16:57 UTC, Max Maisel
none Details | Review
sftp: Add support for setting timestamps (v3) (8.28 KB, patch)
2017-08-25 17:50 UTC, Max Maisel
none Details | Review
sftp: Add support for setting timestamps (v4) (7.69 KB, patch)
2017-09-01 15:42 UTC, Max Maisel
none Details | Review
sftp: Add support for setting timestamps (v5) (7.77 KB, patch)
2017-09-04 15:34 UTC, Max Maisel
committed Details | Review

Description Alexandre Rostovtsev 2008-04-10 12:55:40 UTC
Currently, gvfs doesn't seem to have much support for setting file attributes. Grepping through the code, the only backend that implements try_set_attribute() is sftp, and it only allows you to set UNIX_MODE.

Without the ability to set attributes on all writeable backends, 'gvfs-copy --preserve' is useless, and it is impossible to truly fix bug 515777.

However, adding attribute writing is more complex than just implementing try_set_attribute(). For example, the sftp protocol does not allow you to set atime and mtime independently: both must be set in a single command. As a result, you are trying to set all file attributes once, the obvious implementation of try_set_attribute() will result in race conditions.

I think the solution is to instead create a try_set_attributes_from_info() (and corresponding g_daemon_set_attributes_from_info()) mechanism. Not only will it enable a race-free file-attribute setting, it will also decrease network traffic and remove the need to wait for a reply after setting each unit of metadata.
Comment 1 Alexandre Rostovtsev 2008-04-11 22:20:26 UTC
Created attachment 109087 [details] [review]
gvfs-0.2.3-set_attributes_from_info-v1.patch

First stab at implementing file attribute setting properly.

Adds GVfsJobSetAttributesFromInfo and associated infrastructure, and implements try_set_attributes_from_info() for the sftp backend. Also a couple of bugs in sftp's existing attribute-setting code.

gvfs-copy --preserve now correctly copies the mode, atime, and mtime over sftp.
Comment 2 Alexander Larsson 2008-12-09 10:51:09 UTC
Generally this looks good. Howerver, g_file_set_attributes_from_info() is supposed to set the status on each attribute it set, which the caller can then check with g_file_info_get_attribute_status(). This is not handled in the current patch.

Also, there is some missing code to set sftp_atime in:

+          sftp_attributes |= SSH_FILEXFER_ATTR_ACMODTIME;
+          /* assume year < 2107 */
+          sftp_atime = 
+          is_atime_set = TRUE;
Comment 3 Philip Muskovac 2009-08-01 02:31:17 UTC
Hi, in Ubuntu bug https://bugs.launchpad.net/gvfs/+bug/390713 was filed about this issue in sftp connections a while ago, any update on when this will be fixed?
I tested it with nautilus 2.27.4-0ubuntu3 and gvfs 1.3.2-0ubuntu4 and mtime is still being changed.
Comment 4 Elan Ruusamäe 2011-05-17 06:53:23 UTC
as i still had problem that gvfs 1.8.1 copied via sftp losing mtime:

09:18:51 glen[load: 0.04]@ravenous ~/supybot$ gvfs-copy --preserve sitapott.conf.bak sftp://haarber/tmp/

09:25:08 glen[load: 0.18]@ravenous ~/supybot$ gvfs-info -a 'time::*' sftp://haarber/tmp/sitapott.conf.bak sitapott.conf
attributes:
  time::modified: 1305613142
  time::access: 1305613142
attributes:
  time::modified: 1295337436
  time::access: 1295337436
  time::changed: 1295337436

scp -pr itself is ok:
09:52:15 glen[load: 0.06]@ravenous ~/supybot$ scp -pr sitapott.conf.bak glen@haarber:/tmp
Enter passphrase for key '/home/users/glen/.ssh/id_dsa': 
sitapott.conf.bak                                                                                                                                       100%   37KB  37.4KB/s   00:00    

09:52:37 glen[load: 0.04]@ravenous ~/supybot$ gvfs-info -a 'time::*' sftp://haarber/tmp/sitapott.conf.bak sitapott.conf.bak 
attributes:
  time::modified: 1295337403
  time::access: 1295336423
attributes:
  time::modified: 1295337403
  time::access: 1295336423
  time::changed: 1295337403


i tought i give this patch a try. with minor tweaks it compiles

http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/packages/gvfs/set_attributes_from_info-v1.patch?rev=1.2

but run issues dbus error:
09:47:51 glen[load: 0.06]@ravenous ~/supybot$ gvfs-copy sitapott.conf.bak sftp://haarber/tmp/
process 9427: arguments to dbus_message_unref() were incorrect, assertion "!message->in_cache" failed in file dbus-message.c line 1548.
This is normally a bug in some application using the D-Bus library.
Comment 5 Elan Ruusamäe 2011-05-17 07:28:08 UTC
"fixed" the dbus error (commented out one part that made error dissapear)

http://cvs.pld-linux.org/cgi-bin/cvsweb.cgi/packages/gvfs/set_attributes_from_info-v1.patch?rev=1.3

however sems the original patch was incomplete, or just incompatible with 1.8.1, as the mtime unfortinately is still not preserved:

10:24:31 glen[load: 0.12]@ravenous ~/supybot$ gvfs-copy --preserve sitapott.conf.bak sftp://haarber/tmp/
10:24:33 glen[load: 0.12]@ravenous ~/supybot$ gvfs-info -a 'time::*' sftp://haarber/tmp/sitapott.conf.bak sitapott.conf.bak 
attributes:
  time::modified: 1305617073
  time::access: 1305617073
attributes:
  time::modified: 1295337403
  time::access: 1295336423
  time::changed: 1295337403
10:24:37 glen[load: 0.11]@ravenous ~/supybot$
Comment 6 Elan Ruusamäe 2011-05-17 07:33:37 UTC
sorry, i was too rushy, logged out to ensure old library not present in memory, and now it works:


10:32:22 glen[load: 0.13]@ravenous ~/supybot$ gvfs-copy --preserve sitapott.conf.bak sftp://haarber/tmp/
10:32:28 glen[load: 0.12]@ravenous ~/supybot$ gvfs-info -a 'time::*' sftp://haarber/tmp/sitapott.conf.bak sitapott.conf.bak 
attributes:
  time::modified: 1295337403
  time::access: 1295336423
attributes:
  time::modified: 1295337403
  time::access: 1295336423
  time::changed: 1295337403
10:32:29 glen[load: 0.12]@ravenous ~/supybot$ 

gvfs-1.8.1-1.4.i686
Comment 7 Elan Ruusamäe 2012-10-01 10:17:46 UTC
thought to point out, that pld still tries to keep this patch alive:

http://git.pld-linux.org/?p=packages/gvfs.git;a=history;f=set_attributes_from_info-v1.patch
Comment 8 Tomas Bzatek 2012-10-01 15:01:18 UTC
(In reply to comment #7)
> thought to point out, that pld still tries to keep this patch alive:
> 
> http://git.pld-linux.org/?p=packages/gvfs.git;a=history;f=set_attributes_from_info-v1.patch

Doesn't look bad at a first sight, could you please attach the latest version here so we can do proper review?
Comment 10 Tomas Bzatek 2012-12-11 17:49:10 UTC
Review of attachment 225565 [details] [review]:

We usually work around the problem of requirement of setting multiple attributes at one step by stat-ing existing file, reusing the information, replacing new attributes and calling the target set function. However, having g_file_set_attributes_from_info() implemented properly would be certainly nice addition.

Haven't really tested the patch, generally it looks good, but please see my concerns.

::: gvfs-1.14.0.new/client/gdaemonfile.c
@@ +2681,3 @@
 
+static gboolean
+g_daemon_file_set_attributes_from_info (GFile *file,

We also need to handle setting "metadata::" attributes, see g_daemon_file_set_attribute()

::: gvfs-1.14.0.new/daemon/gvfsbackendsftp.c
@@ +4643,3 @@
 
+  /* atime and mtime must be set in a single sftp command. Therefore, to set them,
+     you must use try_set_attributes_from_info () */

Perhaps adding a test like for G_FILE_ATTRIBUTE_UNIX_MODE and returning an error would be good idea here, as we don't want to allow users to set atime and mtime separately.

@@ +4702,3 @@
+
+  attributes = g_file_info_list_attributes (info, NULL);
+  for (i=0; attributes[i]; i++)

Spaces around the assignment symbol please.

@@ +4704,3 @@
+  for (i=0; attributes[i]; i++)
+    {
+      if (!strcmp (attributes[i], G_FILE_ATTRIBUTE_UNIX_MODE) )

Remove the extra space before closing parenthesis at the very end of the line please.

@@ +4731,3 @@
+
+  /* must set atime and mtime in a single command */
+  if ( (is_atime_set && !is_mtime_set) || (is_mtime_set && !is_atime_set))

Remove the extra space before two parentheses at the beginning of the line.

@@ +4741,3 @@
+  if (sftp_attributes)
+    {
+      command = new_command_stream (op_backend,SSH_FXP_SETSTAT);

Extra space between arguments.

@@ +4757,3 @@
+  else
+    {
+      if (!i)

Using i outside of the cycle may not be safe, please use either separate counter or extra test here, e.g. (*attributes == NULL) but beware of freed memory.

::: gvfs-1.14.0.new/daemon/gvfsjobsetattributesfrominfo.c
@@ +66,3 @@
+  priv->dispose_has_run = TRUE;
+
+  g_object_unref (job->info);

This should go to g_vfs_job_set_attributes_from_info_finalize() and the whole dispose_has_run machinery should be removed. What was the reason behind it?

@@ +106,3 @@
+  GVfsJobSetAttributesFromInfoPrivate *priv;
+
+  job->info = NULL;

AFAIR GObject zeroes all memory on object creation, should not be necessary to explicitly set NULL here.

@@ +158,3 @@
+  if (class->set_attributes_from_info == NULL)
+    {
+      /* TODO : try to fallback using class->set_attribute */

I see this as a critical thing for this machinery to work. We advertise GIO that GDaemonFile implements this method yet it would propagate back to clients (as GIO itself doesn't provide fallback in this case). Clients would either catch the message and go the fallback way or would show the message to user with no attributes set at all.

I could imagine an iterator going through all attributes, calling GVfsJobSetAttribute for every one of them. And like the g_file_set_attributes_from_info() docs are saying, "if there is any error during this operation then error will be set to the first error".

@@ +175,3 @@
+    {
+      /* TODO : try to fallback using class->try_set_attribute */
+      return;

You need to return FALSE.
Comment 11 Tomas Bzatek 2012-12-11 17:52:01 UTC
(In reply to comment #2)
> Generally this looks good. Howerver, g_file_set_attributes_from_info() is
> supposed to set the status on each attribute it set, which the caller can then
> check with g_file_info_get_attribute_status(). This is not handled in the
> current patch.

Also I guess this is still valid point.
Comment 12 Ildar Muyukov 2016-05-05 08:19:47 UTC
nobody's working on this bug these days?
Comment 13 Matthias Clasen 2016-05-05 14:35:07 UTC
no, sadly. Shouldn't be hard to help this patch over the finish line, if you want to address the feedback in comment #10 and comment #11.
Comment 14 Julian Rüger 2017-08-01 08:50:18 UTC
I just posted a bounty for this bug:

https://www.bountysource.com/issues/23459433-gvfs-should-set-file-attributes-properly

If you want this fixed, please consider contributing.
Thanks and sorry for spam ;)
Comment 15 Max Maisel 2017-08-20 16:30:37 UTC
Created attachment 358022 [details] [review]
Patch: Implemented setting atime and mtime in gvfs sftp backend

Added a patch for review which implements setting atime and mtime over sftp.
The SFTP protocol limitation that atime and mtime must be set simultaneously is overcome by stating the file and perform a read-modify-write operation.

With the patch "rsync -t patch/to/local/file /path/to/sftp" now works and preserves mtimes.
Comment 16 Max Maisel 2017-08-21 16:40:35 UTC
Comment on attachment 358022 [details] [review]
Patch: Implemented setting atime and mtime in gvfs sftp backend

From 0a8a553b8787c4e46d2c354f6d938efe7d754c77 Mon Sep 17 00:00:00 2001
From: (null) <]äfU>
Date: Sun, 20 Aug 2017 18:08:26 +0200
Subject: [PATCH] Implemented setting time::access and time::modified in gvfs-sftp.

---
 daemon/gvfsbackendsftp.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 133 insertions(+), 19 deletions(-)

diff --git a/daemon/gvfsbackendsftp.c b/daemon/gvfsbackendsftp.c
index 22ad4db..643289e 100644
--- a/daemon/gvfsbackendsftp.c
+++ b/daemon/gvfsbackendsftp.c
@@ -153,6 +153,12 @@ typedef struct {
   gboolean make_backup;
 } SftpHandle;
 
+typedef struct {
+  char* filename;
+  guint32 timestamp;
+  gboolean is_atime;
+} AcmodtimeContext;
+
 
 typedef struct {
   ReplyCallback callback;
@@ -5194,6 +5200,58 @@ set_attribute_reply (GVfsBackendSftp *backend,
 		      _("Invalid reply received"));
 }
 
+static void
+set_attribute_stat_reply (GVfsBackendSftp *backend,
+                          int reply_type,
+			  GDataInputStream *reply,
+			  guint32 len,
+			  GVfsJob *job,
+			  gpointer user_data)
+{
+  GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
+  GDataOutputStream *command;
+  AcmodtimeContext *context = (AcmodtimeContext*)user_data;
+
+  if (reply_type == SSH_FXP_ATTRS)
+    {
+      guint32 mtime;
+      guint32 atime;
+      GFileInfo *info = g_file_info_new ();
+
+      parse_attributes (backend, info, NULL, reply, NULL);
+
+      // Timestamps must be read as uint64 but sftp only supports uint32
+      if (context->is_atime)
+	{
+	  mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+	  atime = context->timestamp;
+	}
+      else
+	{
+	  atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+	  mtime = context->timestamp;
+	}
+
+      g_object_unref (info);
+
+      command = new_command_stream (op_backend, SSH_FXP_SETSTAT);
+      put_string (command, context->filename);
+
+      g_data_output_stream_put_uint32 (command, SSH_FILEXFER_ATTR_ACMODTIME, NULL, NULL);
+      g_data_output_stream_put_uint32 (command, atime, NULL, NULL);
+      g_data_output_stream_put_uint32 (command, mtime, NULL, NULL);
+      queue_command_stream_and_free (&op_backend->command_connection, command,
+				     set_attribute_reply,
+				     G_VFS_JOB (job), NULL);
+    }
+  else
+    g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
+		      _("Invalid reply received"));
+
+  g_free(context->filename);
+  g_free(context);
+}
+
 static gboolean
 try_set_attribute (GVfsBackend *backend,
 		   GVfsJobSetAttribute *job,
@@ -5206,32 +5264,88 @@ try_set_attribute (GVfsBackend *backend,
   GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
   GDataOutputStream *command;
 
-  if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) != 0)
+  if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
     {
-      g_vfs_job_failed (G_VFS_JOB (job),
-			G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-			_("Operation unsupported"));
-      return TRUE;
+      if (type != G_FILE_ATTRIBUTE_TYPE_UINT32)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job),
+                            G_IO_ERROR,
+                            G_IO_ERROR_INVALID_ARGUMENT,
+                            "%s",
+                            _("Invalid attribute type (uint32 expected)"));
+          return TRUE;
+        }
+
+      command = new_command_stream (op_backend,
+                                    SSH_FXP_SETSTAT);
+      put_string (command, filename);
+      g_data_output_stream_put_uint32 (command, SSH_FILEXFER_ATTR_PERMISSIONS, NULL, NULL);
+      g_data_output_stream_put_uint32 (command, (*(guint32 *)value_p) & 0777, NULL, NULL);
+      queue_command_stream_and_free (&op_backend->command_connection, command,
+                                     set_attribute_reply,
+                                     G_VFS_JOB (job), NULL);
     }
+  else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0 ||
+           strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
+    {
+      GDataOutputStream *command;
+      AcmodtimeContext *context;
+
+      command = new_command_stream (op_backend, SSH_FXP_LSTAT);
+      put_string (command, filename);
+
+      context = g_new(AcmodtimeContext, 1);
+      if (!context)
+	{
+	  g_vfs_job_failed (G_VFS_JOB (job),
+			    G_IO_ERROR, G_IO_ERROR_FAILED,
+			    _("Malloc failed"));
+	  return TRUE;
+	}
+
+      context->filename = g_strdup(filename);
+      if (!context->filename)
+	{
+          g_free (context);
+	  g_vfs_job_failed (G_VFS_JOB (job),
+			    G_IO_ERROR, G_IO_ERROR_FAILED,
+			    _("Malloc failed"));
+	  return TRUE;
+	}
 
-  if (type != G_FILE_ATTRIBUTE_TYPE_UINT32) 
+      if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
+	context->is_atime = TRUE;
+      else
+	context->is_atime = FALSE;
+
+      if (type == G_FILE_ATTRIBUTE_TYPE_UINT32)
+        context->timestamp = *(guint32*)value_p;
+      else if (type == G_FILE_ATTRIBUTE_TYPE_UINT64)
+        context->timestamp = *(guint64*)value_p; // Truncate to uint32
+      else if (type == G_FILE_ATTRIBUTE_TYPE_STRING)
+	context->timestamp = g_ascii_strtoull(value_p, 0, 10);
+      else
+	{
+	  g_vfs_job_failed (G_VFS_JOB (job),
+			    G_IO_ERROR,
+			    G_IO_ERROR_INVALID_ARGUMENT,
+			    "%s",
+			    _("Invalid attribute type (uint32/64 or string expected)"));
+	  return TRUE;
+	}
+
+      queue_command_stream_and_free (&op_backend->command_connection, command,
+				     set_attribute_stat_reply,
+                                     G_VFS_JOB (job), context);
+      return TRUE;
+    }
+  else
     {
       g_vfs_job_failed (G_VFS_JOB (job),
-                        G_IO_ERROR,
-                        G_IO_ERROR_INVALID_ARGUMENT,
-                        "%s",
-                        _("Invalid attribute type (uint32 expected)"));
+			G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+			_("Operation unsupported"));
       return TRUE;
     }
-
-  command = new_command_stream (op_backend,
-                                SSH_FXP_SETSTAT);
-  put_string (command, filename);
-  g_data_output_stream_put_uint32 (command, SSH_FILEXFER_ATTR_PERMISSIONS, NULL, NULL);
-  g_data_output_stream_put_uint32 (command, (*(guint32 *)value_p) & 0777, NULL, NULL);
-  queue_command_stream_and_free (&op_backend->command_connection, command,
-                                 set_attribute_reply,
-                                 G_VFS_JOB (job), NULL);
   
   return TRUE;
 }
--
libgit2 0.24.5
Comment 17 Max Maisel 2017-08-21 16:44:06 UTC
Created attachment 358086 [details] [review]
Patch: Implemented setting atime and mtime in gvfs sftp backend (correctly uploaded)

Sorry, the edit attachment function posted the modified attachment as new comment, please delete the comment above.

I re-uploaded the patch because something went wrong during first upload. The old patch contained syntax errors and could not be applied.
Comment 18 Ondrej Holy 2017-08-24 08:41:51 UTC
Review of attachment 358086 [details] [review]:

Thanks for your contribution, although it needs some work...

Please setup your name and email correctly:
https://wiki.gnome.org/Git/Developers

Please add sftp prefix and commit description:
https://wiki.gnome.org/Git/CommitMessages

Please use spaces instead of tabs for aligning.

Please update also try_query_settable_attributes function.

::: daemon/gvfsbackendsftp.c
@@ +158,3 @@
+  guint32 timestamp;
+  gboolean is_atime;
+} AcmodtimeContext;

This is not needed, use simply GVfsJobSetAttribute internals instead.

@@ +5211,3 @@
+  GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
+  GDataOutputStream *command;
+  AcmodtimeContext *context = (AcmodtimeContext*)user_data;

Add space before star - (AcmodtimeContext *)

@@ +5221,3 @@
+      parse_attributes (backend, info, NULL, reply, NULL);
+
+      // Timestamps must be read as uint64 but sftp only supports uint32

Use /* */ instead of //.

@@ +5265,3 @@
   GDataOutputStream *command;
 
+  if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)

Please use g_strcmp0 for sure, also on other places.

@@ +5272,3 @@
+                            G_IO_ERROR,
+                            G_IO_ERROR_INVALID_ARGUMENT,
+                            "%s",

This is redundant, also on other places.

@@ +5295,3 @@
+      put_string (command, filename);
+
+      context = g_new(AcmodtimeContext, 1);

Please add space before opening parenthesis, also on other places.

@@ +5296,3 @@
+
+      context = g_new(AcmodtimeContext, 1);
+      if (!context)

This is not needed, also on other places. "If any call to allocate memory fails, the application is terminated. This also means that there is no need to check if the call succeeded." See:
https://developer.gnome.org/glib/stable/glib-Memory-Allocation.html

@@ +5320,3 @@
+
+      if (type == G_FILE_ATTRIBUTE_TYPE_UINT32)
+        context->timestamp = *(guint32*)value_p;

It is not wanted to handle something else than G_FILE_ATTRIBUTE_TYPE_UINT64, we should honor types from:
https://developer.gnome.org/gio/stable/GFileInfo.html#G-FILE-ATTRIBUTE-TIME-ACCESS:CAPS

@@ +5332,3 @@
+			    "%s",
+			    _("Invalid attribute type (uint32/64 or string expected)"));
+	  return TRUE;

You should release allocated memory (command, context) before return, but it would be better to check this before the allocation instead...
Comment 19 Max Maisel 2017-08-24 16:57:39 UTC
Created attachment 358369 [details] [review]
Implement set timestamps in gvfsbackend-sftp (v2)

I improved my patch according to feedback.

With removed support for G_FILE_ATTRIBUTE_TYPE_STRING "gio set" does not work.
I guess this is a bug in "gio set".
Comment 20 Ondrej Holy 2017-08-25 06:50:02 UTC
"gio set" should work correctly if you specify correct "--type=", see "man gio".
Comment 21 Ondrej Holy 2017-08-25 08:45:17 UTC
Review of attachment 358369 [details] [review]:

Thanks for update. I still see some issues to fix...

> gvfsbackendsftp.c: Implement set timestamps
sftp: Add support for setting timestamps

> work over gvfs-sftp.
work over gvfsd-sftp.

::: daemon/gvfsbackendsftp.c
@@ +5176,3 @@
+  g_file_attribute_info_list_add (list,
+                                  G_FILE_ATTRIBUTE_TIME_MODIFIED,
+                                  G_FILE_ATTRIBUTE_TYPE_UINT32,

_UINT64?

@@ +5182,3 @@
+  g_file_attribute_info_list_add (list,
+                                  G_FILE_ATTRIBUTE_TIME_ACCESS,
+                                  G_FILE_ATTRIBUTE_TYPE_UINT32,

dtto

@@ +5183,3 @@
+                                  G_FILE_ATTRIBUTE_TIME_ACCESS,
+                                  G_FILE_ATTRIBUTE_TYPE_UINT32,
+                                  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |

I think that this flag is not wanted for _ACCESS. Please check glocalfileinfo.c implementation in GLib...

@@ +5218,3 @@
+  GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
+  GDataOutputStream *command;
+  struct _GVfsJobSetAttribute *_job = (GVfsJobSetAttribute *)job;

GVfsJobSetAttribute *op_job = G_VFS_JOB_SET_ATTRIBUTE (job);

@@ +5226,3 @@
+      GFileInfo *info = g_file_info_new ();
+
+      parse_attributes (backend, info, NULL, reply, NULL);

You should check that info contains the necessary attributes - g_file_info_has_attribute...

@@ +5228,3 @@
+      parse_attributes (backend, info, NULL, reply, NULL);
+
+      /* Timestamps must be read as uint64 but sftp only supports uint32 */

Maybe we should add at least some g_warning in case if mtime/atime > G_MAXUINT32, or fail with "Internal error"...

@@ +5249,3 @@
+      g_data_output_stream_put_uint32 (command, mtime, NULL, NULL);
+      queue_command_stream_and_free (&op_backend->command_connection, command,
+                                    set_attribute_reply,

Wrong alignment.

@@ +5307,3 @@
+                                     set_attribute_stat_reply,
+                                     G_VFS_JOB (job), NULL);
+      return TRUE;

This is redundant...

@@ +5316,1 @@
       return TRUE;

dtto
Comment 22 Max Maisel 2017-08-25 17:50:05 UTC
Created attachment 358436 [details] [review]
sftp: Add support for setting timestamps (v3)

Improved patch according to feedback.
Comment 23 Ondrej Holy 2017-08-31 12:38:23 UTC
Review of attachment 358436 [details] [review]:

Thanks for the update, but still see some issues...

::: daemon/gvfsbackendsftp.c
@@ +5217,3 @@
+  GVfsBackendSftp *op_backend = G_VFS_BACKEND_SFTP (backend);
+  GDataOutputStream *command;
+  GVfsJobSetAttribute *op_job = (GVfsJobSetAttribute *)job;

Please use G_VFS_JOB_SET_ATTRIBUTE () instead of (GVfsJobSetAttribute *). It is not exactly the same, the macro does some additional checks...

@@ +5227,3 @@
+      parse_attributes (backend, info, NULL, reply, NULL);
+
+      if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))

It doesn't make much sense to have two if-statements for each attribute, because both attributes depends on SSH_FILEXFER_ATTR_ACMODTIME flag.

@@ +5258,3 @@
+
+      /* Timestamps must be read as uint64 but sftp only supports uint32 */
+      if (mtime > G_MAXUINT32)

It is enough to check just the new value, because the current one is always G_MAXUINT32 and remove the second statement:
if (op_job->value.uint64 > G_MAXUINT32)

@@ +5261,3 @@
+        {
+          g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
+                            _("%s value out of range, sftp only supports 32bit timestamps"),

I am not sure it is necessary to report such internals like GFileInfo attribute. It would be probably enough to just say "Value out of range...". Otherwise, you should add translators comment on the line before explaining what is %s (/* Translators: %s is ... */).
Comment 24 Max Maisel 2017-09-01 15:42:51 UTC
Created attachment 358945 [details] [review]
sftp: Add support for setting timestamps (v4)

Optimized error checks in patch.
Comment 25 Ondrej Holy 2017-09-04 08:05:12 UTC
Review of attachment 358945 [details] [review]:

Thanks.

::: daemon/gvfsbackendsftp.c
@@ +5232,3 @@
+        {
+          g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,
+                            _("SSH_FXP_LSTAT failed"));

It is not true that SSH_FXP_LSTAT failed at this point, but you are right that we should also handle the possible SSH_FXP_LSTAT failures...:
if (reply_type == SSH_FXP_STATUS)
  {
    result_from_status (job, reply->data, -1, -1);
    return;
  }
else if...

Sorry that I did not realize this earlier...

I would just use _("Operation unsupported") here or so, because I suppose it should be usually set, so no need to add new strings...
Comment 26 Max Maisel 2017-09-04 15:34:22 UTC
Created attachment 359090 [details] [review]
sftp: Add support for setting timestamps (v5)

Updated patch.
Comment 27 Ondrej Holy 2017-09-04 15:50:32 UTC
Review of attachment 359090 [details] [review]:

Thanks for your contribution, it looks ok now, I will test and push after freeze with the following change...

::: daemon/gvfsbackendsftp.c
@@ +5231,3 @@
+      if (!g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED))
+        {
+          g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_FAILED,

G_IO_ERROR_NOT_SUPPORTED
Comment 28 Ondrej Holy 2017-09-29 11:29:58 UTC
Comment on attachment 359090 [details] [review]
sftp: Add support for setting timestamps (v5)

Thanks for your contribution, pushed as commit 28e5ef8. Let the bug open, because there are similar issues for other backends...
Comment 29 GNOME Infrastructure Team 2018-09-21 16:21:24 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to GNOME's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gvfs/issues/46.