mirror of
https://github.com/jarun/advcpmv.git
synced 2026-08-12 03:50:50 +02:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a574b81d8 | |||
| 14e3206e79 | |||
| 21556b579c | |||
| 8dc8419e5d | |||
| 95b3ff2fbc | |||
| 7ad6ab4d6c | |||
| 7312ed3039 | |||
| 1635eb96e5 | |||
| 0df9ccf0f4 | |||
| 3d6c670089 | |||
| 1e039bdd64 | |||
| 1e2b1c6b74 | |||
| ba7b157dd8 | |||
| 42cadf5b79 | |||
| a1f8b505e6 | |||
| 2961dc3ec8 | |||
| 4fe520c882 | |||
| 066ba086bf | |||
| 69d2f9d3c7 | |||
| 0064105957 | |||
| 2253f7a380 | |||
| d63f908a3a | |||
| 35988dc8d7 | |||
| 2845cfcc0d | |||
| 2eec987a8c | |||
| b6ceba0130 | |||
| 376337eea1 | |||
| ea268d870b | |||
| 195034f1cd | |||
| 9121e8dc4f | |||
| 32275808ba | |||
| a047797e92 | |||
| dff0994e1f | |||
| 096b047523 | |||
| 74254ddf1c | |||
| c878eab0f8 | |||
| f231f05455 | |||
| bb5b892ace | |||
| f854b119e9 | |||
| dfb9623dcb | |||
| 7fe882ec46 | |||
| b62cfd957e | |||
| 2532fc3ca3 | |||
| 46703ea4f5 | |||
| fb08e1aba6 | |||
| 8a8af288bb | |||
| 30b6aff569 | |||
| 1e12a7c529 | |||
| 53a449f84c | |||
| b79170e69b | |||
| ae89bfdb24 | |||
| d09e9fb8b6 | |||
| d8013b9f35 | |||
| 2f468f6896 | |||
| 60daf2a133 | |||
| a054d7d892 | |||
| 72b2b58117 | |||
| ac2cac8d4e | |||
| 54f1b797db | |||
| 801478c31a | |||
| cf51b9bd8b | |||
| c8149fab75 | |||
| 2fc918bd98 | |||
| a620f86965 | |||
| 04bae585e6 | |||
| 3ac56d553f | |||
| e529e310ea | |||
| a1cc785674 | |||
| aa4d645a11 | |||
| 24ad5c292c | |||
| edec49ec6f | |||
| 7e2df2e0b7 | |||
| c9d7d6779f | |||
| 3b2fdc6f42 | |||
| d337f35f5b | |||
| 9d614d1883 | |||
| 4989cfaf78 | |||
| 4e9c8bc2b4 | |||
| 17957ce329 | |||
| 4839af6e65 | |||
| 47dbf85998 | |||
| 4144872297 | |||
| 3ef18c8f20 | |||
| 35d117d60b | |||
| 39c571c505 | |||
| 8e1c0d4f8a | |||
| fd0fc50b1a | |||
| e81fa04c0a |
@@ -1,4 +1,6 @@
|
||||
## Advanced Copy ##
|
||||

|
||||
|
||||
## Advanced Copy
|
||||
|
||||
Advanced Copy is a mod for the GNU cp and GNU mv tools which adds a progress bar and provides some info on what's going on. It was written by Florian Zwicke and released under the GPL.
|
||||
|
||||
@@ -8,40 +10,69 @@ advcpmv-0.5-8.21.patch was the last patch released by the author (on February 14
|
||||
|
||||
## Build instructions
|
||||
|
||||
The latest GNU Core Utilities source can be found here: https://ftp.gnu.org/gnu/coreutils/
|
||||
Requires the following dependencies:
|
||||
|
||||
- patch
|
||||
- gcc
|
||||
|
||||
Run the following command to download, patch, compile coreutils and generate the files: `./advcpmv/advcp` and `./advcpmv/advmv`.
|
||||
|
||||
Bash:
|
||||
|
||||
```
|
||||
wget http://ftp.gnu.org/gnu/coreutils/coreutils-8.32.tar.xz
|
||||
tar xvJf coreutils-8.32.tar.xz
|
||||
cd coreutils-8.32/
|
||||
wget https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-0.8-8.32.patch
|
||||
patch -p1 -i advcpmv-0.8-8.32.patch
|
||||
./configure
|
||||
make
|
||||
curl https://raw.githubusercontent.com/jarun/advcpmv/master/install.sh --create-dirs -o ./advcpmv/install.sh && (cd advcpmv && sh install.sh)
|
||||
```
|
||||
|
||||
Fish:
|
||||
|
||||
```
|
||||
curl https://raw.githubusercontent.com/jarun/advcpmv/master/install.sh --create-dirs -o ./advcpmv/install.sh; and begin; cd advcpmv; and sh install.sh; end
|
||||
```
|
||||
|
||||
To install an older version than the latest one, you can specify the version by passing it as an argument to the install script (at the end of the command, before the closing parenthesis). For example, if you want to install `advcpmv-0.8-8.32.patch` you would modify the command above like so.
|
||||
|
||||
```
|
||||
... sh install.sh 0.8 8.32 ...
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Change your behaviour
|
||||
|
||||
You can install the binaries and use `cpg -g` and `mvg -g` instead of cp and mv
|
||||
You can install the binaries and use `cpg -g` and `mvg -g` instead of cp and mv:
|
||||
|
||||
```
|
||||
sudo mv ./src/cp /usr/local/bin/cpg
|
||||
sudo mv ./src/mv /usr/local/bin/mvg
|
||||
sudo mv ./advcpmv/advcp /usr/local/bin/cpg
|
||||
sudo mv ./advcpmv/advmv /usr/local/bin/mvg
|
||||
```
|
||||
|
||||
Progress bar does not work with reflink (introduced v9.0 onwards). So reflink is disabled if using progress bar, left unchanged otherwise.
|
||||
|
||||
### Alias
|
||||
|
||||
You can install the binaries and create aliases for bash (or whatever you use)
|
||||
|
||||
```
|
||||
sudo mv ./src/cp /usr/local/bin/advcp
|
||||
sudo mv ./src/mv /usr/local/bin/advmv
|
||||
echo alias cp '/usr/local/bin/advcp -g' >> ~/.bashrc
|
||||
echo alias mv '/usr/local/bin/advmv -g' >> ~/.bashrc
|
||||
sudo mv ./advcpmv/advcp /usr/local/bin/
|
||||
sudo mv ./advcpmv/advmv /usr/local/bin/
|
||||
```
|
||||
|
||||
Bash:
|
||||
|
||||
```
|
||||
echo -e 'alias cp=\x27/usr/local/bin/cpg -g\x27' >> ~/.bashrc
|
||||
echo -e 'alias mv=\x27/usr/local/bin/mvg -g\x27' >> ~/.bashrc
|
||||
```
|
||||
|
||||
Fish:
|
||||
|
||||
```
|
||||
echo "alias cp '/usr/local/bin/advcp -g'" >> ~/.config/fish/config.fish
|
||||
echo "alias mv '/usr/local/bin/advmv -g'" >> ~/.config/fish/config.fish
|
||||
```
|
||||
|
||||
```
|
||||
## Upstream merge
|
||||
|
||||
The original author sent the patch to the team, that maintains the GNU CoreUtils. They won't merge this patch, because mv and cp are feature complete.
|
||||
```
|
||||
|
||||
+279
-111
@@ -1,10 +1,11 @@
|
||||
diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
--- coreutils-8.32/src/copy.c 2020-01-01 15:13:12.000000000 +0100
|
||||
+++ coreutils-8.32-patched/src/copy.c 2021-08-11 19:48:19.008225844 +0200
|
||||
@@ -129,6 +129,72 @@
|
||||
+++ coreutils-8.32-patched/src/copy.c 2022-04-03 21:03:04.869415222 +0200
|
||||
@@ -129,6 +129,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
@@ -13,7 +14,69 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+/* Begin progress Mod*/
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void file_progress_bar ( char * _cDest, int _iBarLength, long _lProgress, long _lTotal )
|
||||
+{
|
||||
+ double dPercent = (double) _lProgress / (double) _lTotal * 100.f;
|
||||
@@ -68,13 +131,11 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+ 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
|
||||
|
||||
@@ -258,10 +324,11 @@
|
||||
@@ -258,18 +385,125 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
|
||||
@@ -88,13 +149,22 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
{
|
||||
*last_write_made_hole = false;
|
||||
*total_n_read = 0;
|
||||
@@ -270,6 +337,85 @@
|
||||
bool make_hole = false;
|
||||
off_t psize = 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 */
|
||||
+
|
||||
while (max_n_read)
|
||||
{
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* BEGIN progress mod */
|
||||
+ /* update countdown */
|
||||
+ s_progress->iCountDown--;
|
||||
+ char * sProgressBar = s_progress->cProgressField[5];
|
||||
@@ -108,6 +178,7 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+ 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 );
|
||||
@@ -121,20 +192,38 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+
|
||||
+ /* 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 min_remaining = sec_remaining / 60;
|
||||
+ sec_remaining -= min_remaining * 60;
|
||||
+ int hours_remaining = min_remaining / 60;
|
||||
+ min_remaining -= hours_remaining * 60;
|
||||
+ int sec_fremaining = ( int ) ( ( double ) isec_felapsed / cur_fsize
|
||||
+ * g_iFTotalSize ) - isec_felapsed;
|
||||
+ /* print out */
|
||||
+ sprintf ( s_progress->cProgressField[3],
|
||||
+ move_mode
|
||||
+ ? "Moving at %s/s (about %uh %um %us remaining)"
|
||||
+ : "Copying at %s/s (about %uh %um %us remaining)", s_copy_speed,
|
||||
+ hours_remaining, min_remaining, sec_remaining );
|
||||
+
|
||||
+ char f_ttime[20];
|
||||
+ char f_ftime[20];
|
||||
+ format_time(f_ttime, sec_remaining, true);
|
||||
+ format_time(f_ftime, sec_fremaining, true);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ if ( g_iTotalFiles > 1 )
|
||||
+ {
|
||||
+ /* global progress bar */
|
||||
@@ -168,13 +257,13 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+ printf ( "\r\033[3A" );
|
||||
+ fflush ( stdout );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
ssize_t n_read = read (src_fd, buf, MIN (max_n_read, buf_size));
|
||||
if (n_read < 0)
|
||||
{
|
||||
@@ -354,6 +500,14 @@
|
||||
@@ -354,6 +588,14 @@
|
||||
certain files in /proc or /sys with linux kernels. */
|
||||
}
|
||||
|
||||
@@ -189,7 +278,7 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
/* 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))
|
||||
@@ -420,9 +574,11 @@
|
||||
@@ -420,9 +662,11 @@
|
||||
static bool
|
||||
extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size,
|
||||
size_t hole_size, off_t src_total_size,
|
||||
@@ -203,7 +292,7 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
{
|
||||
struct extent_scan scan;
|
||||
off_t last_ext_start = 0;
|
||||
@@ -553,10 +709,16 @@
|
||||
@@ -553,10 +797,16 @@
|
||||
last_ext_len = ext_len;
|
||||
bool read_hole;
|
||||
|
||||
@@ -218,11 +307,11 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
- true, src_name, dst_name, ext_len, &n_read,
|
||||
- &read_hole))
|
||||
+ true, move_mode, src_name, dst_name, ext_len,
|
||||
+ &n_read, &read_hole,&s_progress))
|
||||
+ &n_read, &read_hole, &s_progress))
|
||||
goto fail;
|
||||
|
||||
dest_pos = ext_start + n_read;
|
||||
@@ -1305,6 +1467,71 @@
|
||||
@@ -1305,6 +1555,75 @@
|
||||
buf_alloc = xmalloc (buf_size + buf_alignment);
|
||||
buf = ptr_align (buf_alloc, buf_alignment);
|
||||
|
||||
@@ -261,7 +350,11 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
+ 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 );
|
||||
+ int sum_length = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ cProgressField[1][sum_length] = ' ';
|
||||
+ }
|
||||
+
|
||||
@@ -294,7 +387,7 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
if (sparse_src)
|
||||
{
|
||||
bool normal_copy_required;
|
||||
@@ -1316,7 +1543,9 @@
|
||||
@@ -1316,7 +1635,9 @@
|
||||
if (extent_copy (source_desc, dest_desc, buf, buf_size, hole_size,
|
||||
src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
@@ -305,11 +398,13 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
goto preserve_metadata;
|
||||
|
||||
if (! normal_copy_required)
|
||||
@@ -1328,11 +1557,12 @@
|
||||
@@ -1328,11 +1649,14 @@
|
||||
|
||||
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 ? hole_size : 0,
|
||||
- x->sparse_mode == SPARSE_ALWAYS, src_name, dst_name,
|
||||
@@ -321,22 +416,20 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1343,6 +1573,14 @@
|
||||
@@ -1343,6 +1667,12 @@
|
||||
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:
|
||||
@@ -1716,15 +1954,15 @@
|
||||
@@ -1716,15 +2046,15 @@
|
||||
fprintf (stderr,
|
||||
(x->move_mode || x->unlink_dest_before_opening
|
||||
|| x->unlink_dest_after_failed_open)
|
||||
@@ -357,7 +450,7 @@ diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c
|
||||
|
||||
diff -aur coreutils-8.32/src/copy.h coreutils-8.32-patched/src/copy.h
|
||||
--- coreutils-8.32/src/copy.h 2020-01-01 15:13:12.000000000 +0100
|
||||
+++ coreutils-8.32-patched/src/copy.h 2021-08-11 19:40:37.729820358 +0200
|
||||
+++ coreutils-8.32-patched/src/copy.h 2022-04-03 21:03:04.873415280 +0200
|
||||
@@ -234,6 +234,9 @@
|
||||
Create destination directories as usual. */
|
||||
bool symbolic_link;
|
||||
@@ -368,25 +461,32 @@ diff -aur coreutils-8.32/src/copy.h coreutils-8.32-patched/src/copy.h
|
||||
/* If true, do not copy a nondirectory that has an existing destination
|
||||
with the same or newer modification time. */
|
||||
bool update;
|
||||
@@ -304,4 +307,15 @@
|
||||
@@ -304,4 +307,22 @@
|
||||
bool chown_failure_ok (struct cp_options const *) _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN OF PROGRESS MOD */
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END OF PROGRESS MOD */
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
--- coreutils-8.32/src/cp.c 2020-01-01 15:13:12.000000000 +0100
|
||||
+++ coreutils-8.32-patched/src/cp.c 2021-08-11 19:40:37.729820358 +0200
|
||||
+++ coreutils-8.32-patched/src/cp.c 2022-04-03 21:03:04.873415280 +0200
|
||||
@@ -131,6 +131,7 @@
|
||||
{"symbolic-link", no_argument, NULL, 's'},
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
@@ -395,31 +495,42 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
@@ -170,6 +171,7 @@
|
||||
@@ -170,6 +171,9 @@
|
||||
-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\
|
||||
+ -g, --progress-bar add a progress bar.\n\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -635,6 +637,70 @@
|
||||
@@ -635,6 +639,84 @@
|
||||
die (EXIT_FAILURE, 0, _("target %s is not a directory"),
|
||||
quoteaf (file[n_files - 1]));
|
||||
}
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ /* BEGIN progress mod */
|
||||
+ g_iTotalSize = 0;
|
||||
+ g_iTotalFiles = 0;
|
||||
+ g_iFilesCopied = 0;
|
||||
+ g_iTotalWritten = 0;
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb, &new_dst, forcing))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* save time */
|
||||
+ gettimeofday ( & start_time, NULL );
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ printf ( "Calculating total size... \r" );
|
||||
+ printf ( "calculating total size... \r" );
|
||||
+ fflush ( stdout );
|
||||
+ long iTotalSize = 0;
|
||||
+ int iFiles = n_files;
|
||||
@@ -428,31 +539,36 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
+ 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");
|
||||
+ char fcmd[] = "find";
|
||||
+ fp = spawn(fcmd, (char *[]){ fcmd, file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ g_iTotalFiles = atoi( output ) ;
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ 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");
|
||||
+ char dcmd[] = "du";
|
||||
+ fp = spawn(dcmd, (char *[]){ dcmd, "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du.\n" );
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
@@ -460,26 +576,26 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
+ strchr ( output, '\t' )[0] = '\0';
|
||||
+ iTotalSize += atol ( output );
|
||||
+
|
||||
+ printf ( "Calculating total size... %ld\r", iTotalSize );
|
||||
+ printf ( "calculating total size... %ld\r", iTotalSize );
|
||||
+ fflush ( stdout );
|
||||
+ }
|
||||
+
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+ }
|
||||
+ g_iTotalSize = iTotalSize;
|
||||
+ /* END progress mod */
|
||||
+ g_iTotalSize += iTotalSize;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
|
||||
if (target_directory)
|
||||
{
|
||||
@@ -777,6 +843,46 @@
|
||||
@@ -777,6 +859,56 @@
|
||||
ok = copy (source, new_dest, 0, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* BEGIN progress mod */
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ if ( g_iTotalFiles > 1 )
|
||||
@@ -513,15 +629,25 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
+ 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -812,6 +918,7 @@
|
||||
@@ -812,6 +944,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
@@ -529,7 +655,7 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -950,7 +1057,7 @@
|
||||
@@ -950,7 +1083,7 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
@@ -538,7 +664,7 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1007,6 +1114,10 @@
|
||||
@@ -1007,6 +1140,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
@@ -551,75 +677,103 @@ diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c
|
||||
break;
|
||||
diff -aur coreutils-8.32/src/mv.c coreutils-8.32-patched/src/mv.c
|
||||
--- coreutils-8.32/src/mv.c 2020-01-01 15:13:12.000000000 +0100
|
||||
+++ coreutils-8.32-patched/src/mv.c 2021-08-11 19:40:37.729820358 +0200
|
||||
+++ coreutils-8.32-patched/src/mv.c 2022-04-03 21:03:04.873415280 +0200
|
||||
@@ -66,6 +66,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", no_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-ar", no_argument, NULL, 'g'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -168,10 +169,86 @@
|
||||
static bool
|
||||
do_move (const char *source, const char *dest, const struct cp_options *x)
|
||||
@@ -170,8 +171,130 @@
|
||||
{
|
||||
+ struct timeval start_time;
|
||||
+
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+
|
||||
+ if(progress && x->rename_errno != 0) {
|
||||
+ /* BEGIN progress mod */
|
||||
+ g_iTotalSize = 0;
|
||||
+ g_iFilesCopied = 0;
|
||||
+ g_iTotalWritten = 0;
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ printf ("Calculating total size... \r");
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ char fcmd[] = "find";
|
||||
+ fp = spawn(fcmd, (char *[]){ fcmd, (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ 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");
|
||||
+ char dcmd[] = "du";
|
||||
+ fp = spawn(dcmd, (char *[]){ dcmd, "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ //printf("failed to run du.\n" );
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* isolate size */
|
||||
+ strchr ( output, '\t' )[0] = '\0';
|
||||
+ iTotalSize += atol ( output );
|
||||
+ printf ( "Calculating total size... %ld\r", iTotalSize );
|
||||
+ printf ( "calculating total size... %ld\r", iTotalSize );
|
||||
+ fflush ( stdout );
|
||||
+ }
|
||||
+
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+ g_iTotalSize = iTotalSize;
|
||||
+ /* END progress mod */
|
||||
+
|
||||
+ g_iTotalSize += iTotalSize;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
bool ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* BEGIN progress mod */
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ for ( i = 0; i < limit; i++ )
|
||||
+ printf ( "\033[K\n" );
|
||||
+ printf ( "\r\033[3A" );
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; i++ )
|
||||
+ printf ( "\033[K\n" );
|
||||
+ printf ( "\r\033[3A" );
|
||||
+ }
|
||||
+
|
||||
+ /* save time */
|
||||
+ struct timeval end_time;
|
||||
@@ -638,16 +792,32 @@ diff -aur coreutils-8.32/src/mv.c coreutils-8.32-patched/src/mv.c
|
||||
+ char s_copy_speed[20];
|
||||
+ file_size_format ( s_copy_speed, copy_speed, 1 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* 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 ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -306,6 +383,7 @@
|
||||
@@ -306,6 +429,7 @@
|
||||
\n\
|
||||
-b like --backup but does not accept an argument\n\
|
||||
-f, --force do not prompt before overwriting\n\
|
||||
@@ -655,7 +825,7 @@ diff -aur coreutils-8.32/src/mv.c coreutils-8.32-patched/src/mv.c
|
||||
-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\
|
||||
@@ -361,7 +439,7 @@
|
||||
@@ -361,7 +485,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
@@ -664,15 +834,13 @@ diff -aur coreutils-8.32/src/mv.c coreutils-8.32-patched/src/mv.c
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -407,6 +485,11 @@
|
||||
@@ -407,6 +531,9 @@
|
||||
case 'v':
|
||||
x.verbose = true;
|
||||
break;
|
||||
+
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'S':
|
||||
make_backups = true;
|
||||
backup_suffix = optarg;
|
||||
|
||||
@@ -0,0 +1,959 @@
|
||||
diff -aur coreutils-9.0/src/copy.c coreutils-9.0-patched/src/copy.c
|
||||
--- coreutils-9.0/src/copy.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.0-patched/src/copy.c 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -129,6 +129,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -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 ())
|
||||
@@ -317,8 +453,105 @@
|
||||
surely aligned well. */
|
||||
ssize_t ssize_max = TYPE_MAXIMUM (ssize_t);
|
||||
ptrdiff_t copy_max = MIN (ssize_max, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
+
|
||||
if (n_copied == 0)
|
||||
{
|
||||
/* copy_file_range incorrectly returns 0 when reading from
|
||||
@@ -355,6 +588,14 @@
|
||||
}
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
|
||||
bool make_hole = false;
|
||||
@@ -362,6 +603,104 @@
|
||||
|
||||
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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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 +785,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 +863,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 +939,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 +1729,80 @@
|
||||
buf_alloc = xmalloc (buf_size + buf_alignment);
|
||||
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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1383,15 +1810,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1402,6 +1831,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
diff -aur coreutils-9.0/src/copy.h coreutils-9.0-patched/src/copy.h
|
||||
--- coreutils-9.0/src/copy.h 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.0-patched/src/copy.h 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -236,6 +236,9 @@
|
||||
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;
|
||||
@@ -308,4 +311,22 @@
|
||||
bool chown_failure_ok (struct cp_options const *) _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -aur coreutils-9.0/src/cp.c coreutils-9.0-patched/src/cp.c
|
||||
--- coreutils-9.0/src/cp.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.0-patched/src/cp.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -131,6 +131,7 @@
|
||||
{"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},
|
||||
@@ -170,6 +171,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -634,6 +638,82 @@
|
||||
die (EXIT_FAILURE, 0, _("target %s is not a directory"),
|
||||
quoteaf (file[n_files - 1]));
|
||||
}
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb, &new_dst, forcing))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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)
|
||||
{
|
||||
@@ -781,6 +861,56 @@
|
||||
ok = copy (source, new_dest, 0, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -816,6 +946,9 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+
|
||||
+ x->progress_bar = false;
|
||||
+
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -954,7 +1087,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1011,6 +1145,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1171,6 +1309,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
diff -aur coreutils-9.0/src/mv.c coreutils-9.0-patched/src/mv.c
|
||||
--- coreutils-9.0/src/mv.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.0-patched/src/mv.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -66,6 +66,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", no_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -170,8 +171,128 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -306,6 +427,7 @@
|
||||
\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\
|
||||
@@ -361,7 +483,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- 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)
|
||||
@@ -407,6 +529,9 @@
|
||||
case 'v':
|
||||
x.verbose = true;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'S':
|
||||
make_backups = true;
|
||||
backup_suffix = optarg;
|
||||
@@ -0,0 +1,957 @@
|
||||
diff -aur coreutils-9.1/src/copy.c coreutils-9.1-patched/src/copy.c
|
||||
--- coreutils-9.1/src/copy.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.1-patched/src/copy.c 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -121,6 +121,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -236,14 +363,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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)
|
||||
@@ -253,6 +389,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -291,6 +523,14 @@
|
||||
}
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
|
||||
bool make_hole = false;
|
||||
@@ -298,6 +538,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -385,6 +722,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))
|
||||
@@ -456,9 +801,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -530,10 +877,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, abuf, 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;
|
||||
@@ -1344,8 +1697,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1353,15 +1778,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1372,6 +1799,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
diff -aur coreutils-9.1/src/copy.h coreutils-9.1-patched/src/copy.h
|
||||
--- coreutils-9.1/src/copy.h 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.1-patched/src/copy.h 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -236,6 +236,9 @@
|
||||
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;
|
||||
@@ -313,4 +316,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -aur coreutils-9.1/src/cp.c coreutils-9.1-patched/src/cp.c
|
||||
--- coreutils-9.1/src/cp.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.1-patched/src/cp.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -128,6 +128,7 @@
|
||||
{"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},
|
||||
@@ -167,6 +168,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -640,6 +644,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -779,6 +859,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -814,6 +944,9 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+
|
||||
+ x->progress_bar = false;
|
||||
+
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -952,7 +1085,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1009,6 +1143,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1159,6 +1297,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
diff -aur coreutils-9.1/src/mv.c coreutils-9.1-patched/src/mv.c
|
||||
--- coreutils-9.1/src/mv.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.1-patched/src/mv.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -64,6 +64,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", no_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -155,9 +156,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -255,6 +377,7 @@
|
||||
\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\
|
||||
@@ -311,7 +434,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- 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)
|
||||
@@ -347,6 +470,9 @@
|
||||
case 'v':
|
||||
x.verbose = true;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'S':
|
||||
make_backups = true;
|
||||
backup_suffix = optarg;
|
||||
@@ -0,0 +1,932 @@
|
||||
--- coreutils-9.11/src/copy-file-data.c 2026-07-23 09:47:29.805900811 -0600
|
||||
+++ coreutils-9.11k/src/copy-file-data.c 2026-07-23 09:47:29.837329370 -0600
|
||||
@@ -28,6 +28,153 @@
|
||||
#include "full-write.h"
|
||||
#include "ioblksize.h"
|
||||
|
||||
+#include <sys/ioctl.h>
|
||||
+#include <termios.h>
|
||||
+
|
||||
+/* BEGIN progress mod */
|
||||
+
|
||||
+/* The progress globals (g_iTotalSize, g_iTotalWritten, ...) count KiB, not
|
||||
+ bytes, because the prescan in cp.c/mv.c derives totals from "du -s" which
|
||||
+ reports KiB blocks. Divide a raw byte count by this before accumulating. */
|
||||
+#define PROGRESS_BYTES_PER_KIB 1024
|
||||
+
|
||||
+/* Each progress row is iBarLength chars wide. The right-aligned size readout
|
||||
+ produced by file_size_format ("542.3 MiB") is written starting this many
|
||||
+ columns from the end of the row so it sits just left of the bar tail. */
|
||||
+#define PROGRESS_SIZE_COL 21
|
||||
+
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+/* Progress state for the file currently being copied. Set up in
|
||||
+ copy_file_data (which has the cp_options and source size) and read by
|
||||
+ sparse_copy/lseek_copy while they run. Only touched when the global
|
||||
+ progress flag is set. */
|
||||
+static struct progress_status g_s_progress;
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ /* hours */
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ /* minutes */
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ /* seconds */
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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 */
|
||||
+
|
||||
/* Result of infer_scantype when it returns LSEEK_SCANTYPE. */
|
||||
struct scan_inference
|
||||
{
|
||||
@@ -117,6 +264,16 @@
|
||||
{
|
||||
count_t total_n_read = 0;
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ gettimeofday ( & g_oFStartTime, NULL );
|
||||
+ g_iFTotalWritten = 0;
|
||||
+ struct stat st;
|
||||
+ stat(src_name, &st);
|
||||
+ g_iFTotalSize = st.st_size / PROGRESS_BYTES_PER_KIB;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (debug->sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
debug->sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && debug->sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -131,6 +288,100 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update countdown */
|
||||
+ g_s_progress.iCountDown--;
|
||||
+ char * sProgressBar = g_s_progress.cProgressField[5];
|
||||
+ if ( g_s_progress.iCountDown < 0 )
|
||||
+ g_s_progress.iCountDown = 100;
|
||||
+
|
||||
+ /* just print one line with the percentage, but not always */
|
||||
+ if ( g_s_progress.iCountDown == 0 )
|
||||
+ {
|
||||
+ /* calculate current speed */
|
||||
+ struct timeval cur_time;
|
||||
+ gettimeofday ( & cur_time, NULL );
|
||||
+ int cur_size = g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ int cur_fsize = g_iFTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ int usec_elapsed = cur_time.tv_usec - g_s_progress.last_time.tv_usec;
|
||||
+ double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
|
||||
+ sec_elapsed += ( double ) ( cur_time.tv_sec - g_s_progress.last_time.tv_sec );
|
||||
+ int copy_speed = ( int ) ( ( double ) ( cur_size - g_s_progress.last_size )
|
||||
+ / sec_elapsed );
|
||||
+ char s_copy_speed[PROGRESS_NUM_BUF];
|
||||
+ file_size_format ( s_copy_speed, copy_speed >= 0 ? copy_speed : 0, 1 );
|
||||
+ /* update vars */
|
||||
+ g_s_progress.last_time = cur_time;
|
||||
+ g_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[PROGRESS_NUM_BUF];
|
||||
+ char f_ftime[PROGRESS_NUM_BUF];
|
||||
+ format_time(f_ttime, sec_remaining, true);
|
||||
+ format_time(f_ftime, sec_fremaining, true);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = sprintf ( g_s_progress.cProgressField[1],
|
||||
+ "%d of %d files copied (about %s remaining)",
|
||||
+ g_iFilesCopied, g_iTotalFiles, f_ttime );
|
||||
+ g_s_progress.cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ char s_ftime[PROGRESS_ETA_BUF] = "";
|
||||
+
|
||||
+ if (g_iTotalFiles > 1)
|
||||
+ sprintf ( s_ftime, "(about %s remaining)", f_ftime );
|
||||
+ else
|
||||
+ sprintf ( s_ftime, "(about %s remaining)", f_ttime );
|
||||
+
|
||||
+ if ( g_iTotalFiles > 1 )
|
||||
+ {
|
||||
+ /* global progress bar */
|
||||
+ file_progress_bar ( g_s_progress.cProgressField[2], g_s_progress.iBarLength,
|
||||
+ g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB, g_iTotalSize );
|
||||
+
|
||||
+ /* print the global status */
|
||||
+ fs_len = file_size_format ( g_s_progress.cProgressField[1] + g_s_progress.iBarLength - PROGRESS_SIZE_COL,
|
||||
+ g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB, 1 );
|
||||
+ g_s_progress.cProgressField[1][g_s_progress.iBarLength - PROGRESS_SIZE_COL + fs_len] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, g_s_progress.iBarLength, g_s_progress.src_open_sb.st_size, g_s_progress.src_open_sb.st_size );
|
||||
+ g_s_progress.cProgressField[5][g_s_progress.iBarLength-2] = '0';
|
||||
+ g_s_progress.cProgressField[5][g_s_progress.iBarLength-1] = '%';
|
||||
+ g_s_progress.cProgressField[5][g_s_progress.iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( g_s_progress.cProgressField[4] + g_s_progress.iBarLength - PROGRESS_SIZE_COL, g_s_progress.src_open_sb.st_size, 0 );
|
||||
+ g_s_progress.cProgressField[4][g_s_progress.iBarLength - PROGRESS_SIZE_COL + fs_len] = ' ';
|
||||
+
|
||||
+ /* print the field */
|
||||
+ int it;
|
||||
+ for ( it = g_iTotalFiles>1 ? 0 : 3; it < 6; it++ )
|
||||
+ {
|
||||
+ printf ( "\033[K%s\n", g_s_progress.cProgressField[it] );
|
||||
+ if ( strlen ( g_s_progress.cProgressField[it] ) < (size_t) g_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_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -182,6 +433,14 @@
|
||||
debug->offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
debug->offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -192,6 +451,98 @@
|
||||
|
||||
while (0 < max_n_read)
|
||||
{
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update countdown */
|
||||
+ g_s_progress.iCountDown--;
|
||||
+ char * sProgressBar = g_s_progress.cProgressField[5];
|
||||
+ if ( g_s_progress.iCountDown < 0 )
|
||||
+ g_s_progress.iCountDown = 100;
|
||||
+
|
||||
+ /* just print one line with the percentage, but not always */
|
||||
+ if ( g_s_progress.iCountDown == 0 )
|
||||
+ {
|
||||
+ /* calculate current speed */
|
||||
+ struct timeval cur_time;
|
||||
+ gettimeofday ( & cur_time, NULL );
|
||||
+ int cur_size = g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ int cur_fsize = g_iFTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ int usec_elapsed = cur_time.tv_usec - g_s_progress.last_time.tv_usec;
|
||||
+ double sec_elapsed = ( double ) usec_elapsed / 1000000.f;
|
||||
+ sec_elapsed += ( double ) ( cur_time.tv_sec - g_s_progress.last_time.tv_sec );
|
||||
+ int copy_speed = ( int ) ( ( double ) ( cur_size - g_s_progress.last_size )
|
||||
+ / sec_elapsed );
|
||||
+ char s_copy_speed[PROGRESS_NUM_BUF];
|
||||
+ file_size_format ( s_copy_speed, copy_speed >= 0 ? copy_speed : 0, 1 );
|
||||
+ /* update vars */
|
||||
+ g_s_progress.last_time = cur_time;
|
||||
+ g_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[PROGRESS_NUM_BUF];
|
||||
+ char f_ftime[PROGRESS_NUM_BUF];
|
||||
+ format_time(f_ttime, sec_remaining, true);
|
||||
+ format_time(f_ftime, sec_fremaining, true);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = sprintf ( g_s_progress.cProgressField[1],
|
||||
+ "%d of %d files copied (about %s remaining)",
|
||||
+ g_iFilesCopied, g_iTotalFiles, f_ttime );
|
||||
+ g_s_progress.cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ char s_ftime[PROGRESS_ETA_BUF] = "";
|
||||
+
|
||||
+ if (g_iTotalFiles > 1)
|
||||
+ sprintf ( s_ftime, "(about %s remaining)", f_ftime );
|
||||
+ else
|
||||
+ sprintf ( s_ftime, "(about %s remaining)", f_ttime );
|
||||
+
|
||||
+ sprintf ( g_s_progress.cProgressField[3],
|
||||
+ "copying at %s/s %s", s_copy_speed, s_ftime );
|
||||
+ if ( g_iTotalFiles > 1 )
|
||||
+ {
|
||||
+ /* global progress bar */
|
||||
+ file_progress_bar ( g_s_progress.cProgressField[2], g_s_progress.iBarLength,
|
||||
+ g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB, g_iTotalSize );
|
||||
+
|
||||
+ /* print the global status */
|
||||
+ fs_len = file_size_format ( g_s_progress.cProgressField[1] + g_s_progress.iBarLength - PROGRESS_SIZE_COL,
|
||||
+ g_iTotalWritten + total_n_read / PROGRESS_BYTES_PER_KIB, 1 );
|
||||
+ g_s_progress.cProgressField[1][g_s_progress.iBarLength - PROGRESS_SIZE_COL + fs_len] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* current progress bar */
|
||||
+ file_progress_bar ( sProgressBar, g_s_progress.iBarLength, total_n_read, g_s_progress.src_open_sb.st_size );
|
||||
+
|
||||
+ /* print the status */
|
||||
+ fs_len = file_size_format ( g_s_progress.cProgressField[4] + g_s_progress.iBarLength - PROGRESS_SIZE_COL, total_n_read, 0 );
|
||||
+ g_s_progress.cProgressField[4][g_s_progress.iBarLength - PROGRESS_SIZE_COL + fs_len] = ' ';
|
||||
+
|
||||
+ /* print the field */
|
||||
+ int it;
|
||||
+ for ( it = g_iTotalFiles>1 ? 0 : 3; it < 6; it++ )
|
||||
+ {
|
||||
+ printf ( "\033[K%s\n", g_s_progress.cProgressField[it] );
|
||||
+ if ( strlen ( g_s_progress.cProgressField[it] ) < (size_t) g_s_progress.iBarLength )
|
||||
+ printf ( "%s", "" );
|
||||
+ }
|
||||
+ if ( g_iTotalFiles > 1 )
|
||||
+ printf ( "\r\033[6A" );
|
||||
+ else
|
||||
+ printf ( "\r\033[3A" );
|
||||
+ fflush ( stdout );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -270,6 +621,14 @@
|
||||
certain files in /proc or /sys with linux kernels. */
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += total_n_read / PROGRESS_BYTES_PER_KIB;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (hole_size)
|
||||
*hole_size = make_hole ? psize : 0;
|
||||
return total_n_read;
|
||||
@@ -602,6 +961,86 @@
|
||||
intmax_t result;
|
||||
off_t hole_size = 0;
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ /* Set up the per-file progress field that sparse_copy/lseek_copy render
|
||||
+ into. g_s_progress is a file-scope global read by those functions. */
|
||||
+ char ** cProgressField = NULL;
|
||||
+ if (progress)
|
||||
+ {
|
||||
+ struct stat src_open_sb = *ist;
|
||||
+
|
||||
+ /* create a field of 6 lines */
|
||||
+ 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ cProgressField[1][sum_length] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* truncate filename? */
|
||||
+ int fn_length;
|
||||
+ if ( strlen ( iname ) > (size_t) (iBarLength - 22) )
|
||||
+ fn_length =
|
||||
+ sprintf ( cProgressField[4], "...%s", iname + ( strlen ( iname ) - iBarLength + 25 ) );
|
||||
+ else
|
||||
+ fn_length = sprintf ( cProgressField[4], "%s", iname );
|
||||
+ 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;
|
||||
+
|
||||
+ g_s_progress = ( struct progress_status )
|
||||
+ { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb };
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (scantype == LSEEK_SCANTYPE)
|
||||
{
|
||||
#ifdef SEEK_HOLE
|
||||
@@ -641,6 +1080,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && cProgressField) {
|
||||
+ int i;
|
||||
+ for ( i = 0; i < 6; i++ )
|
||||
+ free ( cProgressField[i] );
|
||||
+ free ( cProgressField );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
alignfree (buf);
|
||||
return result;
|
||||
}
|
||||
--- coreutils-9.11/src/copy.h 2026-07-23 09:47:29.805951169 -0600
|
||||
+++ coreutils-9.11k/src/copy.h 2026-07-23 09:47:29.837358788 -0600
|
||||
@@ -255,6 +255,9 @@
|
||||
Create destination directories as usual. */
|
||||
bool symbolic_link;
|
||||
|
||||
+ /* If true, draw a nice progress bar on screen */
|
||||
+ bool progress_bar;
|
||||
+
|
||||
/* Control if destination files are replaced. */
|
||||
enum Update_type update;
|
||||
|
||||
@@ -360,4 +363,32 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+
|
||||
+/* Scratch-buffer sizes for the short formatted strings the progress code
|
||||
+ builds with sprintf. PROGRESS_NUM_BUF holds a file_size_format /
|
||||
+ format_time result ("542.3 MiB", "1h 2m 3.4s"). PROGRESS_ETA_BUF holds
|
||||
+ the longer "(about ... remaining)" string. PROGRESS_FTYPE_BUF holds the
|
||||
+ file-type label ("folder(s)/file(s)" is the longest at 17 chars). */
|
||||
+#define PROGRESS_NUM_BUF 20
|
||||
+#define PROGRESS_ETA_BUF 40
|
||||
+#define PROGRESS_FTYPE_BUF 20
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
--- coreutils-9.11/src/cp.c 2026-07-23 09:47:29.806107878 -0600
|
||||
+++ coreutils-9.11k/src/cp.c 2026-07-23 09:47:29.837379316 -0600
|
||||
@@ -141,6 +141,7 @@
|
||||
{"symbolic-link", no_argument, NULL, 's'},
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", optional_argument, NULL, 'u'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{"keep-directory-symlink", no_argument, NULL,
|
||||
KEEP_DIRECTORY_SYMLINK_OPTION},
|
||||
@@ -203,6 +204,11 @@
|
||||
again (this option is ignored when the -n option is also used)\n\
|
||||
"));
|
||||
oputs (_("\
|
||||
+ -g, --progress-bar\n\
|
||||
+ add a progress bar. Note that this doesn't work with reflink;\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
+"));
|
||||
+ oputs (_("\
|
||||
-i, --interactive\n\
|
||||
prompt before overwrite (overrides a previous -n option)\n\
|
||||
"));
|
||||
@@ -737,6 +743,74 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb) >= 0)
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -876,6 +950,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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[PROGRESS_NUM_BUF];
|
||||
+ 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[PROGRESS_NUM_BUF];
|
||||
+ file_size_format ( s_copy_speed, copy_speed, 1 );
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ char sFType[PROGRESS_FTYPE_BUF];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[PROGRESS_NUM_BUF];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -911,6 +1035,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -1049,7 +1174,7 @@
|
||||
cp_option_init (&x);
|
||||
|
||||
int c;
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1110,6 +1235,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1276,6 +1405,11 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+ /* END progress mod */
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
--- coreutils-9.11/src/mv.c 2026-07-23 09:47:29.807078459 -0600
|
||||
+++ coreutils-9.11k/src/mv.c 2026-07-23 09:47:29.837402508 -0600
|
||||
@@ -80,6 +80,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", optional_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -171,9 +172,119 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (target_directory_operand (source, &sb) >= 0)
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (char *)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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[PROGRESS_NUM_BUF];
|
||||
+ 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[PROGRESS_NUM_BUF];
|
||||
+ file_size_format ( s_copy_speed, copy_speed, 1 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[PROGRESS_FTYPE_BUF];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[PROGRESS_NUM_BUF];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -283,6 +394,10 @@
|
||||
do not prompt before overwriting\n\
|
||||
"));
|
||||
oputs (_("\
|
||||
+ -g, --progress-bar\n\
|
||||
+ add a progress bar\n\
|
||||
+"));
|
||||
+ oputs (_("\
|
||||
-i, --interactive\n\
|
||||
prompt before overwrite\n\
|
||||
"));
|
||||
@@ -365,7 +480,7 @@
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
int c;
|
||||
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL))
|
||||
+ while ((c = getopt_long (argc, argv, "bfingt:uvS:TZ", long_options, NULL))
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -378,6 +493,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
--- coreutils-9.11/doc/coreutils.texi 2026-07-23 09:47:29.758119162 -0600
|
||||
+++ coreutils-9.11k/doc/coreutils.texi 2026-07-23 09:47:29.838680665 -0600
|
||||
@@ -8825,6 +8825,11 @@
|
||||
This option is ignored when the @option{--no-clobber} or @option{-n} option
|
||||
is also used.
|
||||
|
||||
+@optItem{cp,-g,}
|
||||
+@optItemx{cp,--progress-bar,}
|
||||
+Display a progress bar while copying, showing the percentage complete,
|
||||
+copy speed, estimated time remaining, and per-file and overall progress.
|
||||
+
|
||||
@optItem{cp,-i,}
|
||||
@optItemx{cp,--interactive,}
|
||||
When copying a file other than a directory, prompt whether to
|
||||
@@ -9995,6 +10000,12 @@
|
||||
@end macro
|
||||
@mvOptsIfn
|
||||
|
||||
+@optItem{mv,-g,}
|
||||
+@optItemx{mv,--progress-bar,}
|
||||
+Display a progress bar while moving files across file systems, showing the
|
||||
+percentage complete, copy speed, estimated time remaining, and per-file and
|
||||
+overall progress.
|
||||
+
|
||||
@optItem{mv,-i,}
|
||||
@optItemx{mv,--interactive,}
|
||||
@cindex prompts, forcing
|
||||
@@ -0,0 +1,957 @@
|
||||
diff -aur coreutils-9.2/src/copy.c coreutils-9.2-patched/src/copy.c
|
||||
--- coreutils-9.2/src/copy.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.2-patched/src/copy.c 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -121,6 +121,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -302,14 +429,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
|
||||
@@ -322,6 +458,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -367,6 +599,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -377,6 +617,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -464,6 +801,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))
|
||||
@@ -535,9 +880,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -611,10 +958,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1580,8 +1933,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1589,15 +2014,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1608,6 +2035,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
diff -aur coreutils-9.2/src/copy.h coreutils-9.2-patched/src/copy.h
|
||||
--- coreutils-9.2/src/copy.h 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.2-patched/src/copy.h 2022-04-03 21:03:04.881415398 +0200
|
||||
@@ -235,6 +235,9 @@
|
||||
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;
|
||||
@@ -315,4 +318,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -aur coreutils-9.2/src/cp.c coreutils-9.2-patched/src/cp.c
|
||||
--- coreutils-9.2/src/cp.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.2-patched/src/cp.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -130,6 +130,7 @@
|
||||
{"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},
|
||||
@@ -172,6 +173,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -649,6 +653,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -788,6 +868,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -823,6 +953,9 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+
|
||||
+ x->progress_bar = false;
|
||||
+
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -961,7 +1094,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1022,6 +1156,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1172,6 +1310,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
diff -aur coreutils-9.2/src/mv.c coreutils-9.2-patched/src/mv.c
|
||||
--- coreutils-9.2/src/mv.c 2021-09-24 13:31:05.000000000 +0200
|
||||
+++ coreutils-9.2-patched/src/mv.c 2022-04-03 21:03:04.885415457 +0200
|
||||
@@ -68,6 +68,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", no_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -159,9 +160,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -264,6 +386,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -321,7 +444,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- 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)
|
||||
@@ -363,6 +486,9 @@
|
||||
case 'v':
|
||||
x.verbose = true;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'S':
|
||||
make_backups = true;
|
||||
backup_suffix = optarg;
|
||||
@@ -0,0 +1,972 @@
|
||||
--- coreutils-9.3/src/ls.c 2023-03-13 14:08:10.000000000 -0400
|
||||
+++ coreutils-9.3/src/ls.c 2023-07-02 16:10:41.947444700 -0400
|
||||
@@ -2279,18 +2279,11 @@
|
||||
if (linelen < 0)
|
||||
{
|
||||
/* Suppress bogus warning re comparing ws.ws_col to big integer. */
|
||||
-# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
|
||||
-# pragma GCC diagnostic push
|
||||
-# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
-# endif
|
||||
struct winsize ws;
|
||||
if (stdout_isatty ()
|
||||
&& 0 <= ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws)
|
||||
&& 0 < ws.ws_col)
|
||||
linelen = ws.ws_col <= MIN (PTRDIFF_MAX, SIZE_MAX) ? ws.ws_col : 0;
|
||||
-# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
|
||||
-# pragma GCC diagnostic pop
|
||||
-# endif
|
||||
}
|
||||
#endif
|
||||
if (linelen < 0)
|
||||
--- coreutils-9.3/src/copy.c 2023-04-17 16:43:34.000000000 -0400
|
||||
+++ coreutils-9.3/src/copy.c 2023-07-02 16:25:44.187962600 -0400
|
||||
@@ -121,6 +121,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -317,14 +444,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -339,6 +475,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, NULL, dest_fd, NULL,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -382,6 +614,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -392,6 +632,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -479,6 +816,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))
|
||||
@@ -550,9 +895,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -626,10 +973,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1592,8 +1945,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1601,15 +2026,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1620,6 +2047,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
--- coreutils-9.3/src/copy.h 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.3/src/copy.h 2023-07-02 16:15:50.875580500 -0400
|
||||
@@ -249,6 +249,9 @@
|
||||
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;
|
||||
@@ -329,4 +332,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
--- coreutils-9.3/src/cp.cg 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.3/src/cp.c 2023-07-02 16:26:48.895801600 -0400
|
||||
@@ -140,6 +140,7 @@
|
||||
{"symbolic-link", no_argument, NULL, 's'},
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", optional_argument, NULL, 'u'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
@@ -182,6 +183,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -666,6 +670,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -805,6 +885,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -840,6 +970,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -978,7 +1109,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, NULL))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1039,6 +1171,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1212,6 +1348,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
--- coreutils-9.3/src/mv.c 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.3/src/mv.c 2023-07-02 16:19:42.433714100 -0400
|
||||
@@ -79,6 +79,7 @@
|
||||
{"target-directory", required_argument, NULL, 't'},
|
||||
{"update", optional_argument, NULL, 'u'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
+ {"progress-bar", no_argument, NULL, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -170,9 +171,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -275,6 +397,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -337,7 +460,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- 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)
|
||||
@@ -350,6 +473,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
@@ -0,0 +1,972 @@
|
||||
--- coreutils-9.4/src/ls.c 2023-03-13 14:08:10.000000000 -0400
|
||||
+++ coreutils-9.4/src/ls.c 2023-07-02 16:10:41.947444700 -0400
|
||||
@@ -2279,18 +2279,11 @@
|
||||
if (linelen < 0)
|
||||
{
|
||||
/* Suppress bogus warning re comparing ws.ws_col to big integer. */
|
||||
-# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
|
||||
-# pragma GCC diagnostic push
|
||||
-# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
-# endif
|
||||
struct winsize ws;
|
||||
if (stdout_isatty ()
|
||||
&& 0 <= ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws)
|
||||
&& 0 < ws.ws_col)
|
||||
linelen = ws.ws_col <= MIN (PTRDIFF_MAX, SIZE_MAX) ? ws.ws_col : 0;
|
||||
-# if 4 < __GNUC__ + (6 <= __GNUC_MINOR__)
|
||||
-# pragma GCC diagnostic pop
|
||||
-# endif
|
||||
}
|
||||
#endif
|
||||
if (linelen < 0)
|
||||
--- coreutils-9.4/src/copy.c 2023-04-17 16:43:34.000000000 -0400
|
||||
+++ coreutils-9.4/src/copy.c 2023-07-02 16:25:44.187962600 -0400
|
||||
@@ -121,6 +121,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -317,14 +444,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -339,6 +475,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, nullptr, dest_fd, nullptr,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -382,6 +614,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -392,6 +632,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -479,6 +816,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))
|
||||
@@ -550,9 +895,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -626,10 +973,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1592,8 +1945,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1601,15 +2026,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1620,6 +2047,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
--- coreutils-9.4/src/copy.h 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.4/src/copy.h 2023-07-02 16:15:50.875580500 -0400
|
||||
@@ -249,6 +249,9 @@
|
||||
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;
|
||||
@@ -329,4 +332,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
--- coreutils-9.4/src/cp.cg 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.4/src/cp.c 2023-07-02 16:26:48.895801600 -0400
|
||||
@@ -140,6 +140,7 @@
|
||||
{"symbolic-link", no_argument, nullptr, 's'},
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
@@ -182,6 +183,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -666,6 +670,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -805,6 +885,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -840,6 +970,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -978,7 +1109,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1039,6 +1171,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1212,6 +1348,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
--- coreutils-9.4/src/mv.c 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.4/src/mv.c 2023-07-02 16:19:42.433714100 -0400
|
||||
@@ -79,6 +79,7 @@
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -170,9 +171,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -275,6 +397,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -337,7 +460,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, nullptr))
|
||||
+ while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -350,6 +473,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
@@ -0,0 +1,951 @@
|
||||
--- coreutils-9.5/src/copy.c 2023-04-17 16:43:34.000000000 -0400
|
||||
+++ coreutils-9.5/src/copy.c 2023-07-02 16:25:44.187962600 -0400
|
||||
@@ -121,6 +121,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -317,14 +444,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -339,6 +475,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, nullptr, dest_fd, nullptr,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -382,6 +614,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -392,6 +632,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -479,6 +816,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))
|
||||
@@ -550,9 +895,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -626,10 +973,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1592,8 +1945,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1601,15 +2026,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1620,6 +2047,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
--- coreutils-9.5/src/copy.h 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.5/src/copy.h 2023-07-02 16:15:50.875580500 -0400
|
||||
@@ -249,6 +249,9 @@
|
||||
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;
|
||||
@@ -329,4 +332,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
--- coreutils-9.5/src/cp.cg 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.5/src/cp.c 2023-07-02 16:26:48.895801600 -0400
|
||||
@@ -140,6 +140,7 @@
|
||||
{"symbolic-link", no_argument, nullptr, 's'},
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{GETOPT_SELINUX_CONTEXT_OPTION_DECL},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
@@ -182,6 +183,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -666,6 +670,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -805,6 +885,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, NULL);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -840,6 +970,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -978,7 +1109,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1039,6 +1171,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1212,6 +1348,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
--- coreutils-9.5/src/mv.c 2023-04-10 06:14:08.000000000 -0400
|
||||
+++ coreutils-9.5/src/mv.c 2023-07-02 16:19:42.433714100 -0400
|
||||
@@ -79,6 +79,7 @@
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -170,9 +171,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -275,6 +397,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -337,7 +460,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, nullptr))
|
||||
+ while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -350,6 +473,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
@@ -0,0 +1,976 @@
|
||||
diff -Naur coreutils-9.7/src/copy.c coreutils-9.7k/src/copy.c
|
||||
--- coreutils-9.7/src/copy.c 2025-02-20 09:56:20.000000000 -0300
|
||||
+++ coreutils-9.7k/src/copy.c 2026-01-17 13:17:40.208485733 -0300
|
||||
@@ -113,6 +113,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -317,14 +444,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -339,6 +475,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, nullptr, dest_fd, nullptr,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -382,6 +614,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -392,6 +632,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -479,6 +816,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))
|
||||
@@ -550,9 +895,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -626,10 +973,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1596,8 +1949,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1605,15 +2030,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1624,6 +2051,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
diff -Naur coreutils-9.7/src/copy.h coreutils-9.7k/src/copy.h
|
||||
--- coreutils-9.7/src/copy.h 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/copy.h 2026-01-17 13:24:50.938944306 -0300
|
||||
@@ -98,14 +98,14 @@
|
||||
DEREF_ALWAYS
|
||||
};
|
||||
|
||||
-# define VALID_SPARSE_MODE(Mode) \
|
||||
- ((Mode) == SPARSE_NEVER \
|
||||
- || (Mode) == SPARSE_AUTO \
|
||||
+# define VALID_SPARSE_MODE(Mode) \
|
||||
+ ((Mode) == SPARSE_NEVER \
|
||||
+ || (Mode) == SPARSE_AUTO \
|
||||
|| (Mode) == SPARSE_ALWAYS)
|
||||
|
||||
-# define VALID_REFLINK_MODE(Mode) \
|
||||
- ((Mode) == REFLINK_NEVER \
|
||||
- || (Mode) == REFLINK_AUTO \
|
||||
+# define VALID_REFLINK_MODE(Mode) \
|
||||
+ ((Mode) == REFLINK_NEVER \
|
||||
+ || (Mode) == REFLINK_AUTO \
|
||||
|| (Mode) == REFLINK_ALWAYS)
|
||||
|
||||
/* These options control how files are copied by at least the
|
||||
@@ -255,6 +255,9 @@
|
||||
Create destination directories as usual. */
|
||||
bool symbolic_link;
|
||||
|
||||
+ /* If true, draw a nice progress bar on screen */
|
||||
+ bool progress_bar;
|
||||
+
|
||||
/* Control if destination files are replaced. */
|
||||
enum Update_type update;
|
||||
|
||||
@@ -328,4 +331,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -Naur coreutils-9.7/src/cp.c coreutils-9.7k/src/cp.c
|
||||
--- coreutils-9.7/src/cp.c 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/cp.c 2026-01-17 13:17:40.209427521 -0300
|
||||
@@ -141,6 +141,7 @@
|
||||
{"symbolic-link", no_argument, nullptr, 's'},
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{"keep-directory-symlink", no_argument, nullptr,
|
||||
KEEP_DIRECTORY_SYMLINK_OPTION},
|
||||
@@ -185,6 +186,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -682,6 +686,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -822,6 +902,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, nullptr);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -857,6 +987,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -996,7 +1127,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1057,6 +1189,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1223,6 +1359,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
diff -Naur coreutils-9.7/src/mv.c coreutils-9.7k/src/mv.c
|
||||
--- coreutils-9.7/src/mv.c 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/mv.c 2026-01-17 13:17:40.210002773 -0300
|
||||
@@ -80,6 +80,7 @@
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
@@ -171,9 +172,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -279,6 +401,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -341,7 +464,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, nullptr))
|
||||
+ while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -354,6 +477,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
@@ -0,0 +1,976 @@
|
||||
diff -Naur coreutils-9.7/src/copy.c coreutils-9.7k/src/copy.c
|
||||
--- coreutils-9.7/src/copy.c 2025-02-20 09:56:20.000000000 -0300
|
||||
+++ coreutils-9.7k/src/copy.c 2026-01-17 13:17:40.208485733 -0300
|
||||
@@ -113,6 +113,133 @@
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+struct progress_status {
|
||||
+ int iCountDown;
|
||||
+ char ** cProgressField;
|
||||
+ struct timeval last_time;
|
||||
+ int last_size, iBarLength;
|
||||
+ struct stat src_open_sb;
|
||||
+};
|
||||
+
|
||||
+FILE * spawn( const char *cmd, char *const argv[] )
|
||||
+{
|
||||
+ FILE *ret = NULL;
|
||||
+ int pfd_read[2];
|
||||
+ pid_t pid;
|
||||
+
|
||||
+ if (cmd == NULL || argv == NULL)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (pipe(pfd_read) < 0) {
|
||||
+ error(0, errno, "pipe: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if ((pid = fork()) == 0) {
|
||||
+ int err = dup2(pfd_read[1], 1) < 0;
|
||||
+ close(pfd_read[0]);
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (err)
|
||||
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
|
||||
+ execvp(cmd, argv);
|
||||
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
|
||||
+ }
|
||||
+
|
||||
+ close(pfd_read[1]);
|
||||
+
|
||||
+ if (pid < 0) {
|
||||
+ close(pfd_read[0]);
|
||||
+ error(0, errno, "fork: %s", cmd);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = fdopen(pfd_read[0], "r");
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void format_time ( char * _cDest, double seconds, bool showall )
|
||||
+{
|
||||
+ // hours
|
||||
+ int hr = ( (int) seconds / (60 * 60)) % 24;
|
||||
+ // minutes
|
||||
+ int min = ( (int) seconds / 60) % 60;
|
||||
+ // seconds
|
||||
+ double sec = seconds - (hr * (60 * 60)) - (min * 60);
|
||||
+ if ( showall )
|
||||
+ {
|
||||
+ if ( seconds < 0 )
|
||||
+ sprintf(_cDest, "%2ch %2cm %2cs", '0', '0', '?');
|
||||
+ else
|
||||
+ sprintf(_cDest, "%2dh %2dm %2ds", hr, min, (int) sec);
|
||||
+ } else if ( seconds >= 3600 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dh %2dm %4.1fs", hr, min, sec);
|
||||
+ } else if ( seconds >= 60 )
|
||||
+ {
|
||||
+ sprintf(_cDest, "%2dm %4.1fs", min, sec);
|
||||
+ } else
|
||||
+ {
|
||||
+ sprintf(_cDest, "%4.1fs", sec);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+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
|
||||
|
||||
@@ -317,14 +444,23 @@
|
||||
bytes read. */
|
||||
static bool
|
||||
sparse_copy (int src_fd, int dest_fd, char **abuf, 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 (copy_debug.sparse_detection == COPY_DEBUG_UNKNOWN)
|
||||
copy_debug.sparse_detection = hole_size ? COPY_DEBUG_YES : COPY_DEBUG_NO;
|
||||
else if (hole_size && copy_debug.sparse_detection == COPY_DEBUG_EXTERNAL)
|
||||
@@ -339,6 +475,102 @@
|
||||
(SSIZE_MAX, SIZE_MAX) truncated to a value that is
|
||||
surely aligned well. */
|
||||
ssize_t copy_max = MIN (SSIZE_MAX, SIZE_MAX) >> 30 << 30;
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+
|
||||
+ 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] = ' ';
|
||||
+ }
|
||||
+
|
||||
+ /* set current progress bar to be always 100 % */
|
||||
+ file_progress_bar ( sProgressBar, s_progress->iBarLength, s_progress->src_open_sb.st_size, s_progress->src_open_sb.st_size );
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-2] = '0';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength-1] = '%';
|
||||
+ s_progress->cProgressField[5][s_progress->iBarLength] = '\0';
|
||||
+
|
||||
+ /* print the status as always full filesize*/
|
||||
+ fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, s_progress->src_open_sb.st_size, 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_copied = copy_file_range (src_fd, nullptr, dest_fd, nullptr,
|
||||
MIN (max_n_read, copy_max), 0);
|
||||
if (n_copied == 0)
|
||||
@@ -382,6 +614,14 @@
|
||||
copy_debug.offload = COPY_DEBUG_YES;
|
||||
max_n_read -= n_copied;
|
||||
*total_n_read += n_copied;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* update total size */
|
||||
+ g_iTotalWritten += *total_n_read / 1024;
|
||||
+ g_iFilesCopied++;
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
}
|
||||
else
|
||||
copy_debug.offload = COPY_DEBUG_AVOIDED;
|
||||
@@ -392,6 +632,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);
|
||||
+
|
||||
+ int fs_len;
|
||||
+ fs_len = 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 );
|
||||
+ s_progress->cProgressField[1][fs_len] = ' ';
|
||||
+
|
||||
+ 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 );
|
||||
+ 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 */
|
||||
+ }
|
||||
+
|
||||
if (!*abuf)
|
||||
*abuf = xalignalloc (getpagesize (), buf_size);
|
||||
char *buf = *abuf;
|
||||
@@ -479,6 +816,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))
|
||||
@@ -550,9 +895,11 @@
|
||||
static bool
|
||||
lseek_copy (int src_fd, int dest_fd, char **abuf, 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;
|
||||
@@ -626,10 +973,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, abuf, buf_size,
|
||||
sparse_mode != SPARSE_ALWAYS ? 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;
|
||||
@@ -1596,8 +1949,80 @@
|
||||
buf_size = blcm;
|
||||
}
|
||||
|
||||
+ /* 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 )
|
||||
+ if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */
|
||||
+ 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 = 0;
|
||||
+ sum_length = sprintf ( cProgressField[1],
|
||||
+ x->move_mode
|
||||
+ ? "%d of %d files moved so far"
|
||||
+ : "%d of %d files copied so far", g_iFilesCopied, g_iTotalFiles );
|
||||
+ 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 */
|
||||
+
|
||||
off_t n_read;
|
||||
bool wrote_hole_at_eof = false;
|
||||
+
|
||||
+ struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb};
|
||||
+
|
||||
if (! (
|
||||
#ifdef SEEK_HOLE
|
||||
scantype == LSEEK_SCANTYPE
|
||||
@@ -1605,15 +2030,17 @@
|
||||
scan_inference.ext_start, src_open_sb.st_size,
|
||||
make_holes ? x->sparse_mode : SPARSE_NEVER,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name)
|
||||
+ x->move_mode, src_name, dst_name,
|
||||
+ iCountDown, cProgressField, last_time, last_size,
|
||||
+ iBarLength, src_open_sb)
|
||||
:
|
||||
#endif
|
||||
sparse_copy (source_desc, dest_desc, &buf, buf_size,
|
||||
make_holes ? hole_size : 0,
|
||||
x->sparse_mode == SPARSE_ALWAYS,
|
||||
x->reflink_mode != REFLINK_NEVER,
|
||||
- src_name, dst_name, UINTMAX_MAX, &n_read,
|
||||
- &wrote_hole_at_eof)))
|
||||
+ x->move_mode, src_name, dst_name, UINTMAX_MAX,
|
||||
+ &n_read, &wrote_hole_at_eof, &s_progress)))
|
||||
{
|
||||
return_val = false;
|
||||
goto close_src_and_dst_desc;
|
||||
@@ -1624,6 +2051,14 @@
|
||||
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 */
|
||||
}
|
||||
|
||||
if (x->preserve_timestamps)
|
||||
diff -Naur coreutils-9.7/src/copy.h coreutils-9.7k/src/copy.h
|
||||
--- coreutils-9.7/src/copy.h 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/copy.h 2026-01-17 13:24:50.938944306 -0300
|
||||
@@ -98,14 +98,14 @@
|
||||
DEREF_ALWAYS
|
||||
};
|
||||
|
||||
-# define VALID_SPARSE_MODE(Mode) \
|
||||
- ((Mode) == SPARSE_NEVER \
|
||||
- || (Mode) == SPARSE_AUTO \
|
||||
+# define VALID_SPARSE_MODE(Mode) \
|
||||
+ ((Mode) == SPARSE_NEVER \
|
||||
+ || (Mode) == SPARSE_AUTO \
|
||||
|| (Mode) == SPARSE_ALWAYS)
|
||||
|
||||
-# define VALID_REFLINK_MODE(Mode) \
|
||||
- ((Mode) == REFLINK_NEVER \
|
||||
- || (Mode) == REFLINK_AUTO \
|
||||
+# define VALID_REFLINK_MODE(Mode) \
|
||||
+ ((Mode) == REFLINK_NEVER \
|
||||
+ || (Mode) == REFLINK_AUTO \
|
||||
|| (Mode) == REFLINK_ALWAYS)
|
||||
|
||||
/* These options control how files are copied by at least the
|
||||
@@ -255,6 +255,9 @@
|
||||
Create destination directories as usual. */
|
||||
bool symbolic_link;
|
||||
|
||||
+ /* If true, draw a nice progress bar on screen */
|
||||
+ bool progress_bar;
|
||||
+
|
||||
/* Control if destination files are replaced. */
|
||||
enum Update_type update;
|
||||
|
||||
@@ -328,4 +331,22 @@
|
||||
_GL_ATTRIBUTE_NONNULL () _GL_ATTRIBUTE_PURE;
|
||||
mode_t cached_umask (void);
|
||||
|
||||
+/* BEGIN progress mod */
|
||||
+FILE * spawn( const char *cmd, char *const argv[] );
|
||||
+void format_time ( char * _cDst, double seconds, bool showall );
|
||||
+
|
||||
+int file_size_format ( char * _cDst, long _lSize, int _iCounter );
|
||||
+
|
||||
+__attribute__((__common__)) long g_iTotalSize;
|
||||
+__attribute__((__common__)) long g_iFTotalSize;
|
||||
+__attribute__((__common__)) long g_iTotalWritten;
|
||||
+__attribute__((__common__)) long g_iFTotalWritten;
|
||||
+__attribute__((__common__)) int g_iFilesCopied;
|
||||
+__attribute__((__common__)) int g_iDirectoriesCopied;
|
||||
+__attribute__((__common__)) struct timeval g_oStartTime;
|
||||
+__attribute__((__common__)) struct timeval g_oFStartTime;
|
||||
+__attribute__((__common__)) int g_iTotalFiles;
|
||||
+__attribute__((__common__)) bool progress;
|
||||
+/* END progress mod */
|
||||
+
|
||||
#endif
|
||||
diff -Naur coreutils-9.7/src/cp.c coreutils-9.7k/src/cp.c
|
||||
--- coreutils-9.7/src/cp.c 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/cp.c 2026-01-17 13:17:40.209427521 -0300
|
||||
@@ -141,6 +141,7 @@
|
||||
{"symbolic-link", no_argument, nullptr, 's'},
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{"keep-directory-symlink", no_argument, nullptr,
|
||||
KEEP_DIRECTORY_SYMLINK_OPTION},
|
||||
@@ -185,6 +186,9 @@
|
||||
-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\
|
||||
+ Note that this doesn't work with reflink,\n\
|
||||
+ reflink will be automatically disabled\n\
|
||||
-i, --interactive prompt before overwrite (overrides a previous -n\
|
||||
\n\
|
||||
option)\n\
|
||||
@@ -682,6 +686,82 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ if (progress) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = n_files;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (file[0], &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ /* 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 */
|
||||
+ FILE *fp ;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", file[0], "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ if ( line_count > n_files )
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; j < iFiles; j++)
|
||||
+ {
|
||||
+ /* call du -s for each file */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", file[j], NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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
|
||||
@@ -822,6 +902,56 @@
|
||||
ok = copy (source, dest, AT_FDCWD, dest, -new_dst, x, &unused, nullptr);
|
||||
}
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress) {
|
||||
+ /* 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 */
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) copied in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
return ok;
|
||||
}
|
||||
|
||||
@@ -857,6 +987,7 @@
|
||||
x->recursive = false;
|
||||
x->sparse_mode = SPARSE_AUTO;
|
||||
x->symbolic_link = false;
|
||||
+ x->progress_bar = false;
|
||||
x->set_mode = false;
|
||||
x->mode = 0;
|
||||
|
||||
@@ -996,7 +1127,8 @@
|
||||
selinux_enabled = (0 < is_selinux_enabled ());
|
||||
cp_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
|
||||
+ /* BEGIN and END progress mod - remove the g in the next line!*/
|
||||
+ while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ",
|
||||
long_opts, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
@@ -1057,6 +1189,10 @@
|
||||
x.unlink_dest_after_failed_open = true;
|
||||
break;
|
||||
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
x.dereference = DEREF_COMMAND_LINE_ARGUMENTS;
|
||||
break;
|
||||
@@ -1223,6 +1359,9 @@
|
||||
usage (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+ if (progress)
|
||||
+ x.reflink_mode = REFLINK_NEVER;
|
||||
+
|
||||
x.backup_type = (make_backups
|
||||
? xget_version (_("backup type"),
|
||||
version_control_string)
|
||||
diff -Naur coreutils-9.7/src/mv.c coreutils-9.7k/src/mv.c
|
||||
--- coreutils-9.7/src/mv.c 2025-01-07 14:31:45.000000000 -0300
|
||||
+++ coreutils-9.7k/src/mv.c 2026-01-17 13:17:40.210002773 -0300
|
||||
@@ -80,6 +80,7 @@
|
||||
{"target-directory", required_argument, nullptr, 't'},
|
||||
{"update", optional_argument, nullptr, 'u'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
+ {"progress-bar", no_argument, nullptr, 'g'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
@@ -171,9 +172,130 @@
|
||||
{
|
||||
bool copy_into_self;
|
||||
bool rename_succeeded;
|
||||
+
|
||||
+ /* BEGIN progress mod */
|
||||
+ struct timeval start_time;
|
||||
+ struct stat sb;
|
||||
+
|
||||
+ if (progress && x->rename_errno != 0) {
|
||||
+ if (g_iTotalSize == 0)
|
||||
+ g_iTotalSize = 0;
|
||||
+ if (g_iTotalFiles == 0)
|
||||
+ g_iTotalFiles = 0;
|
||||
+ if (g_iFilesCopied == 0)
|
||||
+ g_iFilesCopied = 0;
|
||||
+ if (g_iDirectoriesCopied == 0)
|
||||
+ g_iDirectoriesCopied = 0;
|
||||
+ if (g_iTotalWritten == 0)
|
||||
+ g_iTotalWritten = 0;
|
||||
+
|
||||
+ if (target_directory_operand (source, &sb))
|
||||
+ g_iDirectoriesCopied++;
|
||||
+
|
||||
+ gettimeofday (& start_time, NULL);
|
||||
+ g_oStartTime = start_time;
|
||||
+
|
||||
+ /* how many files are we copying */
|
||||
+ FILE *fp;
|
||||
+ char output[1024];
|
||||
+ fp = spawn("find", (char *[]){ "find", (char *)source, "-type", "f", NULL });
|
||||
+ if ( fp == NULL)
|
||||
+ printf("failed to run find\r");
|
||||
+ else
|
||||
+ {
|
||||
+ char *line_buf = NULL;
|
||||
+ size_t line_buf_size = 0;
|
||||
+ int line_count = 0;
|
||||
+ ssize_t line_size;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ while (line_size > 0)
|
||||
+ {
|
||||
+ line_count++;
|
||||
+ line_size = getline(&line_buf, &line_buf_size, fp);
|
||||
+ }
|
||||
+ free (line_buf);
|
||||
+ g_iTotalFiles = line_count;
|
||||
+ }
|
||||
+ /* close */
|
||||
+ pclose(fp);
|
||||
+
|
||||
+ printf ("calculating total size... \r");
|
||||
+ fflush (stdout);
|
||||
+ long iTotalSize = 0;
|
||||
+ /* call du -s for source */
|
||||
+ fp = spawn("du", (char *[]){ "du", "-s", (unsigned char *)(size_t)source, NULL });
|
||||
+ if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) {
|
||||
+ printf("failed to run du\r" );
|
||||
+ }
|
||||
+ 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 ok = copy (source, dest, dest_dirfd, dest_relname, 0, x,
|
||||
©_into_self, &rename_succeeded);
|
||||
|
||||
+ /* BEGIN progress mod */
|
||||
+ if (progress && (x->rename_errno != 0 && ok)) {
|
||||
+ /* remove everything */
|
||||
+ int i;
|
||||
+ int limit = (g_iTotalFiles > 1 ? 6 : 3);
|
||||
+ if (!rename_succeeded)
|
||||
+ {
|
||||
+ for ( i = 0; i < limit; 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 );
|
||||
+
|
||||
+ /* increase counter */
|
||||
+ g_iFilesCopied++;
|
||||
+
|
||||
+ /* good-bye message */
|
||||
+ if ( x->last_file )
|
||||
+ {
|
||||
+ char sFType[20];
|
||||
+ if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied == g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)" );
|
||||
+ else if ( g_iDirectoriesCopied > 0 && g_iDirectoriesCopied < g_iFilesCopied )
|
||||
+ sprintf ( sFType, "%s", "folder(s)/file(s)" );
|
||||
+ else
|
||||
+ sprintf ( sFType, "%s", "file(s)" );
|
||||
+
|
||||
+ char f_time[20];
|
||||
+ format_time(f_time, sec_elapsed, false);
|
||||
+ printf ( "%d %s (%s) moved in %s (%s/s).\n", g_iFilesCopied, sFType,
|
||||
+ sTotalWritten, f_time, s_copy_speed );
|
||||
+ }
|
||||
+ }
|
||||
+ /* END progress mod */
|
||||
+
|
||||
if (ok)
|
||||
{
|
||||
char const *dir_to_remove;
|
||||
@@ -279,6 +401,7 @@
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-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\
|
||||
@@ -341,7 +464,7 @@
|
||||
/* Try to disable the ability to unlink a directory. */
|
||||
priv_set_remove_linkdir ();
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, nullptr))
|
||||
+ while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, nullptr))
|
||||
!= -1)
|
||||
{
|
||||
switch (c)
|
||||
@@ -354,6 +477,9 @@
|
||||
case 'f':
|
||||
x.interactive = I_ALWAYS_YES;
|
||||
break;
|
||||
+ case 'g':
|
||||
+ progress = true;
|
||||
+ break;
|
||||
case 'i':
|
||||
x.interactive = I_ASK_USER;
|
||||
break;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
ADVCPMV_VERSION=${1:-0.9}
|
||||
CORE_UTILS_VERSION=${2:-9.11}
|
||||
|
||||
curl -LO https://ftp.gnu.org/gnu/coreutils/coreutils-$CORE_UTILS_VERSION.tar.xz
|
||||
tar xvJf coreutils-$CORE_UTILS_VERSION.tar.xz
|
||||
rm coreutils-$CORE_UTILS_VERSION.tar.xz
|
||||
(
|
||||
cd coreutils-$CORE_UTILS_VERSION/
|
||||
curl -LO https://raw.githubusercontent.com/jarun/advcpmv/master/advcpmv-$ADVCPMV_VERSION-$CORE_UTILS_VERSION.patch
|
||||
patch -p1 -i advcpmv-$ADVCPMV_VERSION-$CORE_UTILS_VERSION.patch
|
||||
./configure
|
||||
make
|
||||
cp ./src/cp ../advcp
|
||||
cp ./src/mv ../advmv
|
||||
)
|
||||
rm -rf coreutils-$CORE_UTILS_VERSION
|
||||
Reference in New Issue
Block a user