Created
April 11, 2015 22:41
-
-
Save Noctem/3e81f726a42beafc6c3a to your computer and use it in GitHub Desktop.
Patch to add progress bar to cp and mv in CoreUtils 8.23
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff -rup coreutils-8.23/src/copy.c coreutils-8.23-patched/src/copy.c | |
--- coreutils-8.23/src/copy.c 2014-07-13 16:09:52.000000000 -0600 | |
+++ coreutils-8.23-patched/src/copy.c 2015-04-11 16:15:00.000000000 -0600 | |
@@ -113,6 +113,71 @@ struct dir_list | |
dev_t dev; | |
}; | |
+struct progress_status { | |
+ int iCountDown; | |
+ char ** cProgressField; | |
+ struct timeval last_time; | |
+ int last_size, iBarLength; | |
+ struct stat src_open_sb; | |
+}; | |
+ | |
+/* Begin progress Mod*/ | |
+static void file_progress_bar ( char * _cDest, int _iBarLength, long _lProgress, long _lTotal ) | |
+{ | |
+ double dPercent = (double) _lProgress / (double) _lTotal * 100.f; | |
+ sprintf( _cDest + ( _iBarLength - 6), "%4.1f", dPercent ); | |
+ _cDest[_iBarLength - 2] = ' '; | |
+ | |
+ int i; | |
+ for ( i=1; i<=_iBarLength - 9; i++) | |
+ { | |
+ if ( dPercent > (double) (i-1) / (_iBarLength - 10) * 100.f ) | |
+ { | |
+ _cDest[i] = '='; | |
+ } | |
+ else | |
+ { | |
+ _cDest[i] = ' '; | |
+ } | |
+ } | |
+ for ( i=1; i<_iBarLength - 9; i++) | |
+ { | |
+ if ( ( _cDest[i+1] == ' ' ) && ( _cDest[i] == '=' ) ) | |
+ _cDest[i] = '>' ; | |
+ } | |
+} | |
+ | |
+int file_size_format ( char * _cDst, long _lSize, int _iCounter ) | |
+{ | |
+ int iCounter = _iCounter; | |
+ double dSize = ( double ) _lSize; | |
+ while ( dSize >= 1000. ) | |
+ { | |
+ dSize /= 1024.; | |
+ iCounter++; | |
+ } | |
+ | |
+ /* get unit */ | |
+ char * sUnit; | |
+ if ( iCounter == 0 ) | |
+ sUnit = "B"; | |
+ else if ( iCounter == 1 ) | |
+ sUnit = "KiB"; | |
+ else if ( iCounter == 2 ) | |
+ sUnit = "MiB"; | |
+ else if ( iCounter == 3 ) | |
+ sUnit = "GiB"; | |
+ else if ( iCounter == 4 ) | |
+ sUnit = "TiB"; | |
+ else | |
+ sUnit = "N/A"; | |
+ | |
+ /* write number */ | |
+ return sprintf ( _cDst, "%5.1f %s", dSize, sUnit ); | |
+} | |
+/* END progress mod */ | |
+ | |
+ | |
/* Initial size of the cp.dest_info hash table. */ | |
#define DEST_INFO_INITIAL_CAPACITY 61 | |
@@ -161,13 +226,92 @@ sparse_copy (int src_fd, int dest_fd, ch | |
bool make_holes, | |
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; | |
while (max_n_read) | |
- { | |
+ { | |
+ | |
+ if (progress) { | |
+ /* BEGIN progress mod */ | |
+ /* 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 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, 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 sec_remaining = ( int ) ( ( double ) isec_elapsed / cur_size | |
+ * g_iTotalSize ) - isec_elapsed; | |
+ int min_remaining = sec_remaining / 60; | |
+ sec_remaining -= min_remaining * 60; | |
+ int hours_remaining = min_remaining / 60; | |
+ min_remaining -= hours_remaining * 60; | |
+ /* print out */ | |
+ sprintf ( s_progress->cProgressField[3], | |
+ "Copying at %s/s (about %uh %um %us remaining)", s_copy_speed, | |
+ hours_remaining, min_remaining, sec_remaining ); | |
+ | |
+ 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 ( "" ); | |
+ } | |
+ if ( g_iTotalFiles > 1 ) | |
+ printf ( "\r\033[6A" ); | |
+ else | |
+ printf ( "\r\033[3A" ); | |
+ fflush ( stdout ); | |
+ } | |
+ /* END progress mod */ | |
+ } | |
+ | |
+ | |
bool make_hole = false; | |
ssize_t n_read = read (src_fd, buf, MIN (max_n_read, buf_size)); | |
@@ -226,6 +370,14 @@ sparse_copy (int src_fd, int dest_fd, ch | |
*last_write_made_hole = make_hole; | |
} | |
+ /* BEGIN progress mod */ | |
+ if (progress) { | |
+ /* update total size */ | |
+ g_iTotalWritten += *total_n_read / 1024; | |
+ g_iFilesCopied++; | |
+ } | |
+ /* END progress mod */ | |
+ | |
return true; | |
} | |
@@ -292,7 +444,9 @@ static bool | |
extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, | |
off_t src_total_size, enum Sparse_type sparse_mode, | |
char const *src_name, char const *dst_name, | |
- bool *require_normal_copy) | |
+ bool *require_normal_copy, | |
+ int iCountDown, char ** cProgressField, struct timeval last_time, | |
+ int last_size, int iBarLength, struct stat src_open_sb) | |
{ | |
struct extent_scan scan; | |
off_t last_ext_start = 0; | |
@@ -409,10 +563,14 @@ extent_copy (int src_fd, int dest_fd, ch | |
empty_extent = false; | |
last_ext_len = ext_len; | |
+ 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_ALWAYS, | |
src_name, dst_name, ext_len, &n_read, | |
- &wrote_hole_at_eof)) | |
+ &wrote_hole_at_eof, &s_progress)) | |
goto fail; | |
dest_pos = ext_start + n_read; | |
@@ -880,7 +1038,6 @@ is_probably_sparse (struct stat const *s | |
&& ST_NBLOCKS (*sb) < sb->st_size / ST_NBLOCKSIZE); | |
} | |
- | |
/* Copy a regular file from SRC_NAME to DST_NAME. | |
If the source file contains holes, copies holes and blocks of zeros | |
in the source file as holes in the destination file. | |
@@ -1156,6 +1313,72 @@ copy_reg (char const *src_name, char con | |
buf_alloc = xmalloc (buf_size + buf_alignment_slop); | |
buf = ptr_align (buf_alloc, buf_alignment); | |
+ /* BEGIN progress mod */ | |
+ /* create a field of 6 lines */ | |
+ char ** cProgressField = ( char ** ) calloc ( 6, sizeof ( char * ) ); | |
+ /* get console width */ | |
+ int iBarLength = 80; | |
+ struct winsize win; | |
+ if ( ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &win) == 0 && win.ws_col > 0 ) | |
+ iBarLength = win.ws_col; | |
+ /* create rows */ | |
+ int it; | |
+ for ( it = 0; it < 6; it++ ) | |
+ { | |
+ cProgressField[it] = ( char * ) malloc ( iBarLength + 1 ); | |
+ /* init with spaces */ | |
+ int j; | |
+ for ( j = 0; j < iBarLength; j++ ) | |
+ cProgressField[it][j] = ' '; | |
+ cProgressField[it][iBarLength] = '\0'; | |
+ } | |
+ | |
+ /* global progress bar? */ | |
+ if ( g_iTotalFiles > 1 ) | |
+ { | |
+ /* init global progress bar */ | |
+ cProgressField[2][0] = '['; | |
+ cProgressField[2][iBarLength - 8] = ']'; | |
+ cProgressField[2][iBarLength - 7] = ' '; | |
+ cProgressField[2][iBarLength - 1] = '%'; | |
+ | |
+ /* total size */ | |
+ cProgressField[1][iBarLength - 11] = '/'; | |
+ file_size_format ( cProgressField[1] + iBarLength - 9, g_iTotalSize, 1 ); | |
+ | |
+ /* show how many files were written */ | |
+ int sum_length = sprintf ( cProgressField[1], "%d files copied so far...", g_iFilesCopied ); | |
+ cProgressField[1][sum_length] = ' '; | |
+ } | |
+ | |
+ /* truncate filename? */ | |
+ int fn_length; | |
+ if ( strlen ( src_name ) > iBarLength - 22 ) | |
+ fn_length = | |
+ sprintf ( cProgressField[4], "...%s", src_name + ( strlen ( src_name ) - iBarLength + 25 ) ); | |
+ else | |
+ fn_length = sprintf ( cProgressField[4], "%s", src_name ); | |
+ cProgressField[4][fn_length] = ' '; | |
+ | |
+ /* filesize */ | |
+ cProgressField[4][iBarLength - 11] = '/'; | |
+ file_size_format ( cProgressField[4] + iBarLength - 9, src_open_sb.st_size, 0 ); | |
+ | |
+ int iCountDown = 1; | |
+ char * sProgressBar = cProgressField[5]; | |
+ sProgressBar[0] = '['; | |
+ sProgressBar[iBarLength - 8] = ']'; | |
+ sProgressBar[iBarLength - 7] = ' '; | |
+ sProgressBar[iBarLength - 1] = '%'; | |
+ | |
+ /* this will always save the time in between */ | |
+ struct timeval last_time; | |
+ gettimeofday ( & last_time, NULL ); | |
+ int last_size = g_iTotalWritten; | |
+ /* END progress mod */ | |
+ | |
+ | |
+ | |
if (sparse_src) | |
{ | |
bool normal_copy_required; | |
@@ -1167,7 +1390,9 @@ copy_reg (char const *src_name, char con | |
if (extent_copy (source_desc, dest_desc, buf, buf_size, | |
src_open_sb.st_size, | |
S_ISREG (sb.st_mode) ? x->sparse_mode : SPARSE_NEVER, | |
- src_name, dst_name, &normal_copy_required)) | |
+ src_name, dst_name, &normal_copy_required, | |
+ iCountDown, cProgressField, last_time, last_size, | |
+ iBarLength, src_open_sb)) | |
goto preserve_metadata; | |
if (! normal_copy_required) | |
@@ -1179,10 +1404,12 @@ copy_reg (char const *src_name, char con | |
off_t n_read; | |
bool wrote_hole_at_eof; | |
+ | |
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb}; | |
if ( ! sparse_copy (source_desc, dest_desc, buf, buf_size, | |
make_holes, src_name, dst_name, | |
UINTMAX_MAX, &n_read, | |
- &wrote_hole_at_eof) | |
+ &wrote_hole_at_eof, &s_progress) | |
|| (wrote_hole_at_eof | |
&& ftruncate (dest_desc, n_read) < 0)) | |
{ | |
@@ -1190,6 +1417,15 @@ copy_reg (char const *src_name, char con | |
return_val = false; | |
goto close_src_and_dst_desc; | |
} | |
+ | |
+ /* BEGIN progress mod */ | |
+ if (progress) { | |
+ int i; | |
+ for ( i = 0; i < 6; i++ ) | |
+ free ( cProgressField[i] ); | |
+ free ( cProgressField ); | |
+ } | |
+ /* END progress mod */ | |
} | |
preserve_metadata: | |
@@ -1290,6 +1526,7 @@ close_src_desc: | |
free (buf_alloc); | |
free (name_alloc); | |
+ | |
return return_val; | |
} | |
diff -rup coreutils-8.23/src/copy.h coreutils-8.23-patched/src/copy.h | |
--- coreutils-8.23/src/copy.h 2014-07-11 05:00:07.000000000 -0600 | |
+++ coreutils-8.23-patched/src/copy.h 2015-04-11 16:15:00.000000000 -0600 | |
@@ -231,6 +231,9 @@ struct cp_options | |
Create destination directories as usual. */ | |
bool symbolic_link; | |
+ /* If true, draw a nice progress bar on screen */ | |
+ bool progress_bar; | |
+ | |
/* If true, do not copy a nondirectory that has an existing destination | |
with the same or newer modification time. */ | |
bool update; | |
@@ -289,4 +292,16 @@ void cp_options_default (struct cp_optio | |
bool chown_failure_ok (struct cp_options const *) _GL_ATTRIBUTE_PURE; | |
mode_t cached_umask (void); | |
+ | |
+/* BEGIN OF PROGRESS MOD */ | |
+int file_size_format ( char * _cDst, long _lSize, int _iCounter ); | |
+ | |
+long g_iTotalSize; | |
+long g_iTotalWritten; | |
+int g_iFilesCopied; | |
+struct timeval g_oStartTime; | |
+int g_iTotalFiles; | |
+bool progress; | |
+/* END OF PROGRESS MOD */ | |
+ | |
#endif | |
diff -rup coreutils-8.23/src/cp.c coreutils-8.23-patched/src/cp.c | |
--- coreutils-8.23/src/cp.c 2014-07-13 16:09:52.000000000 -0600 | |
+++ coreutils-8.23-patched/src/cp.c 2015-04-11 16:18:17.000000000 -0600 | |
@@ -140,6 +140,7 @@ static struct option const long_opts[] = | |
{"symbolic-link", no_argument, NULL, 's'}, | |
{"target-directory", required_argument, NULL, 't'}, | |
{"update", no_argument, NULL, 'u'}, | |
+ {"progress-bar", no_argument, NULL, 'g'}, | |
{"verbose", no_argument, NULL, 'v'}, | |
{GETOPT_SELINUX_CONTEXT_OPTION_DECL}, | |
{GETOPT_HELP_OPTION_DECL}, | |
@@ -179,6 +180,7 @@ Copy SOURCE to DEST, or multiple SOURCE( | |
-f, --force if an existing destination file cannot be\n\ | |
opened, remove it and try again (this option\n\ | |
is ignored when the -n option is also used)\n\ | |
+ -g, --progress-bar add a progress bar\n\ | |
-i, --interactive prompt before overwrite (overrides a previous -n\ | |
\n\ | |
option)\n\ | |
@@ -625,6 +627,72 @@ do_copy (int n_files, char **file, const | |
quote (file[n_files - 1])); | |
} | |
+ struct timeval start_time; | |
+ if (progress) { | |
+ /* BEGIN progress mod */ | |
+ g_iTotalSize = 0; | |
+ g_iTotalFiles = 0; | |
+ g_iFilesCopied = 0; | |
+ g_iTotalWritten = 0; | |
+ | |
+ /* save time */ | |
+ gettimeofday ( & start_time, NULL ); | |
+ g_oStartTime = start_time; | |
+ | |
+ printf ( "Calculating total size... \r" ); | |
+ fflush ( stdout ); | |
+ long iTotalSize = 0; | |
+ int iFiles = n_files; | |
+ if ( ! target_directory ) | |
+ iFiles = n_files - 1; | |
+ int j; | |
+ | |
+ /* how many files are we copying */ | |
+ char command[1024]; | |
+ sprintf( command, "find \"%s\" -type f | wc -l", file[0]); | |
+ FILE *fp ; | |
+ char output[1024]; | |
+ fp = popen(command,"r"); | |
+ if ( fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) | |
+ printf("failed to run find.\n"); | |
+ else | |
+ g_iTotalFiles = atoi( output ) ; | |
+ | |
+ for (j = 0; j < iFiles; j++) | |
+ { | |
+ /* call du -s for each file */ | |
+ /* create command */ | |
+ char command[1024]; | |
+ sprintf ( command, "du -s \"%s\"", file[j] ); | |
+ /* TODO: replace all quote signs in file[i] */ | |
+ | |
+ FILE *fp; | |
+ char output[1024]; | |
+ | |
+ /* run command */ | |
+ fp = popen(command, "r"); | |
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) { | |
+ printf("failed to run du.\n" ); | |
+ } | |
+ else | |
+ { | |
+ /* isolate size */ | |
+ strchr ( output, '\t' )[0] = '\0'; | |
+ iTotalSize += atol ( output ); | |
+ | |
+ printf ( "Calculating total size... %ld\r", iTotalSize ); | |
+ fflush ( stdout ); | |
+ } | |
+ | |
+ /* close */ | |
+ pclose(fp); | |
+ } | |
+ g_iTotalSize = iTotalSize; | |
+ /* END progress mod */ | |
+ } | |
+ | |
+ | |
+ | |
if (target_directory) | |
{ | |
/* cp file1...filen edir | |
@@ -767,6 +835,47 @@ do_copy (int n_files, char **file, const | |
ok = copy (source, new_dest, 0, x, &unused, NULL); | |
} | |
+ if (progress) { | |
+ /* BEGIN progress mod */ | |
+ /* remove everything */ | |
+ int i; | |
+ if ( g_iTotalFiles > 1 ) | |
+ { | |
+ for ( i = 0; i < 6; i++ ) | |
+ printf ( "\033[K\n" ); | |
+ printf ( "\r\033[6A" ); | |
+ } | |
+ else | |
+ { | |
+ for ( i = 0; i < 3; i++ ) | |
+ printf ( "\033[K\n" ); | |
+ printf ( "\r\033[3A" ); | |
+ } | |
+ | |
+ /* save time */ | |
+ struct timeval end_time; | |
+ gettimeofday ( & end_time, NULL ); | |
+ int usec_elapsed = end_time.tv_usec - start_time.tv_usec; | |
+ double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
+ sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec ); | |
+ | |
+ /* get total size */ | |
+ char sTotalWritten[20]; | |
+ file_size_format ( sTotalWritten, g_iTotalSize, 1 ); | |
+ /* TODO: using g_iTotalWritten would be more correct, but is less accurate */ | |
+ | |
+ /* calculate speed */ | |
+ int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed ); | |
+ char s_copy_speed[20]; | |
+ file_size_format ( s_copy_speed, copy_speed, 1 ); | |
+ | |
+ /* good-bye message */ | |
+ printf ( "%d files (%s) copied in %.1f seconds (%s/s).\n", g_iFilesCopied, sTotalWritten, | |
+ sec_elapsed, s_copy_speed ); | |
+ /* END progress mod */ | |
+ } | |
+ | |
+ | |
return ok; | |
} | |
@@ -801,6 +910,7 @@ cp_option_init (struct cp_options *x) | |
x->recursive = false; | |
x->sparse_mode = SPARSE_AUTO; | |
x->symbolic_link = false; | |
+ x->progress_bar = false; | |
x->set_mode = false; | |
x->mode = 0; | |
@@ -943,7 +1053,7 @@ main (int argc, char **argv) | |
we'll actually use backup_suffix_string. */ | |
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); | |
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ", | |
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ", | |
long_opts, NULL)) | |
!= -1) | |
{ | |
@@ -1000,6 +1110,10 @@ main (int argc, char **argv) | |
x.unlink_dest_after_failed_open = true; | |
break; | |
+ case 'g': | |
+ progress = true; | |
+ break; | |
+ | |
case 'H': | |
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; | |
break; | |
diff -rup coreutils-8.23/src/mv.c coreutils-8.23-patched/src/mv.c | |
--- coreutils-8.23/src/mv.c 2014-07-11 05:00:07.000000000 -0600 | |
+++ coreutils-8.23-patched/src/mv.c 2015-04-11 16:19:18.000000000 -0600 | |
@@ -65,6 +65,7 @@ static struct option const long_options[ | |
{"target-directory", required_argument, NULL, 't'}, | |
{"update", no_argument, NULL, 'u'}, | |
{"verbose", no_argument, NULL, 'v'}, | |
+ {"progress-ar", no_argument, NULL, 'g'}, | |
{GETOPT_HELP_OPTION_DECL}, | |
{GETOPT_VERSION_OPTION_DECL}, | |
{NULL, 0, NULL, 0} | |
@@ -164,10 +165,98 @@ target_directory_operand (char const *fi | |
static bool | |
do_move (const char *source, const char *dest, const struct cp_options *x) | |
{ | |
+ | |
+ struct timeval start_time; | |
+ | |
+ if(progress) { | |
+ /* BEGIN progress mod */ | |
+ g_iTotalSize = 0; | |
+ g_iFilesCopied = 0; | |
+ g_iTotalWritten = 0; | |
+ | |
+ gettimeofday (& start_time, NULL); | |
+ g_oStartTime = start_time; | |
+ | |
+ printf ("Calculating total size... \r"); | |
+ fflush (stdout); | |
+ long iTotalSize = 0; | |
+ /* call du -s for each file */ | |
+ /* create command */ | |
+ char command[1024]; | |
+ sprintf ( command, "du -s \"%s\"", source ); | |
+ /* TODO: replace all quote signs in file[i] */ | |
+ | |
+ FILE *fp; | |
+ char output[1024]; | |
+ | |
+ /* run command */ | |
+ fp = popen(command, "r"); | |
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) { | |
+ printf("failed to run du.\n" ); | |
+ } | |
+ else | |
+ { | |
+ /* isolate size */ | |
+ strchr ( output, '\t' )[0] = '\0'; | |
+ iTotalSize += atol ( output ); | |
+ printf ( "Calculating total size... %ld\r", iTotalSize ); | |
+ fflush ( stdout ); | |
+ } | |
+ | |
+ /* close */ | |
+ pclose(fp); | |
+ g_iTotalSize = iTotalSize; | |
+ /* END progress mod */ | |
+ | |
+ } | |
+ | |
+ | |
+ | |
bool copy_into_self; | |
bool rename_succeeded; | |
bool ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded); | |
+ if (progress) { | |
+ /* BEGIN progress mod */ | |
+ /* remove everything */ | |
+ int i; | |
+ if ( g_iTotalFiles > 1 ) | |
+ { | |
+ for ( i = 0; i < 6; i++ ) | |
+ printf ( "\033[K\n" ); | |
+ printf ( "\r\033[6A" ); | |
+ } | |
+ else | |
+ { | |
+ for ( i = 0; i < 3; i++ ) | |
+ printf ( "\033[K\n" ); | |
+ printf ( "\r\033[3A" ); | |
+ } | |
+ | |
+ /* save time */ | |
+ struct timeval end_time; | |
+ gettimeofday ( & end_time, NULL ); | |
+ int usec_elapsed = end_time.tv_usec - start_time.tv_usec; | |
+ double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
+ sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec ); | |
+ | |
+ /* get total size */ | |
+ char sTotalWritten[20]; | |
+ file_size_format ( sTotalWritten, g_iTotalSize, 1 ); | |
+ /* TODO: using g_iTotalWritten would be more correct, but is less accurate */ | |
+ | |
+ /* calculate speed */ | |
+ int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed ); | |
+ char s_copy_speed[20]; | |
+ file_size_format ( s_copy_speed, copy_speed, 1 ); | |
+ | |
+ /* good-bye message */ | |
+ printf ( "%d files (%s) moved in %.1f seconds (%s/s).\n", g_iFilesCopied, sTotalWritten, | |
+ sec_elapsed, s_copy_speed ); | |
+ /* END progress mod */ | |
+ } | |
+ | |
+ | |
if (ok) | |
{ | |
char const *dir_to_remove; | |
@@ -302,6 +391,7 @@ Rename SOURCE to DEST, or move SOURCE(s) | |
\n\ | |
-b like --backup but does not accept an argument\n\ | |
-f, --force do not prompt before overwriting\n\ | |
+ -g, --progress-bar add progress-bar\n\ | |
-i, --interactive prompt before overwrite\n\ | |
-n, --no-clobber do not overwrite an existing file\n\ | |
If you specify more than one of -i, -f, -n, only the final one takes effect.\n\ | |
@@ -373,7 +463,7 @@ main (int argc, char **argv) | |
we'll actually use backup_suffix_string. */ | |
backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); | |
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL)) | |
+ while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, NULL)) | |
!= -1) | |
{ | |
switch (c) | |
@@ -419,6 +509,11 @@ main (int argc, char **argv) | |
case 'v': | |
x.verbose = true; | |
break; | |
+ | |
+ case 'g': | |
+ progress = true; | |
+ break; | |
+ | |
case 'S': | |
make_backups = true; | |
backup_suffix_string = optarg; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is amazing stuff, keep up the good work! I've got a 500GB drive that I'm in the process of recovering, and I really don't feel like having no feedback during the impending copy.