[gvfs] [FTP] split out file code



commit 2f5c4dcfd579f9b9cceb8eb08b71d4318e9c03b6
Author: Benjamin Otte <otte gnome org>
Date:   Wed Jun 3 09:20:20 2009 +0200

    [FTP] split out file code
    
    Next step in cleaning up the ftp backend: Split out FtpFile, which is
    used for the proper translation between FTP paths and gvfs paths.
---
 daemon/Makefile.am      |    1 +
 daemon/gvfsbackendftp.c |  320 ++++++++++++++++++-----------------------------
 daemon/gvfsftpfile.c    |  294 +++++++++++++++++++++++++++++++++++++++++++
 daemon/gvfsftpfile.h    |   54 ++++++++
 4 files changed, 472 insertions(+), 197 deletions(-)

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 0651c08..af8d663 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -231,6 +231,7 @@ gvfsd_obexftp_LDADD = $(OBEXFTP_LIBS) $(XML_LIBS) $(HAL_LIBS) $(libraries)
 
 gvfsd_ftp_SOURCES = \
 	gvfsftpconnection.c gvfsftpconnection.h \
+	gvfsftpfile.c gvfsftpfile.h \
 	gvfsbackendftp.c gvfsbackendftp.h \
 	ParseFTPList.c ParseFTPList.h \
 	daemon-main.c daemon-main.h \
diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c
index 7735959..2646246 100644
--- a/daemon/gvfsbackendftp.c
+++ b/daemon/gvfsbackendftp.c
@@ -50,6 +50,7 @@
 
 #include "ParseFTPList.h"
 #include "gvfsftpconnection.h"
+#include "gvfsftpfile.h"
 
 /* timeout for network connect/send/receive (use 0 for none) */
 #define TIMEOUT_IN_SECONDS 30
@@ -69,7 +70,6 @@
  */
 
 /* unsinged char is on purpose, so we get warnings when we misuse them */
-typedef unsigned char FtpFile;
 typedef struct _FtpConnection FtpConnection;
 
 typedef struct _FtpDirEntry FtpDirEntry;
@@ -81,16 +81,16 @@ struct _FtpDirEntry {
 
 typedef struct FtpDirReader FtpDirReader;
 struct FtpDirReader {
-  void		(* init_data)	(FtpConnection *conn,
-				 const FtpFile *dir);
-  gpointer	(* iter_new)	(FtpConnection *conn);
-  GFileInfo *	(* iter_process)(gpointer       iter,
-				 FtpConnection *conn,
-				 const FtpFile *dirname,
-				 const FtpFile *must_match_file,
-				 const char    *line,
-				 char	      **symlink);
-  void		(* iter_free)	(gpointer	iter);
+  void		(* init_data)	(FtpConnection *    conn,
+				 const GVfsFtpFile *dir);
+  gpointer	(* iter_new)	(FtpConnection *    conn);
+  GFileInfo *	(* iter_process)(gpointer           iter,
+				 FtpConnection *    conn,
+				 const GVfsFtpFile *dirname,
+				 const GVfsFtpFile *must_match_file,
+				 const char *       line,
+				 char **            symlink);
+  void		(* iter_free)	(gpointer	    iter);
 };
 
 typedef enum {
@@ -151,7 +151,7 @@ G_DEFINE_TYPE (GVfsBackendFtp, g_vfs_backend_ftp, G_VFS_TYPE_BACKEND)
 
 #define STATUS_GROUP(status) ((status) / 100)
 
-typedef void (* Ftp550Handler) (FtpConnection *conn, const FtpFile *file);
+typedef void (* Ftp550Handler) (FtpConnection *conn, const GVfsFtpFile *file);
 
 /*** FTP CONNECTION ***/
 
@@ -473,7 +473,7 @@ ftp_connection_send (FtpConnection *conn,
 static void
 ftp_connection_check_file (FtpConnection *conn,
                            const Ftp550Handler *handlers,
-                           const FtpFile *file)
+                           const GVfsFtpFile *file)
 {
   while (*handlers && !ftp_connection_in_error (conn))
     {
@@ -486,14 +486,14 @@ static guint
 ftp_connection_send_and_check (FtpConnection *conn,
                                ResponseFlags flags,
                                const Ftp550Handler *handlers,
-                               const FtpFile *file,
+                               const GVfsFtpFile *file,
                                const char *format,
                                ...) G_GNUC_PRINTF (5, 6);
 static guint
 ftp_connection_send_and_check (FtpConnection *conn,
                                ResponseFlags flags,
                                const Ftp550Handler *handlers,
-                               const FtpFile *file,
+                               const GVfsFtpFile *file,
                                const char *format,
                                ...)
 {
@@ -869,79 +869,14 @@ ftp_connection_close_data_connection (FtpConnection *conn)
   g_vfs_ftp_connection_close_data_connection (conn->conn);
 }
 
-/*** 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.
- */
-
-#define ftp_filename_equal g_str_equal
-#define ftp_filename_copy(name) ((FtpFile *) g_strdup ((const char *) (name)))
-
-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.
- */
-/* let's hope we can live without a connection here, or we have to rewrite LIST */
-static FtpFile *
-ftp_filename_construct (FtpConnection *conn, const FtpFile *dirname, const char *basename)
-{
-  if (strpbrk (basename, "/\r\n"))
-    return NULL;
-
-  return (FtpFile *) g_build_path ("/", (char *) dirname, basename, NULL);
-}
-
-/* NB: returns the root directory for the root directory.
- * Use ftp_filename_equal() afterwards to detect this */
-static FtpFile *
-ftp_filename_get_parent (FtpConnection *conn, const FtpFile *file)
-{
-  char *dirname, *filename;
-  FtpFile *dir;
-
-  filename = ftp_filename_to_gvfs_path (conn, file);
-  dirname = g_path_get_dirname (filename);
-  if (dirname[0] == '.' && dirname[1] == 0)
-    dir = ftp_filename_copy (file);
-  else
-    dir = ftp_filename_from_gvfs_path (conn, dirname);
-  g_free (filename);
-  g_free (dirname);
-
-  return dir;
-}
-
 /*** COMMON FUNCTIONS WITH SPECIAL HANDLING ***/
 
 static gboolean
-ftp_connection_cd (FtpConnection *conn, const FtpFile *file)
+ftp_connection_cd (FtpConnection *conn, const GVfsFtpFile *file)
 {
   guint response = ftp_connection_send (conn,
 					RESPONSE_PASS_500,
-					"CWD %s", file);
+					"CWD %s", g_vfs_ftp_file_get_ftp_path (file));
   if (response == 550)
     {
       g_set_error_literal (&conn->error, 
@@ -959,7 +894,7 @@ ftp_connection_cd (FtpConnection *conn, const FtpFile *file)
 }
 
 static gboolean
-ftp_connection_try_cd (FtpConnection *conn, const FtpFile *file)
+ftp_connection_try_cd (FtpConnection *conn, const GVfsFtpFile *file)
 {
   if (ftp_connection_in_error (conn))
     return FALSE;
@@ -976,7 +911,7 @@ ftp_connection_try_cd (FtpConnection *conn, const FtpFile *file)
 /*** default directory reading ***/
 
 static void
-dir_default_init_data (FtpConnection *conn, const FtpFile *dir)
+dir_default_init_data (FtpConnection *conn, const GVfsFtpFile *dir)
 {
   ftp_connection_cd (conn, dir);
   ftp_connection_ensure_data_connection (conn);
@@ -993,20 +928,21 @@ dir_default_iter_new (FtpConnection *conn)
 }
 
 static GFileInfo *
-dir_default_iter_process (gpointer        iter,
-			  FtpConnection  *conn,
-			  const FtpFile  *dirname,
-			  const FtpFile  *must_match_file,
-			  const char     *line,
-			  char		**symlink)
+dir_default_iter_process (gpointer           iter,
+			  FtpConnection     *conn,
+			  const GVfsFtpFile *dir,
+			  const GVfsFtpFile *must_match_file,
+			  const char        *line,
+			  char		   **symlink)
 {
   struct list_state *state = iter;
   struct list_result result = { 0, };
   GTimeVal tv = { 0, 0 };
   GFileInfo *info;
   int type;
-  FtpFile *name;
-  char *s, *t;
+  GVfsFtpFile *name;
+  const char *s;
+  char *t;
 
   type = ParseFTPList (line, state, &result);
   if (type != 'd' && type != 'f' && type != 'l')
@@ -1026,26 +962,32 @@ dir_default_iter_process (gpointer        iter,
 	return NULL;
     }
 
-  s = g_strndup (result.fe_fname, result.fe_fnlen);
-  if (dirname)
+  t = g_strndup (result.fe_fname, result.fe_fnlen);
+  if (dir)
     {
-      name = ftp_filename_construct (conn, dirname, s);
-      g_free (s);
+      name = g_vfs_ftp_file_new_child  (dir, t, NULL);
+      g_free (t);
     }
   else
-    name = (FtpFile *) s;
+    {
+      name = NULL;
+      g_assert_not_reached (); 
+      // FIXME:
+      //name = (GVfsFtpFile *) t;
+      g_free (t);
+    }
   if (name == NULL)
     return NULL;
 
-  if (must_match_file && !ftp_filename_equal (name, must_match_file))
+  if (must_match_file && !g_vfs_ftp_file_equal (name, must_match_file))
     {
-      g_free (name);
+      g_vfs_ftp_file_free (name);
       return NULL;
     }
 
   info = g_file_info_new ();
 
-  s = ftp_filename_to_gvfs_path (conn, name);
+  s = g_vfs_ftp_file_get_gvfs_path (name);
 
   t = g_path_get_basename (s);
   g_file_info_set_name (info, t);
@@ -1057,7 +999,7 @@ dir_default_iter_process (gpointer        iter,
 
       link = g_strndup (result.fe_lname, result.fe_lnlen);
 
-      /* FIXME: this whole stuff is not FtpFile save */
+      /* FIXME: this whole stuff is not GVfsFtpFile save */
       g_file_info_set_symlink_target (info, link);
       g_file_info_set_is_symlink (info, TRUE);
 
@@ -1103,8 +1045,7 @@ dir_default_iter_process (gpointer        iter,
     g_file_info_set_is_hidden (info, result.fe_fnlen > 0 &&
 	                             result.fe_fname[0] == '.');
 
-  g_free (s);
-  g_free (name);
+  g_vfs_ftp_file_free (name);
 
   /* Workaround:
    * result.fetime.tm_year contains actual year instead of offset-from-1900,
@@ -1312,9 +1253,9 @@ g_vfs_backend_ftp_init (GVfsBackendFtp *ftp)
   ftp->mutex = g_mutex_new ();
   ftp->cond = g_cond_new ();
 
-  ftp->directory_cache = g_hash_table_new_full (g_str_hash,
-					        g_str_equal,
-						g_free,
+  ftp->directory_cache = g_hash_table_new_full (g_vfs_ftp_file_hash,
+					        g_vfs_ftp_file_equal,
+						g_vfs_ftp_file_free,
 						ftp_dir_entry_free);
   g_static_rw_lock_init (&ftp->directory_cache_lock);
 
@@ -1596,7 +1537,7 @@ do_unmount (GVfsBackend *   backend,
 }
 
 static void
-error_550_exists (FtpConnection *conn, const FtpFile *file)
+error_550_exists (FtpConnection *conn, const GVfsFtpFile *file)
 {
   /* FIXME:
    * What we should do here is look at the cache to figure out if the file 
@@ -1607,7 +1548,7 @@ error_550_exists (FtpConnection *conn, const FtpFile *file)
    * directories.
    */
   if (ftp_connection_try_cd (conn, file) ||
-      ftp_connection_send (conn, 0, "SIZE %s", file))
+      ftp_connection_send (conn, 0, "SIZE %s", g_vfs_ftp_file_get_ftp_path (file)))
     {
       g_set_error_literal (&conn->error,
                            G_IO_ERROR,
@@ -1622,11 +1563,11 @@ error_550_exists (FtpConnection *conn, const FtpFile *file)
 }
 
 static void
-error_550_is_directory (FtpConnection *conn, const FtpFile *file)
+error_550_is_directory (FtpConnection *conn, const GVfsFtpFile *file)
 {
   guint response = ftp_connection_send (conn, 
                                         RESPONSE_PASS_550,
-                                        "CWD %s", file);
+                                        "CWD %s", g_vfs_ftp_file_get_ftp_path (file));
 
   if (STATUS_GROUP (response) == 2)
     {
@@ -1637,18 +1578,18 @@ error_550_is_directory (FtpConnection *conn, const FtpFile *file)
 }
 
 static void
-error_550_parent_not_found (FtpConnection *conn, const FtpFile *file)
+error_550_parent_not_found (FtpConnection *conn, const GVfsFtpFile *file)
 {
-  FtpFile *dir = ftp_filename_get_parent (conn, file);
+  GVfsFtpFile *dir = g_vfs_ftp_file_new_parent (file);
 
-  if (!ftp_filename_equal (file, dir) && !ftp_connection_try_cd (conn, dir))
+  if (!g_vfs_ftp_file_equal (file, dir) && !ftp_connection_try_cd (conn, dir))
     {
       g_set_error_literal (&conn->error, G_IO_ERROR,
                            G_IO_ERROR_NOT_FOUND,
                            _("No such file or directory"));
     }
 
-  g_free (dir);
+  g_vfs_ftp_file_free (dir);
 }
 
 static void
@@ -1658,7 +1599,7 @@ do_open_for_read (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *file;
+  GVfsFtpFile *file;
   static const Ftp550Handler open_read_handlers[] = { error_550_is_directory, NULL };
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
@@ -1667,13 +1608,13 @@ do_open_for_read (GVfsBackend *backend,
 
   ftp_connection_ensure_data_connection (conn);
 
-  file = ftp_filename_from_gvfs_path (conn, filename);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
   ftp_connection_send_and_check (conn,
 		                 RESPONSE_PASS_100 | RESPONSE_FAIL_200, 
 		                 &open_read_handlers[0],
 		                 file,
-		                 "RETR %s", file);
-  g_free (file);
+		                 "RETR %s", g_vfs_ftp_file_get_ftp_path (file));
+  g_vfs_ftp_file_free (file);
 
   if (ftp_connection_in_error (conn))
     g_vfs_backend_ftp_push_connection (ftp, conn);
@@ -1763,7 +1704,7 @@ do_start_write (GVfsBackendFtp *ftp,
 
 static void
 gvfs_backend_ftp_purge_cache_directory (GVfsBackendFtp *ftp,
-					const FtpFile * dir)
+					const GVfsFtpFile * dir)
 {
   g_static_rw_lock_writer_lock (&ftp->directory_cache_lock);
   g_hash_table_remove (ftp->directory_cache, dir);
@@ -1773,14 +1714,14 @@ gvfs_backend_ftp_purge_cache_directory (GVfsBackendFtp *ftp,
 static void
 gvfs_backend_ftp_purge_cache_of_file (GVfsBackendFtp *ftp,
 				      FtpConnection * conn,
-				      const FtpFile * file)
+				      const GVfsFtpFile * file)
 {
-  FtpFile *dir = ftp_filename_get_parent (conn, file);
+  GVfsFtpFile *dir = g_vfs_ftp_file_new_parent (file);
 
-  if (!ftp_filename_equal (file, dir))
+  if (!g_vfs_ftp_file_equal (file, dir))
     gvfs_backend_ftp_purge_cache_directory (ftp, dir);
 
-  g_free (dir);
+  g_vfs_ftp_file_free (dir);
 }
 
 /* forward declaration */
@@ -1796,7 +1737,7 @@ do_create (GVfsBackend *backend,
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
   GFileInfo *info;
-  FtpFile *file;
+  GVfsFtpFile *file;
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
   if (conn == NULL)
@@ -1812,10 +1753,10 @@ do_create (GVfsBackend *backend,
 			   _("Target file already exists"));
       goto error;
     }
-  file = ftp_filename_from_gvfs_path (conn, filename);
-  do_start_write (ftp, conn, flags, "STOR %s", file);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
+  do_start_write (ftp, conn, flags, "STOR %s", g_vfs_ftp_file_get_ftp_path (file));
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, file);
-  g_free (file);
+  g_vfs_ftp_file_free (file);
   return;
 
 error:
@@ -1830,16 +1771,16 @@ do_append (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *file;
+  GVfsFtpFile *file;
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
   if (conn == NULL)
     return;
 
-  file = ftp_filename_from_gvfs_path (conn, filename);
-  do_start_write (ftp, conn, flags, "APPE %s", filename);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
+  do_start_write (ftp, conn, flags, "APPE %s", g_vfs_ftp_file_get_ftp_path (file));
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, file);
-  g_free (file);
+  g_vfs_ftp_file_free (file);
   return;
 }
 
@@ -1853,7 +1794,7 @@ do_replace (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *file;
+  GVfsFtpFile *file;
 
   if (make_backup)
     {
@@ -1869,10 +1810,10 @@ do_replace (GVfsBackend *backend,
   if (conn == NULL)
     return;
 
-  file = ftp_filename_from_gvfs_path (conn, filename);
-  do_start_write (ftp, conn, flags, "STOR %s", file);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
+  do_start_write (ftp, conn, flags, "STOR %s", g_vfs_ftp_file_get_ftp_path (file));
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, file);
-  g_free (file);
+  g_vfs_ftp_file_free (file);
   return;
 }
 
@@ -1999,7 +1940,7 @@ do_enumerate_directory (FtpConnection *conn)
 static const FtpDirEntry *
 enumerate_directory (GVfsBackendFtp *ftp,
                      FtpConnection * conn,
-		     const FtpFile * dir,
+		     const GVfsFtpFile * dir,
 		     gboolean	     use_cache)
 {
   FtpDirEntry *entry;
@@ -2021,7 +1962,7 @@ enumerate_directory (GVfsBackendFtp *ftp,
 	if (entry == NULL)
           return NULL;
 	g_static_rw_lock_writer_lock (&ftp->directory_cache_lock);
-	g_hash_table_insert (ftp->directory_cache, g_strdup ((const char *) dir), entry);
+	g_hash_table_insert (ftp->directory_cache, g_vfs_ftp_file_copy (dir), entry);
 	g_static_rw_lock_writer_unlock (&ftp->directory_cache_lock);
 	entry = NULL;
 	g_static_rw_lock_reader_lock (&ftp->directory_cache_lock);
@@ -2033,7 +1974,7 @@ enumerate_directory (GVfsBackendFtp *ftp,
 
 static GFileInfo *
 create_file_info_from_parent (GVfsBackendFtp *ftp, FtpConnection *conn, 
-    const FtpFile *dir, const FtpFile *file, char **symlink)
+    const GVfsFtpFile *dir, const GVfsFtpFile *file, char **symlink)
 {
   GFileInfo *info = NULL;
   gpointer iter;
@@ -2065,7 +2006,7 @@ create_file_info_from_parent (GVfsBackendFtp *ftp, FtpConnection *conn,
 
 static GFileInfo *
 create_file_info_from_file (GVfsBackendFtp *ftp, FtpConnection *conn, 
-    const FtpFile *file, const char *filename, char **symlink)
+    const GVfsFtpFile *file, const char *filename, char **symlink)
 {
   GFileInfo *info;
 
@@ -2083,7 +2024,7 @@ create_file_info_from_file (GVfsBackendFtp *ftp, FtpConnection *conn,
 
       g_file_info_set_is_hidden (info, TRUE);
     }
-  else if (ftp_connection_send (conn, 0, "SIZE %s", file))
+  else if (ftp_connection_send (conn, 0, "SIZE %s", g_vfs_ftp_file_get_ftp_path (file)))
     {
       char *tmp;
 
@@ -2119,8 +2060,7 @@ create_file_info_from_file (GVfsBackendFtp *ftp, FtpConnection *conn,
 static GFileInfo *
 create_file_info (GVfsBackendFtp *ftp, FtpConnection *conn, const char *filename, char **symlink)
 {
-  char *dirname;
-  FtpFile *dir, *file;
+  GVfsFtpFile *dir, *file;
   GFileInfo *info;
 
   if (symlink)
@@ -2129,17 +2069,15 @@ create_file_info (GVfsBackendFtp *ftp, FtpConnection *conn, const char *filename
   if (g_str_equal (filename, "/"))
     return create_file_info_for_root (ftp);
 
-  dirname = g_path_get_dirname (filename);
-  dir = ftp_filename_from_gvfs_path (conn, dirname);
-  g_free (dirname);
-  file = ftp_filename_from_gvfs_path (conn, filename);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
+  dir = g_vfs_ftp_file_new_parent (file);
 
   info = create_file_info_from_parent (ftp, conn, dir, file, symlink);
   if (info == NULL)
     info = create_file_info_from_file (ftp, conn, file, filename, symlink);
 
-  g_free (dir);
-  g_free (file);
+  g_vfs_ftp_file_free (dir);
+  g_vfs_ftp_file_free (file);
   return info;
 }
 
@@ -2271,7 +2209,7 @@ do_enumerate (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *dir;
+  GVfsFtpFile *dir;
   gpointer iter;
   GSList *symlink_targets = NULL;
   GSList *symlink_fileinfos = NULL;
@@ -2288,7 +2226,7 @@ do_enumerate (GVfsBackend *backend,
    * automatically.
    */
 
-  dir = ftp_filename_from_gvfs_path (conn, dirname);
+  dir = g_vfs_ftp_file_new_from_gvfs (ftp, dirname);
   entry = enumerate_directory (ftp, conn, dir, FALSE);
   if (ftp_connection_pop_job (conn))
     {
@@ -2342,7 +2280,7 @@ do_enumerate (GVfsBackend *backend,
     g_assert (entry == NULL);
 
   g_vfs_backend_ftp_push_connection (ftp, conn);
-  g_free (dir);
+  g_vfs_ftp_file_free (dir);
 }
 
 static void
@@ -2353,40 +2291,29 @@ do_set_display_name (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  char *name;
-  FtpFile *original, *dir, *now;
+  GVfsFtpFile *original, *dir, *now;
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
   if (conn == NULL)
     return;
 
-  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);
-  if (now == NULL)
-    {
-      g_set_error_literal (&conn->error, 
-		           G_IO_ERROR,
-		           G_IO_ERROR_INVALID_FILENAME,
-			   _("Invalid filename"));
-    }
+  original = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
+  dir = g_vfs_ftp_file_new_parent (original);
+  now = g_vfs_ftp_file_new_child (dir, display_name, &conn->error);
   ftp_connection_send (conn,
 		       RESPONSE_PASS_300 | RESPONSE_FAIL_200,
-		       "RNFR %s", original);
-  g_free (original);
+		       "RNFR %s", g_vfs_ftp_file_get_ftp_path (original));
   ftp_connection_send (conn,
 		       0,
-		       "RNTO %s", now);
+		       "RNTO %s", g_vfs_ftp_file_get_ftp_path (now));
 
-  name = ftp_filename_to_gvfs_path (conn, now);
-  g_free (now);
-  g_vfs_job_set_display_name_set_new_path (job, name);
-  g_free (name);
+  /* FIXME: parse result of RNTO here? */
+  g_vfs_job_set_display_name_set_new_path (job, g_vfs_ftp_file_get_gvfs_path (now));
   gvfs_backend_ftp_purge_cache_directory (ftp, dir);
-  g_free (dir);
   g_vfs_backend_ftp_push_connection (ftp, conn);
+  g_vfs_ftp_file_free (now);
+  g_vfs_ftp_file_free (dir);
+  g_vfs_ftp_file_free (original);
 }
 
 static void
@@ -2396,7 +2323,7 @@ do_delete (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *file;
+  GVfsFtpFile *file;
   guint response;
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
@@ -2405,15 +2332,15 @@ do_delete (GVfsBackend *backend,
 
   /* We try file deletion first. If that fails, we try directory deletion.
    * The file-first-then-directory order has been decided by coin-toss. */
-  file = ftp_filename_from_gvfs_path (conn, filename);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
   response = ftp_connection_send (conn,
 				  RESPONSE_PASS_500,
-				  "DELE %s", file);
+				  "DELE %s", g_vfs_ftp_file_get_ftp_path (file));
   if (STATUS_GROUP (response) == 5)
     {
       response = ftp_connection_send (conn,
 				      RESPONSE_PASS_500,
-				      "RMD %s", file);
+				      "RMD %s", g_vfs_ftp_file_get_ftp_path (file));
       if (response == 550)
 	{
 	  const FtpDirEntry *entry = enumerate_directory (ftp, conn, file, FALSE);
@@ -2438,7 +2365,7 @@ do_delete (GVfsBackend *backend,
     }
 
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, file);
-  g_free (file);
+  g_vfs_ftp_file_free (file);
   g_vfs_backend_ftp_push_connection (ftp, conn);
 }
 
@@ -2449,24 +2376,24 @@ do_make_directory (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *file;
+  GVfsFtpFile *file;
   static const Ftp550Handler make_directory_handlers[] = { error_550_exists, error_550_parent_not_found, NULL };
 
   conn = g_vfs_backend_ftp_pop_connection (ftp, G_VFS_JOB (job));
   if (conn == NULL)
     return;
 
-  file = ftp_filename_from_gvfs_path (conn, filename);
+  file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
   ftp_connection_send_and_check (conn,
                                  0,
                                  make_directory_handlers,
                                  file,
-                                 "MKD %s", file);
+                                 "MKD %s", g_vfs_ftp_file_get_ftp_path (file));
 
   /* FIXME: Compare created file with name from server result to be sure 
    * it's correct and otherwise fail. */
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, file);
-  g_free (file);
+  g_vfs_ftp_file_free (file);
 
   g_vfs_backend_ftp_push_connection (ftp, conn);
 }
@@ -2482,7 +2409,7 @@ do_move (GVfsBackend *backend,
 {
   GVfsBackendFtp *ftp = G_VFS_BACKEND_FTP (backend);
   FtpConnection *conn;
-  FtpFile *srcfile, *destfile;
+  GVfsFtpFile *srcfile, *destfile;
 
   /* FIXME: what about G_FILE_COPY_NOFOLLOW_SYMLINKS and G_FILE_COPY_ALL_METADATA? */
 
@@ -2500,31 +2427,30 @@ do_move (GVfsBackend *backend,
   if (conn == NULL)
     return;
 
-  srcfile = ftp_filename_from_gvfs_path (conn, source);
-  destfile = ftp_filename_from_gvfs_path (conn, destination);
+  srcfile = g_vfs_ftp_file_new_from_gvfs (ftp, source);
+  destfile = g_vfs_ftp_file_new_from_gvfs (ftp, destination);
   if (ftp_connection_try_cd (conn, destfile))
     {
       char *basename = g_path_get_basename (source);
-      FtpFile *real = ftp_filename_construct (conn, destfile, basename);
+      GVfsFtpFile *real = g_vfs_ftp_file_new_child (destfile, basename, &conn->error);
 
       g_free (basename);
       if (real == NULL)
-	g_set_error_literal (&conn->error, 
-		             G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
-			     _("Invalid destination filename"));
+	goto out;
       else
 	{
-	  g_free (destfile);
+	  g_vfs_ftp_file_free (destfile);
 	  destfile = real;
 	}
     }
 
   if (!(flags & G_FILE_COPY_OVERWRITE))
     {
-      char *destfilename = ftp_filename_to_gvfs_path (conn, destfile);
-      GFileInfo *info = create_file_info (ftp, conn, destfilename, NULL);
+      GFileInfo *info = create_file_info (ftp,
+                                          conn,
+                                          g_vfs_ftp_file_get_gvfs_path (destfile),
+                                          NULL);
 
-      g_free (destfilename);
       if (info)
 	{
 	  g_object_unref (info);
@@ -2538,16 +2464,16 @@ do_move (GVfsBackend *backend,
 
   ftp_connection_send (conn,
 		       RESPONSE_PASS_300 | RESPONSE_FAIL_200,
-		       "RNFR %s", srcfile);
+		       "RNFR %s", g_vfs_ftp_file_get_ftp_path (srcfile));
   ftp_connection_send (conn,
 		       0,
-		       "RNTO %s", destfile);
+		       "RNTO %s", g_vfs_ftp_file_get_ftp_path (destfile));
 
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, srcfile);
   gvfs_backend_ftp_purge_cache_of_file (ftp, conn, destfile);
 out:
-  g_free (srcfile);
-  g_free (destfile);
+  g_vfs_ftp_file_free (srcfile);
+  g_vfs_ftp_file_free (destfile);
   g_vfs_backend_ftp_push_connection (ftp, conn);
 }
 
diff --git a/daemon/gvfsftpfile.c b/daemon/gvfsftpfile.c
new file mode 100644
index 0000000..7f0b45e
--- /dev/null
+++ b/daemon/gvfsftpfile.c
@@ -0,0 +1,294 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2009 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <gio/gio.h>
+#include <glib/gi18n.h>
+
+#include "gvfsftpfile.h"
+
+/**
+ * GVfsFtpFile:
+ *
+ * This structure maps between GVfs paths and the actual paths as used on an 
+ * FTP server. The mapping may not be a 1-to-1 mapping, so always use this
+ * structure if you need to do operations on paths.
+ */
+
+struct _GVfsFtpFile {
+  GVfsBackendFtp *      backend;        /* the backend */
+  char *                gvfs_path;      /* path in gvfs terms */
+  char *                ftp_path;       /* path in ftp terms */
+};
+
+/*** VFUNCS (that aren't yet made into vfuncs) ***/
+
+/* 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.
+ */
+
+static char *
+g_vfs_ftp_file_compute_ftp_path (const char *gvfs_path)
+{
+  return g_strdup (gvfs_path);
+}
+
+static char *
+g_vfs_ftp_file_compute_gvfs_path (const char *ftp_path)
+{
+  return g_strdup (ftp_path);
+}
+
+/*** API ***/
+
+/**
+ * g_vfs_ftp_file_new_from_gvfs:
+ * @ftp: the ftp backend this file is to be used on
+ * @gvfs_path: gvfs path to create the file from
+ *
+ * Constructs a new #GVfsFtpFile representing the given gvfs path.
+ *
+ * Returns: a new file
+ **/
+GVfsFtpFile *
+g_vfs_ftp_file_new_from_gvfs (GVfsBackendFtp *ftp, const char *gvfs_path)
+{
+  GVfsFtpFile *file;
+
+  g_return_val_if_fail (G_VFS_IS_BACKEND_FTP (ftp), NULL);
+  g_return_val_if_fail (gvfs_path != NULL, NULL);
+
+  file = g_slice_new (GVfsFtpFile);
+  file->backend = g_object_ref (ftp);
+  file->gvfs_path = g_strdup (gvfs_path);
+  file->ftp_path = g_vfs_ftp_file_compute_ftp_path (gvfs_path);
+
+  return file;
+}
+
+/**
+ * g_vfs_ftp_file_new_from_ftp:
+ * @ftp: the ftp backend this file is to be used on
+ * @ftp_path: ftp path to create the file from
+ *
+ * Constructs a new #GVfsFtpFile representing the given ftp path.
+ *
+ * Returns: a new file
+ **/
+GVfsFtpFile *
+g_vfs_ftp_file_new_from_ftp (GVfsBackendFtp *ftp, const char *ftp_path)
+{
+  GVfsFtpFile *file;
+
+  g_return_val_if_fail (G_VFS_IS_BACKEND_FTP (ftp), NULL);
+  g_return_val_if_fail (ftp_path != NULL, NULL);
+
+  file = g_slice_new (GVfsFtpFile);
+  file->backend = g_object_ref (ftp);
+  file->ftp_path = g_strdup (ftp_path);
+  file->gvfs_path = g_vfs_ftp_file_compute_ftp_path (ftp_path);
+
+  return file;
+}
+
+/**
+ * g_vfs_ftp_file_new_parent:
+ * @file: file to get the parent directory from
+ *
+ * Creates a new file to represent the parent directory of @file. If @file
+ * already references the root directory, the new file will also reference
+ * the root.
+ *
+ * Returns: a new file representing the parent directory of @file
+ **/
+GVfsFtpFile *
+g_vfs_ftp_file_new_parent (const GVfsFtpFile *file)
+{
+  char *dirname;
+  GVfsFtpFile *dir;
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  dirname = g_path_get_dirname (file->gvfs_path);
+  if (dirname[0] == '.' && dirname[1] == 0)
+    dir = g_vfs_ftp_file_copy (file);
+  else
+    dir = g_vfs_ftp_file_new_from_gvfs (file->backend, dirname);
+  g_free (dirname);
+
+  return dir;
+}
+
+/**
+ * g_vfs_ftp_file_new_child:
+ * @parent: the parent file
+ * @display_name: the basename to use for the new file
+ * @error: location to take an eventual error or %NULL
+ *
+ * Tries to create a new file for the given @display_name in the given @parent 
+ * directory. If the display name is invalid, @error is set and %NULL is 
+ * returned.
+ *
+ * Returns: a new file or %NULL on error
+ **/
+GVfsFtpFile *
+g_vfs_ftp_file_new_child (const GVfsFtpFile *parent, const char *display_name, GError **error)
+{
+  char *new_path;
+  GVfsFtpFile *child;
+
+  g_return_val_if_fail (parent != NULL, NULL);
+  g_return_val_if_fail (display_name != NULL, NULL);
+
+  if (strpbrk (display_name, "/\r\n"))
+    {
+      g_set_error_literal (error, 
+                           G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME,
+                           _("Filename contains invalid characters."));
+      return NULL;
+    }
+
+  new_path = g_strconcat (parent->gvfs_path, "/", display_name, NULL);
+  child = g_vfs_ftp_file_new_from_gvfs (parent->backend, new_path);
+  g_free (new_path);
+  return child;
+}
+
+/**
+ * g_vfs_ftp_file_copy:
+ * @file: file to copy
+ *
+ * Creates a copy of the given @file.
+ *
+ * Returns: an identical copy of @file
+ **/
+GVfsFtpFile *
+g_vfs_ftp_file_copy (const GVfsFtpFile *file)
+{
+  GVfsFtpFile *copy;
+
+  g_return_val_if_fail (file != NULL, NULL);
+
+  copy = g_slice_new (GVfsFtpFile);
+  copy->backend = g_object_ref (file->backend);
+  copy->ftp_path = g_strdup (file->ftp_path);
+  copy->gvfs_path = g_strdup (file->gvfs_path);
+
+  return copy;
+}
+
+/**
+ * g_vfs_ftp_file_free:
+ * @file: file to free
+ *
+ * Frees the given file structure and all associated resources.
+ **/
+void
+g_vfs_ftp_file_free (GVfsFtpFile *file)
+{
+  g_return_if_fail (file != NULL);
+
+  g_object_unref (file->backend);
+  g_free (file->gvfs_path);
+  g_free (file->ftp_path);
+  g_slice_free (GVfsFtpFile, file);
+}
+
+
+/**
+ * g_vfs_ftp_file_get_ftp_path:
+ * @file: a file
+ *
+ * Gets the string to refer to @file on the ftp server. This string may not be
+ * valid UTF-8.
+ *
+ * Returns: the path to refer to @file on the FTP server. 
+ **/
+const char *
+g_vfs_ftp_file_get_ftp_path (const GVfsFtpFile *file)
+{
+  g_return_val_if_fail (file != NULL, NULL);
+
+  return file->ftp_path;
+}
+
+/**
+ * g_vfs_ftp_file_get_gvfs_path:
+ * @file: a file
+ *
+ * Gets the GVfs path used to refer to @file.
+ *
+ * Returns: the GVfs path used to refer to @file.
+ **/
+const char *
+g_vfs_ftp_file_get_gvfs_path (const GVfsFtpFile *file)
+{
+  g_return_val_if_fail (file != NULL, NULL);
+
+  return file->gvfs_path;
+}
+
+/**
+ * g_vfs_ftp_file_equal:
+ * @a: a #GVfsFtpFile
+ * @b: a #GVfsFtpFile
+ *
+ * Compares @a and @b. If they reference the same file, %TRUE is returned. 
+ * This function uses #gconstpointer arguments to the #GEqualFunc type.
+ *
+ * Returns: %TRUE if @a and @b reference the same file.
+ **/
+gboolean
+g_vfs_ftp_file_equal (gconstpointer a,
+                      gconstpointer b)
+{
+  const GVfsFtpFile *af = a;
+  const GVfsFtpFile *bf = b;
+
+  g_return_val_if_fail (a != NULL, FALSE);
+  g_return_val_if_fail (b != NULL, FALSE);
+
+  /* FIXME: use ftp path? */
+  return g_str_equal (af->gvfs_path, bf->gvfs_path);
+}
+
+/**
+ * g_vfs_ftp_file_hash:
+ * @a: a #GvfsFtpFile
+ *
+ * Computes a hash value for the given file to be used in a #GHashTable.
+ * This function uses #gconstpointer arguments to the #GHashFunc type.
+ *
+ * Returns: a hash value for the given file.
+ **/
+guint
+g_vfs_ftp_file_hash (gconstpointer a)
+{
+  const GVfsFtpFile *af = a;
+
+  return g_str_hash (af->gvfs_path);
+}
+
diff --git a/daemon/gvfsftpfile.h b/daemon/gvfsftpfile.h
new file mode 100644
index 0000000..ac007d8
--- /dev/null
+++ b/daemon/gvfsftpfile.h
@@ -0,0 +1,54 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2009 Benjamin Otte <otte gnome org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __G_VFS_FTP_FILE_H__
+#define __G_VFS_FTP_FILE_H__
+
+#include <gvfsbackendftp.h>
+
+G_BEGIN_DECLS
+
+
+typedef struct _GVfsFtpFile GVfsFtpFile;
+
+GVfsFtpFile *     g_vfs_ftp_file_new_from_gvfs          (GVfsBackendFtp *       ftp,
+                                                         const char *           gvfs_path);
+GVfsFtpFile *     g_vfs_ftp_file_new_from_ftp           (GVfsBackendFtp *       ftp,
+                                                         const char *           ftp_path);
+GVfsFtpFile *     g_vfs_ftp_file_new_parent             (const GVfsFtpFile *    file);
+GVfsFtpFile *     g_vfs_ftp_file_new_child              (const GVfsFtpFile *    parent,
+                                                         const char *           display_name,
+                                                         GError **              error);
+GVfsFtpFile *     g_vfs_ftp_file_copy                   (const GVfsFtpFile *    file);
+void              g_vfs_ftp_file_free                   (GVfsFtpFile *          file);
+
+const char *      g_vfs_ftp_file_get_ftp_path           (const GVfsFtpFile *    file);
+const char *      g_vfs_ftp_file_get_gvfs_path          (const GVfsFtpFile *    file);
+
+gboolean          g_vfs_ftp_file_equal                  (gconstpointer          a,
+                                                         gconstpointer          b);
+guint             g_vfs_ftp_file_hash                   (gconstpointer          a);
+
+
+G_END_DECLS
+
+#endif /* __G_VFS_FTP_FILE_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]