summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2009-06-03 09:20:20 +0200
committerBenjamin Otte <otte@gnome.org>2009-06-11 10:05:39 +0200
commit2f5c4dcfd579f9b9cceb8eb08b71d4318e9c03b6 (patch)
treeeae7d94d5ee713147394b576efd00696e819ce67
parent9bc35b2b30b3f43ae7385b078c0b2fdfbdd30b1e (diff)
downloadgvfs-2f5c4dcfd579f9b9cceb8eb08b71d4318e9c03b6.tar.gz
[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.
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gvfsbackendftp.c320
-rw-r--r--daemon/gvfsftpfile.c294
-rw-r--r--daemon/gvfsftpfile.h54
4 files changed, 472 insertions, 197 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 0651c08b..af8d663b 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 77359591..26462463 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 00000000..7f0b45ee
--- /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 00000000..ac007d87
--- /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__ */