LCOV - code coverage report
Current view: top level - g10 - progress.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 10 78 12.8 %
Date: 2016-11-29 15:00:56 Functions: 3 5 60.0 %

          Line data    Source code
       1             : /* progress.c - emit progress status lines
       2             :  * Copyright (C) 2003, 2006 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG 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
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : #include <stdio.h>
      22             : 
      23             : #include "gpg.h"
      24             : #include "iobuf.h"
      25             : #include "filter.h"
      26             : #include "status.h"
      27             : #include "util.h"
      28             : #include "options.h"
      29             : 
      30             : /* Create a new context for use with the progress filter.  We need to
      31             :    allocate such contexts on the heap because there is no guarantee
      32             :    that at the end of a function the filter has already been popped
      33             :    off.  In general this will happen but with malformed packets it is
      34             :    possible that a filter has not yet reached the end-of-stream when
      35             :    the function has done all processing.  Checking in each function
      36             :    that end-of-stream has been reached would be to cumbersome.
      37             : 
      38             :    What we also do is to shortcut the progress handler by having this
      39             :    function return NULL if progress information has not been
      40             :    requested.
      41             : */
      42             : progress_filter_context_t *
      43         495 : new_progress_context (void)
      44             : {
      45             :   progress_filter_context_t *pfx;
      46             : 
      47         495 :   if (!opt.enable_progress_filter)
      48         495 :     return NULL;
      49             : 
      50           0 :   if (!is_status_enabled ())
      51           0 :     return NULL;
      52             : 
      53           0 :   pfx = xcalloc (1, sizeof *pfx);
      54           0 :   pfx->refcount = 1;
      55             : 
      56           0 :   return pfx;
      57             : }
      58             : 
      59             : /* Release a progress filter context.  Passing NULL is explicitly
      60             :    allowed and a no-op.  */
      61             : void
      62         492 : release_progress_context (progress_filter_context_t *pfx)
      63             : {
      64         492 :   if (!pfx)
      65         492 :     return;
      66           0 :   log_assert (pfx->refcount);
      67           0 :   if ( --pfx->refcount )
      68           0 :     return;
      69           0 :   xfree (pfx->what);
      70           0 :   xfree (pfx);
      71             : }
      72             : 
      73             : 
      74             : static void
      75           0 : write_status_progress (const char *what,
      76             :                        unsigned long current, unsigned long total_arg)
      77             : {
      78             :   char buffer[60];
      79           0 :   char units[] = "BKMGTPEZY?";
      80           0 :   int unitidx = 0;
      81           0 :   uint64_t total = total_arg;
      82             : 
      83             :   /* Although we use an unsigned long for the values, 32 bit
      84             :    * applications using GPGME will use an "int" and thus are limited
      85             :    * in the total size which can be represented.  On Windows, where
      86             :    * sizeof(int)==sizeof(long), this is even worse and will lead to an
      87             :    * integer overflow for all files larger than 2 GiB.  Although, the
      88             :    * allowed value range of TOTAL and CURRENT is nowhere specified, we
      89             :    * better protect applications from the need to handle negative
      90             :    * values.  The common usage pattern of the progress information is
      91             :    * to display how many percent of the operation has been done and
      92             :    * thus scaling CURRENT and TOTAL down before they get to large,
      93             :    * should not have a noticeable effect except for rounding
      94             :    * imprecision. */
      95             : 
      96           0 :   if (!total && opt.input_size_hint)
      97           0 :     total = opt.input_size_hint;
      98             : 
      99           0 :   if (total)
     100             :     {
     101           0 :       if (current > total)
     102           0 :         current = total;
     103             : 
     104           0 :       while (total > 1024*1024)
     105             :         {
     106           0 :           total /= 1024;
     107           0 :           current /= 1024;
     108           0 :           unitidx++;
     109             :         }
     110             :     }
     111             :   else
     112             :     {
     113           0 :       while (current > 1024*1024)
     114             :         {
     115           0 :           current /= 1024;
     116           0 :           unitidx++;
     117             :         }
     118             :     }
     119             : 
     120           0 :   if (unitidx > 9)
     121           0 :     unitidx = 9;
     122             : 
     123           0 :   snprintf (buffer, sizeof buffer, "%.20s ? %lu %lu %c%s",
     124             :             what? what : "?", current, (unsigned long)total,
     125           0 :             units[unitidx],
     126             :             unitidx? "iB" : "");
     127           0 :   write_status_text (STATUS_PROGRESS, buffer);
     128           0 : }
     129             : 
     130             : 
     131             : /****************
     132             :  * The filter is used to report progress to the user.
     133             :  */
     134             : static int
     135           0 : progress_filter (void *opaque, int control,
     136             :                  IOBUF a, byte *buf, size_t *ret_len)
     137             : {
     138           0 :   int rc = 0;
     139           0 :   progress_filter_context_t *pfx = opaque;
     140             : 
     141           0 :   if (control == IOBUFCTRL_INIT)
     142             :     {
     143           0 :       pfx->last = 0;
     144           0 :       pfx->offset = 0;
     145           0 :       pfx->last_time = make_timestamp ();
     146             : 
     147           0 :       write_status_progress (pfx->what, pfx->offset, pfx->total);
     148             :     }
     149           0 :   else if (control == IOBUFCTRL_UNDERFLOW)
     150             :     {
     151           0 :       u32 timestamp = make_timestamp ();
     152           0 :       int len = iobuf_read (a, buf, *ret_len);
     153             : 
     154           0 :       if (len >= 0)
     155             :         {
     156           0 :           pfx->offset += len;
     157           0 :           *ret_len = len;
     158             :         }
     159             :       else
     160             :         {
     161           0 :           *ret_len = 0;
     162           0 :           rc = -1;
     163             :         }
     164           0 :       if ((len == -1 && pfx->offset != pfx->last)
     165           0 :           || timestamp - pfx->last_time > 0)
     166             :         {
     167           0 :           write_status_progress (pfx->what, pfx->offset, pfx->total);
     168           0 :           pfx->last = pfx->offset;
     169           0 :           pfx->last_time = timestamp;
     170             :         }
     171             :     }
     172           0 :   else if (control == IOBUFCTRL_FREE)
     173             :     {
     174           0 :       release_progress_context (pfx);
     175             :     }
     176           0 :   else if (control == IOBUFCTRL_DESC)
     177           0 :     mem2str (buf, "progress_filter", *ret_len);
     178           0 :   return rc;
     179             : }
     180             : 
     181             : void
     182         493 : handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
     183             : {
     184         493 :   off_t filesize = 0;
     185             : 
     186         493 :   if (!pfx)
     187         986 :     return;
     188             : 
     189           0 :   log_assert (opt.enable_progress_filter);
     190           0 :   log_assert (is_status_enabled ());
     191             : 
     192           0 :   if ( !iobuf_is_pipe_filename (name) && *name )
     193           0 :     filesize = iobuf_get_filelength (inp, NULL);
     194           0 :   else if (opt.set_filesize)
     195           0 :     filesize = opt.set_filesize;
     196             : 
     197             :   /* register the progress filter */
     198           0 :   pfx->what = xstrdup (name ? name : "stdin");
     199           0 :   pfx->total = filesize;
     200           0 :   pfx->refcount++;
     201           0 :   iobuf_push_filter (inp, progress_filter, pfx);
     202             : }

Generated by: LCOV version 1.11