diff -ruN old/daemon/gvfsbackendftp.c new/daemon/gvfsbackendftp.c
--- old/daemon/gvfsbackendftp.c	2008-10-16 19:54:56.000000000 +0300
+++ new/daemon/gvfsbackendftp.c	2009-02-13 18:20:52.000000000 +0200
@@ -114,6 +114,7 @@
   char *		user;
   gboolean              has_initial_user;
   char *		password;	/* password or NULL for anonymous */
+  gboolean	supports_chmod;
 
   /* vfuncs */
   const FtpDirReader *	dir_ops;
@@ -1093,6 +1094,10 @@
     g_file_info_set_is_hidden (info, result.fe_fnlen > 0 &&
 	                             result.fe_fname[0] == '.');
 
+  if (result.fe_mode>-1) {
+    g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, (guint32)(result.fe_mode));
+  }
+
   g_free (s);
   g_free (name);
 
@@ -1268,6 +1273,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
@@ -2389,6 +2397,95 @@
 }
 
 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
 g_vfs_backend_ftp_class_init (GVfsBackendFtpClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -2413,4 +2510,6 @@
   backend_class->delete = do_delete;
   backend_class->make_directory = do_make_directory;
   backend_class->move = do_move;
+  backend_class->query_settable_attributes = do_query_settable_attributes;
+  backend_class->set_attribute = do_set_attribute;
 }
diff -ruN old/daemon/ParseFTPList.c new/daemon/ParseFTPList.c
--- old/daemon/ParseFTPList.c	2008-09-14 15:05:05.000000000 +0300
+++ new/daemon/ParseFTPList.c	2009-02-10 18:08:41.000000000 +0200
@@ -55,6 +55,9 @@
     return 0;
 
   memset( result, 0, sizeof(*result) );
+  result->fe_mode=-1;
+  result->fe_uid=-1;
+  result->fe_gid=-1;
   if (state->magic != ((void *)ParseFTPList))
   {
     memset( state, 0, sizeof(*state) );
@@ -1022,6 +1025,19 @@
               (p[7] == 'w' || p[7] == '-'))
             /* 'x'/p[9] can be S|s|x|-|T|t or implementation specific */
           {
+            gint32 file_perms;
+            result->fe_mode=0;
+            char binpos;
+            for (binpos=0;binpos<3;binpos++) {
+            	file_perms=0;
+               if (p[binpos*3] == 'r') {file_perms+=4;}
+               if (p[binpos*3+1] == 'w') {file_perms+=2;}
+               if (
+                   (p[binpos*3+2] == 'x') || 
+                   (p[binpos*3+2] == 'S') || 
+                   (p[binpos*3+2] == 'T')) {file_perms+=1;}
+               result->fe_mode = (result->fe_mode<<(binpos==0?0:3))+file_perms;
+            }
             lstyle = 'U'; /* very likely /bin/ls */
           }
         }
diff -ruN old/daemon/ParseFTPList.h new/daemon/ParseFTPList.h
--- old/daemon/ParseFTPList.h	2008-09-14 15:05:05.000000000 +0300
+++ new/daemon/ParseFTPList.h	2009-02-09 19:17:41.000000000 +0200
@@ -116,7 +116,10 @@
   const char *      fe_lname;     /* pointer to symlink name */
   guint32           fe_lnlen;     /* length of symlink name */
   char              fe_size[40];  /* size of file in bytes (<= (2^128 - 1)) */
-  struct tm	    fe_time;	  /* last-modified time */
+  gint32            fe_mode;      /* unix file permissions, octal, -1 if failed */
+  gint32            fe_uid;       /* unix UID */
+  gint32            fe_gid;       /* unix GID */
+  struct tm         fe_time;      /* last-modified time */
   gint32            fe_cinfs;     /* file system is definitely case insensitive */
                                   /* (converting all-upcase names may be desirable) */
 };
