gvfs r1460 - in trunk: . daemon
- From: otte svn gnome org
- To: svn-commits-list gnome org
- Subject: gvfs r1460 - in trunk: . daemon
- Date: Fri, 29 Feb 2008 19:13:40 +0000 (GMT)
Author: otte
Date: Fri Feb 29 19:13:39 2008
New Revision: 1460
URL: http://svn.gnome.org/viewvc/gvfs?rev=1460&view=rev
Log:
2008-02-29 Benjamin Otte <otte gnome org>
* daemon/gvfsbackendftp.c: (ftp_error_set_from_response),
(ftp_connection_parse_features), (ftp_filename_from_gvfs_path),
(ftp_filename_to_gvfs_path), (ftp_filename_construct),
(do_open_for_read), (do_create), (do_append), (do_replace),
(do_set_display_name), (g_vfs_backend_ftp_class_init):
introduce a differentiation between gvfs paths and ftp filenames and
use it. Also implement set_display_name.
Modified:
trunk/ChangeLog
trunk/daemon/gvfsbackendftp.c
Modified: trunk/daemon/gvfsbackendftp.c
==============================================================================
--- trunk/daemon/gvfsbackendftp.c (original)
+++ trunk/daemon/gvfsbackendftp.c Fri Feb 29 19:13:39 2008
@@ -52,9 +52,23 @@
#define DEBUG(...)
#endif
+/*
+ * about filename interpretation in the ftp backend
+ *
+ * As GVfs composes paths using a slash character, we cannot allow a slash as
+ * part of a basename. Other critical characters are \r \n and sometimes the
+ * space. We therefore g_uri_escape_string() filenames by default and concatenate
+ * paths using slashes. This should make GVfs happy.
+ *
+ * Luckily, TVFS (see RFC 3xxx for details) is a specification that does exactly
+ * what we want. It disallows slashes, \r and \n in filenames, so we can happily
+ * use it without the need to escape. We also can operate on full paths as our
+ * paths exactly match those of a TVFS-using FTP server.
+ */
typedef enum {
FTP_FEATURE_MDTM = (1 << 0),
- FTP_FEATURE_SIZE = (1 << 1)
+ FTP_FEATURE_SIZE = (1 << 1),
+ FTP_FEATURE_TVFS = (1 << 2)
} FtpFeatures;
struct _GVfsBackendFtp
@@ -171,11 +185,11 @@
break;
case 553: /* Requested action not taken. File name not allowed. */
code = G_IO_ERROR_INVALID_FILENAME;
- msg = _("Invalid filename.");
+ msg = _("Invalid filename");
break;
default:
code = G_IO_ERROR_FAILED;
- msg = _("Invalid reply from server.");
+ msg = _("Invalid reply from server");
break;
}
@@ -442,7 +456,8 @@
FtpFeatures enable; /* flags to enable with this feature */
} features[] = {
{ "MDTM", FTP_FEATURE_MDTM },
- { "SIZE", FTP_FEATURE_SIZE }
+ { "SIZE", FTP_FEATURE_SIZE },
+ { "TVFS", FTP_FEATURE_TVFS }
};
char **supported;
guint i, j;
@@ -626,6 +641,50 @@
conn->data = NULL;
}
+/*** FILE MAPPINGS ***/
+
+/* FIXME: This most likely needs adaption to non-unix like directory structures.
+ * There's at least the case of multiple roots (Netware) plus probably a shitload
+ * of weird old file systems (starting with MS-DOS)
+ * But we first need a way to detect that.
+ */
+
+/**
+ * FtpFile:
+ *
+ * Byte string used to identify a file on the FTP server. It's typedef'ed to
+ * make it easy to distinguish from GVfs paths.
+ */
+
+/* unsinged char is on purpose, so we get warnings when we misuse them */
+typedef unsigned char FtpFile;
+
+static FtpFile *
+ftp_filename_from_gvfs_path (FtpConnection *conn, const char *pathname)
+{
+ return (FtpFile *) g_strdup (pathname);
+}
+
+static char *
+ftp_filename_to_gvfs_path (FtpConnection *conn, const FtpFile *filename)
+{
+ return g_strdup ((const char *) filename);
+}
+
+/* Takes an FTP dirname and a basename (as used in RNTO or as result from LIST
+ * or similar) and gets the new ftp filename from it.
+ *
+ * Returns: the filename or %NULL if filename construction wasn't possible.
+ */
+static FtpFile *
+ftp_filename_construct (FtpConnection *conn, const FtpFile *dirname, const char *basename)
+{
+ if (strpbrk (basename, "/\r\n"))
+ return NULL;
+
+ return (FtpFile *) g_strconcat ((char *) dirname, "/", basename, NULL);
+}
+
/*** BACKEND ***/
static void
@@ -923,6 +982,7 @@
GError *error = NULL;
FtpConnection *conn;
guint status;
+ FtpFile *file;
conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job)->cancellable, &error);
if (conn == NULL)
@@ -930,10 +990,12 @@
if (!ftp_connection_ensure_data_connection (conn, &error))
goto error;
+ file = ftp_filename_from_gvfs_path (conn, filename);
status = ftp_connection_send (conn,
RESPONSE_PASS_100 | RESPONSE_FAIL_200,
&error,
- "RETR %s", filename);
+ "RETR %s", file);
+ g_free (file);
if (status == 0)
goto error;
@@ -1070,12 +1132,15 @@
GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
FtpConnection *conn;
GError *error = NULL;
+ FtpFile *file;
conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job)->cancellable, &error);
if (conn == NULL)
goto error;
- do_start_write (ftp, conn, job, flags, "STOR %s", filename);
+ file = ftp_filename_from_gvfs_path (conn, filename);
+ do_start_write (ftp, conn, job, flags, "STOR %s", file);
+ g_free (file);
return;
error:
@@ -1093,12 +1158,15 @@
GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
FtpConnection *conn;
GError *error = NULL;
+ FtpFile *file;
conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job)->cancellable, &error);
if (conn == NULL)
goto error;
+ file = ftp_filename_from_gvfs_path (conn, filename);
do_start_write (ftp, conn, job, flags, "APPE %s", filename);
+ g_free (file);
return;
error:
@@ -1118,6 +1186,7 @@
GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
FtpConnection *conn;
GError *error = NULL;
+ FtpFile *file;
if (make_backup)
{
@@ -1133,7 +1202,9 @@
if (conn == NULL)
goto error;
+ file = ftp_filename_from_gvfs_path (conn, filename);
do_start_write (ftp, conn, job, flags, "STOR %s", filename);
+ g_free (file);
return;
error:
@@ -1455,6 +1526,72 @@
}
static void
+do_set_display_name (GVfsBackend *backend,
+ GVfsJobSetDisplayName *job,
+ const char *filename,
+ const char *display_name)
+{
+ GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
+ GError *error = NULL;
+ FtpConnection *conn;
+ char *name;
+ FtpFile *original, *dir, *now;
+ guint response;
+
+ conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job)->cancellable, &error);
+ if (conn == NULL)
+ goto error;
+
+ original = ftp_filename_from_gvfs_path (conn, filename);
+ name = g_path_get_dirname (filename);
+ dir = ftp_filename_from_gvfs_path (conn, name);
+ g_free (name);
+ now = ftp_filename_construct (conn, dir, display_name);
+ g_free (dir);
+ if (now == NULL)
+ {
+ g_set_error (&error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_FILENAME,
+ _("Invalid filename"));
+ goto error;
+ }
+ response = ftp_connection_send (conn,
+ RESPONSE_PASS_300 | RESPONSE_FAIL_200,
+ &error,
+ "RNFR %s", original);
+ g_free (original);
+ if (response == 0)
+ {
+ g_free (now);
+ goto error;
+ }
+ response = ftp_connection_send (conn,
+ 0,
+ &error,
+ "RNTO %s", now);
+ if (response == 0)
+ {
+ g_free (now);
+ goto error;
+ }
+
+ name = ftp_filename_to_gvfs_path (conn, now);
+ g_free (now);
+ g_vfs_backend_ftp_push_connection (ftp, conn);
+ g_vfs_job_set_display_name_set_new_path (job, name);
+ g_free (name);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ return;
+
+error:
+ g_free (dir);
+ g_vfs_backend_ftp_push_connection (ftp, conn);
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+}
+
+static void
g_vfs_backend_ftp_class_init (GVfsBackendFtpClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -1475,4 +1612,5 @@
backend_class->write = do_write;
backend_class->query_info = do_query_info;
backend_class->enumerate = do_enumerate;
+ backend_class->set_display_name = do_set_display_name;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]