]>
Commit | Line | Data |
---|---|---|
e79174a7 AM |
1 | diff -aur coreutils-8.32/src/copy.c coreutils-8.32-patched/src/copy.c |
2 | --- coreutils-8.32/src/copy.c 2020-01-01 19:43:12.000000000 +0530 | |
3 | +++ coreutils-8.32-patched/src/copy.c 2020-12-06 22:25:53.076852462 +0530 | |
4 | @@ -129,6 +129,72 @@ | |
5 | dev_t dev; | |
6 | }; | |
7 | ||
8 | +struct progress_status { | |
9 | + int iCountDown; | |
10 | + char ** cProgressField; | |
11 | + struct timeval last_time; | |
12 | + int last_size, iBarLength; | |
13 | + struct stat src_open_sb; | |
14 | +}; | |
15 | + | |
16 | +/* Begin progress Mod*/ | |
17 | +static void file_progress_bar ( char * _cDest, int _iBarLength, long _lProgress, long _lTotal ) | |
18 | +{ | |
19 | + double dPercent = (double) _lProgress / (double) _lTotal * 100.f; | |
20 | + sprintf( _cDest + ( _iBarLength - 6), "%4.1f", dPercent ); | |
21 | + _cDest[_iBarLength - 2] = ' '; | |
22 | + | |
23 | + int i; | |
24 | + for ( i=1; i<=_iBarLength - 9; i++) | |
25 | + { | |
26 | + if ( dPercent > (double) (i-1) / (_iBarLength - 10) * 100.f ) | |
27 | + { | |
28 | + _cDest[i] = '='; | |
29 | + } | |
30 | + else | |
31 | + { | |
32 | + _cDest[i] = ' '; | |
33 | + } | |
34 | + } | |
35 | + for ( i=1; i<_iBarLength - 9; i++) | |
36 | + { | |
37 | + if ( ( _cDest[i+1] == ' ' ) && ( _cDest[i] == '=' ) ) | |
38 | + _cDest[i] = '>' ; | |
39 | + } | |
40 | +} | |
41 | + | |
42 | +int file_size_format ( char * _cDst, long _lSize, int _iCounter ) | |
43 | +{ | |
44 | + int iCounter = _iCounter; | |
45 | + double dSize = ( double ) _lSize; | |
46 | + while ( dSize >= 1000. ) | |
47 | + { | |
48 | + dSize /= 1024.; | |
49 | + iCounter++; | |
50 | + } | |
51 | + | |
52 | + /* get unit */ | |
53 | + char * sUnit; | |
54 | + if ( iCounter == 0 ) | |
55 | + sUnit = "B"; | |
56 | + else if ( iCounter == 1 ) | |
57 | + sUnit = "KiB"; | |
58 | + else if ( iCounter == 2 ) | |
59 | + sUnit = "MiB"; | |
60 | + else if ( iCounter == 3 ) | |
61 | + sUnit = "GiB"; | |
62 | + else if ( iCounter == 4 ) | |
63 | + sUnit = "TiB"; | |
64 | + else | |
65 | + sUnit = "N/A"; | |
66 | + | |
67 | + /* write number */ | |
68 | + return sprintf ( _cDst, "%5.1f %s", dSize, sUnit ); | |
69 | +} | |
70 | +/* END progress mod */ | |
71 | + | |
72 | + | |
73 | + | |
74 | /* Initial size of the cp.dest_info hash table. */ | |
75 | #define DEST_INFO_INITIAL_CAPACITY 61 | |
76 | ||
77 | @@ -258,10 +324,11 @@ | |
78 | bytes read. */ | |
79 | static bool | |
80 | sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, | |
81 | - size_t hole_size, bool punch_holes, | |
82 | + size_t hole_size, bool punch_holes, bool move_mode, | |
83 | char const *src_name, char const *dst_name, | |
84 | uintmax_t max_n_read, off_t *total_n_read, | |
85 | - bool *last_write_made_hole) | |
86 | + bool *last_write_made_hole, | |
87 | + struct progress_status *s_progress) | |
88 | { | |
89 | *last_write_made_hole = false; | |
90 | *total_n_read = 0; | |
91 | @@ -270,6 +337,85 @@ | |
92 | ||
93 | while (max_n_read) | |
94 | { | |
95 | + | |
96 | + if (progress) { | |
97 | + /* BEGIN progress mod */ | |
98 | + /* update countdown */ | |
99 | + s_progress->iCountDown--; | |
100 | + char * sProgressBar = s_progress->cProgressField[5]; | |
101 | + if ( s_progress->iCountDown < 0 ) | |
102 | + s_progress->iCountDown = 100; | |
103 | + | |
104 | + /* just print one line with the percentage, but not always */ | |
105 | + if ( s_progress->iCountDown == 0 ) | |
106 | + { | |
107 | + /* calculate current speed */ | |
108 | + struct timeval cur_time; | |
109 | + gettimeofday ( & cur_time, NULL ); | |
110 | + int cur_size = g_iTotalWritten + *total_n_read / 1024; | |
111 | + int usec_elapsed = cur_time.tv_usec - s_progress->last_time.tv_usec; | |
112 | + double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
113 | + sec_elapsed += ( double ) ( cur_time.tv_sec - s_progress->last_time.tv_sec ); | |
114 | + int copy_speed = ( int ) ( ( double ) ( cur_size - s_progress->last_size ) | |
115 | + / sec_elapsed ); | |
116 | + char s_copy_speed[20]; | |
117 | + file_size_format ( s_copy_speed, copy_speed >= 0 ? copy_speed : 0, 1 ); | |
118 | + /* update vars */ | |
119 | + s_progress->last_time = cur_time; | |
120 | + s_progress->last_size = cur_size; | |
121 | + | |
122 | + /* how many time has passed since the start? */ | |
123 | + int isec_elapsed = cur_time.tv_sec - g_oStartTime.tv_sec; | |
124 | + int sec_remaining = ( int ) ( ( double ) isec_elapsed / cur_size | |
125 | + * g_iTotalSize ) - isec_elapsed; | |
126 | + int min_remaining = sec_remaining / 60; | |
127 | + sec_remaining -= min_remaining * 60; | |
128 | + int hours_remaining = min_remaining / 60; | |
129 | + min_remaining -= hours_remaining * 60; | |
130 | + /* print out */ | |
131 | + sprintf ( s_progress->cProgressField[3], | |
132 | + move_mode | |
133 | + ? "Moving at %s/s (about %uh %um %us remaining)" | |
134 | + : "Copying at %s/s (about %uh %um %us remaining)", s_copy_speed, | |
135 | + hours_remaining, min_remaining, sec_remaining ); | |
136 | + | |
137 | + int fs_len; | |
138 | + if ( g_iTotalFiles > 1 ) | |
139 | + { | |
140 | + /* global progress bar */ | |
141 | + file_progress_bar ( s_progress->cProgressField[2], s_progress->iBarLength, | |
142 | + g_iTotalWritten + *total_n_read / 1024, g_iTotalSize ); | |
143 | + | |
144 | + /* print the global status */ | |
145 | + fs_len = file_size_format ( s_progress->cProgressField[1] + s_progress->iBarLength - 21, | |
146 | + g_iTotalWritten + *total_n_read / 1024, 1 ); | |
147 | + s_progress->cProgressField[1][s_progress->iBarLength - 21 + fs_len] = ' '; | |
148 | + } | |
149 | + | |
150 | + /* current progress bar */ | |
151 | + file_progress_bar ( sProgressBar, s_progress->iBarLength, *total_n_read, s_progress->src_open_sb.st_size ); | |
152 | + | |
153 | + /* print the status */ | |
154 | + fs_len = file_size_format ( s_progress->cProgressField[4] + s_progress->iBarLength - 21, *total_n_read, 0 ); | |
155 | + s_progress->cProgressField[4][s_progress->iBarLength - 21 + fs_len] = ' '; | |
156 | + | |
157 | + /* print the field */ | |
158 | + int it; | |
159 | + for ( it = g_iTotalFiles>1 ? 0 : 3; it < 6; it++ ) | |
160 | + { | |
161 | + printf ( "\033[K%s\n", s_progress->cProgressField[it] ); | |
162 | + if ( strlen ( s_progress->cProgressField[it] ) < s_progress->iBarLength ) | |
163 | + printf ( "" ); | |
164 | + } | |
165 | + if ( g_iTotalFiles > 1 ) | |
166 | + printf ( "\r\033[6A" ); | |
167 | + else | |
168 | + printf ( "\r\033[3A" ); | |
169 | + fflush ( stdout ); | |
170 | + } | |
171 | + /* END progress mod */ | |
172 | + } | |
173 | + | |
174 | ssize_t n_read = read (src_fd, buf, MIN (max_n_read, buf_size)); | |
175 | if (n_read < 0) | |
176 | { | |
177 | @@ -354,6 +500,14 @@ | |
178 | certain files in /proc or /sys with linux kernels. */ | |
179 | } | |
180 | ||
181 | + /* BEGIN progress mod */ | |
182 | + if (progress) { | |
183 | + /* update total size */ | |
184 | + g_iTotalWritten += *total_n_read / 1024; | |
185 | + g_iFilesCopied++; | |
186 | + } | |
187 | + /* END progress mod */ | |
188 | + | |
189 | /* Ensure a trailing hole is created, so that subsequent | |
190 | calls of sparse_copy() start at the correct offset. */ | |
191 | if (make_hole && ! create_hole (dest_fd, dst_name, punch_holes, psize)) | |
192 | @@ -420,9 +574,11 @@ | |
193 | static bool | |
194 | extent_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, | |
195 | size_t hole_size, off_t src_total_size, | |
196 | - enum Sparse_type sparse_mode, | |
197 | + enum Sparse_type sparse_mode, bool move_mode, | |
198 | char const *src_name, char const *dst_name, | |
199 | - bool *require_normal_copy) | |
200 | + bool *require_normal_copy, | |
201 | + int iCountDown, char ** cProgressField, struct timeval last_time, | |
202 | + int last_size, int iBarLength, struct stat src_open_sb) | |
203 | { | |
204 | struct extent_scan scan; | |
205 | off_t last_ext_start = 0; | |
206 | @@ -553,10 +709,16 @@ | |
207 | last_ext_len = ext_len; | |
208 | bool read_hole; | |
209 | ||
210 | + struct timeval a; | |
211 | + struct stat b; | |
212 | + | |
213 | + struct progress_status s_progress={iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb}; | |
214 | + | |
215 | + | |
216 | if ( ! sparse_copy (src_fd, dest_fd, buf, buf_size, | |
217 | sparse_mode == SPARSE_ALWAYS ? hole_size: 0, | |
218 | - true, src_name, dst_name, ext_len, &n_read, | |
219 | - &read_hole)) | |
220 | + true, move_mode, src_name, dst_name, ext_len, | |
221 | + &n_read, &read_hole,&s_progress)) | |
222 | goto fail; | |
223 | ||
224 | dest_pos = ext_start + n_read; | |
225 | @@ -1305,6 +1467,71 @@ | |
226 | buf_alloc = xmalloc (buf_size + buf_alignment); | |
227 | buf = ptr_align (buf_alloc, buf_alignment); | |
228 | ||
229 | + /* BEGIN progress mod */ | |
230 | + /* create a field of 6 lines */ | |
231 | + char ** cProgressField = ( char ** ) calloc ( 6, sizeof ( char * ) ); | |
232 | + /* get console width */ | |
233 | + int iBarLength = 80; | |
234 | + struct winsize win; | |
235 | + if ( ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &win) == 0 && win.ws_col > 0 ) | |
236 | + if (win.ws_col > iBarLength) /* String printed may be longer on smaller screens */ | |
237 | + iBarLength = win.ws_col; | |
238 | + /* create rows */ | |
239 | + int it; | |
240 | + for ( it = 0; it < 6; it++ ) | |
241 | + { | |
242 | + cProgressField[it] = ( char * ) malloc ( iBarLength + 1 ); | |
243 | + /* init with spaces */ | |
244 | + int j; | |
245 | + for ( j = 0; j < iBarLength; j++ ) | |
246 | + cProgressField[it][j] = ' '; | |
247 | + cProgressField[it][iBarLength] = '\0'; | |
248 | + } | |
249 | + | |
250 | + /* global progress bar? */ | |
251 | + if ( g_iTotalFiles > 1 ) | |
252 | + { | |
253 | + /* init global progress bar */ | |
254 | + cProgressField[2][0] = '['; | |
255 | + cProgressField[2][iBarLength - 8] = ']'; | |
256 | + cProgressField[2][iBarLength - 7] = ' '; | |
257 | + cProgressField[2][iBarLength - 1] = '%'; | |
258 | + | |
259 | + /* total size */ | |
260 | + cProgressField[1][iBarLength - 11] = '/'; | |
261 | + file_size_format ( cProgressField[1] + iBarLength - 9, g_iTotalSize, 1 ); | |
262 | + | |
263 | + /* show how many files were written */ | |
264 | + int sum_length = sprintf ( cProgressField[1], "%d files copied so far...", g_iFilesCopied ); | |
265 | + cProgressField[1][sum_length] = ' '; | |
266 | + } | |
267 | + | |
268 | + /* truncate filename? */ | |
269 | + int fn_length; | |
270 | + if ( strlen ( src_name ) > iBarLength - 22 ) | |
271 | + fn_length = | |
272 | + sprintf ( cProgressField[4], "...%s", src_name + ( strlen ( src_name ) - iBarLength + 25 ) ); | |
273 | + else | |
274 | + fn_length = sprintf ( cProgressField[4], "%s", src_name ); | |
275 | + cProgressField[4][fn_length] = ' '; | |
276 | + | |
277 | + /* filesize */ | |
278 | + cProgressField[4][iBarLength - 11] = '/'; | |
279 | + file_size_format ( cProgressField[4] + iBarLength - 9, src_open_sb.st_size, 0 ); | |
280 | + | |
281 | + int iCountDown = 1; | |
282 | + char * sProgressBar = cProgressField[5]; | |
283 | + sProgressBar[0] = '['; | |
284 | + sProgressBar[iBarLength - 8] = ']'; | |
285 | + sProgressBar[iBarLength - 7] = ' '; | |
286 | + sProgressBar[iBarLength - 1] = '%'; | |
287 | + | |
288 | + /* this will always save the time in between */ | |
289 | + struct timeval last_time; | |
290 | + gettimeofday ( & last_time, NULL ); | |
291 | + int last_size = g_iTotalWritten; | |
292 | + /* END progress mod */ | |
293 | + | |
294 | if (sparse_src) | |
295 | { | |
296 | bool normal_copy_required; | |
297 | @@ -1316,7 +1543,9 @@ | |
298 | if (extent_copy (source_desc, dest_desc, buf, buf_size, hole_size, | |
299 | src_open_sb.st_size, | |
300 | make_holes ? x->sparse_mode : SPARSE_NEVER, | |
301 | - src_name, dst_name, &normal_copy_required)) | |
302 | + x->move_mode, src_name, dst_name, &normal_copy_required, | |
303 | + iCountDown, cProgressField, last_time, last_size, | |
304 | + iBarLength, src_open_sb)) | |
305 | goto preserve_metadata; | |
306 | ||
307 | if (! normal_copy_required) | |
308 | @@ -1328,11 +1557,12 @@ | |
309 | ||
310 | off_t n_read; | |
311 | bool wrote_hole_at_eof; | |
312 | + struct progress_status s_progress = { iCountDown, cProgressField, last_time, last_size, iBarLength, src_open_sb}; | |
313 | if (! sparse_copy (source_desc, dest_desc, buf, buf_size, | |
314 | make_holes ? hole_size : 0, | |
315 | - x->sparse_mode == SPARSE_ALWAYS, src_name, dst_name, | |
316 | - UINTMAX_MAX, &n_read, | |
317 | - &wrote_hole_at_eof)) | |
318 | + x->sparse_mode == SPARSE_ALWAYS, x->move_mode, | |
319 | + src_name, dst_name, UINTMAX_MAX, &n_read, | |
320 | + &wrote_hole_at_eof, &s_progress)) | |
321 | { | |
322 | return_val = false; | |
323 | goto close_src_and_dst_desc; | |
324 | @@ -1343,6 +1573,14 @@ | |
325 | return_val = false; | |
326 | goto close_src_and_dst_desc; | |
327 | } | |
328 | + /* BEGIN progress mod */ | |
329 | + if (progress) { | |
330 | + int i; | |
331 | + for ( i = 0; i < 6; i++ ) | |
332 | + free ( cProgressField[i] ); | |
333 | + free ( cProgressField ); | |
334 | + } | |
335 | + /* END progress mod */ | |
336 | } | |
337 | ||
338 | preserve_metadata: | |
339 | diff -aur coreutils-8.32/src/copy.h coreutils-8.32-patched/src/copy.h | |
340 | --- coreutils-8.32/src/copy.h 2020-01-01 19:43:12.000000000 +0530 | |
341 | +++ coreutils-8.32-patched/src/copy.h 2020-12-06 22:24:03.488405684 +0530 | |
342 | @@ -234,6 +234,9 @@ | |
343 | Create destination directories as usual. */ | |
344 | bool symbolic_link; | |
345 | ||
346 | + /* If true, draw a nice progress bar on screen */ | |
347 | + bool progress_bar; | |
348 | + | |
349 | /* If true, do not copy a nondirectory that has an existing destination | |
350 | with the same or newer modification time. */ | |
351 | bool update; | |
352 | @@ -304,4 +307,15 @@ | |
353 | bool chown_failure_ok (struct cp_options const *) _GL_ATTRIBUTE_PURE; | |
354 | mode_t cached_umask (void); | |
355 | ||
356 | +/* BEGIN OF PROGRESS MOD */ | |
357 | +int file_size_format ( char * _cDst, long _lSize, int _iCounter ); | |
358 | + | |
359 | +__attribute__((__common__)) long g_iTotalSize; | |
360 | +__attribute__((__common__)) long g_iTotalWritten; | |
361 | +__attribute__((__common__)) int g_iFilesCopied; | |
362 | +__attribute__((__common__)) struct timeval g_oStartTime; | |
363 | +__attribute__((__common__)) int g_iTotalFiles; | |
364 | +__attribute__((__common__)) bool progress; | |
365 | +/* END OF PROGRESS MOD */ | |
366 | + | |
367 | #endif | |
368 | diff -aur coreutils-8.32/src/cp.c coreutils-8.32-patched/src/cp.c | |
369 | --- coreutils-8.32/src/cp.c 2020-01-01 19:43:12.000000000 +0530 | |
370 | +++ coreutils-8.32-patched/src/cp.c 2020-12-06 22:24:03.488405684 +0530 | |
371 | @@ -131,6 +131,7 @@ | |
372 | {"symbolic-link", no_argument, NULL, 's'}, | |
373 | {"target-directory", required_argument, NULL, 't'}, | |
374 | {"update", no_argument, NULL, 'u'}, | |
375 | + {"progress-bar", no_argument, NULL, 'g'}, | |
376 | {"verbose", no_argument, NULL, 'v'}, | |
377 | {GETOPT_SELINUX_CONTEXT_OPTION_DECL}, | |
378 | {GETOPT_HELP_OPTION_DECL}, | |
379 | @@ -170,6 +171,7 @@ | |
380 | -f, --force if an existing destination file cannot be\n\ | |
381 | opened, remove it and try again (this option\n\ | |
382 | is ignored when the -n option is also used)\n\ | |
383 | + -g, --progress-bar add a progress bar\n\ | |
384 | -i, --interactive prompt before overwrite (overrides a previous -n\ | |
385 | \n\ | |
386 | option)\n\ | |
387 | @@ -635,6 +637,70 @@ | |
388 | die (EXIT_FAILURE, 0, _("target %s is not a directory"), | |
389 | quoteaf (file[n_files - 1])); | |
390 | } | |
391 | + struct timeval start_time; | |
392 | + if (progress) { | |
393 | + /* BEGIN progress mod */ | |
394 | + g_iTotalSize = 0; | |
395 | + g_iTotalFiles = 0; | |
396 | + g_iFilesCopied = 0; | |
397 | + g_iTotalWritten = 0; | |
398 | + | |
399 | + /* save time */ | |
400 | + gettimeofday ( & start_time, NULL ); | |
401 | + g_oStartTime = start_time; | |
402 | + | |
403 | + printf ( "Calculating total size... \r" ); | |
404 | + fflush ( stdout ); | |
405 | + long iTotalSize = 0; | |
406 | + int iFiles = n_files; | |
407 | + if ( ! target_directory ) | |
408 | + iFiles = n_files - 1; | |
409 | + int j; | |
410 | + | |
411 | + /* how many files are we copying */ | |
412 | + char command[1024]; | |
413 | + sprintf( command, "find \"%s\" -type f | wc -l", file[0]); | |
414 | + FILE *fp ; | |
415 | + char output[1024]; | |
416 | + fp = popen(command,"r"); | |
417 | + if ( fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) | |
418 | + printf("failed to run find.\n"); | |
419 | + else | |
420 | + g_iTotalFiles = atoi( output ) ; | |
421 | + | |
422 | + for (j = 0; j < iFiles; j++) | |
423 | + { | |
424 | + /* call du -s for each file */ | |
425 | + /* create command */ | |
426 | + char command[1024]; | |
427 | + sprintf ( command, "du -s \"%s\"", file[j] ); | |
428 | + /* TODO: replace all quote signs in file[i] */ | |
429 | + | |
430 | + FILE *fp; | |
431 | + char output[1024]; | |
432 | + | |
433 | + /* run command */ | |
434 | + fp = popen(command, "r"); | |
435 | + if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) { | |
436 | + printf("failed to run du.\n" ); | |
437 | + } | |
438 | + else | |
439 | + { | |
440 | + /* isolate size */ | |
441 | + strchr ( output, '\t' )[0] = '\0'; | |
442 | + iTotalSize += atol ( output ); | |
443 | + | |
444 | + printf ( "Calculating total size... %ld\r", iTotalSize ); | |
445 | + fflush ( stdout ); | |
446 | + } | |
447 | + | |
448 | + /* close */ | |
449 | + pclose(fp); | |
450 | + } | |
451 | + g_iTotalSize = iTotalSize; | |
452 | + /* END progress mod */ | |
453 | + } | |
454 | + | |
455 | ||
456 | if (target_directory) | |
457 | { | |
458 | @@ -777,6 +843,46 @@ | |
459 | ok = copy (source, new_dest, 0, x, &unused, NULL); | |
460 | } | |
461 | ||
462 | + if (progress) { | |
463 | + /* BEGIN progress mod */ | |
464 | + /* remove everything */ | |
465 | + int i; | |
466 | + if ( g_iTotalFiles > 1 ) | |
467 | + { | |
468 | + for ( i = 0; i < 6; i++ ) | |
469 | + printf ( "\033[K\n" ); | |
470 | + printf ( "\r\033[6A" ); | |
471 | + } | |
472 | + else | |
473 | + { | |
474 | + for ( i = 0; i < 3; i++ ) | |
475 | + printf ( "\033[K\n" ); | |
476 | + printf ( "\r\033[3A" ); | |
477 | + } | |
478 | + | |
479 | + /* save time */ | |
480 | + struct timeval end_time; | |
481 | + gettimeofday ( & end_time, NULL ); | |
482 | + int usec_elapsed = end_time.tv_usec - start_time.tv_usec; | |
483 | + double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
484 | + sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec ); | |
485 | + | |
486 | + /* get total size */ | |
487 | + char sTotalWritten[20]; | |
488 | + file_size_format ( sTotalWritten, g_iTotalSize, 1 ); | |
489 | + /* TODO: using g_iTotalWritten would be more correct, but is less accurate */ | |
490 | + | |
491 | + /* calculate speed */ | |
492 | + int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed ); | |
493 | + char s_copy_speed[20]; | |
494 | + file_size_format ( s_copy_speed, copy_speed, 1 ); | |
495 | + | |
496 | + /* good-bye message */ | |
497 | + printf ( "%d files (%s) copied in %.1f seconds (%s/s).\n", g_iFilesCopied, sTotalWritten, | |
498 | + sec_elapsed, s_copy_speed ); | |
499 | + /* END progress mod */ | |
500 | + } | |
501 | + | |
502 | return ok; | |
503 | } | |
504 | ||
505 | @@ -812,6 +918,7 @@ | |
506 | x->recursive = false; | |
507 | x->sparse_mode = SPARSE_AUTO; | |
508 | x->symbolic_link = false; | |
509 | + x->progress_bar = false; | |
510 | x->set_mode = false; | |
511 | x->mode = 0; | |
512 | ||
513 | @@ -950,7 +1057,7 @@ | |
514 | selinux_enabled = (0 < is_selinux_enabled ()); | |
515 | cp_option_init (&x); | |
516 | ||
517 | - while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ", | |
518 | + while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:TZ", | |
519 | long_opts, NULL)) | |
520 | != -1) | |
521 | { | |
522 | @@ -1007,6 +1114,10 @@ | |
523 | x.unlink_dest_after_failed_open = true; | |
524 | break; | |
525 | ||
526 | + case 'g': | |
527 | + progress = true; | |
528 | + break; | |
529 | + | |
530 | case 'H': | |
531 | x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; | |
532 | break; | |
533 | diff -aur coreutils-8.32/src/mv.c coreutils-8.32-patched/src/mv.c | |
534 | --- coreutils-8.32/src/mv.c 2020-01-01 19:43:12.000000000 +0530 | |
535 | +++ coreutils-8.32-patched/src/mv.c 2020-12-06 22:24:03.488405684 +0530 | |
536 | @@ -66,6 +66,7 @@ | |
537 | {"target-directory", required_argument, NULL, 't'}, | |
538 | {"update", no_argument, NULL, 'u'}, | |
539 | {"verbose", no_argument, NULL, 'v'}, | |
540 | + {"progress-ar", no_argument, NULL, 'g'}, | |
541 | {GETOPT_HELP_OPTION_DECL}, | |
542 | {GETOPT_VERSION_OPTION_DECL}, | |
543 | {NULL, 0, NULL, 0} | |
544 | @@ -168,10 +169,86 @@ | |
545 | static bool | |
546 | do_move (const char *source, const char *dest, const struct cp_options *x) | |
547 | { | |
548 | + struct timeval start_time; | |
549 | + | |
550 | bool copy_into_self; | |
551 | bool rename_succeeded; | |
552 | + if(progress && x->rename_errno != 0) { | |
553 | + /* BEGIN progress mod */ | |
554 | + g_iTotalSize = 0; | |
555 | + g_iFilesCopied = 0; | |
556 | + g_iTotalWritten = 0; | |
557 | + | |
558 | + gettimeofday (& start_time, NULL); | |
559 | + g_oStartTime = start_time; | |
560 | + | |
561 | + printf ("Calculating total size... \r"); | |
562 | + fflush (stdout); | |
563 | + long iTotalSize = 0; | |
564 | + /* call du -s for each file */ | |
565 | + /* create command */ | |
566 | + char command[1024]; | |
567 | + sprintf ( command, "du -s '%s'", source ); | |
568 | + /* TODO: replace all quote signs in file[i] */ | |
569 | + | |
570 | + FILE *fp; | |
571 | + char output[1024]; | |
572 | + | |
573 | + /* run command */ | |
574 | + fp = popen(command, "r"); | |
575 | + if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) { | |
576 | + //printf("failed to run du.\n" ); | |
577 | + } | |
578 | + else | |
579 | + { | |
580 | + /* isolate size */ | |
581 | + strchr ( output, '\t' )[0] = '\0'; | |
582 | + iTotalSize += atol ( output ); | |
583 | + printf ( "Calculating total size... %ld\r", iTotalSize ); | |
584 | + fflush ( stdout ); | |
585 | + } | |
586 | + | |
587 | + /* close */ | |
588 | + pclose(fp); | |
589 | + g_iTotalSize = iTotalSize; | |
590 | + /* END progress mod */ | |
591 | + | |
592 | + } | |
593 | + | |
594 | bool ok = copy (source, dest, false, x, ©_into_self, &rename_succeeded); | |
595 | ||
596 | + if (progress && (x->rename_errno != 0 && ok)) { | |
597 | + /* BEGIN progress mod */ | |
598 | + /* remove everything */ | |
599 | + int i; | |
600 | + int limit = (g_iTotalFiles > 1 ? 6 : 3); | |
601 | + for ( i = 0; i < limit; i++ ) | |
602 | + printf ( "\033[K\n" ); | |
603 | + printf ( "\r\033[3A" ); | |
604 | + | |
605 | + /* save time */ | |
606 | + struct timeval end_time; | |
607 | + gettimeofday ( & end_time, NULL ); | |
608 | + int usec_elapsed = end_time.tv_usec - start_time.tv_usec; | |
609 | + double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
610 | + sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec ); | |
611 | + | |
612 | + /* get total size */ | |
613 | + char sTotalWritten[20]; | |
614 | + file_size_format ( sTotalWritten, g_iTotalSize, 1 ); | |
615 | + /* TODO: using g_iTotalWritten would be more correct, but is less accurate */ | |
616 | + | |
617 | + /* calculate speed */ | |
618 | + int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed ); | |
619 | + char s_copy_speed[20]; | |
620 | + file_size_format ( s_copy_speed, copy_speed, 1 ); | |
621 | + | |
622 | + /* good-bye message */ | |
623 | + printf ( "%d files (%s) moved in %.1f seconds (%s/s).\n", g_iFilesCopied, sTotalWritten, | |
624 | + sec_elapsed, s_copy_speed ); | |
625 | + /* END progress mod */ | |
626 | + } | |
627 | + | |
628 | if (ok) | |
629 | { | |
630 | char const *dir_to_remove; | |
631 | @@ -306,6 +383,7 @@ | |
632 | \n\ | |
633 | -b like --backup but does not accept an argument\n\ | |
634 | -f, --force do not prompt before overwriting\n\ | |
635 | + -g, --progress-bar add progress-bar\n\ | |
636 | -i, --interactive prompt before overwrite\n\ | |
637 | -n, --no-clobber do not overwrite an existing file\n\ | |
638 | If you specify more than one of -i, -f, -n, only the final one takes effect.\n\ | |
639 | @@ -361,7 +439,7 @@ | |
640 | /* Try to disable the ability to unlink a directory. */ | |
641 | priv_set_remove_linkdir (); | |
642 | ||
643 | - while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL)) | |
644 | + while ((c = getopt_long (argc, argv, "bfint:uvgS:TZ", long_options, NULL)) | |
645 | != -1) | |
646 | { | |
647 | switch (c) | |
648 | @@ -407,6 +485,11 @@ | |
649 | case 'v': | |
650 | x.verbose = true; | |
651 | break; | |
652 | + | |
653 | + case 'g': | |
654 | + progress = true; | |
655 | + break; | |
656 | + | |
657 | case 'S': | |
658 | make_backups = true; | |
659 | backup_suffix = optarg; |