| /* | |
| * Copyright 2015 Red Hat, Inc. | |
| * | |
| * SPDX-License-Identifier: LGPL-2.1-or-later | |
| * | |
| * 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.1 of the License, 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 }, | |
| G_OPTION_ENTRY_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); | |
| g_option_context_free (context); | |
| return 0; | |
| } | |
| if (!g_option_context_parse (context, &argc, &argv, &error)) | |
| { | |
| show_help (context, error->message); | |
| g_error_free (error); | |
| g_option_context_free (context); | |
| return 1; | |
| } | |
| if (argc < 3) | |
| { | |
| show_help (context, NULL); | |
| g_option_context_free (context); | |
| 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); | |
| g_option_context_free (context); | |
| 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); | |
| g_option_context_free (context); | |
| 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; | |
| } |