diff options
author | Matthias Clasen <mclasen@redhat.com> | 2015-05-25 13:29:02 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2016-07-01 16:01:34 -0400 |
commit | 9edba4e49cf84116903ca8a7c29080e7dca56607 (patch) | |
tree | d2194560208374cf5688738440903d912bce5e41 /gio | |
parent | 669a0f72a1b67dc9e3262c3a5ccf29c4aed98028 (diff) | |
download | glib-9edba4e49cf84116903ca8a7c29080e7dca56607.tar.gz |
Add a new gio commandline tool
This command collects the various commandline utilities that
are currently shipped in gvfs, and unifies them under a single,
command-style binary.
The tools just use GIO APIs, so it makes sense for them to live here.
Diffstat (limited to 'gio')
-rw-r--r-- | gio/Makefile.am | 30 | ||||
-rw-r--r-- | gio/gio-tool-cat.c | 154 | ||||
-rw-r--r-- | gio/gio-tool-copy.c | 218 | ||||
-rw-r--r-- | gio/gio-tool-info.c | 325 | ||||
-rw-r--r-- | gio/gio-tool-list.c | 228 | ||||
-rw-r--r-- | gio/gio-tool-mime.c | 176 | ||||
-rw-r--r-- | gio/gio-tool-mkdir.c | 108 | ||||
-rw-r--r-- | gio/gio-tool-monitor.c | 278 | ||||
-rw-r--r-- | gio/gio-tool-mount.c | 1174 | ||||
-rw-r--r-- | gio/gio-tool-move.c | 211 | ||||
-rw-r--r-- | gio/gio-tool-open.c | 97 | ||||
-rw-r--r-- | gio/gio-tool-remove.c | 94 | ||||
-rw-r--r-- | gio/gio-tool-rename.c | 99 | ||||
-rw-r--r-- | gio/gio-tool-save.c | 193 | ||||
-rw-r--r-- | gio/gio-tool-set.c | 195 | ||||
-rw-r--r-- | gio/gio-tool-trash.c | 135 | ||||
-rw-r--r-- | gio/gio-tool-tree.c | 285 | ||||
-rw-r--r-- | gio/gio-tool.c | 316 | ||||
-rw-r--r-- | gio/gio-tool.h | 52 |
19 files changed, 4368 insertions, 0 deletions
diff --git a/gio/Makefile.am b/gio/Makefile.am index 0ed84b2bc..3b3c104db 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -833,11 +833,41 @@ gresource_LDADD = libgio-2.0.la \ # ------------------------------------------------------------------------ # ------ MSVC Project File Generation ------ +# ------------------------------------------------------------------------ +# MSVCPROJS = gio glib-compile-resources glib-compile-schemas gio_FILES = $(libgio_2_0_la_SOURCES) $(win32_actual_sources) $(win32_more_sources_for_vcproj) gio_EXCLUDES = gunix*.c|gdesktopappinfo.c|gnetworkmonitornetlink.c|gcontenttype.c|gnetworkmonitornm.c +# gio tool + +bin_PROGRAMS += gio +gio_SOURCES = \ + gio-tool.c \ + gio-tool.h \ + gio-tool-cat.c \ + gio-tool-copy.c \ + gio-tool-info.c \ + gio-tool-list.c \ + gio-tool-mime.c \ + gio-tool-mkdir.c \ + gio-tool-monitor.c \ + gio-tool-mount.c \ + gio-tool-move.c \ + gio-tool-open.c \ + gio-tool-rename.c \ + gio-tool-remove.c \ + gio-tool-save.c \ + gio-tool-set.c \ + gio-tool-trash.c \ + gio-tool-tree.c \ + $(NULL) +gio_LDADD = libgio-2.0.la \ + $(top_builddir)/gobject/libgobject-2.0.la \ + $(top_builddir)/glib/libglib-2.0.la \ + $(NULL) + gio_HEADERS_DIR = $(includedir)/glib-2.0/gio gio_HEADERS_INST = $(gioinclude_HEADERS) $(nodist_gioinclude_HEADERS) gio_HEADERS_EXCLUDES = dummy diff --git a/gio/gio-tool-cat.c b/gio/gio-tool-cat.c new file mode 100644 index 000000000..c4f5189cd --- /dev/null +++ b/gio/gio-tool-cat.c @@ -0,0 +1,154 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <errno.h> + +#include "gio-tool.h" + + +static const GOptionEntry entries[] = { + { NULL } +}; + +static gboolean +cat (GFile *file) +{ + GInputStream *in; + char buffer[1024 * 8 + 1]; + char *p; + gssize res; + gboolean close_res; + GError *error; + gboolean success; + + error = NULL; + in = (GInputStream *) g_file_read (file, NULL, &error); + if (in == NULL) + { + print_file_error (file, error->message); + g_error_free (error); + return FALSE; + } + + success = TRUE; + while (1) + { + res = g_input_stream_read (in, buffer, sizeof (buffer) - 1, NULL, &error); + if (res > 0) + { + ssize_t written; + + p = buffer; + while (res > 0) + { + written = write (STDOUT_FILENO, p, res); + + if (written == -1 && errno != EINTR) + { + print_file_error (file, "error writing to stdout"); + success = FALSE; + goto out; + } + res -= written; + p += written; + } + } + else if (res < 0) + { + print_file_error (file, error->message); + g_error_free (error); + error = NULL; + success = FALSE; + break; + } + else if (res == 0) + break; + } + + out: + close_res = g_input_stream_close (in, NULL, &error); + if (!close_res) + { + print_file_error (file, error->message); + g_error_free (error); + success = FALSE; + } + + return success; +} + +int +handle_cat (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + int i; + gboolean res; + GFile *file; + + g_set_prgname ("gio cat"); + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s...", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Concatenate files and print to standard output.")); + g_option_context_set_description (context, + _("gio cat works just like the traditional cat utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/file.txt as location.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("No files given")); + return 1; + } + + g_option_context_free (context); + + res = TRUE; + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + res &= cat (file); + g_object_unref (file); + } + + return res ? 0 : 2; +} diff --git a/gio/gio-tool-copy.c b/gio/gio-tool-copy.c new file mode 100644 index 000000000..6f776f17f --- /dev/null +++ b/gio/gio-tool-copy.c @@ -0,0 +1,218 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <stdio.h> +#if 0 +#include <locale.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#endif + +#include "gio-tool.h" + +static gboolean no_target_directory = FALSE; +static gboolean progress = FALSE; +static gboolean interactive = FALSE; +static gboolean preserve = FALSE; +static gboolean backup = FALSE; +static gboolean no_dereference = FALSE; + +static const GOptionEntry entries[] = { + { "no-target-directory", 'T', 0, G_OPTION_ARG_NONE, &no_target_directory, N_("No target directory"), NULL }, + { "progress", 'p', 0, G_OPTION_ARG_NONE, &progress, N_("Show progress"), NULL }, + { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive, N_("Prompt before overwrite"), NULL }, + { "preserve", 'p', 0, G_OPTION_ARG_NONE, &preserve, N_("Preserve all attributes"), NULL }, + { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL }, + { "no-dereference", 'P', 0, G_OPTION_ARG_NONE, &no_dereference, N_("Never follow symbolic links"), NULL }, + { NULL } +}; + +static gint64 start_time; +static gint64 previous_time; + +static void +show_progress (goffset current_num_bytes, + goffset total_num_bytes, + gpointer user_data) +{ + gint64 tv; + char *current_size, *total_size, *rate; + + tv = g_get_monotonic_time (); + if (tv - previous_time < (G_USEC_PER_SEC / 5) && + current_num_bytes != total_num_bytes) + return; + + current_size = g_format_size (current_num_bytes); + total_size = g_format_size (total_num_bytes); + rate = g_format_size (current_num_bytes / + MAX ((tv - start_time) / G_USEC_PER_SEC, 1)); + g_print ("\r\033[K"); + g_print (_("Transferred %s out of %s (%s/s)"), current_size, total_size, rate); + + previous_time = tv; + + g_free (current_size); + g_free (total_size); + g_free (rate); +} + +int +handle_copy (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + char *param; + GFile *source, *dest, *target; + gboolean dest_is_dir; + char *basename; + char *uri; + int i; + GFileCopyFlags flags; + int retval = 0; + + g_set_prgname ("gio copy"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s... %s", _("SOURCE"), _("DESTINATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Copy one or more files from SOURCE to DESTINATION.")); + g_option_context_set_description (context, + _("gio copy is similar to the traditional cp utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/file.txt as location.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 3) + { + show_help (context, NULL); + return 1; + } + + dest = g_file_new_for_commandline_arg (argv[argc - 1]); + + if (no_target_directory && argc > 3) + { + show_help (context, NULL); + g_object_unref (dest); + return 1; + } + + dest_is_dir = file_is_dir (dest); + if (!dest_is_dir && argc > 3) + { + char *message; + + message = g_strdup_printf (_("Destination %s is not a directory"), argv[argc - 1]); + show_help (context, message); + g_free (message); + g_object_unref (dest); + return 1; + } + + g_option_context_free (context); + + for (i = 1; i < argc - 1; i++) + { + source = g_file_new_for_commandline_arg (argv[i]); + if (dest_is_dir && !no_target_directory) + { + basename = g_file_get_basename (source); + target = g_file_get_child (dest, basename); + g_free (basename); + } + else + target = g_object_ref (dest); + + flags = 0; + if (backup) + flags |= G_FILE_COPY_BACKUP; + if (!interactive) + flags |= G_FILE_COPY_OVERWRITE; + if (no_dereference) + flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS; + if (preserve) + flags |= G_FILE_COPY_ALL_METADATA; + + error = NULL; + start_time = g_get_monotonic_time (); + + if (!g_file_copy (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error)) + { + if (interactive && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + { + char line[16]; + + g_error_free (error); + error = NULL; + + uri = g_file_get_uri (target); + g_print (_("%s: overwrite '%s' ? "), argv[0], uri); + g_free (uri); + + if (fgets (line, sizeof (line), stdin) && + (line[0] == 'y' || line[0] == 'Y')) + { + flags |= G_FILE_COPY_OVERWRITE; + start_time = g_get_monotonic_time (); + if (!g_file_copy (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error)) + goto copy_failed; + } + } + else + { + copy_failed: + print_file_error (source, error->message); + g_error_free (error); + retval = 1; + } + } + + if (progress && retval == 0) + g_print ("\n"); + + g_object_unref (source); + g_object_unref (target); + } + + g_object_unref (dest); + + return retval; +} diff --git a/gio/gio-tool-info.c b/gio/gio-tool-info.c new file mode 100644 index 000000000..055fd5892 --- /dev/null +++ b/gio/gio-tool-info.c @@ -0,0 +1,325 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static gboolean writable = FALSE; +static gboolean filesystem = FALSE; +static char *attributes = NULL; +static gboolean nofollow_symlinks = FALSE; + +static const GOptionEntry entries[] = { + { "query-writable", 'w', 0, G_OPTION_ARG_NONE, &writable, N_("List writable attributes"), NULL }, + { "filesystem", 'f', 0, G_OPTION_ARG_NONE, &filesystem, N_("Get file system info"), NULL }, + { "attributes", 'a', 0, G_OPTION_ARG_STRING, &attributes, N_("The attributes to get"), N_("ATTRIBUTES") }, + { "nofollow-symlinks", 'n', 0, G_OPTION_ARG_NONE, &nofollow_symlinks, N_("Don't follow symbolic links"), NULL }, + { NULL } +}; + +static char * +escape_string (const char *in) +{ + GString *str; + static char *hex_digits = "0123456789abcdef"; + unsigned char c; + + + str = g_string_new (""); + + while ((c = *in++) != 0) + { + if (c >= 32 && c <= 126 && c != '\\') + g_string_append_c (str, c); + else + { + g_string_append (str, "\\x"); + g_string_append_c (str, hex_digits[(c >> 4) & 0xf]); + g_string_append_c (str, hex_digits[c & 0xf]); + } + } + + return g_string_free (str, FALSE); +} + +static void +show_attributes (GFileInfo *info) +{ + char **attributes; + char *s; + int i; + + attributes = g_file_info_list_attributes (info, NULL); + + g_print (_("attributes:\n")); + for (i = 0; attributes[i] != NULL; i++) + { + /* list the icons in order rather than displaying "GThemedIcon:0x8df7200" */ + if (strcmp (attributes[i], "standard::icon") == 0 || + strcmp (attributes[i], "standard::symbolic-icon") == 0) + { + GIcon *icon; + int j; + const char * const *names = NULL; + + if (strcmp (attributes[i], "standard::symbolic-icon") == 0) + icon = g_file_info_get_symbolic_icon (info); + else + icon = g_file_info_get_icon (info); + + /* only look up names if GThemedIcon */ + if (G_IS_THEMED_ICON(icon)) + { + names = g_themed_icon_get_names (G_THEMED_ICON (icon)); + g_print (" %s: ", attributes[i]); + for (j = 0; names[j] != NULL; j++) + g_print ("%s%s", names[j], (names[j+1] == NULL)?"":", "); + g_print ("\n"); + } + else + { + s = g_file_info_get_attribute_as_string (info, attributes[i]); + g_print (" %s: %s\n", attributes[i], s); + g_free (s); + } + } + else + { + s = g_file_info_get_attribute_as_string (info, attributes[i]); + g_print (" %s: %s\n", attributes[i], s); + g_free (s); + } + } + g_strfreev (attributes); +} + +static void +show_info (GFile *file, GFileInfo *info) +{ + const char *name, *type; + char *escaped, *uri; + goffset size; + + name = g_file_info_get_display_name (info); + if (name) + /* Translators: This is a noun and represents and attribute of a file */ + g_print (_("display name: %s\n"), name); + + name = g_file_info_get_edit_name (info); + if (name) + /* Translators: This is a noun and represents and attribute of a file */ + g_print (_("edit name: %s\n"), name); + + name = g_file_info_get_name (info); + if (name) + { + escaped = escape_string (name); + g_print (_("name: %s\n"), escaped); + g_free (escaped); + } + + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE)) + { + type = file_type_to_string (g_file_info_get_file_type (info)); + g_print (_("type: %s\n"), type); + } + + if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) + { + size = g_file_info_get_size (info); + g_print (_("size: ")); + g_print (" %"G_GUINT64_FORMAT"\n", (guint64)size); + } + + if (g_file_info_get_is_hidden (info)) + g_print (_("hidden\n")); + + uri = g_file_get_uri (file); + g_print (_("uri: %s\n"), uri); + g_free (uri); + + show_attributes (info); +} + +static gboolean +query_info (GFile *file) +{ + GFileQueryInfoFlags flags; + GFileInfo *info; + GError *error; + + if (file == NULL) + return FALSE; + + if (attributes == NULL) + attributes = "*"; + + flags = 0; + if (nofollow_symlinks) + flags |= G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS; + + error = NULL; + if (filesystem) + info = g_file_query_filesystem_info (file, attributes, NULL, &error); + else + info = g_file_query_info (file, attributes, flags, NULL, &error); + + if (info == NULL) + { + g_printerr ("Error getting info: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + if (filesystem) + show_attributes (info); + else + show_info (file, info); + + g_object_unref (info); + + return TRUE; +} + +static gboolean +get_writable_info (GFile *file) +{ + GFileAttributeInfoList *list; + GError *error; + int i; + char *flags; + + if (file == NULL) + return FALSE; + + error = NULL; + + list = g_file_query_settable_attributes (file, NULL, &error); + if (list == NULL) + { + g_printerr (_("Error getting writable attributes: %s\n"), error->message); + g_error_free (error); + return FALSE; + } + + g_print (_("Settable attributes:\n")); + for (i = 0; i < list->n_infos; i++) + { + flags = attribute_flags_to_string (list->infos[i].flags); + g_print (" %s (%s%s%s)\n", + list->infos[i].name, + attribute_type_to_string (list->infos[i].type), + (*flags != 0)?", ":"", flags); + g_free (flags); + } + + g_file_attribute_info_list_unref (list); + + list = g_file_query_writable_namespaces (file, NULL, &error); + if (list == NULL) + { + g_printerr ("Error getting writable namespaces: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + if (list->n_infos > 0) + { + g_print (_("Writable attribute namespaces:\n")); + for (i = 0; i < list->n_infos; i++) + { + flags = attribute_flags_to_string (list->infos[i].flags); + g_print (" %s (%s%s%s)\n", + list->infos[i].name, + attribute_type_to_string (list->infos[i].type), + (*flags != 0)?", ":"", flags); + } + } + + g_file_attribute_info_list_unref (list); + + return TRUE; +} + +int +handle_info (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + gboolean res; + gint i; + GFile *file; + + g_set_prgname ("gio info"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s...", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Show information about locations.")); + g_option_context_set_description (context, + _("gio info is similar to the traditional ls utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/file.txt as location. File attributes can\n" + "be specified with their GIO name, e.g. standard::icon, or just by\n" + "namespace, e.g. unix, or by '*', which matches all attributes")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("No locations given")); + return 1; + } + + g_option_context_free (context); + + res = TRUE; + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + if (writable) + res &= get_writable_info (file); + else + res &= query_info (file); + g_object_unref (file); + } + + return res ? 0 : 2; +} diff --git a/gio/gio-tool-list.c b/gio/gio-tool-list.c new file mode 100644 index 000000000..ec3858385 --- /dev/null +++ b/gio/gio-tool-list.c @@ -0,0 +1,228 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static char *attributes = NULL; +static gboolean show_hidden = FALSE; +static gboolean show_long = FALSE; +static gboolean nofollow_symlinks = FALSE; +static gboolean print_uris = FALSE; + +static const GOptionEntry entries[] = { + { "attributes", 'a', 0, G_OPTION_ARG_STRING, &attributes, N_("The attributes to get"), N_("ATTRIBUTES") }, + { "hidden", 'h', 0, G_OPTION_ARG_NONE, &show_hidden, N_("Show hidden files"), NULL }, + { "long", 'l', 0, G_OPTION_ARG_NONE, &show_long, N_("Use a long listing format"), NULL }, + { "nofollow-symlinks", 'n', 0, G_OPTION_ARG_NONE, &nofollow_symlinks, N_("Don't follow symbolic links"), NULL}, + { "print-uris", 'u', 0, G_OPTION_ARG_NONE, &print_uris, N_("Print full URIs"), NULL}, + { NULL } +}; + +static void +show_file_listing (GFileInfo *info, GFile *parent) +{ + const char *name, *type; + char *uri = NULL; + goffset size; + char **attributes; + int i; + gboolean first_attr; + GFile *child; + + if ((g_file_info_get_is_hidden (info)) && !show_hidden) + return; + + name = g_file_info_get_name (info); + if (name == NULL) + name = ""; + + if (print_uris) { + child = g_file_get_child (parent, name); + uri = g_file_get_uri (child); + g_object_unref (child); + } + + size = g_file_info_get_size (info); + type = file_type_to_string (g_file_info_get_file_type (info)); + if (show_long) + g_print ("%s\t%"G_GUINT64_FORMAT"\t(%s)", print_uris? uri: name, (guint64)size, type); + else + g_print ("%s", print_uris? uri: name); + + if (print_uris) + g_free (uri); + + first_attr = TRUE; + attributes = g_file_info_list_attributes (info, NULL); + for (i = 0 ; attributes[i] != NULL; i++) + { + char *val_as_string; + + if (!show_long || + strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_NAME) == 0 || + strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_SIZE) == 0 || + strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_TYPE) == 0 || + strcmp (attributes[i], G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN) == 0) + continue; + + if (first_attr) + { + g_print ("\t"); + first_attr = FALSE; + } + else + g_print (" "); + val_as_string = g_file_info_get_attribute_as_string (info, attributes[i]); + g_print ("%s=%s", attributes[i], val_as_string); + g_free (val_as_string); + } + + g_strfreev (attributes); + + g_print ("\n"); +} + +static gboolean +list (GFile *file) +{ + GFileEnumerator *enumerator; + GFileInfo *info; + GError *error; + gboolean res; + + error = NULL; + enumerator = g_file_enumerate_children (file, + attributes, + nofollow_symlinks ? G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS : 0, + NULL, + &error); + if (enumerator == NULL) + { + print_file_error (file, error->message); + g_error_free (error); + return FALSE; + } + + res = TRUE; + while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)) != NULL) + { + show_file_listing (info, file); + g_object_unref (info); + } + + if (error) + { + print_file_error (file, error->message); + g_clear_error (&error); + res = FALSE; + } + + if (!g_file_enumerator_close (enumerator, NULL, &error)) + { + print_file_error (file, error->message); + g_clear_error (&error); + res = FALSE; + } + + return res; +} + +int +handle_list (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + gboolean res; + gint i; + GFile *file; + + g_set_prgname ("gio list"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("[%s...]", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("List the contents of the locations.")); + g_option_context_set_description (context, + _("gio list is similar to the traditional ls utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/file.txt as location. File attributes can\n" + "be specified with their GIO name, e.g. standard::icon")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + g_option_context_free (context); + + if (attributes != NULL) + show_long = TRUE; + + attributes = g_strconcat (G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE "," + G_FILE_ATTRIBUTE_STANDARD_SIZE "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, + attributes != NULL ? "," : "", + attributes, + NULL); + + res = TRUE; + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + res &= list (file); + g_object_unref (file); + } + } + else + { + char *cwd; + + cwd = g_get_current_dir (); + file = g_file_new_for_path (cwd); + res = list (file); + g_object_unref (file); + g_free (cwd); + } + + g_free (attributes); + + return res ? 0 : 2; +} diff --git a/gio/gio-tool-mime.c b/gio/gio-tool-mime.c new file mode 100644 index 000000000..467808d89 --- /dev/null +++ b/gio/gio-tool-mime.c @@ -0,0 +1,176 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include "gio-tool.h" + +static const GOptionEntry entries[] = { + { NULL } +}; + +static GAppInfo * +get_app_info_for_id (const char *id) +{ + GList *list, *l; + GAppInfo *ret_info; + + list = g_app_info_get_all (); + ret_info = NULL; + for (l = list; l != NULL; l = l->next) + { + GAppInfo *info; + + info = l->data; + if (ret_info == NULL && g_strcmp0 (g_app_info_get_id (info), id) == 0) + ret_info = info; + else + g_object_unref (info); + } + g_list_free (list); + + return ret_info; +} + +int +handle_mime (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + gchar *param; + const gchar *mimetype; + const char *handler; + + g_set_prgname ("gio mime"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s [%s]", _("MIMETYPE"), _("HANDLER")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Get or set the handler for a mimetype.")); + g_option_context_set_description (context, + _("If no handler is given, lists registered and recommended applications\n" + "for the mimetype. If a handler is given, it is set as the default\n" + "handler for the mimetype.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc != 2 && argc != 3) + { + show_help (context, _("Must specify a single mimetype, and maybe a handler")); + return 1; + } + + g_option_context_free (context); + + if (argc == 2) + { + GAppInfo *info; + + mimetype = argv[1]; + + info = g_app_info_get_default_for_type (mimetype, FALSE); + if (!info) + { + g_print (_("No default applications for '%s'\n"), mimetype); + } + else + { + GList *list, *l; + + g_print (_("Default application for '%s': %s\n"), mimetype, g_app_info_get_id (info)); + g_object_unref (info); + + list = g_app_info_get_all_for_type (mimetype); + if (list != NULL) + g_print (_("Registered applications:\n")); + else + g_print (_("No registered applications\n")); + for (l = list; l != NULL; l = l->next) + { + info = l->data; + g_print ("\t%s\n", g_app_info_get_id (info)); + g_object_unref (info); + } + g_list_free (list); + + list = g_app_info_get_recommended_for_type (mimetype); + if (list != NULL) + g_print (_("Recommended applications:\n")); + else + g_print (_("No recommended applications\n")); + for (l = list; l != NULL; l = l->next) + { + info = l->data; + g_print ("\t%s\n", g_app_info_get_id (info)); + g_object_unref (info); + } + g_list_free (list); + } + } + else + { + GAppInfo *info; + + mimetype = argv[1]; + handler = argv[2]; + + info = get_app_info_for_id (handler); + if (info == NULL) + { + g_printerr (_("Failed to load info for handler '%s'\n"), handler); + return 1; + } + + if (g_app_info_set_as_default_for_type (info, mimetype, &error) == FALSE) + { + g_printerr (_("Failed to set '%s' as the default handler for '%s': %s\n"), + handler, mimetype, error->message); + g_error_free (error); + g_object_unref (info); + return 1; + } + g_print ("Set %s as the default for %s\n", g_app_info_get_id (info), mimetype); + g_object_unref (info); + } + + return 0; +} diff --git a/gio/gio-tool-mkdir.c b/gio/gio-tool-mkdir.c new file mode 100644 index 000000000..11065c324 --- /dev/null +++ b/gio/gio-tool-mkdir.c @@ -0,0 +1,108 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static gboolean parent = FALSE; + +static const GOptionEntry entries[] = { + { "parent", 'p', 0, G_OPTION_ARG_NONE, &parent, N_("Create parent directories"), NULL }, + { NULL } +}; + +int +handle_mkdir (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + GFile *file; + int retval = 0; + int i; + + g_set_prgname ("gio mkdir"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s...", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, _("Create directories.")); + g_option_context_set_description (context, + _("gio mkdir is similar to the traditional mkdir utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/mydir as location.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("No locations gives")); + return 1; + } + + g_option_context_free (context); + + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + error = NULL; + if (parent) + { + if (!g_file_make_directory_with_parents (file, NULL, &error)) + { + print_file_error (file, error->message); + g_error_free (error); + retval = 1; + } + } + else + { + if (!g_file_make_directory (file, NULL, &error)) + { + print_file_error (file, error->message); + g_error_free (error); + retval = 1; + } + g_object_unref (file); + } + } + + return retval; + +} + diff --git a/gio/gio-tool-monitor.c b/gio/gio-tool-monitor.c new file mode 100644 index 000000000..e137a5d16 --- /dev/null +++ b/gio/gio-tool-monitor.c @@ -0,0 +1,278 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + +static gchar **watch_dirs; +static gchar **watch_files; +static gchar **watch_direct; +static gchar **watch_silent; +static gchar **watch_default; +static gboolean no_moves; +static gboolean mounts; + +static const GOptionEntry entries[] = { + { "dir", 'd', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_dirs, + N_("Monitor a directory (default: depends on type)"), N_("LOCATION") }, + { "file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_files, + N_("Monitor a file (default: depends on type)"), N_("LOCATION") }, + { "direct", 'D', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_direct, + N_("Monitor a file directly (notices changes made via hardlinks)"), N_("LOCATION") }, + { "silent", 's', 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_silent, + N_("Monitors a file directly, but doesn't report changes"), N_("LOCATION") }, + { "no-moves", 'n', 0, G_OPTION_ARG_NONE, &no_moves, + N_("Report moves and renames as simple deleted/created events"), NULL }, + { "mounts", 'm', 0, G_OPTION_ARG_NONE, &mounts, + N_("Watch for mount events"), NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &watch_default }, + { NULL } +}; + +static void +watch_callback (GFileMonitor *monitor, + GFile *child, + GFile *other, + GFileMonitorEvent event_type, + gpointer user_data) +{ + gchar *child_str; + gchar *other_str; + + g_assert (child); + + if (g_file_is_native (child)) + child_str = g_file_get_path (child); + else + child_str = g_file_get_uri (child); + + if (other) + { + if (g_file_is_native (other)) + other_str = g_file_get_path (other); + else + other_str = g_file_get_uri (other); + } + else + other_str = g_strdup ("(none)"); + + g_print ("%s: ", (gchar *) user_data); + switch (event_type) + { + case G_FILE_MONITOR_EVENT_CHANGED: + g_assert (!other); + g_print ("%s: changed", child_str); + break; + case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: + g_assert (!other); + g_print ("%s: changes done", child_str); + break; + case G_FILE_MONITOR_EVENT_DELETED: + g_assert (!other); + g_print ("%s: deleted", child_str); + break; + case G_FILE_MONITOR_EVENT_CREATED: + g_assert (!other); + g_print ("%s: created", child_str); + break; + case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: + g_assert (!other); + g_print ("%s: attributes changed", child_str); + break; + case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: + g_assert (!other); + g_print ("%s: pre-unmount", child_str); + break; + case G_FILE_MONITOR_EVENT_UNMOUNTED: + g_assert (!other); + g_print ("%s: unmounted", child_str); + break; + case G_FILE_MONITOR_EVENT_MOVED_IN: + g_print ("%s: moved in", child_str); + if (other) + g_print (" (from %s)", other_str); + break; + case G_FILE_MONITOR_EVENT_MOVED_OUT: + g_print ("%s: moved out", child_str); + if (other) + g_print (" (to %s)", other_str); + break; + case G_FILE_MONITOR_EVENT_RENAMED: + g_assert (other); + g_print ("%s: renamed to %s\n", child_str, other_str); + break; + + case G_FILE_MONITOR_EVENT_MOVED: + default: + g_assert_not_reached (); + } + + g_free (child_str); + g_free (other_str); + g_print ("\n"); +} + +typedef enum +{ + WATCH_DIR, + WATCH_FILE, + WATCH_AUTO +} WatchType; + +static gboolean +add_watch (const gchar *cmdline, + WatchType watch_type, + GFileMonitorFlags flags, + gboolean connect_handler) +{ + GFileMonitor *monitor = NULL; + GError *error = NULL; + GFile *file; + + file = g_file_new_for_commandline_arg (cmdline); + + if (watch_type == WATCH_AUTO) + { + GFileInfo *info; + guint32 type; + + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error); + if (!info) + goto err; + + type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE); + watch_type = (type == G_FILE_TYPE_DIRECTORY) ? WATCH_DIR : WATCH_FILE; + } + + if (watch_type == WATCH_DIR) + monitor = g_file_monitor_directory (file, flags, NULL, &error); + else + monitor = g_file_monitor (file, flags, NULL, &error); + + if (!monitor) + goto err; + + if (connect_handler) + g_signal_connect (monitor, "changed", G_CALLBACK (watch_callback), g_strdup (cmdline)); + + monitor = NULL; /* leak */ + + return TRUE; + +err: + g_printerr ("error: %s: %s", cmdline, error->message); + g_error_free (error); + + return FALSE; +} + +int +handle_monitor (int argc, gchar *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + GFileMonitorFlags flags; + guint total = 0; + guint i; + + g_set_prgname ("gio monitor"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("[%s...]", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Monitor files or directories for changes.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + g_option_context_free (context); + + flags = (no_moves ? 0 : G_FILE_MONITOR_WATCH_MOVES) | + (mounts ? G_FILE_MONITOR_WATCH_MOUNTS : 0); + + if (watch_dirs) + { + for (i = 0; watch_dirs[i]; i++) + if (!add_watch (watch_dirs[i], WATCH_DIR, flags, TRUE)) + return 1; + total++; + } + + if (watch_files) + { + for (i = 0; watch_files[i]; i++) + if (!add_watch (watch_files[i], WATCH_FILE, flags, TRUE)) + return 1; + total++; + } + + if (watch_direct) + { + for (i = 0; watch_direct[i]; i++) + if (!add_watch (watch_direct[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, TRUE)) + return 1; + total++; + } + + if (watch_silent) + { + for (i = 0; watch_silent[i]; i++) + if (!add_watch (watch_silent[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, FALSE)) + return 1; + total++; + } + + if (watch_default) + { + for (i = 0; watch_default[i]; i++) + if (!add_watch (watch_default[i], WATCH_AUTO, flags, TRUE)) + return 1; + total++; + } + + if (!total) + { + g_printerr ("gio: Must give at least one file to monitor\n"); + return 1; + } + + while (TRUE) + g_main_context_iteration (NULL, TRUE); + + return 0; +} diff --git a/gio/gio-tool-mount.c b/gio/gio-tool-mount.c new file mode 100644 index 000000000..9f5b217a6 --- /dev/null +++ b/gio/gio-tool-mount.c @@ -0,0 +1,1174 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#endif + +#include "gio-tool.h" + +#define STDIN_FILENO 0 + +typedef enum { + MOUNT_OP_NONE, + MOUNT_OP_ASKED, + MOUNT_OP_ABORTED +} MountOpState; + +static int outstanding_mounts = 0; +static GMainLoop *main_loop; + +static gboolean mount_mountable = FALSE; +static gboolean mount_unmount = FALSE; +static gboolean mount_eject = FALSE; +static gboolean force = FALSE; +static gboolean anonymous = FALSE; +static gboolean mount_list = FALSE; +static gboolean extra_detail = FALSE; +static gboolean mount_monitor = FALSE; +static const char *unmount_scheme = NULL; +static const char *mount_device_file = NULL; +static gboolean success = TRUE; + + +static const GOptionEntry entries[] = +{ + { "mountable", 'm', 0, G_OPTION_ARG_NONE, &mount_mountable, N_("Mount as mountable"), NULL }, + { "device", 'd', 0, G_OPTION_ARG_STRING, &mount_device_file, N_("Mount volume with device file"), N_("DEVICE") }, + { "unmount", 'u', 0, G_OPTION_ARG_NONE, &mount_unmount, N_("Unmount"), NULL}, + { "eject", 'e', 0, G_OPTION_ARG_NONE, &mount_eject, N_("Eject"), NULL}, + { "unmount-scheme", 's', 0, G_OPTION_ARG_STRING, &unmount_scheme, N_("Unmount all mounts with the given scheme"), N_("SCHEME") }, + { "force", 'f', 0, G_OPTION_ARG_NONE, &force, N_("Ignore outstanding file operations when unmounting or ejecting"), NULL }, + { "anonymous", 'a', 0, G_OPTION_ARG_NONE, &anonymous, N_("Use an anonymous user when authenticating"), NULL }, + /* Translator: List here is a verb as in 'List all mounts' */ + { "list", 'l', 0, G_OPTION_ARG_NONE, &mount_list, N_("List"), NULL}, + { "monitor", 'o', 0, G_OPTION_ARG_NONE, &mount_monitor, N_("Monitor events"), NULL}, + { "detail", 'i', 0, G_OPTION_ARG_NONE, &extra_detail, N_("Show extra information"), NULL}, + { NULL } +}; + +static char * +prompt_for (const char *prompt, const char *default_value, gboolean echo) +{ +#ifdef HAVE_TERMIOS_H + struct termios term_attr; + int old_flags; + gboolean restore_flags; +#endif + char data[256]; + int len; + + if (default_value && *default_value != 0) + g_print ("%s [%s]: ", prompt, default_value); + else + g_print ("%s: ", prompt); + + data[0] = 0; + +#ifdef HAVE_TERMIOS_H + restore_flags = FALSE; + if (!echo && tcgetattr (STDIN_FILENO, &term_attr) == 0) + { + old_flags = term_attr.c_lflag; + term_attr.c_lflag &= ~ECHO; + restore_flags = TRUE; + + if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_attr) != 0) + g_print ("Warning! Password will be echoed"); + } + +#endif + + fgets(data, sizeof (data), stdin); + +#ifdef HAVE_TERMIOS_H + if (restore_flags) + { + term_attr.c_lflag = old_flags; + tcsetattr (STDIN_FILENO, TCSAFLUSH, &term_attr); + } +#endif + + len = strlen (data); + if (len == 0) + { + g_print ("\n"); + return NULL; + } + if (data[len-1] == '\n') + data[len-1] = 0; + + if (!echo) + g_print ("\n"); + + if (*data == 0 && default_value) + return g_strdup (default_value); + return g_strdup (data); +} + +static void +ask_password_cb (GMountOperation *op, + const char *message, + const char *default_user, + const char *default_domain, + GAskPasswordFlags flags) +{ + if ((flags & G_ASK_PASSWORD_ANONYMOUS_SUPPORTED) && anonymous) + { + g_mount_operation_set_anonymous (op, TRUE); + } + else + { + char *s; + g_print ("%s\n", message); + + if (flags & G_ASK_PASSWORD_NEED_USERNAME) + { + s = prompt_for ("User", default_user, TRUE); + if (!s) + goto error; + g_mount_operation_set_username (op, s); + g_free (s); + } + + if (flags & G_ASK_PASSWORD_NEED_DOMAIN) + { + s = prompt_for ("Domain", default_domain, TRUE); + if (!s) + goto error; + g_mount_operation_set_domain (op, s); + g_free (s); + } + + if (flags & G_ASK_PASSWORD_NEED_PASSWORD) + { + s = prompt_for ("Password", NULL, FALSE); + if (!s) + goto error; + g_mount_operation_set_password (op, s); + g_free (s); + } + } + + /* Only try anonymous access once. */ + if (anonymous && + GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ASKED) + { + g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_ABORTED)); + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); + } + else + { + g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_ASKED)); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + } + + return; + +error: + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); +} + +static void +ask_question_cb (GMountOperation *op, + char *message, + char **choices, + gpointer user_data) +{ + char **ptr = choices; + char *s; + int i, choice; + + g_print ("%s\n", message); + + i = 1; + while (*ptr) + { + g_print ("[%d] %s\n", i, *ptr++); + i++; + } + + s = prompt_for ("Choice", NULL, TRUE); + if (!s) + goto error; + + choice = atoi (s); + if (choice > 0 && choice < i) + { + g_mount_operation_set_choice (op, choice - 1); + g_mount_operation_reply (op, G_MOUNT_OPERATION_HANDLED); + } + g_free (s); + + return; + +error: + g_mount_operation_reply (op, G_MOUNT_OPERATION_ABORTED); +} + +static void +mount_mountable_done_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GFile *target; + GError *error = NULL; + GMountOperation *op = user_data; + + target = g_file_mount_mountable_finish (G_FILE (object), res, &error); + + if (target == NULL) + { + success = FALSE; + if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ABORTED) + g_printerr (_("Error mounting location: Anonymous access denied\n")); + else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED)) + g_printerr (_("Error mounting location: %s\n"), error->message); + } + else + g_object_unref (target); + + outstanding_mounts--; + + if (outstanding_mounts == 0) + g_main_loop_quit (main_loop); +} + +static void +mount_done_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean succeeded; + GError *error = NULL; + GMountOperation *op = user_data; + + succeeded = g_file_mount_enclosing_volume_finish (G_FILE (object), res, &error); + + if (!succeeded) + { + success = FALSE; + if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (op), "state")) == MOUNT_OP_ABORTED) + g_printerr (_("Error mounting location: Anonymous access denied\n")); + else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED)) + g_printerr (_("Error mounting location: %s\n"), error->message); + } + + outstanding_mounts--; + + if (outstanding_mounts == 0) + g_main_loop_quit (main_loop); +} + +static GMountOperation * +new_mount_op (void) +{ + GMountOperation *op; + + op = g_mount_operation_new (); + + g_object_set_data (G_OBJECT (op), "state", GINT_TO_POINTER (MOUNT_OP_NONE)); + + g_signal_connect (op, "ask_password", G_CALLBACK (ask_password_cb), NULL); + g_signal_connect (op, "ask_question", G_CALLBACK (ask_question_cb), NULL); + + /* TODO: we *should* also connect to the "aborted" signal but since the + * main thread is blocked handling input we won't get that signal anyway... + */ + + return op; +} + + +static void +mount (GFile *file) +{ + GMountOperation *op; + + if (file == NULL) + return; + + op = new_mount_op (); + + if (mount_mountable) + g_file_mount_mountable (file, 0, op, NULL, mount_mountable_done_cb, op); + else + g_file_mount_enclosing_volume (file, 0, op, NULL, mount_done_cb, op); + + outstanding_mounts++; +} + +static void +unmount_done_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean succeeded; + GError *error = NULL; + + succeeded = g_mount_unmount_with_operation_finish (G_MOUNT (object), res, &error); + + g_object_unref (G_MOUNT (object)); + + if (!succeeded) + { + g_printerr (_("Error unmounting mount: %s\n"), error->message); + success = FALSE; + } + + outstanding_mounts--; + + if (outstanding_mounts == 0) + g_main_loop_quit (main_loop); +} + +static void +unmount (GFile *file) +{ + GMount *mount; + GError *error = NULL; + GMountOperation *mount_op; + GMountUnmountFlags flags; + + if (file == NULL) + return; + + mount = g_file_find_enclosing_mount (file, NULL, &error); + if (mount == NULL) + { + g_printerr (_("Error finding enclosing mount: %s\n"), error->message); + success = FALSE; + return; + } + + mount_op = new_mount_op (); + flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE; + g_mount_unmount_with_operation (mount, flags, mount_op, NULL, unmount_done_cb, NULL); + g_object_unref (mount_op); + + outstanding_mounts++; +} + +static void +eject_done_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + gboolean succeeded; + GError *error = NULL; + + succeeded = g_mount_eject_with_operation_finish (G_MOUNT (object), res, &error); + + g_object_unref (G_MOUNT (object)); + + if (!succeeded) + { + g_printerr (_("Error ejecting mount: %s\n"), error->message); + success = FALSE; + } + + outstanding_mounts--; + + if (outstanding_mounts == 0) + g_main_loop_quit (main_loop); +} + +static void +eject (GFile *file) +{ + GMount *mount; + GError *error = NULL; + GMountOperation *mount_op; + GMountUnmountFlags flags; + + if (file == NULL) + return; + + mount = g_file_find_enclosing_mount (file, NULL, &error); + if (mount == NULL) + { + g_printerr (_("Error finding enclosing mount: %s\n"), error->message); + success = FALSE; + return; + } + + mount_op = new_mount_op (); + flags = force ? G_MOUNT_UNMOUNT_FORCE : G_MOUNT_UNMOUNT_NONE; + g_mount_eject_with_operation (mount, flags, mount_op, NULL, eject_done_cb, NULL); + g_object_unref (mount_op); + + outstanding_mounts++; +} + +static gboolean +iterate_gmain_timeout_function (gpointer data) +{ + g_main_loop_quit (main_loop); + return FALSE; +} + +static void +iterate_gmain(void) +{ + g_timeout_add (500, iterate_gmain_timeout_function, NULL); + g_main_loop_run (main_loop); +} + +static void +show_themed_icon_names (GThemedIcon *icon, gboolean symbolic, int indent) +{ + char **names; + char **iter; + + g_print ("%*s%sthemed icons:", indent, " ", symbolic ? "symbolic " : ""); + + names = NULL; + + g_object_get (icon, "names", &names, NULL); + + for (iter = names; *iter; iter++) + g_print (" [%s]", *iter); + + g_print ("\n"); + g_strfreev (names); +} + +/* don't copy-paste this code */ +static char * +get_type_name (gpointer object) +{ + const char *type_name; + char *ret; + + type_name = g_type_name (G_TYPE_FROM_INSTANCE (object)); + if (strcmp ("GProxyDrive", type_name) == 0) + { + ret = g_strdup_printf ("%s (%s)", + type_name, + (const char *) g_object_get_data (G_OBJECT (object), + "g-proxy-drive-volume-monitor-name")); + } + else if (strcmp ("GProxyVolume", type_name) == 0) + { + ret = g_strdup_printf ("%s (%s)", + type_name, + (const char *) g_object_get_data (G_OBJECT (object), + "g-proxy-volume-volume-monitor-name")); + } + else if (strcmp ("GProxyMount", type_name) == 0) + { + ret = g_strdup_printf ("%s (%s)", + type_name, + (const char *) g_object_get_data (G_OBJECT (object), + "g-proxy-mount-volume-monitor-name")); + } + else if (strcmp ("GProxyShadowMount", type_name) == 0) + { + ret = g_strdup_printf ("%s (%s)", + type_name, + (const char *) g_object_get_data (G_OBJECT (object), + "g-proxy-shadow-mount-volume-monitor-name")); + } + else + { + ret = g_strdup (type_name); + } + + return ret; +} + +static void +list_mounts (GList *mounts, + int indent, + gboolean only_with_no_volume) +{ + GList *l; + int c; + GMount *mount; + GVolume *volume; + char *name, *uuid, *uri; + GFile *root, *default_location; + GIcon *icon; + char **x_content_types; + char *type_name; + const gchar *sort_key; + + for (c = 0, l = mounts; l != NULL; l = l->next, c++) + { + mount = (GMount *) l->data; + + if (only_with_no_volume) + { + volume = g_mount_get_volume (mount); + if (volume != NULL) + { + g_object_unref (volume); + continue; + } + } + + name = g_mount_get_name (mount); + root = g_mount_get_root (mount); + uri = g_file_get_uri (root); + + g_print ("%*sMount(%d): %s -> %s\n", indent, "", c, name, uri); + + type_name = get_type_name (mount); + g_print ("%*sType: %s\n", indent+2, "", type_name); + g_free (type_name); + + if (extra_detail) + { + uuid = g_mount_get_uuid (mount); + if (uuid) + g_print ("%*suuid=%s\n", indent + 2, "", uuid); + + default_location = g_mount_get_default_location (mount); + if (default_location) + { + char *loc_uri = g_file_get_uri (default_location); + g_print ("%*sdefault_location=%s\n", indent + 2, "", loc_uri); + g_free (loc_uri); + g_object_unref (default_location); + } + + icon = g_mount_get_icon (mount); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2); + + g_object_unref (icon); + } + + icon = g_mount_get_symbolic_icon (mount); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2); + + g_object_unref (icon); + } + + x_content_types = g_mount_guess_content_type_sync (mount, FALSE, NULL, NULL); + if (x_content_types != NULL && g_strv_length (x_content_types) > 0) + { + int n; + g_print ("%*sx_content_types:", indent + 2, ""); + for (n = 0; x_content_types[n] != NULL; n++) + g_print (" %s", x_content_types[n]); + g_print ("\n"); + } + g_strfreev (x_content_types); + + g_print ("%*scan_unmount=%d\n", indent + 2, "", g_mount_can_unmount (mount)); + g_print ("%*scan_eject=%d\n", indent + 2, "", g_mount_can_eject (mount)); + g_print ("%*sis_shadowed=%d\n", indent + 2, "", g_mount_is_shadowed (mount)); + sort_key = g_mount_get_sort_key (mount); + if (sort_key != NULL) + g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key); + g_free (uuid); + } + + g_object_unref (root); + g_free (name); + g_free (uri); + } +} + +static void +list_volumes (GList *volumes, + int indent, + gboolean only_with_no_drive) +{ + GList *l, *mounts; + int c, i; + GMount *mount; + GVolume *volume; + GDrive *drive; + char *name; + char *uuid; + GFile *activation_root; + char **ids; + GIcon *icon; + char *type_name; + const gchar *sort_key; + + for (c = 0, l = volumes; l != NULL; l = l->next, c++) + { + volume = (GVolume *) l->data; + + if (only_with_no_drive) + { + drive = g_volume_get_drive (volume); + if (drive != NULL) + { + g_object_unref (drive); + continue; + } + } + + name = g_volume_get_name (volume); + + g_print ("%*sVolume(%d): %s\n", indent, "", c, name); + g_free (name); + + type_name = get_type_name (volume); + g_print ("%*sType: %s\n", indent+2, "", type_name); + g_free (type_name); + + if (extra_detail) + { + ids = g_volume_enumerate_identifiers (volume); + if (ids && ids[0] != NULL) + { + g_print ("%*sids:\n", indent+2, ""); + for (i = 0; ids[i] != NULL; i++) + { + char *id = g_volume_get_identifier (volume, + ids[i]); + g_print ("%*s %s: '%s'\n", indent+2, "", ids[i], id); + g_free (id); + } + } + g_strfreev (ids); + + uuid = g_volume_get_uuid (volume); + if (uuid) + g_print ("%*suuid=%s\n", indent + 2, "", uuid); + activation_root = g_volume_get_activation_root (volume); + if (activation_root) + { + char *uri; + uri = g_file_get_uri (activation_root); + g_print ("%*sactivation_root=%s\n", indent + 2, "", uri); + g_free (uri); + g_object_unref (activation_root); + } + icon = g_volume_get_icon (volume); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2); + + g_object_unref (icon); + } + + icon = g_volume_get_symbolic_icon (volume); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2); + + g_object_unref (icon); + } + + g_print ("%*scan_mount=%d\n", indent + 2, "", g_volume_can_mount (volume)); + g_print ("%*scan_eject=%d\n", indent + 2, "", g_volume_can_eject (volume)); + g_print ("%*sshould_automount=%d\n", indent + 2, "", g_volume_should_automount (volume)); + sort_key = g_volume_get_sort_key (volume); + if (sort_key != NULL) + g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key); + g_free (uuid); + } + + mount = g_volume_get_mount (volume); + if (mount) + { + mounts = g_list_prepend (NULL, mount); + list_mounts (mounts, indent + 2, FALSE); + g_list_free (mounts); + g_object_unref (mount); + } + } +} + +static void +list_drives (GList *drives, + int indent) +{ + GList *volumes, *l; + int c, i; + GDrive *drive; + char *name; + char **ids; + GIcon *icon; + char *type_name; + const gchar *sort_key; + + for (c = 0, l = drives; l != NULL; l = l->next, c++) + { + drive = (GDrive *) l->data; + name = g_drive_get_name (drive); + + g_print ("%*sDrive(%d): %s\n", indent, "", c, name); + g_free (name); + + type_name = get_type_name (drive); + g_print ("%*sType: %s\n", indent+2, "", type_name); + g_free (type_name); + + if (extra_detail) + { + GEnumValue *enum_value; + gpointer klass; + + ids = g_drive_enumerate_identifiers (drive); + if (ids && ids[0] != NULL) + { + g_print ("%*sids:\n", indent+2, ""); + for (i = 0; ids[i] != NULL; i++) + { + char *id = g_drive_get_identifier (drive, + ids[i]); + g_print ("%*s %s: '%s'\n", indent+2, "", ids[i], id); + g_free (id); + } + } + g_strfreev (ids); + + icon = g_drive_get_icon (drive); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), FALSE, indent + 2); + g_object_unref (icon); + } + + icon = g_drive_get_symbolic_icon (drive); + if (icon) + { + if (G_IS_THEMED_ICON (icon)) + show_themed_icon_names (G_THEMED_ICON (icon), TRUE, indent + 2); + + g_object_unref (icon); + } + + g_print ("%*sis_media_removable=%d\n", indent + 2, "", g_drive_is_media_removable (drive)); + g_print ("%*shas_media=%d\n", indent + 2, "", g_drive_has_media (drive)); + g_print ("%*sis_media_check_automatic=%d\n", indent + 2, "", g_drive_is_media_check_automatic (drive)); + g_print ("%*scan_poll_for_media=%d\n", indent + 2, "", g_drive_can_poll_for_media (drive)); + g_print ("%*scan_eject=%d\n", indent + 2, "", g_drive_can_eject (drive)); + g_print ("%*scan_start=%d\n", indent + 2, "", g_drive_can_start (drive)); + g_print ("%*scan_stop=%d\n", indent + 2, "", g_drive_can_stop (drive)); + + enum_value = NULL; + klass = g_type_class_ref (G_TYPE_DRIVE_START_STOP_TYPE); + if (klass != NULL) + { + enum_value = g_enum_get_value (klass, g_drive_get_start_stop_type (drive)); + g_print ("%*sstart_stop_type=%s\n", indent + 2, "", + enum_value != NULL ? enum_value->value_nick : "UNKNOWN"); + g_type_class_unref (klass); + } + + sort_key = g_drive_get_sort_key (drive); + if (sort_key != NULL) + g_print ("%*ssort_key=%s\n", indent + 2, "", sort_key); + } + volumes = g_drive_get_volumes (drive); + list_volumes (volumes, indent + 2, FALSE); + g_list_free_full (volumes, g_object_unref); + } +} + + +static void +list_monitor_items (void) +{ + GVolumeMonitor *volume_monitor; + GList *drives, *volumes, *mounts; + + volume_monitor = g_volume_monitor_get(); + + /* populate gvfs network mounts */ + iterate_gmain(); + + drives = g_volume_monitor_get_connected_drives (volume_monitor); + list_drives (drives, 0); + g_list_free_full (drives, g_object_unref); + + volumes = g_volume_monitor_get_volumes (volume_monitor); + list_volumes (volumes, 0, TRUE); + g_list_free_full (volumes, g_object_unref); + + mounts = g_volume_monitor_get_mounts (volume_monitor); + list_mounts (mounts, 0, TRUE); + g_list_free_full (mounts, g_object_unref); + + g_object_unref (volume_monitor); +} + +static void +unmount_all_with_scheme (const char *scheme) +{ + GVolumeMonitor *volume_monitor; + GList *mounts; + GList *l; + + volume_monitor = g_volume_monitor_get(); + + /* populate gvfs network mounts */ + iterate_gmain(); + + mounts = g_volume_monitor_get_mounts (volume_monitor); + for (l = mounts; l != NULL; l = l->next) { + GMount *mount = G_MOUNT (l->data); + GFile *root; + + root = g_mount_get_root (mount); + if (g_file_has_uri_scheme (root, scheme)) { + unmount (root); + } + g_object_unref (root); + } + g_list_free_full (mounts, g_object_unref); + + g_object_unref (volume_monitor); +} + +static void +mount_with_device_file_cb (GObject *object, + GAsyncResult *res, + gpointer user_data) +{ + GVolume *volume; + gboolean succeeded; + GError *error = NULL; + + volume = G_VOLUME (object); + + succeeded = g_volume_mount_finish (volume, res, &error); + + if (!succeeded) + { + g_printerr (_("Error mounting %s: %s\n"), + g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE), + error->message); + success = FALSE; + } + else + { + GMount *mount; + GFile *root; + char *mount_path; + + mount = g_volume_get_mount (volume); + root = g_mount_get_root (mount); + mount_path = g_file_get_path (root); + + g_print (_("Mounted %s at %s\n"), + g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE), + mount_path); + + g_object_unref (mount); + g_object_unref (root); + g_free (mount_path); + } + + outstanding_mounts--; + + if (outstanding_mounts == 0) + g_main_loop_quit (main_loop); +} + +static void +mount_with_device_file (const char *device_file) +{ + GVolumeMonitor *volume_monitor; + GList *volumes; + GList *l; + + volume_monitor = g_volume_monitor_get(); + + volumes = g_volume_monitor_get_volumes (volume_monitor); + for (l = volumes; l != NULL; l = l->next) + { + GVolume *volume = G_VOLUME (l->data); + + if (g_strcmp0 (g_volume_get_identifier (volume, + G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE), device_file) == 0) + { + GMountOperation *op; + + op = new_mount_op (); + + g_volume_mount (volume, + G_MOUNT_MOUNT_NONE, + op, + NULL, + mount_with_device_file_cb, + op); + + outstanding_mounts++; + } + } + g_list_free_full (volumes, g_object_unref); + + if (outstanding_mounts == 0) + { + g_print (_("No volume for device file %s\n"), device_file); + return; + } + + g_object_unref (volume_monitor); +} + +static void +monitor_print_mount (GMount *mount) +{ + if (extra_detail) + { + GList *l; + l = g_list_prepend (NULL, mount); + list_mounts (l, 2, FALSE); + g_list_free (l); + g_print ("\n"); + } +} + +static void +monitor_print_volume (GVolume *volume) +{ + if (extra_detail) + { + GList *l; + l = g_list_prepend (NULL, volume); + list_volumes (l, 2, FALSE); + g_list_free (l); + g_print ("\n"); + } +} + +static void +monitor_print_drive (GDrive *drive) +{ + if (extra_detail) + { + GList *l; + l = g_list_prepend (NULL, drive); + list_drives (l, 2); + g_list_free (l); + g_print ("\n"); + } +} + +static void +monitor_mount_added (GVolumeMonitor *volume_monitor, GMount *mount) +{ + char *name; + name = g_mount_get_name (mount); + g_print ("Mount added: '%s'\n", name); + g_free (name); + monitor_print_mount (mount); +} + +static void +monitor_mount_removed (GVolumeMonitor *volume_monitor, GMount *mount) +{ + char *name; + name = g_mount_get_name (mount); + g_print ("Mount removed: '%s'\n", name); + g_free (name); + monitor_print_mount (mount); +} + +static void +monitor_mount_changed (GVolumeMonitor *volume_monitor, GMount *mount) +{ + char *name; + name = g_mount_get_name (mount); + g_print ("Mount changed: '%s'\n", name); + g_free (name); + monitor_print_mount (mount); +} + +static void +monitor_mount_pre_unmount (GVolumeMonitor *volume_monitor, GMount *mount) +{ + char *name; + name = g_mount_get_name (mount); + g_print ("Mount pre-unmount: '%s'\n", name); + g_free (name); + monitor_print_mount (mount); +} + +static void +monitor_volume_added (GVolumeMonitor *volume_monitor, GVolume *volume) +{ + char *name; + name = g_volume_get_name (volume); + g_print ("Volume added: '%s'\n", name); + g_free (name); + monitor_print_volume (volume); +} + +static void +monitor_volume_removed (GVolumeMonitor *volume_monitor, GVolume *volume) +{ + char *name; + name = g_volume_get_name (volume); + g_print ("Volume removed: '%s'\n", name); + g_free (name); + monitor_print_volume (volume); +} + +static void +monitor_volume_changed (GVolumeMonitor *volume_monitor, GVolume *volume) +{ + char *name; + name = g_volume_get_name (volume); + g_print ("Volume changed: '%s'\n", name); + g_free (name); + monitor_print_volume (volume); +} + +static void +monitor_drive_connected (GVolumeMonitor *volume_monitor, GDrive *drive) +{ + char *name; + name = g_drive_get_name (drive); + g_print ("Drive connected: '%s'\n", name); + g_free (name); + monitor_print_drive (drive); +} + +static void +monitor_drive_disconnected (GVolumeMonitor *volume_monitor, GDrive *drive) +{ + char *name; + name = g_drive_get_name (drive); + g_print ("Drive disconnected: '%s'\n", name); + g_free (name); + monitor_print_drive (drive); +} + +static void +monitor_drive_changed (GVolumeMonitor *volume_monitor, GDrive *drive) +{ + char *name; + name = g_drive_get_name (drive); + g_print ("Drive changed: '%s'\n", name); + g_free (name); + monitor_print_drive (drive); +} + +static void +monitor_drive_eject_button (GVolumeMonitor *volume_monitor, GDrive *drive) +{ + char *name; + name = g_drive_get_name (drive); + g_print ("Drive eject button: '%s'\n", name); + g_free (name); +} + +static void +monitor (void) +{ + GVolumeMonitor *volume_monitor; + + volume_monitor = g_volume_monitor_get (); + + g_signal_connect (volume_monitor, "mount-added", (GCallback) monitor_mount_added, NULL); + g_signal_connect (volume_monitor, "mount-removed", (GCallback) monitor_mount_removed, NULL); + g_signal_connect (volume_monitor, "mount-changed", (GCallback) monitor_mount_changed, NULL); + g_signal_connect (volume_monitor, "mount-pre-unmount", (GCallback) monitor_mount_pre_unmount, NULL); + g_signal_connect (volume_monitor, "volume-added", (GCallback) monitor_volume_added, NULL); + g_signal_connect (volume_monitor, "volume-removed", (GCallback) monitor_volume_removed, NULL); + g_signal_connect (volume_monitor, "volume-changed", (GCallback) monitor_volume_changed, NULL); + g_signal_connect (volume_monitor, "drive-connected", (GCallback) monitor_drive_connected, NULL); + g_signal_connect (volume_monitor, "drive-disconnected", (GCallback) monitor_drive_disconnected, NULL); + g_signal_connect (volume_monitor, "drive-changed", (GCallback) monitor_drive_changed, NULL); + g_signal_connect (volume_monitor, "drive-eject-button", (GCallback) monitor_drive_eject_button, NULL); + + g_print ("Monitoring events. Press Ctrl+C to quit.\n"); + + g_main_loop_run (main_loop); +} + +int +handle_mount (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + GFile *file; + int i; + + g_set_prgname ("gio mount"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("[%s...]", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, _("Mount or unmount the locations.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + g_option_context_free (context); + + main_loop = g_main_loop_new (NULL, FALSE); + + if (mount_list) + list_monitor_items (); + else if (mount_device_file != NULL) + mount_with_device_file (mount_device_file); + else if (unmount_scheme != NULL) + unmount_all_with_scheme (unmount_scheme); + else if (mount_monitor) + monitor (); + else if (argc > 1) + { + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + if (mount_unmount) + unmount (file); + else if (mount_eject) + eject (file); + else + mount (file); + g_object_unref (file); + } + } + + if (outstanding_mounts > 0) + g_main_loop_run (main_loop); + + return success ? 0 : 2; +} diff --git a/gio/gio-tool-move.c b/gio/gio-tool-move.c new file mode 100644 index 000000000..1946299c3 --- /dev/null +++ b/gio/gio-tool-move.c @@ -0,0 +1,211 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <stdio.h> + +#include "gio-tool.h" + + +/* statics {{{1 */ + +static gboolean no_target_directory = FALSE; +static gboolean progress = FALSE; +static gboolean interactive = FALSE; +static gboolean backup = FALSE; +static gboolean no_copy_fallback = FALSE; + +static const GOptionEntry entries[] = { + { "no-target-directory", 'T', 0, G_OPTION_ARG_NONE, &no_target_directory, N_("No target directory"), NULL }, + { "progress", 'p', 0, G_OPTION_ARG_NONE, &progress, N_("Show progress"), NULL }, + { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive, N_("Prompt before overwrite"), NULL }, + { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL }, + { "no-copy-fallback", 'C', 0, G_OPTION_ARG_NONE, &no_copy_fallback, N_("Don't use copy and delete fallback"), NULL }, + { NULL } +}; + +static gint64 start_time; +static gint64 previous_time; + +static void +show_progress (goffset current_num_bytes, + goffset total_num_bytes, + gpointer user_data) +{ + gint64 tv; + char *current_size, *total_size, *rate; + + tv = g_get_monotonic_time (); + if (tv - previous_time < (G_USEC_PER_SEC / 5) && + current_num_bytes != total_num_bytes) + return; + + current_size = g_format_size (current_num_bytes); + total_size = g_format_size (total_num_bytes); + rate = g_format_size (current_num_bytes / + MAX ((tv - start_time) / G_USEC_PER_SEC, 1)); + g_print ("\r\033[K"); + g_print (_("Transferred %s out of %s (%s/s)"), + current_size, total_size, rate); + + previous_time = tv; + + g_free (current_size); + g_free (total_size); + g_free (rate); +} + +int +handle_move (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + GFile *source, *dest, *target; + gboolean dest_is_dir; + char *basename; + char *uri; + int i; + GFileCopyFlags flags; + int retval = 0; + + g_set_prgname ("gio move"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s... %s", _("SOURCE"), _("DESTINATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Move one or more files from SOURCE to DEST.")); + g_option_context_set_description (context, + _("gio move is similar to the traditional mv utility, but using GIO\n" + "locations instead of local files: for example, you can use something\n" + "like smb://server/resource/file.txt as location")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 3) + { + show_help (context, NULL); + return 1; + } + + dest = g_file_new_for_commandline_arg (argv[argc - 1]); + + if (no_target_directory && argc > 3) + { + show_help (context, NULL); + g_object_unref (dest); + return 1; + } + + dest_is_dir = file_is_dir (dest); + + if (!dest_is_dir && argc > 3) + { + char *message; + message = g_strdup_printf (_("Target %s is not a directory"), argv[argc - 1]); + show_help (context, message); + g_free (message); + g_object_unref (dest); + return 1; + } + + g_option_context_free (context); + + for (i = 1; i < argc - 1; i++) + { + source = g_file_new_for_commandline_arg (argv[i]); + + if (dest_is_dir && !no_target_directory) + { + basename = g_file_get_basename (source); + target = g_file_get_child (dest, basename); + g_free (basename); + } + else + target = g_object_ref (dest); + + flags = 0; + if (backup) + flags |= G_FILE_COPY_BACKUP; + if (!interactive) + flags |= G_FILE_COPY_OVERWRITE; + if (no_copy_fallback) + flags |= G_FILE_COPY_NO_FALLBACK_FOR_MOVE; + + error = NULL; + start_time = g_get_monotonic_time (); + if (!g_file_move (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error)) + { + if (interactive && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + { + char line[16]; + + g_error_free (error); + error = NULL; + + uri = g_file_get_uri (target); + g_print (_("%s: overwrite '%s' ? "), argv[0], uri); + g_free (uri); + if (fgets (line, sizeof (line), stdin) && + (line[0] == 'y' || line[0] == 'Y')) + { + flags |= G_FILE_COPY_OVERWRITE; + start_time = g_get_monotonic_time (); + if (!g_file_move (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error)) + goto move_failed; + } + } + else + { + move_failed: + print_file_error (source, error->message); + g_error_free (error); + retval = 1; + } + } + + if (progress && retval == 0) + g_print("\n"); + + g_object_unref (source); + g_object_unref (target); + } + + g_object_unref (dest); + + return retval; +} diff --git a/gio/gio-tool-open.c b/gio/gio-tool-open.c new file mode 100644 index 000000000..125b5607b --- /dev/null +++ b/gio/gio-tool-open.c @@ -0,0 +1,97 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static const GOptionEntry entries[] = { + { NULL } +}; + +int +handle_open (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + int i; + gboolean success; + gboolean res; + + g_set_prgname ("gio open"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s...", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Open files with the default application that\n" + "is registered to handle files of this type.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("No files to open")); + return 1; + } + + g_option_context_free (context); + + success = TRUE; + for (i = 1; i < argc; i++) + { + GFile *file; + char *uri; + + file = g_file_new_for_commandline_arg (argv[i]); + uri = g_file_get_uri (file); + res = g_app_info_launch_default_for_uri (uri, NULL, &error); + + if (!res) + { + print_file_error (file, error->message); + g_clear_error (&error); + success = FALSE; + } + + g_object_unref (file); + g_free (uri); + } + + return success ? 0 : 2; +} diff --git a/gio/gio-tool-remove.c b/gio/gio-tool-remove.c new file mode 100644 index 000000000..2921d016a --- /dev/null +++ b/gio/gio-tool-remove.c @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static gboolean force = FALSE; + +static const GOptionEntry entries[] = { + {"force", 'f', 0, G_OPTION_ARG_NONE, &force, N_("Ignore nonexistent files, never prompt"), NULL}, + { NULL } +}; + +int +handle_remove (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + GFile *file; + int retval; + int i; + + g_set_prgname ("gio remove"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s...", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, _("Delete the given files.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc == 1) + { + show_help (context, _("No files to delete")); + return 1; + } + + g_option_context_free (context); + + retval = 0; + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + if (!g_file_delete (file, NULL, &error)) + { + if (!force || + !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + print_file_error (file, error->message); + retval = 1; + } + g_clear_error (&error); + } + g_object_unref (file); + } + + return retval; +} diff --git a/gio/gio-tool-rename.c b/gio/gio-tool-rename.c new file mode 100644 index 000000000..c27d668af --- /dev/null +++ b/gio/gio-tool-rename.c @@ -0,0 +1,99 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static const GOptionEntry entries[] = { + { NULL } +}; + +int +handle_rename (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + GFile *file; + GFile *new_file; + int retval = 0; + gchar *param; + + g_set_prgname ("gio rename"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s %s", _("LOCATION"), _("NAME")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + + g_option_context_set_summary (context, _("Rename a file.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 3) + { + show_help (context, _("Missing argument")); + return 1; + } + if (argc > 3) + { + show_help (context, _("Too many arguments")); + return 1; + } + + g_option_context_free (context); + + file = g_file_new_for_commandline_arg (argv[1]); + new_file = g_file_set_display_name (file, argv[2], NULL, &error); + + if (new_file == NULL) + { + g_printerr (_("Error: %s\n"), error->message); + g_error_free (error); + retval = 1; + } + else + { + char *uri = g_file_get_uri (new_file); + g_print (_("Rename successful. New uri: %s\n"), uri); + g_object_unref (new_file); + g_free (uri); + } + + g_object_unref (file); + + return retval; +} diff --git a/gio/gio-tool-save.c b/gio/gio-tool-save.c new file mode 100644 index 000000000..74e4de162 --- /dev/null +++ b/gio/gio-tool-save.c @@ -0,0 +1,193 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static char *etag = NULL; +static gboolean backup = FALSE; +static gboolean create = FALSE; +static gboolean append = FALSE; +static gboolean priv = FALSE; +static gboolean replace_dest = FALSE; +static gboolean print_etag = FALSE; + +static const GOptionEntry entries[] = +{ + { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL }, + { "create", 'c', 0, G_OPTION_ARG_NONE, &create, N_("Only create if not existing"), NULL }, + { "append", 'a', 0, G_OPTION_ARG_NONE, &append, N_("Append to end of file"), NULL }, + { "private", 'p', 0, G_OPTION_ARG_NONE, &priv, N_("When creating, restrict access to the current user"), NULL }, + { "unlink", 'u', 0, G_OPTION_ARG_NONE, &replace_dest, N_("When replacing, replace as if the destination did not exist"), NULL }, + /* Translators: The "etag" is a token allowing to verify whether a file has been modified */ + { "print-etag", 'v', 0, G_OPTION_ARG_NONE, &print_etag, N_("Print new etag at end"), NULL }, + /* Translators: The "etag" is a token allowing to verify whether a file has been modified */ + { "etag", 'e', 0, G_OPTION_ARG_STRING, &etag, N_("The etag of the file being overwritten"), N_("ETAG") }, + { NULL } +}; + +static gboolean +save (GFile *file) +{ + GOutputStream *out; + GFileCreateFlags flags; + char buffer[1025]; + char *p; + gssize res; + gboolean close_res; + GError *error; + gboolean save_res; + + error = NULL; + + flags = priv ? G_FILE_CREATE_PRIVATE : G_FILE_CREATE_NONE; + flags |= replace_dest ? G_FILE_CREATE_REPLACE_DESTINATION : 0; + + if (create) + out = (GOutputStream *)g_file_create (file, flags, NULL, &error); + else if (append) + out = (GOutputStream *)g_file_append_to (file, flags, NULL, &error); + else + out = (GOutputStream *)g_file_replace (file, etag, backup, flags, NULL, &error); + if (out == NULL) + { + print_file_error (file, error->message); + g_error_free (error); + return FALSE; + } + + save_res = TRUE; + + while (1) + { + res = read (STDIN_FILENO, buffer, 1024); + if (res > 0) + { + ssize_t written; + + p = buffer; + while (res > 0) + { + error = NULL; + written = g_output_stream_write (out, p, res, NULL, &error); + if (written == -1) + { + save_res = FALSE; + g_printerr ("gio: Error writing to stream: %s\n", error->message); + g_error_free (error); + goto out; + } + res -= written; + p += written; + } + } + else if (res < 0) + { + save_res = FALSE; + g_printerr ("gio: Error reading from standard input\n"); + break; + } + else if (res == 0) + break; + } + + out: + + close_res = g_output_stream_close (out, NULL, &error); + if (!close_res) + { + save_res = FALSE; + g_printerr ("gio: Error closing: %s\n", error->message); + g_error_free (error); + } + + if (close_res && print_etag) + { + char *etag; + etag = g_file_output_stream_get_etag (G_FILE_OUTPUT_STREAM (out)); + + if (etag) + g_print ("Etag: %s\n", etag); + else + /* Translators: The "etag" is a token allowing to verify whether a file has been modified */ + g_print (_("Etag not available\n")); + g_free (etag); + } + + g_object_unref (out); + + return save_res; +} + +int +handle_save (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + GFile *file; + gboolean res; + + g_set_prgname ("gio save"); + + /* Translators: commandline placeholder */ + context = g_option_context_new (_("DESTINATION")); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Read from standard input and save to DEST.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("No destination given")); + return 1; + } + + if (argc > 2); + { + show_help (context, _("Too many arguments")); + return 1; + } + + g_option_context_free (context); + + file = g_file_new_for_commandline_arg (argv[1]); + res = save (file); + g_object_unref (file); + + return res ? 0 : 2; +} + diff --git a/gio/gio-tool-set.c b/gio/gio-tool-set.c new file mode 100644 index 000000000..3a0e2e489 --- /dev/null +++ b/gio/gio-tool-set.c @@ -0,0 +1,195 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <stdlib.h> + +#include "gio-tool.h" + + +static char *attr_type = "string"; +static gboolean nofollow_symlinks = FALSE; + +static const GOptionEntry entries[] = { + { "type", 't', 0, G_OPTION_ARG_STRING, &attr_type, N_("Type of the attribute"), N_("TYPE") }, + { "nofollow-symlinks", 'n', 0, G_OPTION_ARG_NONE, &nofollow_symlinks, N_("Don't follow symbolic links"), NULL }, + { NULL } +}; + +static char * +hex_unescape (const char *str) +{ + int i; + char *unescaped_str, *p; + unsigned char c; + int len; + + len = strlen (str); + unescaped_str = g_malloc (len + 1); + + p = unescaped_str; + for (i = 0; i < len; i++) + { + if (str[i] == '\\' && + str[i+1] == 'x' && + len - i >= 4) + { + c = + (g_ascii_xdigit_value (str[i+2]) << 4) | + g_ascii_xdigit_value (str[i+3]); + *p++ = c; + i += 3; + } + else + *p++ = str[i]; + } + *p++ = 0; + + return unescaped_str; +} + +int +handle_set (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + GFile *file; + const char *attribute; + GFileAttributeType type; + gpointer value; + gboolean b; + guint32 uint32; + gint32 int32; + guint64 uint64; + gint64 int64; + gchar *param; + + g_set_prgname ("gio set"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("%s %s %s...", _("LOCATION"), _("ATTRIBUTE"), _("VALUE")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, _("Set a file attribute of LOCATION.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + if (argc < 2) + { + show_help (context, _("Location not specified")); + return 1; + } + + file = g_file_new_for_commandline_arg (argv[1]); + + if (argc < 3) + { + show_help (context, _("Attribute not specified")); + return 1; + } + + attribute = argv[2]; + + type = attribute_type_from_string (attr_type); + if ((argc < 4) && (type != G_FILE_ATTRIBUTE_TYPE_INVALID)) + { + show_help (context, _("Value not specified")); + return 1; + } + + if ((argc > 4) && (type != G_FILE_ATTRIBUTE_TYPE_STRINGV)) + { + show_help (context, _("Too many arguments")); + return 1; + } + + g_option_context_free (context); + + switch (type) + { + case G_FILE_ATTRIBUTE_TYPE_STRING: + value = argv[3]; + break; + case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING: + value = hex_unescape (argv[3]); + break; + case G_FILE_ATTRIBUTE_TYPE_BOOLEAN: + b = g_ascii_strcasecmp (argv[3], "true") == 0; + value = &b; + break; + case G_FILE_ATTRIBUTE_TYPE_UINT32: + uint32 = atol (argv[3]); + value = &uint32; + break; + case G_FILE_ATTRIBUTE_TYPE_INT32: + int32 = atol (argv[3]); + value = &int32; + break; + case G_FILE_ATTRIBUTE_TYPE_UINT64: + uint64 = g_ascii_strtoull (argv[3], NULL, 10); + value = &uint64; + break; + case G_FILE_ATTRIBUTE_TYPE_INT64: + int64 = g_ascii_strtoll (argv[3], NULL, 10); + value = &int64; + break; + case G_FILE_ATTRIBUTE_TYPE_STRINGV: + value = &argv[3]; + break; + case G_FILE_ATTRIBUTE_TYPE_INVALID: + value = NULL; + break; + case G_FILE_ATTRIBUTE_TYPE_OBJECT: + default: + g_printerr (_("Invalid attribute type %s\n"), attr_type); + return 1; + } + + if (!g_file_set_attribute (file, + attribute, + type, + value, + nofollow_symlinks ? + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS : + G_FILE_QUERY_INFO_NONE, + NULL, &error)) + { + g_printerr (_("Error setting attribute: %s\n"), error->message); + g_error_free (error); + return 1; + } + + return 0; +} diff --git a/gio/gio-tool-trash.c b/gio/gio-tool-trash.c new file mode 100644 index 000000000..40f378c8f --- /dev/null +++ b/gio/gio-tool-trash.c @@ -0,0 +1,135 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static gboolean force = FALSE; +static gboolean empty = FALSE; +static const GOptionEntry entries[] = { + { "force", 'f', 0, G_OPTION_ARG_NONE, &force, N_("Ignore nonexistent files, never prompt"), NULL }, + { "empty", 0, 0, G_OPTION_ARG_NONE, &empty, N_("Empty the trash"), NULL }, + { NULL } +}; + +static void +delete_trash_file (GFile *file, gboolean del_file, gboolean del_children) +{ + GFileInfo *info; + GFile *child; + GFileEnumerator *enumerator; + + if (del_children) + { + enumerator = g_file_enumerate_children (file, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, + NULL); + if (enumerator) + { + while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) + { + child = g_file_get_child (file, g_file_info_get_name (info)); + delete_trash_file (child, TRUE, g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY); + g_object_unref (child); + g_object_unref (info); + } + g_file_enumerator_close (enumerator, NULL, NULL); + g_object_unref (enumerator); + } + } + + if (del_file) + g_file_delete (file, NULL, NULL); +} + +int +handle_trash (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + gchar *param; + GError *error = NULL; + int retval = 0; + GFile *file; + + g_set_prgname ("gio trash"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("[%s...]", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("Move files or directories to the trash.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + g_option_context_free (context); + + if (argc > 1) + { + int i; + + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + error = NULL; + if (!g_file_trash (file, NULL, &error)) + { + if (!force || + !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + print_file_error (file, error->message); + retval = 1; + } + g_error_free (error); + } + g_object_unref (file); + } + } + + if (empty) + { + GFile *file; + file = g_file_new_for_uri ("trash:"); + delete_trash_file (file, FALSE, TRUE); + g_object_unref (file); + } + + return retval; +} diff --git a/gio/gio-tool-tree.c b/gio/gio-tool-tree.c new file mode 100644 index 000000000..415b3990b --- /dev/null +++ b/gio/gio-tool-tree.c @@ -0,0 +1,285 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> + +#include "gio-tool.h" + + +static gboolean show_hidden = FALSE; +static gboolean follow_symlinks = FALSE; + +static const GOptionEntry entries[] = { + { "hidden", 'h', 0, G_OPTION_ARG_NONE, &show_hidden, N_("Show hidden files"), NULL }, + { "follow-symlinks", 'l', 0, G_OPTION_ARG_NONE, &follow_symlinks, N_("Follow symbolic links, mounts and shortcuts"), NULL }, + { NULL } +}; + +static gint +sort_info_by_name (GFileInfo *a, GFileInfo *b) +{ + const char *na; + const char *nb; + + na = g_file_info_get_name (a); + nb = g_file_info_get_name (b); + + if (na == NULL) + na = ""; + if (nb == NULL) + nb = ""; + + return strcmp (na, nb); +} + +static void +do_tree (GFile *f, int level, guint64 pattern) +{ + GFileEnumerator *enumerator; + GError *error = NULL; + unsigned int n; + GFileInfo *info; + + info = g_file_query_info (f, + G_FILE_ATTRIBUTE_STANDARD_TYPE "," + G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, + 0, + NULL, NULL); + if (info != NULL) + { + if (g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE) == G_FILE_TYPE_MOUNTABLE) + { + /* don't process mountables; we avoid these by getting the target_uri below */ + g_object_unref (info); + return; + } + g_object_unref (info); + } + + enumerator = g_file_enumerate_children (f, + G_FILE_ATTRIBUTE_STANDARD_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE "," + G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," + G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK "," + G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET "," + G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, + 0, + NULL, + &error); + if (enumerator != NULL) + { + GList *l; + GList *info_list; + + info_list = NULL; + while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)) != NULL) + { + if (g_file_info_get_is_hidden (info) && !show_hidden) + { + g_object_unref (info); + } + else + { + info_list = g_list_prepend (info_list, info); + } + } + g_file_enumerator_close (enumerator, NULL, NULL); + + info_list = g_list_sort (info_list, (GCompareFunc) sort_info_by_name); + + for (l = info_list; l != NULL; l = l->next) + { + const char *name; + const char *target_uri; + GFileType type; + gboolean is_last_item; + + info = l->data; + is_last_item = (l->next == NULL); + + name = g_file_info_get_name (info); + type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE); + if (name != NULL) + { + + for (n = 0; n < level; n++) + { + if (pattern & (1<<n)) + { + g_print ("| "); + } + else + { + g_print (" "); + } + } + + if (is_last_item) + { + g_print ("`-- %s", name); + } + else + { + g_print ("|-- %s", name); + } + + target_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); + if (target_uri != NULL) + { + g_print (" -> %s", target_uri); + } + else + { + if (g_file_info_get_is_symlink (info)) + { + const char *target; + target = g_file_info_get_symlink_target (info); + g_print (" -> %s", target); + } + } + + g_print ("\n"); + + if ((type & G_FILE_TYPE_DIRECTORY) && + (follow_symlinks || !g_file_info_get_is_symlink (info))) + { + guint64 new_pattern; + GFile *child; + + if (is_last_item) + new_pattern = pattern; + else + new_pattern = pattern | (1<<level); + + child = NULL; + if (target_uri != NULL) + { + if (follow_symlinks) + child = g_file_new_for_uri (target_uri); + } + else + { + child = g_file_get_child (f, name); + } + + if (child != NULL) + { + do_tree (child, level + 1, new_pattern); + g_object_unref (child); + } + } + } + g_object_unref (info); + } + g_list_free (info_list); + } + else + { + for (n = 0; n < level; n++) + { + if (pattern & (1<<n)) + { + g_print ("| "); + } + else + { + g_print (" "); + } + } + + g_print (" [%s]\n", error->message); + + g_error_free (error); + } +} + +static void +tree (GFile *f) +{ + char *uri; + + uri = g_file_get_uri (f); + g_print ("%s\n", uri); + g_free (uri); + + do_tree (f, 0, 0); +} + +int +handle_tree (int argc, char *argv[], gboolean do_help) +{ + GOptionContext *context; + GError *error = NULL; + GFile *file; + gchar *param; + int i; + + g_set_prgname ("gio tree"); + + /* Translators: commandline placeholder */ + param = g_strdup_printf ("[%s...]", _("LOCATION")); + context = g_option_context_new (param); + g_free (param); + g_option_context_set_help_enabled (context, FALSE); + g_option_context_set_summary (context, + _("List contents of directories in a tree-like format.")); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + + if (do_help) + { + show_help (context, NULL); + return 0; + } + + g_option_context_parse (context, &argc, &argv, &error); + + if (error != NULL) + { + show_help (context, error->message); + g_error_free (error); + return 1; + } + + g_option_context_free (context); + + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + file = g_file_new_for_commandline_arg (argv[i]); + tree (file); + g_object_unref (file); + } + } + else + { + char *cwd; + + cwd = g_get_current_dir (); + file = g_file_new_for_path (cwd); + g_free (cwd); + tree (file); + g_object_unref (file); + } + + return 0; +} diff --git a/gio/gio-tool.c b/gio/gio-tool.c new file mode 100644 index 000000000..1c084316b --- /dev/null +++ b/gio/gio-tool.c @@ -0,0 +1,316 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gi18n.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include "gio-tool.h" + + +void +print_file_error (GFile *file, const char *message) +{ + g_printerr ("gio: %s: %s\n", g_file_get_uri (file), message); +} + +void +show_help (GOptionContext *context, const char *message) +{ + char *help; + + if (message) + g_printerr ("gio: %s\n\n", message); + + help = g_option_context_get_help (context, TRUE, NULL); + g_printerr ("%s", help); + g_free (help); +} + +const char * +file_type_to_string (GFileType type) +{ + switch (type) + { + case G_FILE_TYPE_UNKNOWN: + return "unknown"; + case G_FILE_TYPE_REGULAR: + return "regular"; + case G_FILE_TYPE_DIRECTORY: + return "directory"; + case G_FILE_TYPE_SYMBOLIC_LINK: + return "symlink"; + case G_FILE_TYPE_SPECIAL: + return "special"; + case G_FILE_TYPE_SHORTCUT: + return "shortcut"; + case G_FILE_TYPE_MOUNTABLE: + return "mountable"; + default: + return "invalid type"; + } +} + +const char * +attribute_type_to_string (GFileAttributeType type) +{ + switch (type) + { + case G_FILE_ATTRIBUTE_TYPE_INVALID: + return "invalid"; + case G_FILE_ATTRIBUTE_TYPE_STRING: + return "string"; + case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING: + return "bytestring"; + case G_FILE_ATTRIBUTE_TYPE_BOOLEAN: + return "boolean"; + case G_FILE_ATTRIBUTE_TYPE_UINT32: + return "uint32"; + case G_FILE_ATTRIBUTE_TYPE_INT32: + return "int32"; + case G_FILE_ATTRIBUTE_TYPE_UINT64: + return "uint64"; + case G_FILE_ATTRIBUTE_TYPE_INT64: + return "int64"; + case G_FILE_ATTRIBUTE_TYPE_OBJECT: + return "object"; + default: + return "uknown type"; + } +} + +GFileAttributeType +attribute_type_from_string (const char *str) +{ + if (strcmp (str, "string") == 0) + return G_FILE_ATTRIBUTE_TYPE_STRING; + if (strcmp (str, "stringv") == 0) + return G_FILE_ATTRIBUTE_TYPE_STRINGV; + if (strcmp (str, "bytestring") == 0) + return G_FILE_ATTRIBUTE_TYPE_BYTE_STRING; + if (strcmp (str, "boolean") == 0) + return G_FILE_ATTRIBUTE_TYPE_BOOLEAN; + if (strcmp (str, "uint32") == 0) + return G_FILE_ATTRIBUTE_TYPE_UINT32; + if (strcmp (str, "int32") == 0) + return G_FILE_ATTRIBUTE_TYPE_INT32; + if (strcmp (str, "uint64") == 0) + return G_FILE_ATTRIBUTE_TYPE_UINT64; + if (strcmp (str, "int64") == 0) + return G_FILE_ATTRIBUTE_TYPE_INT64; + if (strcmp (str, "object") == 0) + return G_FILE_ATTRIBUTE_TYPE_OBJECT; + if (strcmp (str, "unset") == 0) + return G_FILE_ATTRIBUTE_TYPE_INVALID; + return -1; +} + +char * +attribute_flags_to_string (GFileAttributeInfoFlags flags) +{ + GString *s; + int i; + gboolean first; + struct { + guint32 mask; + char *descr; + } flag_descr[] = { + { + G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE, + N_("Copy with file") + }, + { + G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED, + N_("Keep with file when moved") + } + }; + + first = TRUE; + + s = g_string_new (""); + for (i = 0; i < G_N_ELEMENTS (flag_descr); i++) + { + if (flags & flag_descr[i].mask) + { + if (!first) + g_string_append (s, ", "); + g_string_append (s, gettext (flag_descr[i].descr)); + first = FALSE; + } + } + + return g_string_free (s, FALSE); +} + +gboolean +file_is_dir (GFile *file) +{ + GFileInfo *info; + gboolean res; + + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, NULL); + res = info && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY; + if (info) + g_object_unref (info); + return res; +} + + +static int +handle_version (int argc, char *argv[], gboolean do_help) +{ + if (do_help || argc > 1) + { + if (!do_help) + g_printerr ("gio: %s\n\n", _("'version' takes no arguments")); + + g_printerr ("%s\n", _("Usage:")); + g_printerr (" gio version\n"); + g_printerr ("\n"); + g_printerr ("%s\n", _("Print version information and exit.")); + + return do_help ? 0 : 2; + } + + g_print ("%d.%d.%d\n", glib_major_version, glib_minor_version, glib_micro_version); + + return 0; +} + +static void +usage (void) +{ + g_printerr ("%s\n", _("Usage:")); + g_printerr (" gio %s %s\n", _("COMMAND"), _("[ARGS...]")); + g_printerr ("\n"); + g_printerr ("%s\n", _("Commands:")); + g_printerr (" help %s\n", _("Print help")); + g_printerr (" version %s\n", _("Print version")); + g_printerr (" cat %s\n", _("Concatenate files to standard output")); + g_printerr (" copy %s\n", _("Copy one or more files")); + g_printerr (" info %s\n", _("Show information about locations")); + g_printerr (" list %s\n", _("List the contents of locations")); + g_printerr (" mime %s\n", _("Get or set the handler for a mimetype")); + g_printerr (" mkdir %s\n", _("Create directories")); + g_printerr (" monitor %s\n", _("Monitor files and directories for changes")); + g_printerr (" mount %s\n", _("Mount or unmount the locations")); + g_printerr (" move %s\n", _("Move one or more files")); + g_printerr (" open %s\n", _("Open files with the default application")); + g_printerr (" rename %s\n", _("Rename a file")); + g_printerr (" remove %s\n", _("Delete one or more files")); + g_printerr (" save %s\n", _("Read from standard input and save")); + g_printerr (" set %s\n", _("Set a file attribute")); + g_printerr (" trash %s\n", _("Move files or directories to the trash")); + g_printerr (" tree %s\n", _("Lists the contents of locations in a tree")); + g_printerr ("\n"); + g_printerr (_("Use %s to get detailed help.\n"), "'gio help COMMAND'"); + exit (1); +} + +int +main (int argc, char **argv) +{ + const char *command; + gboolean do_help; + + setlocale (LC_ALL, ""); + textdomain (GETTEXT_PACKAGE); + bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR); + +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); +#endif + + if (argc < 2) + { + usage (); + return 1; + } + + command = argv[1]; + argc -= 1; + argv += 1; + + do_help = FALSE; + if (g_str_equal (command, "help")) + { + if (argc == 1) + { + usage (); + return 0; + } + else + { + command = argv[1]; + do_help = TRUE; + } + } + else if (g_str_equal (command, "--help")) + { + usage (); + return 0; + } + else if (g_str_equal (command, "--version")) + command = "version"; + + if (g_str_equal (command, "version")) + return handle_version (argc, argv, do_help); + else if (g_str_equal (command, "cat")) + return handle_cat (argc, argv, do_help); + else if (g_str_equal (command, "copy")) + return handle_copy (argc, argv, do_help); + else if (g_str_equal (command, "info")) + return handle_info (argc, argv, do_help); + else if (g_str_equal (command, "list")) + return handle_list (argc, argv, do_help); + else if (g_str_equal (command, "mime")) + return handle_mime (argc, argv, do_help); + else if (g_str_equal (command, "mkdir")) + return handle_mkdir (argc, argv, do_help); + else if (g_str_equal (command, "monitor")) + return handle_monitor (argc, argv, do_help); + else if (g_str_equal (command, "mount")) + return handle_mount (argc, argv, do_help); + else if (g_str_equal (command, "move")) + return handle_move (argc, argv, do_help); + else if (g_str_equal (command, "open")) + return handle_open (argc, argv, do_help); + else if (g_str_equal (command, "rename")) + return handle_rename (argc, argv, do_help); + else if (g_str_equal (command, "remove")) + return handle_remove (argc, argv, do_help); + else if (g_str_equal (command, "save")) + return handle_save (argc, argv, do_help); + else if (g_str_equal (command, "set")) + return handle_set (argc, argv, do_help); + else if (g_str_equal (command, "trash")) + return handle_trash (argc, argv, do_help); + else if (g_str_equal (command, "tree")) + return handle_tree (argc, argv, do_help); + else + usage (); + + return 1; +} diff --git a/gio/gio-tool.h b/gio/gio-tool.h new file mode 100644 index 000000000..966500de0 --- /dev/null +++ b/gio/gio-tool.h @@ -0,0 +1,52 @@ +/* + * Copyright 2015 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the licence, or (at your option) any later version. + * + * This 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Matthias Clasen <mclasen@redhat.com> + */ + +#ifndef __GIO_TOOL_H__ +#define __GIO_TOOL_H__ + +void print_file_error (GFile *file, + const char *message); +void show_help (GOptionContext *context, + const char *message); + +const char *file_type_to_string (GFileType type); +const char *attribute_type_to_string (GFileAttributeType type); +GFileAttributeType attribute_type_from_string (const char *str); +char *attribute_flags_to_string (GFileAttributeInfoFlags flags); + +gboolean file_is_dir (GFile *file); + +int handle_cat (int argc, char *argv[], gboolean do_help); +int handle_copy (int argc, char *argv[], gboolean do_help); +int handle_info (int argc, char *argv[], gboolean do_help); +int handle_list (int argc, char *argv[], gboolean do_help); +int handle_mime (int argc, char *argv[], gboolean do_help); +int handle_mkdir (int argc, char *argv[], gboolean do_help); +int handle_monitor (int argc, char *argv[], gboolean do_help); +int handle_mount (int argc, char *argv[], gboolean do_help); +int handle_move (int argc, char *argv[], gboolean do_help); +int handle_open (int argc, char *argv[], gboolean do_help); +int handle_rename (int argc, char *argv[], gboolean do_help); +int handle_remove (int argc, char *argv[], gboolean do_help); +int handle_save (int argc, char *argv[], gboolean do_help); +int handle_set (int argc, char *argv[], gboolean do_help); +int handle_trash (int argc, char *argv[], gboolean do_help); +int handle_tree (int argc, char *argv[], gboolean do_help); + +#endif /* __GIO_TOOL_H__ */ |