/* nautilus-file-utilities.c - implementation of file manipulation routines. * * Copyright (C) 1999, 2000, 2001 Eazel, Inc. * * The Gnome Library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * The Gnome 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with the Gnome Library; see the file COPYING.LIB. If not, * see . * * Authors: John Sullivan */ #include #include "nautilus-file-utilities.h" #include "nautilus-global-preferences.h" #include "nautilus-icon-names.h" #include "nautilus-lib-self-check-functions.h" #include "nautilus-metadata.h" #include "nautilus-file.h" #include "nautilus-file-operations.h" #include "nautilus-search-directory.h" #include "nautilus-starred-directory.h" #include "nautilus-ui-utilities.h" #include #include #include #include #include #include #include #include #include #include #define NAUTILUS_USER_DIRECTORY_NAME "nautilus" #define DEFAULT_NAUTILUS_DIRECTORY_MODE (0755) /* Allowed characters outside alphanumeric for unreserved. */ #define G_URI_OTHER_UNRESERVED "-._~" /* This or something equivalent will eventually go into glib/guri.h */ gboolean nautilus_uri_parse (const char *uri, char **host, guint16 *port, char **userinfo) { char *tmp_str; const char *start, *p; char c; g_return_val_if_fail (uri != NULL, FALSE); if (host) { *host = NULL; } if (port) { *port = 0; } if (userinfo) { *userinfo = NULL; } /* From RFC 3986 Decodes: * URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] * hier-part = "//" authority path-abempty * path-abempty = *( "/" segment ) * authority = [ userinfo "@" ] host [ ":" port ] */ /* Check we have a valid scheme */ tmp_str = g_uri_parse_scheme (uri); if (tmp_str == NULL) { return FALSE; } g_free (tmp_str); /* Decode hier-part: * hier-part = "//" authority path-abempty */ p = uri; start = strstr (p, "//"); if (start == NULL) { return FALSE; } start += 2; if (strchr (start, '@') != NULL) { /* Decode userinfo: * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" * pct-encoded = "%" HEXDIG HEXDIG */ p = start; while (1) { c = *p++; if (c == '@') { break; } /* pct-encoded */ if (c == '%') { if (!(g_ascii_isxdigit (p[0]) || g_ascii_isxdigit (p[1]))) { return FALSE; } p++; continue; } /* unreserved / sub-delims / : */ if (!(g_ascii_isalnum (c) || strchr (G_URI_OTHER_UNRESERVED, c) || strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) || c == ':')) { return FALSE; } } if (userinfo) { *userinfo = g_strndup (start, p - start - 1); } start = p; } else { p = start; } /* decode host: * host = IP-literal / IPv4address / reg-name * reg-name = *( unreserved / pct-encoded / sub-delims ) */ /* If IPv6 or IPvFuture */ if (*p == '[') { start++; p++; while (1) { c = *p++; if (c == ']') { break; } /* unreserved / sub-delims */ if (!(g_ascii_isalnum (c) || strchr (G_URI_OTHER_UNRESERVED, c) || strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c) || c == ':' || c == '.')) { goto error; } } } else { while (1) { c = *p++; if (c == ':' || c == '/' || c == '?' || c == '#' || c == '\0') { break; } /* pct-encoded */ if (c == '%') { if (!(g_ascii_isxdigit (p[0]) || g_ascii_isxdigit (p[1]))) { goto error; } p++; continue; } /* unreserved / sub-delims */ if (!(g_ascii_isalnum (c) || strchr (G_URI_OTHER_UNRESERVED, c) || strchr (G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS, c))) { goto error; } } } if (host) { *host = g_uri_unescape_segment (start, p - 1, NULL); } if (c == ':') { /* Decode pot: * port = *DIGIT */ guint tmp = 0; while (1) { c = *p++; if (c == '/' || c == '?' || c == '#' || c == '\0') { break; } if (!g_ascii_isdigit (c)) { goto error; } tmp = (tmp * 10) + (c - '0'); if (tmp > 65535) { goto error; } } if (port) { *port = (guint16) tmp; } } return TRUE; error: if (host && *host) { g_free (*host); *host = NULL; } if (userinfo && *userinfo) { g_free (*userinfo); *userinfo = NULL; } return FALSE; } char * nautilus_compute_title_for_location (GFile *location) { NautilusFile *file; GMount *mount; char *title; /* TODO-gio: This doesn't really work all that great if the * info about the file isn't known atm... */ if (nautilus_is_home_directory (location)) { return g_strdup (_("Home")); } if ((mount = nautilus_get_mounted_mount_for_root (location)) != NULL) { title = g_mount_get_name (mount); g_object_unref (mount); return title; } title = NULL; if (location) { file = nautilus_file_get (location); if (nautilus_file_is_other_locations (file)) { title = g_strdup (_("Other Locations")); } else if (nautilus_file_is_starred_location (file)) { title = g_strdup (_("Starred")); } { title = nautilus_file_get_description (file); if (title == NULL) { title = nautilus_file_get_display_name (file); } } nautilus_file_unref (file); } if (title == NULL) { title = g_file_get_basename (location); } return title; } /** * nautilus_get_user_directory: * * Get the path for the directory containing nautilus settings. * * Return value: the directory path. **/ char * nautilus_get_user_directory (void) { char *user_directory = NULL; user_directory = g_build_filename (g_get_user_config_dir (), NAUTILUS_USER_DIRECTORY_NAME, NULL); if (!g_file_test (user_directory, G_FILE_TEST_EXISTS)) { g_mkdir_with_parents (user_directory, DEFAULT_NAUTILUS_DIRECTORY_MODE); /* FIXME bugzilla.gnome.org 41286: * How should we handle the case where this mkdir fails? * Note that nautilus_application_startup will refuse to launch if this * directory doesn't get created, so that case is OK. But the directory * could be deleted after Nautilus was launched, and perhaps * there is some bad side-effect of not handling that case. */ } return user_directory; } /** * nautilus_get_scripts_directory_path: * * Get the path for the directory containing nautilus scripts. * * Return value: the directory path containing nautilus scripts **/ char * nautilus_get_scripts_directory_path (void) { return g_build_filename (g_get_user_data_dir (), "nautilus", "scripts", NULL); } char * nautilus_get_home_directory_uri (void) { return g_filename_to_uri (g_get_home_dir (), NULL, NULL); } gboolean nautilus_should_use_templates_directory (void) { const char *dir; gboolean res; dir = g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES); res = dir && (g_strcmp0 (dir, g_get_home_dir ()) != 0); return res; } char * nautilus_get_templates_directory (void) { return g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)); } char * nautilus_get_templates_directory_uri (void) { char *directory, *uri; directory = nautilus_get_templates_directory (); uri = g_filename_to_uri (directory, NULL, NULL); g_free (directory); return uri; } gboolean nautilus_is_home_directory_file (GFile *dir, const char *filename) { char *dirname; static GFile *home_dir_dir = NULL; static char *home_dir_filename = NULL; if (home_dir_dir == NULL) { dirname = g_path_get_dirname (g_get_home_dir ()); home_dir_dir = g_file_new_for_path (dirname); g_free (dirname); home_dir_filename = g_path_get_basename (g_get_home_dir ()); } return (g_file_equal (dir, home_dir_dir) && strcmp (filename, home_dir_filename) == 0); } gboolean nautilus_is_home_directory (GFile *dir) { static GFile *home_dir = NULL; if (home_dir == NULL) { home_dir = g_file_new_for_path (g_get_home_dir ()); } return g_file_equal (dir, home_dir); } gboolean nautilus_is_root_directory (GFile *dir) { static GFile *root_dir = NULL; if (root_dir == NULL) { root_dir = g_file_new_for_path ("/"); } return g_file_equal (dir, root_dir); } gboolean nautilus_is_search_directory (GFile *dir) { g_autofree gchar *uri = NULL; uri = g_file_get_uri (dir); return eel_uri_is_search (uri); } gboolean nautilus_is_recent_directory (GFile *dir) { g_autofree gchar *uri = NULL; uri = g_file_get_uri (dir); return eel_uri_is_recent (uri); } gboolean nautilus_is_starred_directory (GFile *dir) { g_autofree gchar *uri = NULL; uri = g_file_get_uri (dir); if (eel_uri_is_starred (uri)) { return TRUE; } return FALSE; } gboolean nautilus_is_trash_directory (GFile *dir) { g_autofree gchar *uri = NULL; uri = g_file_get_uri (dir); return eel_uri_is_trash (uri); } gboolean nautilus_is_other_locations_directory (GFile *dir) { g_autofree gchar *uri = NULL; uri = g_file_get_uri (dir); return eel_uri_is_other_locations (uri); } GMount * nautilus_get_mounted_mount_for_root (GFile *location) { GVolumeMonitor *volume_monitor; GList *mounts; GList *l; GMount *mount; GMount *result = NULL; GFile *root = NULL; GFile *default_location = NULL; volume_monitor = g_volume_monitor_get (); mounts = g_volume_monitor_get_mounts (volume_monitor); for (l = mounts; l != NULL; l = l->next) { mount = l->data; if (g_mount_is_shadowed (mount)) { continue; } root = g_mount_get_root (mount); if (g_file_equal (location, root)) { result = g_object_ref (mount); break; } default_location = g_mount_get_default_location (mount); if (!g_file_equal (default_location, root) && g_file_equal (location, default_location)) { result = g_object_ref (mount); break; } } g_clear_object (&root); g_clear_object (&default_location); g_list_free_full (mounts, g_object_unref); return result; } GFile * nautilus_generate_unique_file_in_directory (GFile *directory, const char *basename) { g_autofree char *basename_without_extension = NULL; const char *extension; GFile *child; int copy; g_return_val_if_fail (directory != NULL, NULL); g_return_val_if_fail (basename != NULL, NULL); g_return_val_if_fail (g_file_query_exists (directory, NULL), NULL); basename_without_extension = eel_filename_strip_extension (basename); extension = eel_filename_get_extension_offset (basename); child = g_file_get_child (directory, basename); copy = 1; while (g_file_query_exists (child, NULL)) { g_autofree char *filename = NULL; g_object_unref (child); filename = g_strdup_printf ("%s (%d)%s", basename_without_extension, copy, extension ? extension : ""); child = g_file_get_child (directory, filename); copy++; } return child; } GFile * nautilus_find_existing_uri_in_hierarchy (GFile *location) { GFileInfo *info; GFile *tmp; g_assert (location != NULL); location = g_object_ref (location); while (location != NULL) { info = g_file_query_info (location, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); g_object_unref (info); if (info != NULL) { return location; } tmp = location; location = g_file_get_parent (location); g_object_unref (tmp); } return location; } static gboolean have_program_in_path (const char *name) { gchar *path; gboolean result; path = g_find_program_in_path (name); result = (path != NULL); g_free (path); return result; } static GIcon * special_directory_get_icon (GUserDirectory directory, gboolean symbolic) { #define ICON_CASE(x) \ case G_USER_DIRECTORY_ ## x: \ return (symbolic) ? g_themed_icon_new (NAUTILUS_ICON_FOLDER_ ## x) : g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER_ ## x); switch (directory) { ICON_CASE (DOCUMENTS); ICON_CASE (DOWNLOAD); ICON_CASE (MUSIC); ICON_CASE (PICTURES); ICON_CASE (PUBLIC_SHARE); ICON_CASE (TEMPLATES); ICON_CASE (VIDEOS); default: return (symbolic) ? g_themed_icon_new (NAUTILUS_ICON_FOLDER) : g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER); } #undef ICON_CASE } GIcon * nautilus_special_directory_get_symbolic_icon (GUserDirectory directory) { return special_directory_get_icon (directory, TRUE); } GIcon * nautilus_special_directory_get_icon (GUserDirectory directory) { return special_directory_get_icon (directory, FALSE); } gboolean nautilus_is_file_roller_installed (void) { static int installed = -1; if (installed < 0) { if (have_program_in_path ("file-roller")) { installed = 1; } else { installed = 0; } } return installed > 0 ? TRUE : FALSE; } /* Returns TRUE if the file is in XDG_DATA_DIRS. This is used for * deciding if a desktop file is "trusted" based on the path */ gboolean nautilus_is_in_system_dir (GFile *file) { const char * const *data_dirs; char *path; int i; gboolean res; if (!g_file_is_native (file)) { return FALSE; } path = g_file_get_path (file); res = FALSE; data_dirs = g_get_system_data_dirs (); for (i = 0; path != NULL && data_dirs[i] != NULL; i++) { if (g_str_has_prefix (path, data_dirs[i])) { res = TRUE; break; } } g_free (path); return res; } GHashTable * nautilus_trashed_files_get_original_directories (GList *files, GList **unhandled_files) { GHashTable *directories; NautilusFile *file, *original_file, *original_dir; GList *l, *m; directories = NULL; if (unhandled_files != NULL) { *unhandled_files = NULL; } for (l = files; l != NULL; l = l->next) { file = NAUTILUS_FILE (l->data); original_file = nautilus_file_get_trash_original_file (file); original_dir = NULL; if (original_file != NULL) { original_dir = nautilus_file_get_parent (original_file); } if (original_dir != NULL) { if (directories == NULL) { directories = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) nautilus_file_unref, (GDestroyNotify) nautilus_file_list_free); } nautilus_file_ref (original_dir); m = g_hash_table_lookup (directories, original_dir); if (m != NULL) { g_hash_table_steal (directories, original_dir); nautilus_file_unref (original_dir); } m = g_list_append (m, nautilus_file_ref (file)); g_hash_table_insert (directories, original_dir, m); } else if (unhandled_files != NULL) { *unhandled_files = g_list_append (*unhandled_files, nautilus_file_ref (file)); } nautilus_file_unref (original_file); nautilus_file_unref (original_dir); } return directories; } GList * nautilus_file_list_from_uri_list (GList *uris) { GList *l; GList *result = NULL; for (l = uris; l != NULL; l = l->next) { g_autoptr (GFile) location = NULL; location = g_file_new_for_uri (l->data); result = g_list_prepend (result, nautilus_file_get (location)); } return g_list_reverse (result); } static GList * locations_from_file_list (GList *file_list) { NautilusFile *file; GList *l, *ret; ret = NULL; for (l = file_list; l != NULL; l = l->next) { file = NAUTILUS_FILE (l->data); ret = g_list_prepend (ret, nautilus_file_get_location (file)); } return g_list_reverse (ret); } typedef struct { GHashTable *original_dirs_hash; GtkWindow *parent_window; } RestoreFilesData; static void ensure_dirs_task_ready_cb (GObject *_source, GAsyncResult *res, gpointer user_data) { NautilusFile *original_dir; GFile *original_dir_location; GList *original_dirs, *files, *locations, *l; RestoreFilesData *data = user_data; original_dirs = g_hash_table_get_keys (data->original_dirs_hash); for (l = original_dirs; l != NULL; l = l->next) { original_dir = NAUTILUS_FILE (l->data); original_dir_location = nautilus_file_get_location (original_dir); files = g_hash_table_lookup (data->original_dirs_hash, original_dir); locations = locations_from_file_list (files); nautilus_file_operations_move (locations, original_dir_location, data->parent_window, NULL, NULL); g_list_free_full (locations, g_object_unref); g_object_unref (original_dir_location); } g_list_free (original_dirs); g_hash_table_unref (data->original_dirs_hash); g_slice_free (RestoreFilesData, data); } static void ensure_dirs_task_thread_func (GTask *task, gpointer source, gpointer task_data, GCancellable *cancellable) { RestoreFilesData *data = task_data; NautilusFile *original_dir; GFile *original_dir_location; GList *original_dirs, *l; original_dirs = g_hash_table_get_keys (data->original_dirs_hash); for (l = original_dirs; l != NULL; l = l->next) { original_dir = NAUTILUS_FILE (l->data); original_dir_location = nautilus_file_get_location (original_dir); g_file_make_directory_with_parents (original_dir_location, cancellable, NULL); g_object_unref (original_dir_location); } g_task_return_pointer (task, NULL, NULL); } static void restore_files_ensure_parent_directories (GHashTable *original_dirs_hash, GtkWindow *parent_window) { RestoreFilesData *data; GTask *ensure_dirs_task; data = g_slice_new0 (RestoreFilesData); data->parent_window = parent_window; data->original_dirs_hash = g_hash_table_ref (original_dirs_hash); ensure_dirs_task = g_task_new (NULL, NULL, ensure_dirs_task_ready_cb, data); g_task_set_task_data (ensure_dirs_task, data, NULL); g_task_run_in_thread (ensure_dirs_task, ensure_dirs_task_thread_func); g_object_unref (ensure_dirs_task); } void nautilus_restore_files_from_trash (GList *files, GtkWindow *parent_window) { NautilusFile *file; GHashTable *original_dirs_hash; GList *unhandled_files, *l; char *message, *file_name; original_dirs_hash = nautilus_trashed_files_get_original_directories (files, &unhandled_files); for (l = unhandled_files; l != NULL; l = l->next) { file = NAUTILUS_FILE (l->data); file_name = nautilus_file_get_display_name (file); message = g_strdup_printf (_("Could not determine original location of ā€œ%sā€ "), file_name); g_free (file_name); show_dialog (message, _("The item cannot be restored from trash"), parent_window, GTK_MESSAGE_WARNING); g_free (message); } if (original_dirs_hash != NULL) { restore_files_ensure_parent_directories (original_dirs_hash, parent_window); g_hash_table_unref (original_dirs_hash); } nautilus_file_list_unref (unhandled_files); } typedef struct { NautilusMountGetContent callback; gpointer user_data; } GetContentTypesData; static void get_types_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GetContentTypesData *data; char **types; data = user_data; types = g_mount_guess_content_type_finish (G_MOUNT (source_object), res, NULL); g_object_set_data_full (source_object, "nautilus-content-type-cache", g_strdupv (types), (GDestroyNotify) g_strfreev); if (data->callback) { data->callback ((const char **) types, data->user_data); } g_strfreev (types); g_slice_free (GetContentTypesData, data); } void nautilus_get_x_content_types_for_mount_async (GMount *mount, NautilusMountGetContent callback, GCancellable *cancellable, gpointer user_data) { char **cached; GetContentTypesData *data; if (mount == NULL) { if (callback) { callback (NULL, user_data); } return; } cached = g_object_get_data (G_OBJECT (mount), "nautilus-content-type-cache"); if (cached != NULL) { if (callback) { callback ((const char **) cached, user_data); } return; } data = g_slice_new0 (GetContentTypesData); data->callback = callback; data->user_data = user_data; g_mount_guess_content_type (mount, FALSE, cancellable, get_types_cb, data); } char ** nautilus_get_cached_x_content_types_for_mount (GMount *mount) { char **cached; if (mount == NULL) { return NULL; } cached = g_object_get_data (G_OBJECT (mount), "nautilus-content-type-cache"); if (cached != NULL) { return g_strdupv (cached); } return NULL; } char * get_message_for_content_type (const char *content_type) { char *message; char *description; description = g_content_type_get_description (content_type); /* Customize greeting for well-known content types */ if (strcmp (content_type, "x-content/audio-cdda") == 0) { /* translators: these describe the contents of removable media */ message = g_strdup (_("Audio CD")); } else if (strcmp (content_type, "x-content/audio-dvd") == 0) { message = g_strdup (_("Audio DVD")); } else if (strcmp (content_type, "x-content/video-dvd") == 0) { message = g_strdup (_("Video DVD")); } else if (strcmp (content_type, "x-content/video-vcd") == 0) { message = g_strdup (_("Video CD")); } else if (strcmp (content_type, "x-content/video-svcd") == 0) { message = g_strdup (_("Super Video CD")); } else if (strcmp (content_type, "x-content/image-photocd") == 0) { message = g_strdup (_("Photo CD")); } else if (strcmp (content_type, "x-content/image-picturecd") == 0) { message = g_strdup (_("Picture CD")); } else if (strcmp (content_type, "x-content/image-dcf") == 0) { message = g_strdup (_("Contains digital photos")); } else if (strcmp (content_type, "x-content/audio-player") == 0) { message = g_strdup (_("Contains music")); } else if (strcmp (content_type, "x-content/unix-software") == 0) { message = g_strdup (_("Contains software")); } else { /* fallback to generic greeting */ message = g_strdup_printf (_("Detected as ā€œ%sā€"), description); } g_free (description); return message; } char * get_message_for_two_content_types (const char * const *content_types) { char *message; g_assert (content_types[0] != NULL); g_assert (content_types[1] != NULL); /* few combinations make sense */ if (strcmp (content_types[0], "x-content/image-dcf") == 0 || strcmp (content_types[1], "x-content/image-dcf") == 0) { if (strcmp (content_types[0], "x-content/audio-player") == 0) { /* translators: these describe the contents of removable media */ message = g_strdup (_("Contains music and photos")); } else if (strcmp (content_types[1], "x-content/audio-player") == 0) { message = g_strdup (_("Contains photos and music")); } else { message = g_strdup (_("Contains digital photos")); } } else if ((strcmp (content_types[0], "x-content/video-vcd") == 0 || strcmp (content_types[1], "x-content/video-vcd") == 0) && (strcmp (content_types[0], "x-content/video-dvd") == 0 || strcmp (content_types[1], "x-content/video-dvd") == 0)) { message = g_strdup_printf ("%s/%s", get_message_for_content_type (content_types[0]), get_message_for_content_type (content_types[1])); } else { message = get_message_for_content_type (content_types[0]); } return message; } gboolean should_handle_content_type (const char *content_type) { GAppInfo *default_app; default_app = g_app_info_get_default_for_type (content_type, FALSE); return !g_str_has_prefix (content_type, "x-content/blank-") && !g_content_type_is_a (content_type, "x-content/win32-software") && default_app != NULL; } gboolean should_handle_content_types (const char * const *content_types) { int i; for (i = 0; content_types[i] != NULL; i++) { if (should_handle_content_type (content_types[i])) { return TRUE; } } return FALSE; } gboolean nautilus_file_selection_equal (GList *selection_a, GList *selection_b) { GList *al, *bl; gboolean selection_matches; if (selection_a == NULL || selection_b == NULL) { return (selection_a == selection_b); } if (g_list_length (selection_a) != g_list_length (selection_b)) { return FALSE; } selection_matches = TRUE; for (al = selection_a; al; al = al->next) { GFile *a_location = nautilus_file_get_location (NAUTILUS_FILE (al->data)); gboolean found = FALSE; for (bl = selection_b; bl; bl = bl->next) { GFile *b_location = nautilus_file_get_location (NAUTILUS_FILE (bl->data)); found = g_file_equal (b_location, a_location); g_object_unref (b_location); if (found) { break; } } selection_matches = found; g_object_unref (a_location); if (!selection_matches) { break; } } return selection_matches; } static char * trim_whitespace (const gchar *string) { glong space_count; glong length; gchar *offset; space_count = 0; length = g_utf8_strlen (string, -1); offset = g_utf8_offset_to_pointer (string, length); while (space_count <= length) { gunichar character; offset = g_utf8_prev_char (offset); character = g_utf8_get_char (offset); if (!g_unichar_isspace (character)) { break; } space_count++; } if (space_count == 0) { return g_strdup (string); } return g_utf8_substring (string, 0, length - space_count); } char * nautilus_get_common_filename_prefix (GList *file_list, int min_required_len) { GList *file_names = NULL; GList *directory_names = NULL; char *result_files; g_autofree char *result = NULL; g_autofree char *result_trimmed = NULL; if (file_list == NULL) { return NULL; } for (GList *l = file_list; l != NULL; l = l->next) { char *name; g_return_val_if_fail (NAUTILUS_IS_FILE (l->data), NULL); name = nautilus_file_get_display_name (l->data); /* Since the concept of file extensions does not apply to directories, * we filter those out. */ if (nautilus_file_is_directory (l->data)) { directory_names = g_list_prepend (directory_names, name); } else { file_names = g_list_prepend (file_names, name); } } result_files = nautilus_get_common_filename_prefix_from_filenames (file_names, min_required_len); if (directory_names == NULL) { return result_files; } if (result_files != NULL) { directory_names = g_list_prepend (directory_names, result_files); } result = eel_str_get_common_prefix (directory_names, min_required_len); g_list_free_full (file_names, g_free); g_list_free_full (directory_names, g_free); if (result == NULL) { return NULL; } result_trimmed = trim_whitespace (result); if (g_utf8_strlen (result_trimmed, -1) < min_required_len) { return NULL; } return g_steal_pointer (&result_trimmed); } char * nautilus_get_common_filename_prefix_from_filenames (GList *filenames, int min_required_len) { GList *stripped_filenames = NULL; char *common_prefix; char *truncated; int common_prefix_len; for (GList *i = filenames; i != NULL; i = i->next) { gchar *stripped_filename; stripped_filename = eel_filename_strip_extension (i->data); stripped_filenames = g_list_prepend (stripped_filenames, stripped_filename); } common_prefix = eel_str_get_common_prefix (stripped_filenames, min_required_len); if (common_prefix == NULL) { return NULL; } g_list_free_full (stripped_filenames, g_free); truncated = trim_whitespace (common_prefix); g_free (common_prefix); common_prefix_len = g_utf8_strlen (truncated, -1); if (common_prefix_len < min_required_len) { g_free (truncated); return NULL; } return truncated; } #if !defined (NAUTILUS_OMIT_SELF_CHECK) void nautilus_self_check_file_utilities (void) { } void nautilus_ensure_extension_builtins (void) { /* Please add new extension types here, even if you can guarantee * that they will be registered by the time the extension point * is iterating over its extensions. */ g_type_ensure (NAUTILUS_TYPE_SEARCH_DIRECTORY); g_type_ensure (NAUTILUS_TYPE_STARRED_DIRECTORY); } void nautilus_ensure_extension_points (void) { static gsize once_init_value = 0; if (g_once_init_enter (&once_init_value)) { GIOExtensionPoint *extension_point; extension_point = g_io_extension_point_register (NAUTILUS_DIRECTORY_PROVIDER_EXTENSION_POINT_NAME); g_io_extension_point_set_required_type (extension_point, NAUTILUS_TYPE_DIRECTORY); g_once_init_leave (&once_init_value, 1); } } #endif /* !NAUTILUS_OMIT_SELF_CHECK */ gboolean nautilus_file_can_rename_files (GList *files) { GList *l; NautilusFile *file; for (l = files; l != NULL; l = l->next) { file = NAUTILUS_FILE (l->data); if (!nautilus_file_can_rename (file)) { return FALSE; } } return TRUE; } /* Try to get a native file:// URI instead of any other GVFS * scheme, for interoperability with apps only handling file:// URIs. */ gchar * nautilus_uri_to_native_uri (const gchar *uri) { g_autoptr (GFile) file = NULL; g_autofree gchar *path = NULL; file = g_file_new_for_uri (uri); path = g_file_get_path (file); if (path != NULL) { return g_filename_to_uri (path, NULL, NULL); } return NULL; }