Index: daemon/gvfsbackendftp.c
===================================================================
--- daemon/gvfsbackendftp.c	(revision 2146)
+++ daemon/gvfsbackendftp.c	(working copy)
@@ -128,6 +128,7 @@
   char *		user;
   gboolean              has_initial_user;
   char *		password;	/* password or NULL for anonymous */
+  gboolean		supports_chmod;
 
   /* vfuncs */
   const FtpDirReader *	dir_ops;
@@ -503,7 +504,7 @@
  * codes other than 2xx cause an error. The last read ftp command will be put 
  * into @conn->read_buffer.
  *
- * Returns: 0 on error or the receied FTP code otherwise.
+ * Returns: 0 on error or the received FTP code otherwise.
  *     
  **/
 static guint
@@ -1406,6 +1407,9 @@
   g_static_rw_lock_init (&ftp->directory_cache_lock);
 
   ftp->dir_ops = &dir_default;
+
+  /* default to believing we have chmod; */
+  ftp->supports_chmod = TRUE;
 }
 
 static void
@@ -2256,6 +2260,94 @@
 }
 
 static void
+do_query_settable_attributes (GVfsBackend *backend,
+			      GVfsJobQueryAttributes *job,
+			      const char *filename)
+{
+  GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
+
+  if (ftp->supports_chmod)
+    {
+       GFileAttributeInfoList *list;
+       list = g_file_attribute_info_list_new ();
+       /* TODO: Add all settable attributes here */
+       g_file_attribute_info_list_add (list,
+                                       G_FILE_ATTRIBUTE_UNIX_MODE,
+                                       G_FILE_ATTRIBUTE_TYPE_UINT32,
+                                       G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
+                                       G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
+
+       g_vfs_job_query_attributes_set_list (job, list);
+       g_vfs_job_succeeded (G_VFS_JOB (job));
+  
+       g_file_attribute_info_list_unref (list);
+    }
+  else
+    {
+       g_vfs_job_succeeded (G_VFS_JOB (job));
+    }
+}
+
+static void
+do_set_attribute (GVfsBackend *backend,
+                  GVfsJobSetAttribute *job,
+                  const char *filename,
+                  const char *attribute,
+                  GFileAttributeType type,
+                  gpointer value_p,
+                  GFileQueryInfoFlags flags)
+{
+  GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
+  FtpConnection *conn;
+  guint32 perms;
+  guint response;
+
+  if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) != 0 ||
+      !ftp->supports_chmod)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+			G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+			_("Operation unsupported"));
+      return;
+    }
+
+  conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
+  if (conn == NULL)
+    return;
+
+  perms = (*(guint32 *)value_p) & 0777;
+#ifdef PRINT_DEBUG
+  g_printf ("file: %s\n permissions: %o\n", filename, perms); 
+#endif
+
+  response = ftp_connection_send (conn,
+		                  0,
+		                  "SITE CHMOD %o %s", perms, filename);
+
+  if (STATUS_GROUP (response) == 2)
+    g_vfs_job_succeeded (G_VFS_JOB (job));
+  else if (response == 500) 
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                        _("Server does not support CHMOD"));
+      ftp->supports_chmod = FALSE;
+    }
+  else
+    {
+#ifdef PRINT_DEBUG
+      g_printf ("Got odd response code: %d\n", response); 
+#endif
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR, G_IO_ERROR_FAILED,
+                        _("Unknown error"));
+    }
+
+  g_vfs_backend_ftp_push_connection (ftp, conn);
+  
+}
+
+static void
 do_enumerate (GVfsBackend *backend,
 	      GVfsJobEnumerate *job,
 	      const char *dirname,
@@ -2554,6 +2646,8 @@
   backend_class->close_write = do_close_write;
   backend_class->write = do_write;
   backend_class->query_info = do_query_info;
+  backend_class->query_settable_attributes = do_query_settable_attributes;
+  backend_class->set_attribute = do_set_attribute;
   backend_class->enumerate = do_enumerate;
   backend_class->set_display_name = do_set_display_name;
   backend_class->delete = do_delete;
