quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

progress.c (21086B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #include "urldata.h"
     28 #include "sendf.h"
     29 #include "multiif.h"
     30 #include "progress.h"
     31 #include "curlx/timeval.h"
     32 #include "curl_printf.h"
     33 
     34 /* check rate limits within this many recent milliseconds, at minimum. */
     35 #define MIN_RATE_LIMIT_PERIOD 3000
     36 
     37 #ifndef CURL_DISABLE_PROGRESS_METER
     38 /* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
     39    byte) */
     40 static void time2str(char *r, curl_off_t seconds)
     41 {
     42   curl_off_t h;
     43   if(seconds <= 0) {
     44     strcpy(r, "--:--:--");
     45     return;
     46   }
     47   h = seconds / 3600;
     48   if(h <= 99) {
     49     curl_off_t m = (seconds - (h * 3600)) / 60;
     50     curl_off_t s = (seconds - (h * 3600)) - (m * 60);
     51     msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s);
     52   }
     53   else {
     54     /* this equals to more than 99 hours, switch to a more suitable output
     55        format to fit within the limits. */
     56     curl_off_t d = seconds / 86400;
     57     h = (seconds - (d * 86400)) / 3600;
     58     if(d <= 999)
     59       msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h);
     60     else
     61       msnprintf(r, 9, "%7" FMT_OFF_T "d", d);
     62   }
     63 }
     64 
     65 /* The point of this function would be to return a string of the input data,
     66    but never longer than 5 columns (+ one zero byte).
     67    Add suffix k, M, G when suitable... */
     68 static char *max5data(curl_off_t bytes, char *max5)
     69 {
     70 #define ONE_KILOBYTE (curl_off_t)1024
     71 #define ONE_MEGABYTE (1024 * ONE_KILOBYTE)
     72 #define ONE_GIGABYTE (1024 * ONE_MEGABYTE)
     73 #define ONE_TERABYTE (1024 * ONE_GIGABYTE)
     74 #define ONE_PETABYTE (1024 * ONE_TERABYTE)
     75 
     76   if(bytes < 100000)
     77     msnprintf(max5, 6, "%5" FMT_OFF_T, bytes);
     78 
     79   else if(bytes < 10000 * ONE_KILOBYTE)
     80     msnprintf(max5, 6, "%4" FMT_OFF_T "k", bytes/ONE_KILOBYTE);
     81 
     82   else if(bytes < 100 * ONE_MEGABYTE)
     83     /* 'XX.XM' is good as long as we are less than 100 megs */
     84     msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
     85               FMT_OFF_T "M", bytes/ONE_MEGABYTE,
     86               (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/10) );
     87 
     88   else if(bytes < 10000 * ONE_MEGABYTE)
     89     /* 'XXXXM' is good until we are at 10000MB or above */
     90     msnprintf(max5, 6, "%4" FMT_OFF_T "M", bytes/ONE_MEGABYTE);
     91 
     92   else if(bytes < 100 * ONE_GIGABYTE)
     93     /* 10000 MB - 100 GB, we show it as XX.XG */
     94     msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
     95               FMT_OFF_T "G", bytes/ONE_GIGABYTE,
     96               (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/10) );
     97 
     98   else if(bytes < 10000 * ONE_GIGABYTE)
     99     /* up to 10000GB, display without decimal: XXXXG */
    100     msnprintf(max5, 6, "%4" FMT_OFF_T "G", bytes/ONE_GIGABYTE);
    101 
    102   else if(bytes < 10000 * ONE_TERABYTE)
    103     /* up to 10000TB, display without decimal: XXXXT */
    104     msnprintf(max5, 6, "%4" FMT_OFF_T "T", bytes/ONE_TERABYTE);
    105 
    106   else
    107     /* up to 10000PB, display without decimal: XXXXP */
    108     msnprintf(max5, 6, "%4" FMT_OFF_T "P", bytes/ONE_PETABYTE);
    109 
    110   /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can
    111      hold, but our data type is signed so 8192PB will be the maximum. */
    112 
    113   return max5;
    114 }
    115 #endif
    116 
    117 /*
    118 
    119    New proposed interface, 9th of February 2000:
    120 
    121    pgrsStartNow() - sets start time
    122    pgrsSetDownloadSize(x) - known expected download size
    123    pgrsSetUploadSize(x) - known expected upload size
    124    pgrsSetDownloadCounter() - amount of data currently downloaded
    125    pgrsSetUploadCounter() - amount of data currently uploaded
    126    pgrsUpdate() - show progress
    127    pgrsDone() - transfer complete
    128 
    129 */
    130 
    131 int Curl_pgrsDone(struct Curl_easy *data)
    132 {
    133   int rc;
    134   data->progress.lastshow = 0;
    135   rc = Curl_pgrsUpdate(data); /* the final (forced) update */
    136   if(rc)
    137     return rc;
    138 
    139   if(!data->progress.hide && !data->progress.callback)
    140     /* only output if we do not use a progress callback and we are not
    141      * hidden */
    142     fprintf(data->set.err, "\n");
    143 
    144   data->progress.speeder_c = 0; /* reset the progress meter display */
    145   return 0;
    146 }
    147 
    148 /* reset the known transfer sizes */
    149 void Curl_pgrsResetTransferSizes(struct Curl_easy *data)
    150 {
    151   Curl_pgrsSetDownloadSize(data, -1);
    152   Curl_pgrsSetUploadSize(data, -1);
    153 }
    154 
    155 /*
    156  *
    157  * Curl_pgrsTimeWas(). Store the timestamp time at the given label.
    158  */
    159 void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
    160                       struct curltime timestamp)
    161 {
    162   timediff_t *delta = NULL;
    163 
    164   switch(timer) {
    165   default:
    166   case TIMER_NONE:
    167     /* mistake filter */
    168     break;
    169   case TIMER_STARTOP:
    170     /* This is set at the start of a transfer */
    171     data->progress.t_startop = timestamp;
    172     data->progress.t_startqueue = timestamp;
    173     data->progress.t_postqueue = 0;
    174     break;
    175   case TIMER_STARTSINGLE:
    176     /* This is set at the start of each single transfer */
    177     data->progress.t_startsingle = timestamp;
    178     data->progress.is_t_startransfer_set = FALSE;
    179     break;
    180   case TIMER_POSTQUEUE:
    181     /* Queue time is accumulative from all involved redirects */
    182     data->progress.t_postqueue +=
    183       curlx_timediff_us(timestamp, data->progress.t_startqueue);
    184     break;
    185   case TIMER_STARTACCEPT:
    186     data->progress.t_acceptdata = timestamp;
    187     break;
    188   case TIMER_NAMELOOKUP:
    189     delta = &data->progress.t_nslookup;
    190     break;
    191   case TIMER_CONNECT:
    192     delta = &data->progress.t_connect;
    193     break;
    194   case TIMER_APPCONNECT:
    195     delta = &data->progress.t_appconnect;
    196     break;
    197   case TIMER_PRETRANSFER:
    198     delta = &data->progress.t_pretransfer;
    199     break;
    200   case TIMER_STARTTRANSFER:
    201     delta = &data->progress.t_starttransfer;
    202     /* prevent updating t_starttransfer unless:
    203      *   1) this is the first time we are setting t_starttransfer
    204      *   2) a redirect has occurred since the last time t_starttransfer was set
    205      * This prevents repeated invocations of the function from incorrectly
    206      * changing the t_starttransfer time.
    207      */
    208     if(data->progress.is_t_startransfer_set) {
    209       return;
    210     }
    211     else {
    212       data->progress.is_t_startransfer_set = TRUE;
    213       break;
    214     }
    215   case TIMER_POSTRANSFER:
    216     delta = &data->progress.t_posttransfer;
    217     break;
    218   case TIMER_REDIRECT:
    219     data->progress.t_redirect = curlx_timediff_us(timestamp,
    220                                                  data->progress.start);
    221     data->progress.t_startqueue = timestamp;
    222     break;
    223   }
    224   if(delta) {
    225     timediff_t us = curlx_timediff_us(timestamp, data->progress.t_startsingle);
    226     if(us < 1)
    227       us = 1; /* make sure at least one microsecond passed */
    228     *delta += us;
    229   }
    230 }
    231 
    232 /*
    233  *
    234  * Curl_pgrsTime(). Store the current time at the given label. This fetches a
    235  * fresh "now" and returns it.
    236  *
    237  * @unittest: 1399
    238  */
    239 struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer)
    240 {
    241   struct curltime now = curlx_now();
    242 
    243   Curl_pgrsTimeWas(data, timer, now);
    244   return now;
    245 }
    246 
    247 void Curl_pgrsStartNow(struct Curl_easy *data)
    248 {
    249   struct Progress *p = &data->progress;
    250   p->speeder_c = 0; /* reset the progress meter display */
    251   p->start = curlx_now();
    252   p->is_t_startransfer_set = FALSE;
    253   p->ul.limit.start = p->start;
    254   p->dl.limit.start = p->start;
    255   p->ul.limit.start_size = 0;
    256   p->dl.limit.start_size = 0;
    257   p->dl.cur_size = 0;
    258   p->ul.cur_size = 0;
    259   /* the sizes are unknown at start */
    260   p->dl_size_known = FALSE;
    261   p->ul_size_known = FALSE;
    262   Curl_ratelimit(data, p->start);
    263 }
    264 
    265 /*
    266  * This is used to handle speed limits, calculating how many milliseconds to
    267  * wait until we are back under the speed limit, if needed.
    268  *
    269  * The way it works is by having a "starting point" (time & amount of data
    270  * transferred by then) used in the speed computation, to be used instead of
    271  * the start of the transfer. This starting point is regularly moved as
    272  * transfer goes on, to keep getting accurate values (instead of average over
    273  * the entire transfer).
    274  *
    275  * This function takes the current amount of data transferred, the amount at
    276  * the starting point, the limit (in bytes/s), the time of the starting point
    277  * and the current time.
    278  *
    279  * Returns 0 if no waiting is needed or when no waiting is needed but the
    280  * starting point should be reset (to current); or the number of milliseconds
    281  * to wait to get back under the speed limit.
    282  */
    283 timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
    284                                   curl_off_t speed_limit,
    285                                   struct curltime now)
    286 {
    287   curl_off_t size = d->cur_size - d->limit.start_size;
    288   timediff_t minimum;
    289   timediff_t actual;
    290 
    291   if(!speed_limit || !size)
    292     return 0;
    293 
    294   /*
    295    * 'minimum' is the number of milliseconds 'size' should take to download to
    296    * stay below 'limit'.
    297    */
    298   if(size < CURL_OFF_T_MAX/1000)
    299     minimum = (timediff_t) (1000 * size / speed_limit);
    300   else {
    301     minimum = (timediff_t) (size / speed_limit);
    302     if(minimum < TIMEDIFF_T_MAX/1000)
    303       minimum *= 1000;
    304     else
    305       minimum = TIMEDIFF_T_MAX;
    306   }
    307 
    308   /*
    309    * 'actual' is the time in milliseconds it took to actually download the
    310    * last 'size' bytes.
    311    */
    312   actual = curlx_timediff_ceil(now, d->limit.start);
    313   if(actual < minimum) {
    314     /* if it downloaded the data faster than the limit, make it wait the
    315        difference */
    316     return minimum - actual;
    317   }
    318 
    319   return 0;
    320 }
    321 
    322 /*
    323  * Set the number of downloaded bytes so far.
    324  */
    325 CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
    326 {
    327   data->progress.dl.cur_size = size;
    328   return CURLE_OK;
    329 }
    330 
    331 /*
    332  * Update the timestamp and sizestamp to use for rate limit calculations.
    333  */
    334 void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
    335 {
    336   /* do not set a new stamp unless the time since last update is long enough */
    337   if(data->set.max_recv_speed) {
    338     if(curlx_timediff(now, data->progress.dl.limit.start) >=
    339        MIN_RATE_LIMIT_PERIOD) {
    340       data->progress.dl.limit.start = now;
    341       data->progress.dl.limit.start_size = data->progress.dl.cur_size;
    342     }
    343   }
    344   if(data->set.max_send_speed) {
    345     if(curlx_timediff(now, data->progress.ul.limit.start) >=
    346        MIN_RATE_LIMIT_PERIOD) {
    347       data->progress.ul.limit.start = now;
    348       data->progress.ul.limit.start_size = data->progress.ul.cur_size;
    349     }
    350   }
    351 }
    352 
    353 /*
    354  * Set the number of uploaded bytes so far.
    355  */
    356 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
    357 {
    358   data->progress.ul.cur_size = size;
    359 }
    360 
    361 void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
    362 {
    363   if(size >= 0) {
    364     data->progress.dl.total_size = size;
    365     data->progress.dl_size_known = TRUE;
    366   }
    367   else {
    368     data->progress.dl.total_size = 0;
    369     data->progress.dl_size_known = FALSE;
    370   }
    371 }
    372 
    373 void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
    374 {
    375   if(size >= 0) {
    376     data->progress.ul.total_size = size;
    377     data->progress.ul_size_known = TRUE;
    378   }
    379   else {
    380     data->progress.ul.total_size = 0;
    381     data->progress.ul_size_known = FALSE;
    382   }
    383 }
    384 
    385 void Curl_pgrsEarlyData(struct Curl_easy *data, curl_off_t sent)
    386 {
    387     data->progress.earlydata_sent = sent;
    388 }
    389 
    390 /* returns the average speed in bytes / second */
    391 static curl_off_t trspeed(curl_off_t size, /* number of bytes */
    392                           curl_off_t us)   /* microseconds */
    393 {
    394   if(us < 1)
    395     return size * 1000000;
    396   else if(size < CURL_OFF_T_MAX/1000000)
    397     return (size * 1000000) / us;
    398   else if(us >= 1000000)
    399     return size / (us / 1000000);
    400   else
    401     return CURL_OFF_T_MAX;
    402 }
    403 
    404 /* returns TRUE if it is time to show the progress meter */
    405 static bool progress_calc(struct Curl_easy *data, struct curltime now)
    406 {
    407   bool timetoshow = FALSE;
    408   struct Progress * const p = &data->progress;
    409 
    410   /* The time spent so far (from the start) in microseconds */
    411   p->timespent = curlx_timediff_us(now, p->start);
    412   p->dl.speed = trspeed(p->dl.cur_size, p->timespent);
    413   p->ul.speed = trspeed(p->ul.cur_size, p->timespent);
    414 
    415   /* Calculations done at most once a second, unless end is reached */
    416   if(p->lastshow != now.tv_sec) {
    417     int countindex; /* amount of seconds stored in the speeder array */
    418     int nowindex = p->speeder_c% CURR_TIME;
    419     p->lastshow = now.tv_sec;
    420     timetoshow = TRUE;
    421 
    422     /* Let's do the "current speed" thing, with the dl + ul speeds
    423        combined. Store the speed at entry 'nowindex'. */
    424     p->speeder[ nowindex ] = p->dl.cur_size + p->ul.cur_size;
    425 
    426     /* remember the exact time for this moment */
    427     p->speeder_time [ nowindex ] = now;
    428 
    429     /* advance our speeder_c counter, which is increased every time we get
    430        here and we expect it to never wrap as 2^32 is a lot of seconds! */
    431     p->speeder_c++;
    432 
    433     /* figure out how many index entries of data we have stored in our speeder
    434        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
    435        transfer. Imagine, after one second we have filled in two entries,
    436        after two seconds we have filled in three entries etc. */
    437     countindex = ((p->speeder_c >= CURR_TIME) ? CURR_TIME : p->speeder_c) - 1;
    438 
    439     /* first of all, we do not do this if there is no counted seconds yet */
    440     if(countindex) {
    441       int checkindex;
    442       timediff_t span_ms;
    443       curl_off_t amount;
    444 
    445       /* Get the index position to compare with the 'nowindex' position.
    446          Get the oldest entry possible. While we have less than CURR_TIME
    447          entries, the first entry will remain the oldest. */
    448       checkindex = (p->speeder_c >= CURR_TIME) ? p->speeder_c%CURR_TIME : 0;
    449 
    450       /* Figure out the exact time for the time span */
    451       span_ms = curlx_timediff(now, p->speeder_time[checkindex]);
    452       if(0 == span_ms)
    453         span_ms = 1; /* at least one millisecond MUST have passed */
    454 
    455       /* Calculate the average speed the last 'span_ms' milliseconds */
    456       amount = p->speeder[nowindex]- p->speeder[checkindex];
    457 
    458       if(amount > (0xffffffff/1000))
    459         /* the 'amount' value is bigger than would fit in 32 bits if
    460            multiplied with 1000, so we use the double math for this */
    461         p->current_speed = (curl_off_t)
    462           ((double)amount/((double)span_ms/1000.0));
    463       else
    464         /* the 'amount' value is small enough to fit within 32 bits even
    465            when multiplied with 1000 */
    466         p->current_speed = amount * 1000/span_ms;
    467     }
    468     else
    469       /* the first second we use the average */
    470       p->current_speed = p->ul.speed + p->dl.speed;
    471 
    472   } /* Calculations end */
    473   return timetoshow;
    474 }
    475 
    476 #ifndef CURL_DISABLE_PROGRESS_METER
    477 
    478 struct pgrs_estimate {
    479   curl_off_t secs;
    480   curl_off_t percent;
    481 };
    482 
    483 static curl_off_t pgrs_est_percent(curl_off_t total, curl_off_t cur)
    484 {
    485   if(total > 10000)
    486     return cur / (total / 100);
    487   else if(total > 0)
    488     return (cur*100) / total;
    489   return 0;
    490 }
    491 
    492 static void pgrs_estimates(struct pgrs_dir *d,
    493                            bool total_known,
    494                            struct pgrs_estimate *est)
    495 {
    496   est->secs = 0;
    497   est->percent = 0;
    498   if(total_known && (d->speed > 0)) {
    499     est->secs = d->total_size / d->speed;
    500     est->percent = pgrs_est_percent(d->total_size, d->cur_size);
    501   }
    502 }
    503 
    504 static void progress_meter(struct Curl_easy *data)
    505 {
    506   struct Progress *p = &data->progress;
    507   char max5[6][10];
    508   struct pgrs_estimate dl_estm;
    509   struct pgrs_estimate ul_estm;
    510   struct pgrs_estimate total_estm;
    511   curl_off_t total_cur_size;
    512   curl_off_t total_expected_size;
    513   curl_off_t dl_size;
    514   char time_left[10];
    515   char time_total[10];
    516   char time_spent[10];
    517   curl_off_t cur_secs = (curl_off_t)p->timespent/1000000; /* seconds */
    518 
    519   if(!p->headers_out) {
    520     if(data->state.resume_from) {
    521       fprintf(data->set.err,
    522               "** Resuming transfer from byte position %" FMT_OFF_T "\n",
    523               data->state.resume_from);
    524     }
    525     fprintf(data->set.err,
    526             "  %% Total    %% Received %% Xferd  Average Speed   "
    527             "Time    Time     Time  Current\n"
    528             "                                 Dload  Upload   "
    529             "Total   Spent    Left  Speed\n");
    530     p->headers_out = TRUE; /* headers are shown */
    531   }
    532 
    533   /* Figure out the estimated time of arrival for upload and download */
    534   pgrs_estimates(&p->ul, (bool)p->ul_size_known, &ul_estm);
    535   pgrs_estimates(&p->dl, (bool)p->dl_size_known, &dl_estm);
    536 
    537   /* Since both happen at the same time, total expected duration is max. */
    538   total_estm.secs = CURLMAX(ul_estm.secs, dl_estm.secs);
    539   /* create the three time strings */
    540   time2str(time_left, total_estm.secs > 0 ? (total_estm.secs - cur_secs) : 0);
    541   time2str(time_total, total_estm.secs);
    542   time2str(time_spent, cur_secs);
    543 
    544   /* Get the total amount of data expected to get transferred */
    545   total_expected_size =
    546     p->ul_size_known ? p->ul.total_size : p->ul.cur_size;
    547 
    548   dl_size =
    549     p->dl_size_known ? p->dl.total_size : p->dl.cur_size;
    550 
    551   /* integer overflow check */
    552   if((CURL_OFF_T_MAX - total_expected_size) < dl_size)
    553     total_expected_size = CURL_OFF_T_MAX; /* capped */
    554   else
    555     total_expected_size += dl_size;
    556 
    557   /* We have transferred this much so far */
    558   total_cur_size = p->dl.cur_size + p->ul.cur_size;
    559 
    560   /* Get the percentage of data transferred so far */
    561   total_estm.percent = pgrs_est_percent(total_expected_size, total_cur_size);
    562 
    563   fprintf(data->set.err,
    564           "\r"
    565           "%3" FMT_OFF_T " %s  "
    566           "%3" FMT_OFF_T " %s  "
    567           "%3" FMT_OFF_T " %s  %s  %s %s %s %s %s",
    568           total_estm.percent, /* 3 letters */           /* total % */
    569           max5data(total_expected_size, max5[2]),       /* total size */
    570           dl_estm.percent, /* 3 letters */              /* rcvd % */
    571           max5data(p->dl.cur_size, max5[0]),            /* rcvd size */
    572           ul_estm.percent, /* 3 letters */              /* xfer % */
    573           max5data(p->ul.cur_size, max5[1]),            /* xfer size */
    574           max5data(p->dl.speed, max5[3]),               /* avrg dl speed */
    575           max5data(p->ul.speed, max5[4]),               /* avrg ul speed */
    576           time_total,    /* 8 letters */                /* total time */
    577           time_spent,    /* 8 letters */                /* time spent */
    578           time_left,     /* 8 letters */                /* time left */
    579           max5data(p->current_speed, max5[5])
    580     );
    581 
    582   /* we flush the output stream to make it appear as soon as possible */
    583   fflush(data->set.err);
    584 }
    585 #else
    586  /* progress bar disabled */
    587 #define progress_meter(x) Curl_nop_stmt
    588 #endif
    589 
    590 
    591 /*
    592  * Curl_pgrsUpdate() returns 0 for success or the value returned by the
    593  * progress callback!
    594  */
    595 static int pgrsupdate(struct Curl_easy *data, bool showprogress)
    596 {
    597   if(!data->progress.hide) {
    598     if(data->set.fxferinfo) {
    599       int result;
    600       /* There is a callback set, call that */
    601       Curl_set_in_callback(data, TRUE);
    602       result = data->set.fxferinfo(data->set.progress_client,
    603                                    data->progress.dl.total_size,
    604                                    data->progress.dl.cur_size,
    605                                    data->progress.ul.total_size,
    606                                    data->progress.ul.cur_size);
    607       Curl_set_in_callback(data, FALSE);
    608       if(result != CURL_PROGRESSFUNC_CONTINUE) {
    609         if(result)
    610           failf(data, "Callback aborted");
    611         return result;
    612       }
    613     }
    614     else if(data->set.fprogress) {
    615       int result;
    616       /* The older deprecated callback is set, call that */
    617       Curl_set_in_callback(data, TRUE);
    618       result = data->set.fprogress(data->set.progress_client,
    619                                    (double)data->progress.dl.total_size,
    620                                    (double)data->progress.dl.cur_size,
    621                                    (double)data->progress.ul.total_size,
    622                                    (double)data->progress.ul.cur_size);
    623       Curl_set_in_callback(data, FALSE);
    624       if(result != CURL_PROGRESSFUNC_CONTINUE) {
    625         if(result)
    626           failf(data, "Callback aborted");
    627         return result;
    628       }
    629     }
    630 
    631     if(showprogress)
    632       progress_meter(data);
    633   }
    634 
    635   return 0;
    636 }
    637 
    638 int Curl_pgrsUpdate(struct Curl_easy *data)
    639 {
    640   struct curltime now = curlx_now(); /* what time is it */
    641   bool showprogress = progress_calc(data, now);
    642   return pgrsupdate(data, showprogress);
    643 }
    644 
    645 /*
    646  * Update all progress, do not do progress meter/callbacks.
    647  */
    648 void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
    649 {
    650   struct curltime now = curlx_now(); /* what time is it */
    651   (void)progress_calc(data, now);
    652 }