Lines 17-22
Link Here
|
17 |
|
17 |
|
18 |
/* Extracted from cp.c and librarified by Jim Meyering. */ |
18 |
/* Extracted from cp.c and librarified by Jim Meyering. */ |
19 |
|
19 |
|
|
|
20 |
/* Progress bar support added by Miika Pekkarinen. miipekk@ihme.org */ |
21 |
|
20 |
#include <config.h> |
22 |
#include <config.h> |
21 |
#include <stdio.h> |
23 |
#include <stdio.h> |
22 |
#include <assert.h> |
24 |
#include <assert.h> |
Lines 29-34
Link Here
|
29 |
# include <priv.h> |
31 |
# include <priv.h> |
30 |
#endif |
32 |
#endif |
31 |
|
33 |
|
|
|
34 |
#ifdef GWINSZ_IN_SYS_IOCTL |
35 |
# include <sys/ioctl.h> |
36 |
#endif |
37 |
|
32 |
#include "system.h" |
38 |
#include "system.h" |
33 |
#include "backupfile.h" |
39 |
#include "backupfile.h" |
34 |
#include "copy.h" |
40 |
#include "copy.h" |
Lines 50-55
Link Here
|
50 |
#include "utimens.h" |
56 |
#include "utimens.h" |
51 |
#include "xreadlink.h" |
57 |
#include "xreadlink.h" |
52 |
#include "yesno.h" |
58 |
#include "yesno.h" |
|
|
59 |
#include "xstrtol.h" |
60 |
#include "human.h" |
61 |
#include "quotearg.h" |
53 |
|
62 |
|
54 |
#ifndef HAVE_FCHMOD |
63 |
#ifndef HAVE_FCHMOD |
55 |
# define HAVE_FCHMOD false |
64 |
# define HAVE_FCHMOD false |
Lines 85-90
Link Here
|
85 |
/* Initial size of the above hash table. */ |
94 |
/* Initial size of the above hash table. */ |
86 |
#define DEST_INFO_INITIAL_CAPACITY 61 |
95 |
#define DEST_INFO_INITIAL_CAPACITY 61 |
87 |
|
96 |
|
|
|
97 |
#define SAMPLE_MAX 10 |
98 |
|
88 |
static bool copy_internal (char const *src_name, char const *dst_name, |
99 |
static bool copy_internal (char const *src_name, char const *dst_name, |
89 |
bool new_dst, dev_t device, |
100 |
bool new_dst, dev_t device, |
90 |
struct dir_list *ancestors, |
101 |
struct dir_list *ancestors, |
Lines 191-196
Link Here
|
191 |
return ok; |
202 |
return ok; |
192 |
} |
203 |
} |
193 |
|
204 |
|
|
|
205 |
/* Shorten a string '/long path/long file' to 'long fi...' |
206 |
Also adds padding bytes to end of the string if necessary */ |
207 |
char *shorten_name(const char *str, size_t max_width) |
208 |
{ |
209 |
char *shortname; |
210 |
const char *filename; |
211 |
size_t len; |
212 |
|
213 |
filename = base_name (str); |
214 |
len = strlen(filename); |
215 |
shortname = (char *) xmalloc (max_width + 1); |
216 |
strncpy (shortname, filename, max_width); |
217 |
shortname[max_width] = '\0'; |
218 |
if (len > max_width) |
219 |
{ |
220 |
memset(shortname + max_width - 3, '.', 3); |
221 |
} |
222 |
else |
223 |
{ |
224 |
memset(shortname + len, ' ', max_width - len); |
225 |
} |
226 |
|
227 |
return shortname; |
228 |
} |
229 |
|
194 |
/* Copy a regular file from SRC_NAME to DST_NAME. |
230 |
/* Copy a regular file from SRC_NAME to DST_NAME. |
195 |
If the source file contains holes, copies holes and blocks of zeros |
231 |
If the source file contains holes, copies holes and blocks of zeros |
196 |
in the source file as holes in the destination file. |
232 |
in the source file as holes in the destination file. |
Lines 222-227
Link Here
|
222 |
off_t n_read_total = 0; |
258 |
off_t n_read_total = 0; |
223 |
bool last_write_made_hole = false; |
259 |
bool last_write_made_hole = false; |
224 |
bool make_holes = false; |
260 |
bool make_holes = false; |
|
|
261 |
time_t t_start; |
262 |
time_t t_last; |
263 |
time_t t_now; |
264 |
off_t last_bytes = 0; |
265 |
int progress_bar_printed = 0; |
266 |
char *shortname = NULL; |
267 |
off_t sample_window[SAMPLE_MAX]; |
268 |
off_t sample_sum = 0; |
269 |
int sample_count = 0; |
270 |
long int line_length = 0; |
271 |
#ifdef TIOCGWINSZ |
272 |
struct winsize ws; |
273 |
#endif |
225 |
|
274 |
|
226 |
source_desc = open (src_name, O_RDONLY | O_BINARY); |
275 |
source_desc = open (src_name, O_RDONLY | O_BINARY); |
227 |
if (source_desc < 0) |
276 |
if (source_desc < 0) |
Lines 326-331
Link Here
|
326 |
buf = alloca (buf_size + sizeof (int) + buf_alignment - 1); |
375 |
buf = alloca (buf_size + sizeof (int) + buf_alignment - 1); |
327 |
buf = ptr_align (buf, buf_alignment); |
376 |
buf = ptr_align (buf, buf_alignment); |
328 |
|
377 |
|
|
|
378 |
time (&t_start); |
379 |
t_last = t_start; |
380 |
|
329 |
for (;;) |
381 |
for (;;) |
330 |
{ |
382 |
{ |
331 |
ssize_t n_read = read (source_desc, buf, buf_size); |
383 |
ssize_t n_read = read (source_desc, buf, buf_size); |
Lines 390-395
Link Here
|
390 |
} |
442 |
} |
391 |
last_write_made_hole = false; |
443 |
last_write_made_hole = false; |
392 |
} |
444 |
} |
|
|
445 |
|
446 |
time (&t_now); |
447 |
|
448 |
/* Progress bar stuff */ |
449 |
if (! x->pbar_show || t_now - t_start < x->pbar_delay) |
450 |
{ |
451 |
continue; |
452 |
} |
453 |
|
454 |
if (! progress_bar_printed) |
455 |
{ |
456 |
/* Column width check code copied from ls.c */ |
457 |
char const *p = getenv ("COLUMNS"); |
458 |
if (p && *p) |
459 |
{ |
460 |
long int tmp_long; |
461 |
if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK |
462 |
&& 0 < tmp_long && tmp_long <= INT_MAX) |
463 |
{ |
464 |
line_length = tmp_long; |
465 |
} |
466 |
else |
467 |
{ |
468 |
error (0, 0, |
469 |
_("ignoring invalid width in environment \ |
470 |
variable COLUMNS: %s"), |
471 |
quotearg (p)); |
472 |
} |
473 |
} |
474 |
|
475 |
#ifdef TIOCGWINSZ |
476 |
if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) |
477 |
{ |
478 |
line_length = ws.ws_col; |
479 |
} |
480 |
#endif |
481 |
if (line_length < 50) |
482 |
{ |
483 |
continue; |
484 |
} |
485 |
|
486 |
/* Take a short filename for progress bar */ |
487 |
shortname = shorten_name(src_name, line_length - 48); |
488 |
progress_bar_printed = 1; |
489 |
} |
490 |
|
491 |
if (t_now == t_last) |
492 |
{ |
493 |
continue; |
494 |
} |
495 |
|
496 |
if (sample_count == SAMPLE_MAX) |
497 |
{ |
498 |
int i; |
499 |
|
500 |
sample_sum -= sample_window[0]; |
501 |
for (i = 0; i < SAMPLE_MAX - 1; i++) |
502 |
{ |
503 |
sample_window[i] = sample_window[i + 1]; |
504 |
} |
505 |
} |
506 |
else |
507 |
{ |
508 |
sample_count++; |
509 |
} |
510 |
|
511 |
{ |
512 |
char str_size[LONGEST_HUMAN_READABLE + 1]; |
513 |
char str_speed[LONGEST_HUMAN_READABLE + 1]; |
514 |
char etabuf[64]; |
515 |
time_t t_temp; |
516 |
|
517 |
sample_window[sample_count - 1] = (n_read_total - last_bytes) / |
518 |
(t_now - t_last); |
519 |
sample_sum += sample_window[sample_count - 1]; |
520 |
|
521 |
/* Calculate the remaining time */ |
522 |
t_temp = (src_open_sb.st_size - n_read_total) / (sample_sum / sample_count); |
523 |
|
524 |
/* Don't print the progress bar if the estimated remaining |
525 |
time is low. */ |
526 |
if (progress_bar_printed == 1 && t_temp < x->pbar_min_est) |
527 |
{ |
528 |
continue; |
529 |
} |
530 |
progress_bar_printed = 2; |
531 |
|
532 |
strftime(etabuf, sizeof etabuf, "%H:%M.%S", |
533 |
gmtime(&t_temp)); |
534 |
printf (_("%s | %3lu%% | %9s | %9s/s | ETA %s\r"), shortname, |
535 |
(unsigned long)(n_read_total * 100 / src_open_sb.st_size), |
536 |
human_readable(src_open_sb.st_size, str_size, human_autoscale|human_base_1024|human_space_before_unit|human_SI|human_B, 1, 1), |
537 |
human_readable(sample_sum / sample_count, str_speed, human_autoscale|human_base_1024|human_space_before_unit|human_SI|human_B, 1, 1), |
538 |
etabuf); |
539 |
fflush (stdout); |
540 |
t_last = t_now; |
541 |
last_bytes = n_read_total; |
542 |
} |
543 |
} |
544 |
|
545 |
/* Print a newline if progress bar is enabled and has been shown */ |
546 |
if (progress_bar_printed == 2) |
547 |
{ |
548 |
printf ("%s | 100%%\n", shortname); |
393 |
} |
549 |
} |
394 |
|
550 |
|
395 |
/* If the file ends with a `hole', something needs to be written at |
551 |
/* If the file ends with a `hole', something needs to be written at |
Lines 488-493
Link Here
|
488 |
return_val = false; |
644 |
return_val = false; |
489 |
} |
645 |
} |
490 |
|
646 |
|
|
|
647 |
if (shortname != NULL) |
648 |
{ |
649 |
free (shortname); |
650 |
} |
651 |
|
491 |
return return_val; |
652 |
return return_val; |
492 |
} |
653 |
} |
493 |
|
654 |
|