pathbar: Handle webdav where is the root is a path

Our webdav server has a root which is davs://mynextcloud/remote.php/webdav
When once creates a GFile out of or out of a subdirectory, and one call
g_file_get_parent(), it recurses too far up and try to query
davs://mynextcloud/remote.php which fails, resulting in a broken pathbar.

To fix that, before querying the metadata of each element of the path,
I query the "enclosing mount", then use it's root to compare the GFile
against.

This is a backport of !5830 to 3.24
This commit is contained in:
Olivier Crête
2023-04-13 16:09:48 -06:00
parent 6104130af2
commit d5bace3779

View File

@ -1506,10 +1506,10 @@ gtk_path_bar_update_button_appearance (GtkPathBar *path_bar,
static ButtonType static ButtonType
find_button_type (GtkPathBar *path_bar, find_button_type (GtkPathBar *path_bar,
GFile *file) GFile *file,
GFile *root_file)
{ {
if (path_bar->priv->root_file != NULL && if (root_file != NULL && g_file_equal (file, root_file))
g_file_equal (file, path_bar->priv->root_file))
return ROOT_BUTTON; return ROOT_BUTTON;
if (path_bar->priv->home_file != NULL && if (path_bar->priv->home_file != NULL &&
g_file_equal (file, path_bar->priv->home_file)) g_file_equal (file, path_bar->priv->home_file))
@ -1546,6 +1546,7 @@ static ButtonData *
make_directory_button (GtkPathBar *path_bar, make_directory_button (GtkPathBar *path_bar,
const char *dir_name, const char *dir_name,
GFile *file, GFile *file,
GFile *root_file,
gboolean current_dir, gboolean current_dir,
gboolean file_is_hidden) gboolean file_is_hidden)
{ {
@ -1556,7 +1557,7 @@ make_directory_button (GtkPathBar *path_bar,
file_is_hidden = !! file_is_hidden; file_is_hidden = !! file_is_hidden;
/* Is it a special button? */ /* Is it a special button? */
button_data = g_new0 (ButtonData, 1); button_data = g_new0 (ButtonData, 1);
button_data->type = find_button_type (path_bar, file); button_data->type = find_button_type (path_bar, file, root_file);
button_data->button = gtk_toggle_button_new (); button_data->button = gtk_toggle_button_new ();
atk_obj = gtk_widget_get_accessible (button_data->button); atk_obj = gtk_widget_get_accessible (button_data->button);
gtk_widget_set_focus_on_click (button_data->button, FALSE); gtk_widget_set_focus_on_click (button_data->button, FALSE);
@ -1678,6 +1679,9 @@ struct SetFileInfo
GList *new_buttons; GList *new_buttons;
GList *fake_root; GList *fake_root;
gboolean first_directory; gboolean first_directory;
GFile *root_file;
GCancellable *cancellable;
}; };
static void static void
@ -1725,6 +1729,8 @@ gtk_path_bar_set_file_finish (struct SetFileInfo *info,
g_object_unref (info->file); g_object_unref (info->file);
if (info->parent_file) if (info->parent_file)
g_object_unref (info->parent_file); g_object_unref (info->parent_file);
if (info->root_file)
g_object_unref (info->root_file);
g_free (info); g_free (info);
} }
@ -1748,9 +1754,6 @@ gtk_path_bar_get_info_callback (GCancellable *cancellable,
return; return;
} }
g_assert (GTK_IS_PATH_BAR (file_info->path_bar));
g_assert (G_OBJECT (file_info->path_bar)->ref_count > 0);
g_assert (cancellable == file_info->path_bar->priv->get_info_cancellable); g_assert (cancellable == file_info->path_bar->priv->get_info_cancellable);
cancellable_async_done (file_info->path_bar, cancellable); cancellable_async_done (file_info->path_bar, cancellable);
file_info->path_bar->priv->get_info_cancellable = NULL; file_info->path_bar->priv->get_info_cancellable = NULL;
@ -1767,6 +1770,7 @@ gtk_path_bar_get_info_callback (GCancellable *cancellable,
button_data = make_directory_button (file_info->path_bar, display_name, button_data = make_directory_button (file_info->path_bar, display_name,
file_info->file, file_info->file,
file_info->root_file,
file_info->first_directory, is_hidden); file_info->first_directory, is_hidden);
g_clear_object (&file_info->file); g_clear_object (&file_info->file);
@ -1789,7 +1793,10 @@ gtk_path_bar_get_info_callback (GCancellable *cancellable,
return; return;
} }
file_info->parent_file = g_file_get_parent (file_info->file); if (g_file_equal (file_info->file, file_info->root_file))
file_info->parent_file = NULL;
else
file_info->parent_file = g_file_get_parent (file_info->file);
/* Recurse asynchronously */ /* Recurse asynchronously */
file_info->path_bar->priv->get_info_cancellable = file_info->path_bar->priv->get_info_cancellable =
@ -1801,6 +1808,63 @@ gtk_path_bar_get_info_callback (GCancellable *cancellable,
add_cancellable (file_info->path_bar, file_info->path_bar->priv->get_info_cancellable); add_cancellable (file_info->path_bar, file_info->path_bar->priv->get_info_cancellable);
} }
static void
gtk_path_bar_get_mount_callback (GObject *source,
GAsyncResult *result,
gpointer data)
{
GFile *file = G_FILE (source);
struct SetFileInfo *file_info = data;
GMount *mount;
GError *error = NULL;
gdk_threads_enter ();
mount = g_file_find_enclosing_mount_finish (file, result, &error);
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
gtk_path_bar_set_file_finish (file_info, FALSE);
g_clear_error (&error);
gdk_threads_leave ();
return;
}
g_clear_error (&error);
if (mount)
{
file_info->root_file = g_mount_get_root (mount);
g_object_unref (mount);
}
if (file_info->root_file == NULL)
file_info->root_file = g_object_ref (file_info->path_bar->priv->root_file);
if (g_file_equal (file_info->file, file_info->root_file))
file_info->parent_file = NULL;
else
file_info->parent_file = g_file_get_parent (file_info->file);
cancellable_async_done (file_info->path_bar, file_info->cancellable);
if (file_info->path_bar->priv->get_info_cancellable == file_info->cancellable)
file_info->path_bar->priv->get_info_cancellable = NULL;
file_info->cancellable = NULL;
/* Recurse asynchronously */
file_info->path_bar->priv->get_info_cancellable =
_gtk_file_system_get_info (file_info->path_bar->priv->file_system,
file_info->file,
"standard::display-name,standard::is-hidden,standard::is-backup",
gtk_path_bar_get_info_callback,
file_info);
add_cancellable (file_info->path_bar,
file_info->path_bar->priv->get_info_cancellable);
gdk_threads_leave ();
}
void void
_gtk_path_bar_set_file (GtkPathBar *path_bar, _gtk_path_bar_set_file (GtkPathBar *path_bar,
GFile *file, GFile *file,
@ -1828,12 +1892,29 @@ _gtk_path_bar_set_file (GtkPathBar *path_bar,
cancel_cancellable (path_bar, path_bar->priv->get_info_cancellable); cancel_cancellable (path_bar, path_bar->priv->get_info_cancellable);
} }
path_bar->priv->get_info_cancellable = if (g_file_is_native (info->file))
_gtk_file_system_get_info (path_bar->priv->file_system, {
info->file, info->root_file = g_object_ref (path_bar->priv->root_file);
"standard::display-name,standard::is-hidden,standard::is-backup", info->parent_file = g_file_get_parent (info->file);
gtk_path_bar_get_info_callback,
info); path_bar->priv->get_info_cancellable =
_gtk_file_system_get_info (path_bar->priv->file_system,
info->file,
"standard::display-name,standard::is-hidden,standard::is-backup",
gtk_path_bar_get_info_callback,
info);
}
else
{
info->cancellable = g_cancellable_new ();
path_bar->priv->get_info_cancellable = info->cancellable;
g_file_find_enclosing_mount_async (info->file,
G_PRIORITY_DEFAULT,
info->cancellable,
gtk_path_bar_get_mount_callback,
info);
}
add_cancellable (path_bar, path_bar->priv->get_info_cancellable); add_cancellable (path_bar, path_bar->priv->get_info_cancellable);
} }