diff options
-rw-r--r-- | daemon/gvfsbackendftp.c | 114 | ||||
-rw-r--r-- | daemon/gvfsftpdircache.c | 180 | ||||
-rw-r--r-- | daemon/gvfsftpdircache.h | 5 |
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, |