+ /* Initial size of the cp.dest_info hash table. */
+ #define DEST_INFO_INITIAL_CAPACITY 61
+
+@@ -299,14 +426,23 @@
+ bytes read. */
+ static bool
+ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
+- size_t hole_size, bool punch_holes, bool allow_reflink,
++ size_t hole_size, bool punch_holes, bool allow_reflink, bool move_mode,
+ char const *src_name, char const *dst_name,
+ uintmax_t max_n_read, off_t *total_n_read,
+- bool *last_write_made_hole)
++ bool *last_write_made_hole,
++ struct progress_status *s_progress)
+ {
+ *last_write_made_hole = false;
+ *total_n_read = 0;
+
++ /* BEGIN progress mod */
++ gettimeofday ( & g_oFStartTime, NULL );
++ g_iFTotalWritten = 0;
++ struct stat st;
++ stat(src_name, &st);
++ g_iFTotalSize = st.st_size/1024;
++ /* END progress mod */
++
+ /* If not looking for holes, use copy_file_range if functional,
+ but don't use if reflink disallowed as that may be implicit. */
+ if ((! hole_size) && allow_reflink && functional_copy_file_range ())
+@@ -362,6 +498,103 @@
+
+ while (max_n_read)
+ {
++
++ /* BEGIN progress mod */
++ if (progress) {
++ /* update countdown */
++ s_progress->iCountDown--;
++ char * sProgressBar = s_progress->cProgressField[5];
++ if ( s_progress->iCountDown < 0 )
++ s_progress->iCountDown = 100;
++
++ /* just print one line with the percentage, but not always */
++ if ( s_progress->iCountDown == 0 )
++ {
++ /* calculate current speed */
++ struct timeval cur_time;
++ gettimeofday ( & cur_time, NULL );
++ int cur_size = g_iTotalWritten + *total_n_read / 1024;
++ int cur_fsize = g_iFTotalWritten + *total_n_read / 1024;
++ int usec_elapsed = cur_time.tv_usec - s_progress->last_time.tv_usec;
++ double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
++ sec_elapsed += ( double ) ( cur_time.tv_sec - s_progress->last_time.tv_sec );
++ int copy_speed = ( int ) ( ( double ) ( cur_size - s_progress->last_size )
++ / sec_elapsed );
++ char s_copy_speed[20];
++ file_size_format ( s_copy_speed, copy_speed >= 0 ? copy_speed : 0, 1 );
++ /* update vars */
++ s_progress->last_time = cur_time;
++ s_progress->last_size = cur_size;
++
++ /* how many time has passed since the start? */
++ int isec_elapsed = cur_time.tv_sec - g_oStartTime.tv_sec;
++ int isec_felapsed = cur_time.tv_sec - g_oFStartTime.tv_sec;
++ int sec_remaining = ( int ) ( ( double ) isec_elapsed / cur_size
++ * g_iTotalSize ) - isec_elapsed;
++ int sec_fremaining = ( int ) ( ( double ) isec_felapsed / cur_fsize
++ * g_iFTotalSize ) - isec_felapsed;
++ /* print out */
++
++ char f_ttime[20];
++ char f_ftime[20];
++ format_time(f_ttime, sec_remaining, true);
++ format_time(f_ftime, sec_fremaining, true);
++
++ sprintf ( s_progress->cProgressField[1],
++ move_mode
++ ? "%d of %d files moved (about %s remaining) "
++ : "%d of %d files copied (about %s remaining) ",
++ g_iFilesCopied, g_iTotalFiles, f_ttime );
++
++ char s_ftime[40] = "";
++
++ if (g_iTotalFiles > 1)
++ sprintf ( s_ftime, "(about %s remaining)", f_ftime );
++ else
++ sprintf ( s_ftime, "(about %s remaining)", f_ttime );
++
++ sprintf ( s_progress->cProgressField[3],
++ move_mode
++ ? "moving at %s/s %s"
++ : "copying at %s/s %s", s_copy_speed, s_ftime );
++
++ int fs_len;
++ if ( g_iTotalFiles > 1 )
++ {
++ /* global progress bar */
++ file_progress_bar ( s_progress->cProgressField[2], s_progress->iBarLength,
++ g_iTotalWritten + *total_n_read / 1024, g_iTotalSize );
++
++ /* print the global status */
++ fs_len = file_size_format ( s_progress->cProgressField[1] + s_progress->iBarLength - 21,
++ g_iTotalWritten + *total_n_read / 1024, 1 );
++ s_progress->cProgressField[1][s_progress->iBarLength - 21 + fs_len] = ' ';
++ }
++
++ /* current progress bar */
++ file_progress_bar ( sProgressBar, s_progress->iBarLength, *total_n_read, s_progress->src_open_sb.st_size );
++
++ /* print the status */
++ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, *total_n_read, 0 );
++ s_progress->cProgressField[4][s_progress->iBarLength - 21 + fs_len] = ' ';
++
++ /* print the field */
++ int it;
++ for ( it = g_iTotalFiles>1 ? 0 : 3; it < 6; it++ )
++ {
++ printf ( "\033[K%s\n", s_progress->cProgressField[it] );
++ if ( strlen ( s_progress->cProgressField[it] ) < s_progress->iBarLength )
++ printf ( "%s", "" );
++ }
++ if ( g_iTotalFiles > 1 )
++ printf ( "\r\033[6A" );
++ else
++ printf ( "\r\033[3A" );
++ fflush ( stdout );
++ }
++ }
++ /* END progress mod */
++
+ ssize_t n_read = read (src_fd, buf, MIN (max_n_read, buf_size));
+ if (n_read < 0)
+ {
+@@ -446,6 +679,14 @@
+ certain files in /proc or /sys with linux kernels. */
+ }
+
++ /* BEGIN progress mod */
++ if (progress) {
++ /* update total size */
++ g_iTotalWritten += *total_n_read / 1024;
++ g_iFilesCopied++;
++ }
++ /* END progress mod */
++
+ /* Ensure a trailing hole is created, so that subsequent
+ calls of sparse_copy() start at the correct offset. */
+ if (make_hole && ! create_hole (dest_fd, dst_name, punch_holes, psize))
+@@ -516,9 +757,11 @@
+ static bool
+ lseek_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
+ size_t hole_size, off_t ext_start, off_t src_total_size,
+- enum Sparse_type sparse_mode,
++ enum Sparse_type sparse_mode, bool move_mode,
+ bool allow_reflink,
+- char const *src_name, char const *dst_name)
++ char const *src_name, char const *dst_name,
++ int iCountDown, char ** cProgressField, struct timeval last_time,
++ int last_size, int iBarLength, struct stat src_open_sb)
+ {
+ off_t last_ext_start = 0;
+ off_t last_ext_len = 0;
+@@ -590,10 +833,16 @@
+ is conservative and may miss some holes. */
+ off_t n_read;
+ bool read_hole;
++
++ struct timeval a;
++ struct stat b;
++
++ struct progress_status s_progress={iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
++
+ if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size,
+ sparse_mode == SPARSE_NEVER ? 0 : hole_size,
+- true, allow_reflink, src_name, dst_name,
+- ext_len, &n_read, &read_hole))
++ true, allow_reflink, move_mode, src_name,
++ dst_name, ext_len, &n_read, &read_hole, &s_progress))
+ return false;
+
+ dest_pos = ext_start + n_read;
+@@ -1374,8 +1623,80 @@
+ buf_alloc = xmalloc (buf_size + buf_alignment);