summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--daemon/gvfsbackendftp.c114
-rw-r--r--daemon/gvfsftpdircache.c180
-rw-r--r--daemon/gvfsftpdircache.h5
3 files changed, 150 insertions, 149 deletions
diff --git a/daemon/gvfsbackendftp.c b/daemon/gvfsbackendftp.c
index 0c35fa3e..67f9e4ca 100644
--- a/daemon/gvfsbackendftp.c
+++ b/daemon/gvfsbackendftp.c
@@ -160,32 +160,6 @@ gvfs_backend_ftp_determine_system (GVfsFtpTask *task)
g_strfreev (reply);
}
-static GFileInfo *
-g_vfs_bacend_ftp_create_root_file_info (GVfsBackendFtp *ftp)
-{
- GFileInfo *info;
- GIcon *icon;
- char *display_name;
-
- info = g_file_info_new ();
- g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
-
- g_file_info_set_name (info, "/");
- display_name = g_strdup_printf (_("/ on %s"), ftp->host_display_name);
- g_file_info_set_display_name (info, display_name);
- g_free (display_name);
- g_file_info_set_edit_name (info, "/");
-
- g_file_info_set_content_type (info, "inode/directory");
- g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, "inode/directory");
-
- icon = g_themed_icon_new ("folder-remote");
- g_file_info_set_icon (info, icon);
- g_object_unref (icon);
-
- return info;
-}
-
static void
gvfs_backend_ftp_setup_directory_cache (GVfsBackendFtp *ftp)
{
@@ -194,8 +168,7 @@ gvfs_backend_ftp_setup_directory_cache (GVfsBackendFtp *ftp)
else
ftp->dir_funcs = &g_vfs_ftp_dir_cache_funcs_default;
- ftp->dir_cache = g_vfs_ftp_dir_cache_new (ftp->dir_funcs,
- g_vfs_bacend_ftp_create_root_file_info (ftp));
+ ftp->dir_cache = g_vfs_ftp_dir_cache_new (ftp->dir_funcs);
}
/*** COMMON FUNCTIONS WITH SPECIAL HANDLING ***/
@@ -720,75 +693,6 @@ do_start_write (GVfsFtpTask *task,
}
}
-/* NB: This gets a file info for the given object, no matter if it's a dir
- * or a file */
-static GFileInfo *
-create_file_info (GVfsFtpTask *task, GVfsFtpFile *file, gboolean resolve_symlinks)
-{
- GFileInfo *info;
- char **reply;
-
- if (g_vfs_ftp_task_is_in_error (task))
- return NULL;
-
- info = g_vfs_ftp_dir_cache_lookup_file (task->backend->dir_cache, task, file, resolve_symlinks);
- if (info)
- return info;
-
- g_vfs_ftp_task_clear_error (task);
-
- /* the directory cache fails when the parent directory of the file is not readable.
- * This cannot happen on Unix, but it can happen on FTP.
- * In this case we try to figure out as much as possible about the file (does it even exist?)
- * using standard ftp commands.
- */
- if (g_vfs_ftp_task_try_cd (task, file))
- {
- char *tmp;
-
- info = g_file_info_new ();
-
- tmp = g_path_get_basename (g_vfs_ftp_file_get_gvfs_path (file));
- g_file_info_set_name (info, tmp);
- g_free (tmp);
-
- gvfs_file_info_populate_default (info, g_vfs_ftp_file_get_gvfs_path (file), G_FILE_TYPE_DIRECTORY);
-
- g_file_info_set_is_hidden (info, TRUE);
- }
- else if (g_vfs_ftp_task_send_and_check (task, 0, NULL, NULL, &reply, "SIZE %s", g_vfs_ftp_file_get_ftp_path (file)))
- {
- char *tmp;
-
- info = g_file_info_new ();
-
- tmp = g_path_get_basename (g_vfs_ftp_file_get_gvfs_path (file));
- g_file_info_set_name (info, tmp);
- g_free (tmp);
-
- gvfs_file_info_populate_default (info, g_vfs_ftp_file_get_gvfs_path (file), G_FILE_TYPE_REGULAR);
-
- g_file_info_set_size (info, g_ascii_strtoull (reply[0] + 4, NULL, 0));
- g_strfreev (reply);
-
- g_file_info_set_is_hidden (info, TRUE);
- }
- else
- {
- info = NULL;
- /* clear error from ftp_connection_send() in else if line above */
- g_vfs_ftp_task_clear_error (task);
-
- /* note that there might still be a file/directory, we just have
- * no way to figure this out (in particular on ftp servers that
- * don't support SIZE.
- * If you have ways to improve file detection, patches are welcome. */
- }
-
- return info;
-}
-
-
static void
do_create (GVfsBackend *backend,
GVfsJobOpenForWrite *job,
@@ -801,7 +705,7 @@ do_create (GVfsBackend *backend,
GVfsFtpFile *file;
file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
- info = create_file_info (&task, file, FALSE);
+ info = g_vfs_ftp_dir_cache_lookup_file (ftp->dir_cache, &task, file, FALSE);
if (info)
{
g_object_unref (info);
@@ -924,7 +828,10 @@ do_query_info (GVfsBackend *backend,
GFileInfo *real;
file = g_vfs_ftp_file_new_from_gvfs (ftp, filename);
- real = create_file_info (&task, file, query_flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS ? FALSE : TRUE);
+ real = g_vfs_ftp_dir_cache_lookup_file (ftp->dir_cache,
+ &task,
+ file,
+ query_flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS ? FALSE : TRUE);
if (real)
{
@@ -1131,9 +1038,10 @@ do_move (GVfsBackend *backend,
if (!(flags & G_FILE_COPY_OVERWRITE))
{
- GFileInfo *info = create_file_info (&task,
- destfile,
- FALSE);
+ GFileInfo *info = g_vfs_ftp_dir_cache_lookup_file (ftp->dir_cache,
+ &task,
+ destfile,
+ FALSE);
if (info)
{
@@ -1311,7 +1219,7 @@ do_pull (GVfsBackend * backend,
src = g_vfs_ftp_file_new_from_gvfs (ftp, source);
if (progress_callback)
- info = create_file_info (&task, src, TRUE);
+ info = g_vfs_ftp_dir_cache_lookup_file (ftp->dir_cache, &task, src, TRUE);
else
info = NULL;
if (info)
diff --git a/daemon/gvfsftpdircache.c b/daemon/gvfsftpdircache.c
index 536f3e62..b94a3b3c 100644
--- a/daemon/gvfsftpdircache.c
+++ b/daemon/gvfsftpdircache.c
@@ -96,17 +96,15 @@ struct _GVfsFtpDirCache
GHashTable * directories; /* GVfsFtpFile of directory => GVfsFtpDirCacheEntry mapping */
guint stamp; /* used to identify validity of cache when flushing */
GMutex * lock; /* mutex for thread safety of stamp and hash table */
- GFileInfo * root; /* file info for '/' */
const GVfsFtpDirFuncs *funcs; /* functions to call */
};
GVfsFtpDirCache *
-g_vfs_ftp_dir_cache_new (const GVfsFtpDirFuncs *funcs, GFileInfo *root)
+g_vfs_ftp_dir_cache_new (const GVfsFtpDirFuncs *funcs)
{
GVfsFtpDirCache *cache;
g_return_val_if_fail (funcs != NULL, NULL);
- g_return_val_if_fail (G_IS_FILE_INFO (root), NULL);
cache = g_slice_new0 (GVfsFtpDirCache);
cache->directories = g_hash_table_new_full (g_vfs_ftp_file_hash,
@@ -115,7 +113,6 @@ g_vfs_ftp_dir_cache_new (const GVfsFtpDirFuncs *funcs, GFileInfo *root)
(GDestroyNotify) g_vfs_ftp_dir_cache_entry_unref);
cache->lock = g_mutex_new();
cache->funcs = funcs;
- cache->root = root;
return cache;
}
@@ -127,7 +124,6 @@ g_vfs_ftp_dir_cache_free (GVfsFtpDirCache *cache)
g_hash_table_destroy (cache->directories);
g_mutex_free (cache->lock);
- g_object_unref (cache->root);
g_slice_free (GVfsFtpDirCache, cache);
}
@@ -191,13 +187,51 @@ g_vfs_ftp_dir_cache_lookup_entry (GVfsFtpDirCache * cache,
}
static GFileInfo *
+g_vfs_ftp_dir_cache_lookup_file_internal (GVfsFtpDirCache * cache,
+ GVfsFtpTask * task,
+ const GVfsFtpFile *file,
+ guint stamp)
+{
+ GVfsFtpDirCacheEntry *entry;
+ GVfsFtpFile *dir;
+ GFileInfo *info;
+
+ if (g_vfs_ftp_task_is_in_error (task))
+ return NULL;
+
+ if (!g_vfs_ftp_file_is_root (file))
+ {
+ dir = g_vfs_ftp_file_new_parent (file);
+ entry = g_vfs_ftp_dir_cache_lookup_entry (cache, task, dir, stamp);
+ g_vfs_ftp_file_free (dir);
+ if (entry == NULL)
+ return NULL;
+
+ info = g_hash_table_lookup (entry->files, file);
+ if (info != NULL)
+ {
+ /* NB: the order of ref/unref is important here */
+ g_object_ref (info);
+ g_vfs_ftp_dir_cache_entry_unref (entry);
+ return info;
+ }
+
+ g_vfs_ftp_dir_cache_entry_unref (entry);
+ }
+
+ if (!g_vfs_ftp_task_is_in_error (task))
+ info = cache->funcs->lookup_uncached (task, file);
+
+ return info;
+}
+
+static GFileInfo *
g_vfs_ftp_dir_cache_resolve_symlink (GVfsFtpDirCache * cache,
GVfsFtpTask * task,
const GVfsFtpFile *file,
GFileInfo * original,
guint stamp)
{
- GVfsFtpDirCacheEntry *entry;
static const char *copy_attributes[] = {
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK,
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN,
@@ -230,28 +264,13 @@ g_vfs_ftp_dir_cache_resolve_symlink (GVfsFtpDirCache * cache,
g_vfs_ftp_task_clear_error (task);
return original;
}
- tmp = g_vfs_ftp_file_new_parent (link);
- entry = g_vfs_ftp_dir_cache_lookup_entry (cache, task, tmp, stamp);
- g_vfs_ftp_file_free (tmp);
- if (entry == NULL)
- {
- g_vfs_ftp_file_free (link);
- /* clear the (potential) error here, dangling symlinks etc should not cause errors */
- g_vfs_ftp_task_clear_error (task);
- return original;
- }
- info = g_hash_table_lookup (entry->files, link);
+ info = g_vfs_ftp_dir_cache_lookup_file_internal (cache, task, link, stamp);
if (info == NULL)
{
- g_vfs_ftp_dir_cache_entry_unref (entry);
g_vfs_ftp_file_free (link);
+ g_vfs_ftp_task_clear_error (task);
return original;
}
- else
- {
- g_object_ref (info);
- g_vfs_ftp_dir_cache_entry_unref (entry);
- }
}
while (g_file_info_get_is_symlink (info) && lookups++ < 8);
@@ -293,35 +312,17 @@ g_vfs_ftp_dir_cache_lookup_file (GVfsFtpDirCache * cache,
const GVfsFtpFile *file,
gboolean resolve_symlinks)
{
- GVfsFtpDirCacheEntry *entry;
- GVfsFtpFile *dir;
GFileInfo *info;
g_return_val_if_fail (cache != NULL, NULL);
g_return_val_if_fail (task != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
- if (g_vfs_ftp_task_is_in_error (task))
- return NULL;
-
- if (g_vfs_ftp_file_is_root (file))
- return g_object_ref (cache->root);
-
- dir = g_vfs_ftp_file_new_parent (file);
- entry = g_vfs_ftp_dir_cache_lookup_entry (cache, task, dir, 0);
- g_vfs_ftp_file_free (dir);
- if (entry == NULL)
- return NULL;
+ info = g_vfs_ftp_dir_cache_lookup_file_internal (cache, task, file, 0);
- info = g_hash_table_lookup (entry->files, file);
- if (info != NULL)
- {
- g_object_ref (info);
- if (resolve_symlinks)
- info = g_vfs_ftp_dir_cache_resolve_symlink (cache, task, file, info, 0);
- }
+ if (info != NULL && resolve_symlinks)
+ info = g_vfs_ftp_dir_cache_resolve_symlink (cache, task, file, info, 0);
- g_vfs_ftp_dir_cache_entry_unref (entry);
return info;
}
@@ -365,6 +366,7 @@ g_vfs_ftp_dir_cache_lookup_dir (GVfsFtpDirCache * cache,
g_object_ref (info);
if (resolve_symlinks)
info = g_vfs_ftp_dir_cache_resolve_symlink (cache, task, file, info, stamp);
+ g_assert (!g_vfs_ftp_task_is_in_error (task));
result = g_list_prepend (result, info);
}
g_vfs_ftp_dir_cache_entry_unref (entry);
@@ -406,6 +408,94 @@ g_vfs_ftp_dir_cache_purge_file (GVfsFtpDirCache * cache,
#include "ParseFTPList.h"
#include "gvfsdaemonutils.h"
+static GFileInfo *
+create_root_file_info (GVfsBackendFtp *ftp)
+{
+ GFileInfo *info;
+ GIcon *icon;
+ char *display_name;
+
+ info = g_file_info_new ();
+ g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+
+ g_file_info_set_name (info, "/");
+ display_name = g_strdup_printf (_("/ on %s"), ftp->host_display_name);
+ g_file_info_set_display_name (info, display_name);
+ g_free (display_name);
+ g_file_info_set_edit_name (info, "/");
+
+ g_file_info_set_content_type (info, "inode/directory");
+ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, "inode/directory");
+
+ icon = g_themed_icon_new ("folder-remote");
+ g_file_info_set_icon (info, icon);
+ g_object_unref (icon);
+
+ return info;
+}
+
+static GFileInfo *
+g_vfs_ftp_dir_cache_funcs_lookup_uncached (GVfsFtpTask * task,
+ const GVfsFtpFile *file)
+{
+ GFileInfo *info;
+ char **reply;
+
+ if (g_vfs_ftp_file_is_root (file))
+ return create_root_file_info (task->backend);
+
+ /* the directory cache fails when the parent directory of the file is not readable.
+ * This cannot happen on Unix, but it can happen on FTP.
+ * In this case we try to figure out as much as possible about the file (does it even exist?)
+ * using standard ftp commands.
+ */
+ if (g_vfs_ftp_task_send (task, 0, "CWD %s", g_vfs_ftp_file_get_ftp_path (file)))
+ {
+ char *tmp;
+
+ info = g_file_info_new ();
+
+ tmp = g_path_get_basename (g_vfs_ftp_file_get_gvfs_path (file));
+ g_file_info_set_name (info, tmp);
+ g_free (tmp);
+
+ gvfs_file_info_populate_default (info, g_vfs_ftp_file_get_gvfs_path (file), G_FILE_TYPE_DIRECTORY);
+
+ g_file_info_set_is_hidden (info, TRUE);
+
+ return info;
+ }
+
+ g_vfs_ftp_task_clear_error (task);
+ if (g_vfs_ftp_task_send_and_check (task, 0, NULL, NULL, &reply, "SIZE %s", g_vfs_ftp_file_get_ftp_path (file)))
+ {
+ char *tmp;
+
+ info = g_file_info_new ();
+
+ tmp = g_path_get_basename (g_vfs_ftp_file_get_gvfs_path (file));
+ g_file_info_set_name (info, tmp);
+ g_free (tmp);
+
+ gvfs_file_info_populate_default (info, g_vfs_ftp_file_get_gvfs_path (file), G_FILE_TYPE_REGULAR);
+
+ g_file_info_set_size (info, g_ascii_strtoull (reply[0] + 4, NULL, 0));
+ g_strfreev (reply);
+
+ g_file_info_set_is_hidden (info, TRUE);
+ return info;
+ }
+
+ g_vfs_ftp_task_clear_error (task);
+
+ /* note that there might still be a file/directory, we just have
+ * no way to figure this out (in particular on ftp servers that
+ * don't support SIZE.
+ * If you have ways to improve file detection, patches are welcome. */
+
+ return NULL;
+}
+
static gboolean
g_vfs_ftp_dir_cache_funcs_process (GInputStream * stream,
int debug_id,
@@ -591,11 +681,13 @@ g_vfs_ftp_dir_cache_funcs_process_default (GInputStream * stream,
const GVfsFtpDirFuncs g_vfs_ftp_dir_cache_funcs_unix = {
"LIST -a",
g_vfs_ftp_dir_cache_funcs_process_unix,
+ g_vfs_ftp_dir_cache_funcs_lookup_uncached,
g_vfs_ftp_dir_cache_funcs_resolve_default
};
const GVfsFtpDirFuncs g_vfs_ftp_dir_cache_funcs_default = {
"LIST",
g_vfs_ftp_dir_cache_funcs_process_default,
+ g_vfs_ftp_dir_cache_funcs_lookup_uncached,
g_vfs_ftp_dir_cache_funcs_resolve_default
};
diff --git a/daemon/gvfsftpdircache.h b/daemon/gvfsftpdircache.h
index c007d07c..52e49ba6 100644
--- a/daemon/gvfsftpdircache.h
+++ b/daemon/gvfsftpdircache.h
@@ -41,6 +41,8 @@ struct _GVfsFtpDirFuncs {
GVfsFtpDirCacheEntry * entry,
GCancellable * cancellable,
GError ** error);
+ GFileInfo * (* lookup_uncached) (GVfsFtpTask * task,
+ const GVfsFtpFile * file);
GVfsFtpFile * (* resolve_symlink) (GVfsFtpTask * task,
const GVfsFtpFile * file,
const char * target);
@@ -49,8 +51,7 @@ struct _GVfsFtpDirFuncs {
extern const GVfsFtpDirFuncs g_vfs_ftp_dir_cache_funcs_unix;
extern const GVfsFtpDirFuncs g_vfs_ftp_dir_cache_funcs_default;
-GVfsFtpDirCache * g_vfs_ftp_dir_cache_new (const GVfsFtpDirFuncs *funcs,
- GFileInfo * root);
+GVfsFtpDirCache * g_vfs_ftp_dir_cache_new (const GVfsFtpDirFuncs *funcs);
void g_vfs_ftp_dir_cache_free (GVfsFtpDirCache * cache);
GFileInfo * g_vfs_ftp_dir_cache_lookup_file (GVfsFtpDirCache * cache,