]> TLD Linux GIT Repositories - packages/coreutils.git/blob - coreutils-advcopy.patch
- merged 9.0 from PLD
[packages/coreutils.git] / coreutils-advcopy.patch
1 diff -aur coreutils-9.0/src/copy.c coreutils-9.0-patched/src/copy.c
2 --- coreutils-9.0/src/copy.c    2021-09-24 17:01:05.000000000 +0530
3 +++ coreutils-9.0-patched/src/copy.c    2022-03-27 05:54:15.840209369 +0530
4 @@ -129,6 +129,133 @@
5    dev_t dev;
6  };
7  
8 +/* BEGIN progress mod */
9 +struct progress_status {
10 +  int iCountDown;
11 +  char ** cProgressField;
12 +  struct timeval last_time;
13 +  int last_size, iBarLength;
14 +  struct stat src_open_sb;
15 +};
16 +
17 +FILE * spawn( const char *cmd, char *const argv[] )
18 +{
19 +    FILE *ret = NULL;
20 +    int pfd_read[2];
21 +    pid_t pid;
22 +
23 +    if (cmd == NULL || argv == NULL)
24 +        return ret;
25 +
26 +    if (pipe(pfd_read) < 0) {
27 +        error(0, errno, "pipe: %s", cmd);
28 +        return ret;
29 +    }
30 +
31 +    if ((pid = fork()) == 0) {
32 +        int err = dup2(pfd_read[1], 1) < 0;
33 +        close(pfd_read[0]);
34 +        close(pfd_read[1]);
35 +
36 +        if (err)
37 +            error(EXIT_FAILURE, errno, "dup2: %s", cmd);
38 +        execvp(cmd, argv);
39 +        error(EXIT_FAILURE, errno, "exec: %s", cmd);
40 +    }
41 +
42 +    close(pfd_read[1]);
43 +
44 +    if (pid < 0) {
45 +        close(pfd_read[0]);
46 +        error(0, errno, "fork: %s", cmd);
47 +        return ret;
48 +    }
49 +
50 +    ret = fdopen(pfd_read[0], "r");
51 +    return ret;
52 +}
53 +
54 +void format_time ( char * _cDest, double seconds, bool showall )
55 +{
56 +  // hours
57 +  int hr = ( (int) seconds / (60 * 60)) % 24;
58 +  // minutes
59 +  int min = ( (int) seconds / 60) % 60;
60 +  // seconds
61 +  double sec = seconds - (hr * (60 * 60)) - (min * 60);
62 +  if ( showall )
63 +  {
64 +    if ( seconds < 0 )
65 +      sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
66 +    else
67 +      sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
68 +  } else  if ( seconds >= 3600 )
69 +  {
70 +    sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
71 +  } else if ( seconds >= 60 )
72 +  {
73 +    sprintf(_cDest, "%2dm %4.1fs", min, sec);
74 +  } else
75 +  {
76 +    sprintf(_cDest, "%4.1fs", sec);
77 +  }
78 +}
79 +
80 +static void file_progress_bar ( char * _cDest, int _iBarLength, long _lProgress, long _lTotal )
81 +{
82 +    double dPercent = (double) _lProgress / (double) _lTotal * 100.f;
83 +    sprintf( _cDest + ( _iBarLength - 6), "%4.1f", dPercent );
84 +    _cDest[_iBarLength - 2] = ' ';
85 +
86 +    int i;
87 +    for ( i=1; i<=_iBarLength - 9; i++)
88 +    {
89 +        if ( dPercent > (double) (i-1) / (_iBarLength - 10) * 100.f )
90 +        {
91 +            _cDest[i] = '=';
92 +        }
93 +        else
94 +        {
95 +            _cDest[i] = ' ';
96 +        }
97 +    }
98 +    for ( i=1; i<_iBarLength - 9; i++)
99 +    {
100 +        if ( ( _cDest[i+1] == ' ' ) && ( _cDest[i] == '=' ) )
101 +            _cDest[i] = '>' ;
102 +    }
103 +}
104 +
105 +int file_size_format ( char * _cDst, long _lSize, int _iCounter )
106 +{
107 +  int iCounter = _iCounter;
108 +  double dSize = ( double ) _lSize;
109 +  while ( dSize >= 1000. )
110 +  {
111 +    dSize /= 1024.;
112 +    iCounter++;
113 +  }
114 +
115 +  /* get unit */
116 +  char * sUnit;
117 +  if ( iCounter == 0 )
118 +    sUnit = "B";
119 +  else if ( iCounter == 1 )
120 +    sUnit = "KiB";
121 +  else if ( iCounter == 2 )
122 +    sUnit = "MiB";
123 +  else if ( iCounter == 3 )
124 +    sUnit = "GiB";
125 +  else if ( iCounter == 4 )
126 +    sUnit = "TiB";
127 +  else
128 +    sUnit = "N/A";
129 +
130 +  /* write number */
131 +  return sprintf ( _cDst, "%5.1f %s", dSize, sUnit );
132 +}
133 +/* END progress mod */
134 +
135  /* Initial size of the cp.dest_info hash table.  */
136  #define DEST_INFO_INITIAL_CAPACITY 61
137  
138 @@ -299,14 +426,23 @@
139     bytes read.  */
140  static bool
141  sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
142 -             size_t hole_size, bool punch_holes, bool allow_reflink,
143 +             size_t hole_size, bool punch_holes, bool allow_reflink, bool move_mode,
144               char const *src_name, char const *dst_name,
145               uintmax_t max_n_read, off_t *total_n_read,
146 -             bool *last_write_made_hole)
147 +             bool *last_write_made_hole,
148 +             struct progress_status *s_progress)
149  {
150    *last_write_made_hole = false;
151    *total_n_read = 0;
152  
153 +  /* BEGIN progress mod */
154 +  gettimeofday ( & g_oFStartTime, NULL );
155 +  g_iFTotalWritten = 0;
156 +  struct stat st;
157 +  stat(src_name, &st);
158 +  g_iFTotalSize = st.st_size/1024;
159 +  /* END progress mod */
160 +
161    /* If not looking for holes, use copy_file_range if functional,
162       but don't use if reflink disallowed as that may be implicit.  */
163    if ((! hole_size) && allow_reflink && functional_copy_file_range ())
164 @@ -362,6 +498,103 @@
165  
166    while (max_n_read)
167      {
168 +
169 +    /* BEGIN progress mod */
170 +    if (progress) {
171 +          /* update countdown */
172 +          s_progress->iCountDown--;
173 +          char * sProgressBar = s_progress->cProgressField[5];
174 +          if ( s_progress->iCountDown < 0 )
175 +            s_progress->iCountDown = 100;
176 +
177 +          /* just print one line with the percentage, but not always */
178 +          if ( s_progress->iCountDown == 0 )
179 +          {
180 +            /* calculate current speed */
181 +            struct timeval cur_time;
182 +            gettimeofday ( & cur_time, NULL );
183 +            int cur_size = g_iTotalWritten + *total_n_read / 1024;
184 +            int cur_fsize = g_iFTotalWritten + *total_n_read / 1024;
185 +            int usec_elapsed = cur_time.tv_usec - s_progress->last_time.tv_usec;
186 +            double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
187 +            sec_elapsed += ( double ) ( cur_time.tv_sec - s_progress->last_time.tv_sec );
188 +            int copy_speed = ( int ) ( ( double ) ( cur_size - s_progress->last_size )
189 +              / sec_elapsed );
190 +            char s_copy_speed[20];
191 +            file_size_format ( s_copy_speed, copy_speed >= 0 ? copy_speed : 0, 1 );
192 +            /* update vars */
193 +            s_progress->last_time = cur_time;
194 +            s_progress->last_size = cur_size;
195 +
196 +            /* how many time has passed since the start? */
197 +            int isec_elapsed = cur_time.tv_sec - g_oStartTime.tv_sec;
198 +            int isec_felapsed = cur_time.tv_sec - g_oFStartTime.tv_sec;
199 +            int sec_remaining = ( int ) ( ( double ) isec_elapsed / cur_size
200 +              * g_iTotalSize ) - isec_elapsed;
201 +            int sec_fremaining = ( int ) ( ( double ) isec_felapsed / cur_fsize
202 +              * g_iFTotalSize ) - isec_felapsed;
203 +            /* print out */
204 +
205 +            char f_ttime[20];
206 +            char f_ftime[20];
207 +            format_time(f_ttime, sec_remaining, true);
208 +            format_time(f_ftime, sec_fremaining, true);
209 +
210 +            sprintf ( s_progress->cProgressField[1],
211 +              move_mode
212 +                ? "%d of %d files moved (about %s remaining) "
213 +                : "%d of %d files copied (about %s remaining) ",
214 +                g_iFilesCopied, g_iTotalFiles, f_ttime );
215 +
216 +            char s_ftime[40] = "";
217 +
218 +            if (g_iTotalFiles > 1)
219 +              sprintf ( s_ftime, "(about %s remaining)", f_ftime );
220 +            else
221 +              sprintf ( s_ftime, "(about %s remaining)", f_ttime );
222 +
223 +            sprintf ( s_progress->cProgressField[3],
224 +              move_mode
225 +                ? "moving at %s/s %s"
226 +                : "copying at %s/s %s", s_copy_speed, s_ftime );
227 +
228 +            int fs_len;
229 +            if ( g_iTotalFiles > 1 )
230 +            {
231 +              /* global progress bar */
232 +              file_progress_bar ( s_progress->cProgressField[2], s_progress->iBarLength,
233 +                                  g_iTotalWritten + *total_n_read / 1024, g_iTotalSize );
234 +
235 +              /* print the global status */
236 +              fs_len = file_size_format ( s_progress->cProgressField[1] + s_progress->iBarLength - 21,
237 +                                              g_iTotalWritten + *total_n_read / 1024, 1 );
238 +              s_progress->cProgressField[1][s_progress->iBarLength - 21 + fs_len] = ' ';
239 +            }
240 +
241 +            /* current progress bar */
242 +            file_progress_bar ( sProgressBar, s_progress->iBarLength, *total_n_read, s_progress->src_open_sb.st_size );
243 +
244 +            /* print the status */
245 +            fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, *total_n_read, 0 );
246 +            s_progress->cProgressField[4][s_progress->iBarLength - 21 + fs_len] = ' ';
247 +
248 +            /* print the field */
249 +            int it;
250 +            for ( it = g_iTotalFiles>1 ? 0 : 3; it < 6; it++ )
251 +            {
252 +              printf ( "\033[K%s\n", s_progress->cProgressField[it] );
253 +              if ( strlen ( s_progress->cProgressField[it] ) < s_progress->iBarLength )
254 +                printf ( "%s", "" );
255 +            }
256 +            if ( g_iTotalFiles > 1 )
257 +              printf ( "\r\033[6A" );
258 +            else
259 +              printf ( "\r\033[3A" );
260 +            fflush ( stdout );
261 +          }
262 +      }
263 +      /* END progress mod */
264 +
265        ssize_t n_read = read (src_fd, buf, MIN (max_n_read, buf_size));
266        if (n_read < 0)
267          {
268 @@ -446,6 +679,14 @@
269           certain files in /proc or /sys with linux kernels.  */
270      }
271  
272 +    /* BEGIN progress mod */
273 +    if (progress) {
274 +          /* update total size */
275 +          g_iTotalWritten += *total_n_read / 1024;
276 +          g_iFilesCopied++;
277 +    }
278 +    /* END progress mod */
279 +
280    /* Ensure a trailing hole is created, so that subsequent
281       calls of sparse_copy() start at the correct offset.  */
282    if (make_hole && ! create_hole (dest_fd, dst_name, punch_holes, psize))
283 @@ -516,9 +757,11 @@
284  static bool
285  lseek_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
286              size_t hole_size, off_t ext_start, off_t src_total_size,
287 -            enum Sparse_type sparse_mode,
288 +            enum Sparse_type sparse_mode, bool move_mode,
289              bool allow_reflink,
290 -            char const *src_name, char const *dst_name)
291 +            char const *src_name, char const *dst_name,
292 +            int iCountDown, char ** cProgressField, struct timeval last_time,
293 +            int last_size, int iBarLength, struct stat src_open_sb)
294  {
295    off_t last_ext_start = 0;
296    off_t last_ext_len = 0;
297 @@ -590,10 +833,16 @@
298           is conservative and may miss some holes.  */
299        off_t n_read;
300        bool read_hole;
301 +
302 +      struct timeval a;
303 +      struct stat b;
304 +
305 +      struct progress_status s_progress={iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
306 +
307        if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
308                            sparse_mode == SPARSE_NEVER ? 0 : hole_size,
309 -                          true, allow_reflink, src_name, dst_name,
310 -                          ext_len, &n_read, &read_hole))
311 +                          true, allow_reflink, move_mode, src_name,
312 +                          dst_name, ext_len, &n_read, &read_hole, &s_progress))
313          return false;
314  
315        dest_pos = ext_start + n_read;
316 @@ -1374,8 +1623,80 @@
317        buf_alloc = xmalloc (buf_size + buf_alignment);
318        buf = ptr_align (buf_alloc, buf_alignment);
319  
320 +      /* BEGIN progress mod */
321 +      /* create a field of 6 lines */
322 +      char ** cProgressField = ( char ** ) calloc ( 6, sizeof ( char * ) );
323 +      /* get console width */
324 +      int iBarLength = 80;
325 +      struct winsize win;
326 +      if ( ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &win) == 0 && win.ws_col > 0 )
327 +         if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
328 +            iBarLength = win.ws_col;
329 +      /* create rows */
330 +      int it;
331 +      for ( it = 0; it < 6; it++ )
332 +      {
333 +        cProgressField[it] = ( char * ) malloc ( iBarLength + 1 );
334 +        /* init with spaces */
335 +        int j;
336 +        for ( j = 0; j < iBarLength; j++ )
337 +          cProgressField[it][j] = ' ';
338 +        cProgressField[it][iBarLength] = '\0';
339 +      }
340 +
341 +      /* global progress bar? */
342 +      if ( g_iTotalFiles > 1 )
343 +      {
344 +        /* init global progress bar */
345 +        cProgressField[2][0] = '[';
346 +        cProgressField[2][iBarLength - 8] = ']';
347 +        cProgressField[2][iBarLength - 7] = ' ';
348 +        cProgressField[2][iBarLength - 1] = '%';
349 +
350 +        /* total size */
351 +        cProgressField[1][iBarLength - 11] = '/';
352 +        file_size_format ( cProgressField[1] + iBarLength - 9, g_iTotalSize, 1 );
353 +
354 +        /* show how many files were written */
355 +        int sum_length = 0;
356 +        sum_length = sprintf ( cProgressField[1],
357 +          x->move_mode
358 +            ? "%d of %d files moved so far"
359 +            : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
360 +        cProgressField[1][sum_length] = ' ';
361 +      }
362 +
363 +      /* truncate filename? */
364 +      int fn_length;
365 +      if ( strlen ( src_name ) > iBarLength - 22 )
366 +        fn_length =
367 +          sprintf ( cProgressField[4], "...%s", src_name + ( strlen ( src_name ) - iBarLength + 25 ) );
368 +      else
369 +        fn_length = sprintf ( cProgressField[4], "%s", src_name );
370 +      cProgressField[4][fn_length] = ' ';
371 +
372 +      /* filesize */
373 +      cProgressField[4][iBarLength - 11] = '/';
374 +      file_size_format ( cProgressField[4] + iBarLength - 9, src_open_sb.st_size, 0 );
375 +
376 +      int iCountDown = 1;
377 +      char * sProgressBar = cProgressField[5];
378 +      sProgressBar[0] = '[';
379 +      sProgressBar[iBarLength - 8] = ']';
380 +      sProgressBar[iBarLength - 7] = ' ';
381 +      sProgressBar[iBarLength - 1] = '%';
382 +
383 +      /* this will always save the time in between */
384 +      struct timeval last_time;
385 +      gettimeofday ( & last_time, NULL );
386 +      int last_size = g_iTotalWritten;
387 +      /* END progress mod */
388 +
389        off_t n_read;
390        bool wrote_hole_at_eof = false;
391 +
392 +      struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
393 +
394        if (! (
395  #ifdef SEEK_HOLE
396               scantype == LSEEK_SCANTYPE
397 @@ -1383,15 +1704,17 @@
398                             scan_inference.ext_start, src_open_sb.st_size,
399                             make_holes ? x->sparse_mode : SPARSE_NEVER,
400                             x->reflink_mode != REFLINK_NEVER,
401 -                           src_name, dst_name)
402 +                           x->move_mode, src_name, dst_name,
403 +                           iCountDown, cProgressField, last_time, last_size,
404 +                           iBarLength, src_open_sb)
405               :
406  #endif
407               sparse_copy (source_desc, dest_desc, buf, buf_size,
408                              make_holes ? hole_size : 0,
409                              x->sparse_mode == SPARSE_ALWAYS,
410                              x->reflink_mode != REFLINK_NEVER,
411 -                            src_name, dst_name, UINTMAX_MAX, &n_read,
412 -                            &wrote_hole_at_eof)))
413 +                            x->move_mode, src_name, dst_name, UINTMAX_MAX,
414 +                            &n_read, &wrote_hole_at_eof, &s_progress)))
415          {
416            return_val = false;
417            goto close_src_and_dst_desc;
418 @@ -1402,6 +1725,14 @@
419            return_val = false;
420            goto close_src_and_dst_desc;
421          }
422 +      /* BEGIN progress mod */
423 +      if (progress) {
424 +            int i;
425 +            for ( i = 0; i < 6; i++ )
426 +              free ( cProgressField[i] );
427 +            free ( cProgressField );
428 +      }
429 +      /* END progress mod */
430      }
431  
432    if (x->preserve_timestamps)
433 diff -aur coreutils-9.0/src/copy.h coreutils-9.0-patched/src/copy.h
434 --- coreutils-9.0/src/copy.h    2021-09-24 17:01:05.000000000 +0530
435 +++ coreutils-9.0-patched/src/copy.h    2022-03-27 05:54:15.844209471 +0530
436 @@ -236,6 +236,9 @@
437       Create destination directories as usual. */
438    bool symbolic_link;
439  
440 +  /* If true, draw a nice progress bar on screen */
441 +  bool progress_bar;
442 +
443    /* If true, do not copy a nondirectory that has an existing destination
444       with the same or newer modification time. */
445    bool update;
446 @@ -308,4 +311,22 @@
447  bool chown_failure_ok (struct cp_options const *) _GL_ATTRIBUTE_PURE;
448  mode_t cached_umask (void);
449  
450 +/* BEGIN progress mod */
451 +FILE * spawn( const char *cmd, char *const argv[] );
452 +void format_time ( char * _cDst, double seconds, bool showall );
453 +
454 +int file_size_format ( char * _cDst, long _lSize, int _iCounter );
455 +
456 +__attribute__((__common__)) long g_iTotalSize;
457 +__attribute__((__common__)) long g_iFTotalSize;
458 +__attribute__((__common__)) long g_iTotalWritten;
459 +__attribute__((__common__)) long g_iFTotalWritten;
460 +__attribute__((__common__)) int g_iFilesCopied;
461 +__attribute__((__common__)) int g_iDirectoriesCopied;
462 +__attribute__((__common__)) struct timeval g_oStartTime;
463 +__attribute__((__common__)) struct timeval g_oFStartTime;
464 +__attribute__((__common__)) int g_iTotalFiles;
465 +__attribute__((__common__)) bool progress;
466 +/* END progress mod */
467 +
468  #endif
469 diff -aur coreutils-9.0/src/cp.c coreutils-9.0-patched/src/cp.c
470 --- coreutils-9.0/src/cp.c      2021-09-24 17:01:05.000000000 +0530
471 +++ coreutils-9.0-patched/src/cp.c      2022-03-27 06:28:53.896713403 +0530
472 @@ -131,6 +131,7 @@
473    {"symbolic-link", no_argument, NULL, 's'},
474    {"target-directory", required_argument, NULL, 't'},
475    {"update", no_argument, NULL, 'u'},
476 +  {"progress-bar", no_argument, NULL, 'g'},
477    {"verbose", no_argument, NULL, 'v'},
478    {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
479    {GETOPT_HELP_OPTION_DECL},
480 @@ -170,6 +171,9 @@
481    -f, --force                  if an existing destination file cannot be\n\
482                                   opened, remove it and try again (this option\n\
483                                   is ignored when the -n option is also used)\n\
484 +  -g, --progress-bar           add a progress bar.\n\
485 +                                 Note that this doesn't work with reflink,\n\
486 +                                 reflink will be automatically disabled\n\
487    -i, --interactive            prompt before overwrite (overrides a previous -n\
488  \n\
489                                    option)\n\
490 @@ -634,6 +638,82 @@
491          die (EXIT_FAILURE, 0, _("target %s is not a directory"),
492               quoteaf (file[n_files - 1]));
493      }
494 +    /* BEGIN progress mod */
495 +    struct timeval start_time;
496 +    if (progress) {
497 +        if (g_iTotalSize == 0)
498 +          g_iTotalSize = 0;
499 +        if (g_iTotalFiles == 0)
500 +          g_iTotalFiles = n_files;
501 +        if (g_iFilesCopied == 0)
502 +          g_iFilesCopied = 0;
503 +        if (g_iDirectoriesCopied == 0)
504 +          g_iDirectoriesCopied = 0;
505 +        if (g_iTotalWritten == 0)
506 +          g_iTotalWritten = 0;
507 +
508 +        if (target_directory_operand (file[0], &sb, &new_dst, forcing))
509 +          g_iDirectoriesCopied++;
510 +
511 +        /* save time */
512 +        gettimeofday ( & start_time, NULL );
513 +        g_oStartTime = start_time;
514 +
515 +        printf ( "calculating total size... \r" );
516 +        fflush ( stdout );
517 +        long iTotalSize = 0;
518 +        int iFiles = n_files;
519 +        if ( ! target_directory )
520 +          iFiles = n_files - 1;
521 +        int j;
522 +
523 +        /* how many files are we copying */
524 +        FILE *fp ;
525 +        char output[1024];
526 +        fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
527 +        if ( fp == NULL)
528 +            printf("failed to run find\r");
529 +        else
530 +        {
531 +          char *line_buf = NULL;
532 +          size_t line_buf_size = 0;
533 +          int line_count = 0;
534 +          ssize_t line_size;
535 +          line_size = getline(&line_buf, &line_buf_size, fp);
536 +          while (line_size > 0)
537 +          {
538 +              line_count++;
539 +              line_size = getline(&line_buf, &line_buf_size, fp);
540 +          }
541 +          free (line_buf);
542 +          if ( line_count > n_files )
543 +            g_iTotalFiles = line_count;
544 +        }
545 +
546 +        for (j = 0; j < iFiles; j++)
547 +        {
548 +          /* call du -s for each file */
549 +          fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
550 +          if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
551 +            printf("failed to run du\r" );
552 +          }
553 +          else
554 +          {
555 +            /* isolate size */
556 +            strchr ( output, '\t' )[0] = '\0';
557 +            iTotalSize += atol ( output );
558 +
559 +            printf ( "calculating total size... %ld\r", iTotalSize );
560 +            fflush ( stdout );
561 +          }
562 +
563 +          /* close */
564 +          pclose(fp);
565 +        }
566 +        g_iTotalSize += iTotalSize;
567 +    }
568 +    /* END progress mod */
569 +
570  
571    if (target_directory)
572      {
573 @@ -781,6 +861,56 @@
574        ok = copy (source, new_dest, 0, x, &unused, NULL);
575      }
576  
577 +    /* BEGIN progress mod */
578 +    if (progress) {
579 +        /* remove everything */
580 +        int i;
581 +        if ( g_iTotalFiles > 1 )
582 +        {
583 +          for ( i = 0; i < 6; i++ )
584 +            printf ( "\033[K\n" );
585 +          printf ( "\r\033[6A" );
586 +        }
587 +        else
588 +        {
589 +          for ( i = 0; i < 3; i++ )
590 +            printf ( "\033[K\n" );
591 +          printf ( "\r\033[3A" );
592 +        }
593 +
594 +        /* save time */
595 +        struct timeval end_time;
596 +        gettimeofday ( & end_time, NULL );
597 +        int usec_elapsed = end_time.tv_usec - start_time.tv_usec;
598 +        double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
599 +        sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec );
600 +
601 +        /* get total size */
602 +        char sTotalWritten[20];
603 +        file_size_format ( sTotalWritten, g_iTotalSize, 1 );
604 +        /* TODO: using g_iTotalWritten would be more correct, but is less accurate */
605 +
606 +        /* calculate speed */
607 +        int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed );
608 +        char s_copy_speed[20];
609 +        file_size_format ( s_copy_speed, copy_speed, 1 );
610 +
611 +        /* good-bye message */
612 +        char sFType[20];
613 +        if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
614 +          sprintf ( sFType, "%s", "folder(s)" );
615 +        else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
616 +          sprintf ( sFType, "%s", "folder(s)/file(s)" );
617 +        else
618 +          sprintf ( sFType, "%s", "file(s)" );
619 +
620 +        char f_time[20];
621 +        format_time(f_time, sec_elapsed, false);
622 +        printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
623 +                 sTotalWritten, f_time, s_copy_speed );
624 +    }
625 +    /* END progress mod */
626 +
627    return ok;
628  }
629  
630 @@ -816,6 +946,9 @@
631    x->recursive = false;
632    x->sparse_mode = SPARSE_AUTO;
633    x->symbolic_link = false;
634 +
635 +  x->progress_bar = false;
636 +
637    x->set_mode = false;
638    x->mode = 0;
639  
640 @@ -954,7 +1087,8 @@
641    selinux_enabled = (0 < is_selinux_enabled ());
642    cp_option_init (&x);
643  
644 -  while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
645 +  /* BEGIN and END progress mod - remove the g in the next line!*/
646 +  while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
647                             long_opts, NULL))
648           != -1)
649      {
650 @@ -1011,6 +1145,10 @@
651            x.unlink_dest_after_failed_open = true;
652            break;
653  
654 +        case 'g':
655 +          progress = true;
656 +          break;
657 +
658          case 'H':
659            x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
660            break;
661 @@ -1171,6 +1309,9 @@
662        usage (EXIT_FAILURE);
663      }
664  
665 +  if (progress)
666 +    x.reflink_mode = REFLINK_NEVER;
667 +
668    x.backup_type = (make_backups
669                     ? xget_version (_("backup type"),
670                                     version_control_string)
671 diff -aur coreutils-9.0/src/mv.c coreutils-9.0-patched/src/mv.c
672 --- coreutils-9.0/src/mv.c      2021-09-24 17:01:05.000000000 +0530
673 +++ coreutils-9.0-patched/src/mv.c      2022-03-27 06:38:49.800838574 +0530
674 @@ -66,6 +66,7 @@
675    {"target-directory", required_argument, NULL, 't'},
676    {"update", no_argument, NULL, 'u'},
677    {"verbose", no_argument, NULL, 'v'},
678 +  {"progress-bar", no_argument, NULL, 'g'},
679    {GETOPT_HELP_OPTION_DECL},
680    {GETOPT_VERSION_OPTION_DECL},
681    {NULL, 0, NULL, 0}
682 @@ -170,8 +171,128 @@
683  {
684    bool copy_into_self;
685    bool rename_succeeded;
686 +
687 +  /* BEGIN progress mod */
688 +  struct timeval start_time;
689 +
690 +  if (progress && x->rename_errno != 0) {
691 +    if (g_iTotalSize == 0)
692 +      g_iTotalSize = 0;
693 +    if (g_iTotalFiles == 0)
694 +      g_iTotalFiles = 0;
695 +    if (g_iFilesCopied == 0)
696 +      g_iFilesCopied = 0;
697 +    if (g_iDirectoriesCopied == 0)
698 +      g_iDirectoriesCopied = 0;
699 +    if (g_iTotalWritten == 0)
700 +      g_iTotalWritten = 0;
701 +
702 +    if (target_directory_operand (source))
703 +      g_iDirectoriesCopied++;
704 +
705 +    gettimeofday (& start_time, NULL);
706 +    g_oStartTime = start_time;
707 +
708 +    /* how many files are we copying */
709 +    FILE *fp ;
710 +    char output[1024];
711 +    fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
712 +    if ( fp == NULL)
713 +      printf("failed to run find\r");
714 +    else
715 +    {
716 +      char *line_buf = NULL;
717 +      size_t line_buf_size = 0;
718 +      int line_count = 0;
719 +      ssize_t line_size;
720 +      line_size = getline(&line_buf, &line_buf_size, fp);
721 +      while (line_size > 0)
722 +      {
723 +        line_count++;
724 +        line_size = getline(&line_buf, &line_buf_size, fp);
725 +      }
726 +      free (line_buf);
727 +      g_iTotalFiles = line_count;
728 +    }
729 +    /* close */
730 +    pclose(fp);
731 +
732 +    printf ("calculating total size... \r");
733 +    fflush (stdout);
734 +    long iTotalSize = 0;
735 +    /* call du -s for source */
736 +    fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
737 +    if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
738 +      printf("failed to run du\r" );
739 +    }
740 +    else
741 +    {
742 +      /* isolate size */
743 +      strchr ( output, '\t' )[0] = '\0';
744 +      iTotalSize += atol ( output );
745 +      printf ( "calculating total size... %ld\r", iTotalSize );
746 +      fflush ( stdout );
747 +    }
748 +
749 +    /* close */
750 +    pclose(fp);
751 +    g_iTotalSize += iTotalSize;
752 +  }
753 +  /* END progress mod */
754 +
755    bool ok = copy (source, dest, false, x, &copy_into_self, &rename_succeeded);
756  
757 +  /* BEGIN progress mod */
758 +  if (progress && (x->rename_errno != 0 && ok)) {
759 +    /* remove everything */
760 +    int i;
761 +    int limit = (g_iTotalFiles > 1 ? 6 : 3);
762 +    if (!rename_succeeded)
763 +    {
764 +      for ( i = 0; i < limit; i++ )
765 +        printf ( "\033[K\n" );
766 +      printf ( "\r\033[3A" );
767 +    }
768 +
769 +    /* save time */
770 +    struct timeval end_time;
771 +    gettimeofday ( & end_time, NULL );
772 +    int usec_elapsed = end_time.tv_usec - start_time.tv_usec;
773 +    double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
774 +    sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec );
775 +
776 +    /* get total size */
777 +    char sTotalWritten[20];
778 +    file_size_format ( sTotalWritten, g_iTotalSize, 1 );
779 +    /* TODO: using g_iTotalWritten would be more correct, but is less accurate */
780 +
781 +    /* calculate speed */
782 +    int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed );
783 +    char s_copy_speed[20];
784 +    file_size_format ( s_copy_speed, copy_speed, 1 );
785 +
786 +    /* increase counter */
787 +    g_iFilesCopied++;
788 +
789 +    /* good-bye message */
790 +    if ( x->last_file )
791 +    {
792 +      char sFType[20];
793 +      if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
794 +        sprintf ( sFType, "%s", "folder(s)" );
795 +      else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
796 +        sprintf ( sFType, "%s", "folder(s)/file(s)" );
797 +      else
798 +        sprintf ( sFType, "%s", "file(s)" );
799 +
800 +      char f_time[20];
801 +      format_time(f_time, sec_elapsed, false);
802 +      printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
803 +               sTotalWritten, f_time, s_copy_speed );
804 +    }
805 +  }
806 +  /* END progress mod */
807 +
808    if (ok)
809      {
810        char const *dir_to_remove;
811 @@ -306,6 +427,7 @@
812  \n\
813    -b                           like --backup but does not accept an argument\n\
814    -f, --force                  do not prompt before overwriting\n\
815 +  -g, --progress-bar           add progress-bar\n\
816    -i, --interactive            prompt before overwrite\n\
817    -n, --no-clobber             do not overwrite an existing file\n\
818  If you specify more than one of -i, -f, -n, only the final one takes effect.\n\
819 @@ -361,7 +483,7 @@
820    /* Try to disable the ability to unlink a directory.  */
821    priv_set_remove_linkdir ();
822  
823 -  while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL))
824 +  while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, NULL))
825           != -1)
826      {
827        switch (c)
828 @@ -407,6 +529,9 @@
829          case 'v':
830            x.verbose = true;
831            break;
832 +        case 'g':
833 +          progress = true;
834 +          break;
835          case 'S':
836            make_backups = true;
837            backup_suffix = optarg;