diff -urN coreutils-6.10/src/copy.c coreutils-6.10-patched/src/copy.c --- coreutils-6.10/src/copy.c 2008-01-06 09:29:11.000000000 +1030 +++ coreutils-6.10-patched/src/copy.c 2009-02-20 14:49:18.000000000 +1030 @@ -170,6 +170,173 @@ return ok; } +/* This function displays a progress bar + if the progress flag is set. + It uses a 1:2 scales. */ + +void +progress_bar_print(size_t dim_tot, size_t dim_cur) +{ + int i; + size_t per_tot, per_cur, per_tot_scl, per_cur_scl; + + /* Check: + if filesize is less than 1 KiB, exit */ + if (! (dim_tot / 1024)) + return; + /* display size in KiB */ + dim_tot /= 1024; + dim_cur /= 1024; + + per_tot = 100; + /* total percentage */ + per_cur = (per_tot * dim_cur) / dim_tot; + /* current percentage */ + + /* 1:2 scale */ + per_tot_scl = per_tot / 2; + per_cur_scl = per_cur / 2; + + /* Refresh the bar indicator */ + printf("\r ["); + + /* Display the bar indicator: + - = : indicates a part the bar + - > : indicates the end of the bar + (if it's finish, convert '>' to '='*/ + for (i = 0; i < per_cur_scl; i++) + if ((i + 1) == per_cur_scl) + if (per_cur_scl == 50) + putchar('='); + else + putchar('>'); + else + putchar('='); + + for (i = per_cur_scl; i < per_tot_scl; i++) + putchar(' '); + + printf("] %3d\% | ", per_cur); + fflush(stdout); +} + +size_t speed = 0; +float speed_last = 0; + +/* This function displays speed copy + if the progress flag is set. */ + +void +progress_bar_print_speed(struct tm *tm_init) +{ + time_t time_cur; + struct tm tm_cur; + float speed_, speed_si = (float) 1024; + + time_cur = time(NULL); + tm_cur = *(struct tm *) localtime(&time_cur); + + speed_ = (float) speed; + + if (tm_init->tm_sec == tm_cur.tm_sec) + { + if (tm_init->tm_sec == 60) + tm_init->tm_sec = 0; + else + tm_init->tm_sec += 1; + + speed_last = speed_; + speed = 0; + } + else if (tm_init->tm_sec != tm_cur.tm_sec + 1) + /* If the disk crashes, again */ + tm_init->tm_sec = tm_cur.tm_sec + 1; + + if (speed_last == 0) + speed_last = speed_; + + /* bytes in KiB */ + printf("%12.02f KiB/s | ", speed_last / speed_si, + tm_init->tm_hour, tm_init->tm_min, tm_init->tm_sec, + tm_cur.tm_hour, tm_cur.tm_min, tm_cur.tm_sec); + + + fflush(stdout); +} + +/* This function displays size source/dest files copy + if the progress flag is set. */ + +void +progress_bar_print_size(size_t dim_tot, size_t dim_cur) +{ + char dim_type; + float dim_tot_, dim_cur_, dim_si = (float) 1024; + + dim_tot_ = (float) dim_tot; + dim_cur_ = (float) dim_cur; + + /* display size in KiB */ + dim_tot_ /= dim_si; + dim_cur_ /= dim_si; + dim_type = 'k'; + /* If possible, convert in MiB */ + if (dim_tot / (1024 * 1024)) + { + dim_tot_ /= dim_si; + dim_cur_ /= dim_si; + dim_type = 'M'; + + /* If possible, convert in GiB */ + if (dim_tot / (1024 * 1024 * 1024)) + { + dim_tot_ /= dim_si; + dim_cur_ /= dim_si; + dim_type = 'G'; + } + } + + printf("%10.02f/%.02f %s | ", dim_cur_, dim_tot_, + dim_type == 'k' ? "KiB" : dim_type == 'M' ? "MiB" : "GiB"); + + fflush(stdout); +} + +/* This function displays ETA copy + if the progress flag is set. */ + +void +progress_bar_print_eta(size_t dim_tot, size_t dim_cur) +{ + size_t dim_diff = 0, + speed_last_ = (size_t) speed_last, + eta = 0; + int sec, min, hour; + + /* Convert in KiB */ + dim_tot /= 1024; + dim_cur /= 1024; + + dim_diff = dim_tot - dim_cur; + speed_last_ /= 1024; + + /* speed_last_ : 1 sec = dim_diff : eta + + eta = 1 * dim_diff + ------------ + speed_last_ */ + + eta = dim_diff / speed_last_; + + min = eta / 60; + sec = eta - (min * 60); + hour = min / 60; + + printf("ETA: %02d:%02d:%02d", hour, min, sec); + + fflush(stdout); +} + /* Set the owner and owning group of DEST_DESC to the st_uid and st_gid fields of SRC_SB. If DEST_DESC is undefined (-1), set the owner and owning group of DST_NAME instead; for @@ -482,6 +649,13 @@ bool last_write_made_hole = false; bool make_holes = false; + /* Progress bar */ + size_t dim_tot = 0, + dim_cur = 0; + /* speed time */ + time_t time_init; + struct tm tm_init; + if (S_ISREG (sb.st_mode)) { /* Even with --sparse=always, try to create holes only @@ -537,6 +711,13 @@ buf_alloc = xmalloc (buf_size + buf_alignment_slop); buf = ptr_align (buf_alloc, buf_alignment); + if (x->progress) + { + time_init = time(NULL); + tm_init = *(struct tm *) localtime(&time_init); + tm_init.tm_sec += 1; + } + for (;;) { word *wp = NULL; @@ -552,6 +733,7 @@ return_val = false; goto close_src_and_dst_desc; } + if (n_read == 0) break; @@ -611,6 +793,28 @@ return_val = false; goto close_src_and_dst_desc; } + + /* if the progress flag is set, it uses a progress bar */ + if (x->progress) + { + dim_tot = src_sb->st_size; + dim_cur += n; + + /* print progress bar */ + progress_bar_print(dim_tot, dim_cur); + + speed += n; + + /* print progress bar speed */ + progress_bar_print_speed(&tm_init); + + /* print progress bar size */ + progress_bar_print_size(dim_tot, dim_cur); + + /* print progress bar ETA */ + progress_bar_print_eta(dim_tot, dim_cur); + } + last_write_made_hole = false; /* A short read on a regular file means EOF. */ @@ -619,6 +823,9 @@ } } + if (x->progress) + putchar('\n'); + /* If the file ends with a `hole', we need to do something to record the length of the file. On modern systems, calling ftruncate does the job. On systems without native ftruncate support, we have to diff -urN coreutils-6.10/src/copy.h coreutils-6.10-patched/src/copy.h --- coreutils-6.10/src/copy.h 2008-01-06 09:28:25.000000000 +1030 +++ coreutils-6.10-patched/src/copy.h 2009-02-20 14:50:44.000000000 +1030 @@ -82,6 +82,9 @@ { enum backup_type backup_type; + /* If true, Display a progress bar */ + bool progress; + /* How to handle symlinks in the source. */ enum Dereference_symlink dereference; diff -urN coreutils-6.10/src/cp.c coreutils-6.10-patched/src/cp.c --- coreutils-6.10/src/cp.c 2008-01-11 21:49:53.000000000 +1030 +++ coreutils-6.10-patched/src/cp.c 2009-02-20 14:53:46.000000000 +1030 @@ -124,6 +124,7 @@ { {"archive", no_argument, NULL, 'a'}, {"backup", optional_argument, NULL, 'b'}, + {"progress", no_argument, NULL, 'B'}, {"copy-contents", no_argument, NULL, COPY_CONTENTS_OPTION}, {"dereference", no_argument, NULL, 'L'}, {"force", no_argument, NULL, 'f'}, @@ -177,6 +178,7 @@ -a, --archive same as -dpR\n\ --backup[=CONTROL] make a backup of each existing destination file\n\ -b like --backup but does not accept an argument\n\ + -B --progress show a progress bar (file > 1 kB)\n\ --copy-contents copy contents of special files when recursive\n\ -d same as --no-dereference --preserve=links\n\ "), stdout); @@ -760,6 +762,7 @@ { cp_options_default (x); x->copy_as_regular = true; + x->progress = false; x->dereference = DEREF_UNDEFINED; x->unlink_dest_before_opening = false; x->unlink_dest_after_failed_open = false; @@ -909,7 +912,7 @@ we'll actually use backup_suffix_string. */ backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); - while ((c = getopt_long (argc, argv, "abdfHilLprst:uvxPRS:T", + while ((c = getopt_long (argc, argv, "abBdfHilLprst:uvxPRS:T", long_opts, NULL)) != -1) { @@ -936,6 +939,10 @@ version_control_string = optarg; break; + case 'B': + x.progress = true; + break; + case COPY_CONTENTS_OPTION: copy_contents = true; break;