/** * @file dirlist.cc * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * @copyright This program 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 General Public License for more details. * * @copyright You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "gnome-cmd-includes.h" #include "dirlist.h" #include "gnome-cmd-con.h" #include "gnome-cmd-data.h" #include "utils.h" using namespace std; #define FILES_PER_NOTIFICATION 50 #define LIST_PRIORITY 0 #define FILES_PER_UPDATE 50 void async_list (GnomeCmdDir *dir); void sync_list (GnomeCmdDir *dir); static void enumerate_children_callback(GObject *direnum, GAsyncResult *result, gpointer user_data); static gboolean update_list_progress (GnomeCmdDir *dir) { DEBUG ('l', "Checking list progress...\n"); if (dir->state == GnomeCmdDir::STATE_LISTING) { gchar *msg = g_strdup_printf (ngettext ("%d file listed", "%d files listed", dir->list_counter), dir->list_counter); gtk_label_set_text (GTK_LABEL (dir->label), msg); gtk_progress_bar_pulse (GTK_PROGRESS_BAR (dir->pbar)); DEBUG('l', "%s\n", msg); g_free (msg); return TRUE; } return FALSE; } static GFileEnumerator *get_gfileenumerator_sync(GFile *gFile, GError *error) { GError *tmpError; auto gFileEnumerator = g_file_enumerate_children (gFile, "*", G_FILE_QUERY_INFO_NONE, nullptr, &tmpError); if(tmpError) { g_critical("Unable to enumerate children, error: %s", tmpError->message); g_propagate_error(&error, tmpError); return nullptr; } return gFileEnumerator; } static void get_gfileenumerator_async_callback(GObject *gFileObject, GAsyncResult *result, gpointer gnomeCmdDirPointer) { auto dir = GNOME_CMD_DIR(gnomeCmdDirPointer); auto gFile = (GFile*) gFileObject; GError *error = nullptr; auto gFileEnumerator = g_file_enumerate_children_finish (gFile, result, &error); if (error) { g_warning("g_file_enumerate_children_finish error: %s\n", error->message); g_error_free(error); return; } g_file_enumerator_next_files_async(gFileEnumerator, FILES_PER_UPDATE, G_PRIORITY_LOW, nullptr, enumerate_children_callback, dir); g_timeout_add (gnome_cmd_data.gui_update_rate, (GSourceFunc) update_list_progress, dir); } static void get_gfileenumerator_async(GFile *gFile, GnomeCmdDir *dir, GError *error) { g_file_enumerate_children_async (gFile, "*", G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, nullptr, get_gfileenumerator_async_callback, dir); } void async_list (GnomeCmdDir *dir) { g_return_if_fail(dir != nullptr); GError *error = nullptr; dir->gFileInfoList = nullptr; auto gFile = GNOME_CMD_FILE (dir)->gFile; gchar *uri_str = g_file_get_uri(gFile); DEBUG('l', "async_list: %s\n", uri_str); g_free (uri_str); dir->state = GnomeCmdDir::STATE_LISTING; GFileEnumerator *gFileEnumerator; if (gnome_cmd_dir_get_connection(dir)->is_local) { gFileEnumerator = get_gfileenumerator_sync(gFile, error); if (error) { return; } g_file_enumerator_next_files_async(gFileEnumerator, FILES_PER_UPDATE, G_PRIORITY_LOW, nullptr, enumerate_children_callback, dir); g_timeout_add (gnome_cmd_data.gui_update_rate, (GSourceFunc) update_list_progress, dir); } else { get_gfileenumerator_async(gFile, dir, error); } } void sync_list (GnomeCmdDir *dir) { g_return_if_fail(dir != nullptr); GError *error = nullptr; gchar *uri_str = GNOME_CMD_FILE (dir)->get_uri_str(); DEBUG('l', "sync_list: %s\n", uri_str); g_free (uri_str); dir->gFileInfoList = nullptr; auto gFile = GNOME_CMD_FILE (dir)->gFile; auto gFileEnumerator = g_file_enumerate_children (gFile, "*", G_FILE_QUERY_INFO_NONE, nullptr, &error); if(error) { dir->error = nullptr; g_critical("sync_list: Unable to enumerate children, error: %s", error->message); g_propagate_error(&(dir->error), error); dir->state = GnomeCmdDir::STATE_EMPTY; dir->done_func (dir, dir->gFileInfoList, dir->error); return; } GFileInfo *gFileInfoTmp = nullptr; do { gFileInfoTmp = g_file_enumerator_next_file(gFileEnumerator, nullptr, &error); if(error) { g_critical("sync_list: Unable to enumerate next file, error: %s", error->message); break; } if (gFileInfoTmp) { dir->gFileInfoList = g_list_append(dir->gFileInfoList, gFileInfoTmp); } } while (gFileInfoTmp && !error); g_file_enumerator_close (gFileEnumerator, nullptr, nullptr); g_object_unref(gFileEnumerator); dir->state = error ? GnomeCmdDir::STATE_EMPTY : GnomeCmdDir::STATE_LISTED; dir->done_func (dir, dir->gFileInfoList, error); if (error) g_error_free(error); } static void enumerate_children_callback(GObject *direnum, GAsyncResult *result, gpointer user_data) { auto gFileEnumerator = G_FILE_ENUMERATOR(direnum); auto dir = GNOME_CMD_DIR(user_data); GError *error = nullptr; GList *gFileInfosList = g_file_enumerator_next_files_finish(gFileEnumerator, result, &error); if(error) { g_critical("Unable to iterate the g_file_enumerator, error: %s", error->message); dir->state = GnomeCmdDir::STATE_EMPTY; dir->done_func (dir, dir->gFileInfoList, error); g_file_enumerator_close(gFileEnumerator, nullptr, nullptr); g_object_unref(direnum); g_error_free(error); return; } else if(gFileInfosList == nullptr) { /* DONE */ dir->state = GnomeCmdDir::STATE_LISTED; DEBUG('l', "All files listed, calling list_done func\n"); dir->done_func (dir, dir->gFileInfoList, nullptr); g_file_enumerator_close(gFileEnumerator, nullptr, nullptr); g_object_unref(direnum); return; } else { dir->gFileInfoList = g_list_concat (dir->gFileInfoList, g_list_copy (gFileInfosList)); dir->list_counter += FILES_PER_UPDATE; g_file_enumerator_next_files_async(G_FILE_ENUMERATOR(direnum), FILES_PER_UPDATE, G_PRIORITY_LOW, nullptr, enumerate_children_callback, dir); } g_list_free(gFileInfosList); } void dirlist_list (GnomeCmdDir *dir, gboolean visualProgress) { g_return_if_fail (GNOME_CMD_IS_DIR (dir)); dir->infolist = NULL; dir->gFileInfoList = nullptr; dir->list_counter = 0; dir->state = GnomeCmdDir::STATE_LISTING; if (!visualProgress) { sync_list (dir); return; } async_list (dir); } void dirlist_cancel (GnomeCmdDir *dir) { dir->state = GnomeCmdDir::STATE_EMPTY; // ToDo: Add a cancel-trigger for the async dir listing DEBUG('l', "Cancel dir-listing not implemented yet...\n"); } GList* sync_dir_list (const gchar *absDirPath) { g_return_val_if_fail (absDirPath != nullptr, nullptr); auto gFile = g_file_new_for_path(absDirPath); GList *gFileInfoList = sync_dir_list (gFile, nullptr); g_object_unref(gFile); return gFileInfoList; } GList* sync_dir_list (GFile *gFile, GCancellable* cancellable) { g_return_val_if_fail (gFile != nullptr, nullptr); gchar *pathOrUri = g_file_get_path (gFile); if (!pathOrUri) pathOrUri = g_file_get_uri (gFile); DEBUG('l', "sync_dir_list: %s\n", pathOrUri); if (!g_file_query_exists(gFile, cancellable)) { g_warning("sync_dir_list error: \"%s\" does not exist", pathOrUri); g_free (pathOrUri); return nullptr; } g_free (pathOrUri); GError *error = nullptr; GList *gFileInfoList = nullptr; auto gFileEnumerator = g_file_enumerate_children (gFile, "*", G_FILE_QUERY_INFO_NONE, cancellable, &error); if(error) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_critical("sync_dir_list: Unable to enumerate children, error: %s", error->message); g_error_free(error); return nullptr; } GFileInfo *gFileInfoTmp = nullptr; do { gFileInfoTmp = g_file_enumerator_next_file(gFileEnumerator, cancellable, &error); if(error) { if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_critical("sync_dir_list: Unable to enumerate next file, error: %s", error->message); break; } if (gFileInfoTmp) { gFileInfoList = g_list_append(gFileInfoList, gFileInfoTmp); } } while (gFileInfoTmp && !error); if (error) g_error_free(error); g_file_enumerator_close (gFileEnumerator, nullptr, nullptr); g_object_unref(gFileEnumerator); return gFileInfoList; }