(root)/
glib-2.79.0/
gio/
gio-tool-copy.c
       1  /*
       2   * Copyright 2015 Red Hat, Inc.
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Matthias Clasen <mclasen@redhat.com>
      20   */
      21  
      22  #include "config.h"
      23  
      24  #include <gio/gio.h>
      25  #include <gi18n.h>
      26  #include <stdio.h>
      27  #if 0
      28  #include <locale.h>
      29  #include <string.h>
      30  #include <stdlib.h>
      31  #include <errno.h>
      32  #endif
      33  
      34  #include "gio-tool.h"
      35  
      36  static gboolean no_target_directory = FALSE;
      37  static gboolean progress = FALSE;
      38  static gboolean interactive = FALSE;
      39  static gboolean preserve = FALSE;
      40  static gboolean backup = FALSE;
      41  static gboolean no_dereference = FALSE;
      42  static gboolean default_permissions = FALSE;
      43  static gboolean default_modified_time = FALSE;
      44  
      45  static const GOptionEntry entries[] = {
      46    { "no-target-directory", 'T', 0, G_OPTION_ARG_NONE, &no_target_directory, N_("No target directory"), NULL },
      47    { "progress", 'p', 0, G_OPTION_ARG_NONE, &progress, N_("Show progress"), NULL },
      48    { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive, N_("Prompt before overwrite"), NULL },
      49    { "preserve", 'p', 0, G_OPTION_ARG_NONE, &preserve, N_("Preserve all attributes"), NULL },
      50    { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL },
      51    { "no-dereference", 'P', 0, G_OPTION_ARG_NONE, &no_dereference, N_("Never follow symbolic links"), NULL },
      52    { "default-permissions", 0, 0, G_OPTION_ARG_NONE, &default_permissions, N_("Use default permissions for the destination"), NULL },
      53    { "default-modified-time", 0, 0, G_OPTION_ARG_NONE, &default_modified_time, N_("Use default file modification timestamps for the destination"), NULL },
      54    G_OPTION_ENTRY_NULL
      55  };
      56  
      57  static gint64 start_time;
      58  static gint64 previous_time;
      59  
      60  static void
      61  show_progress (goffset current_num_bytes,
      62                 goffset total_num_bytes,
      63                 gpointer user_data)
      64  {
      65    gint64 tv;
      66    char *current_size, *total_size, *rate;
      67  
      68    tv = g_get_monotonic_time ();
      69    if (tv - previous_time < (G_USEC_PER_SEC / 5) &&
      70        current_num_bytes != total_num_bytes)
      71      return;
      72  
      73    current_size = g_format_size (current_num_bytes);
      74    total_size = g_format_size (total_num_bytes);
      75    rate = g_format_size (current_num_bytes /
      76                          MAX ((tv - start_time) / G_USEC_PER_SEC, 1));
      77    g_print ("\r\033[K");
      78    g_print (_("Transferred %s out of %s (%s/s)"), current_size, total_size, rate);
      79  
      80    previous_time = tv;
      81  
      82    g_free (current_size);
      83    g_free (total_size);
      84    g_free (rate);
      85  }
      86  
      87  int
      88  handle_copy (int argc, char *argv[], gboolean do_help)
      89  {
      90    GOptionContext *context;
      91    GError *error = NULL;
      92    char *param;
      93    GFile *source, *dest, *target;
      94    gboolean dest_is_dir;
      95    char *basename;
      96    char *uri;
      97    int i;
      98    GFileCopyFlags flags;
      99    int retval = 0;
     100  
     101    g_set_prgname ("gio copy");
     102  
     103    /* Translators: commandline placeholder */
     104    param = g_strdup_printf ("%s%s", _("SOURCE"), _("DESTINATION"));
     105    context = g_option_context_new (param);
     106    g_free (param);
     107    g_option_context_set_help_enabled (context, FALSE);
     108    g_option_context_set_summary (context,
     109        _("Copy one or more files from SOURCE to DESTINATION."));
     110    g_option_context_set_description (context,
     111        _("gio copy is similar to the traditional cp utility, but using GIO\n"
     112          "locations instead of local files: for example, you can use something\n"
     113          "like smb://server/resource/file.txt as location."));
     114    g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
     115  
     116    if (do_help)
     117      {
     118        show_help (context, NULL);
     119        g_option_context_free (context);
     120        return 0;
     121      }
     122  
     123    if (!g_option_context_parse (context, &argc, &argv, &error))
     124      {
     125        show_help (context, error->message);
     126        g_error_free (error);
     127        g_option_context_free (context);
     128        return 1;
     129      }
     130  
     131    if (argc < 3)
     132      {
     133        show_help (context, NULL);
     134        g_option_context_free (context);
     135        return 1;
     136      }
     137  
     138    dest = g_file_new_for_commandline_arg (argv[argc - 1]);
     139  
     140    if (no_target_directory && argc > 3)
     141      {
     142        show_help (context, NULL);
     143        g_object_unref (dest);
     144        g_option_context_free (context);
     145        return 1;
     146      }
     147  
     148    dest_is_dir = file_is_dir (dest);
     149    if (!dest_is_dir && argc > 3)
     150      {
     151        char *message;
     152  
     153        message = g_strdup_printf (_("Destination %s is not a directory"), argv[argc - 1]);
     154        show_help (context, message);
     155        g_free (message);
     156        g_object_unref (dest);
     157        g_option_context_free (context);
     158        return 1;
     159      }
     160  
     161    g_option_context_free (context);
     162  
     163    for (i = 1; i < argc - 1; i++)
     164      {
     165        source = g_file_new_for_commandline_arg (argv[i]);
     166        if (dest_is_dir && !no_target_directory)
     167          {
     168            basename = g_file_get_basename (source);
     169            target = g_file_get_child (dest, basename);
     170            g_free (basename);
     171          }
     172        else
     173          target = g_object_ref (dest);
     174  
     175        flags = 0;
     176        if (backup)
     177          flags |= G_FILE_COPY_BACKUP;
     178        if (!interactive)
     179          flags |= G_FILE_COPY_OVERWRITE;
     180        if (no_dereference)
     181          flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS;
     182        if (preserve)
     183          flags |= G_FILE_COPY_ALL_METADATA;
     184        if (default_permissions)
     185          flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS;
     186        if (default_modified_time)
     187          flags |= G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME;
     188  
     189        error = NULL;
     190        start_time = g_get_monotonic_time ();
     191  
     192        if (!g_file_copy (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error))
     193          {
     194            if (interactive && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
     195              {
     196                char line[16];
     197  
     198                g_error_free (error);
     199                error = NULL;
     200  
     201                uri = g_file_get_uri (target);
     202                g_print (_("%s: overwrite “%s”? "), argv[0], uri);
     203                g_free (uri);
     204  
     205                if (fgets (line, sizeof (line), stdin) &&
     206                    (line[0] == 'y' || line[0] == 'Y'))
     207                  {
     208                    flags |= G_FILE_COPY_OVERWRITE;
     209                    start_time = g_get_monotonic_time ();
     210                    if (!g_file_copy (source, target, flags, NULL, progress ? show_progress : NULL, NULL, &error))
     211                      goto copy_failed;
     212                  }
     213              }
     214            else
     215              {
     216              copy_failed:
     217                print_file_error (source, error->message);
     218                g_error_free (error);
     219                retval = 1;
     220              }
     221          }
     222  
     223       if (progress && retval == 0)
     224          g_print ("\n");
     225  
     226        g_object_unref (source);
     227        g_object_unref (target);
     228      }
     229  
     230    g_object_unref (dest);
     231  
     232    return retval;
     233  }