Lines 16-21
Link Here
|
16 |
|
16 |
|
17 |
/* Extracted from cp.c and librarified by Jim Meyering. */ |
17 |
/* Extracted from cp.c and librarified by Jim Meyering. */ |
18 |
|
18 |
|
|
|
19 |
/* Progress bar support added by Miika Pekkarinen. miipekk@ihme.org */ |
20 |
|
19 |
#include <config.h> |
21 |
#include <config.h> |
20 |
#include <stdio.h> |
22 |
#include <stdio.h> |
21 |
#include <assert.h> |
23 |
#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 "acl.h" |
39 |
#include "acl.h" |
34 |
#include "backupfile.h" |
40 |
#include "backupfile.h" |
Lines 53-58
Link Here
|
53 |
#include "write-any-file.h" |
59 |
#include "write-any-file.h" |
54 |
#include "areadlink.h" |
60 |
#include "areadlink.h" |
55 |
#include "yesno.h" |
61 |
#include "yesno.h" |
|
|
62 |
#include "xstrtol.h" |
63 |
#include "human.h" |
64 |
#include "quotearg.h" |
56 |
|
65 |
|
57 |
#if USE_XATTR |
66 |
#if USE_XATTR |
58 |
# include <attr/error_context.h> |
67 |
# include <attr/error_context.h> |
Lines 103-108
Link Here
|
103 |
/* Initial size of the cp.dest_info hash table. */ |
112 |
/* Initial size of the cp.dest_info hash table. */ |
104 |
#define DEST_INFO_INITIAL_CAPACITY 61 |
113 |
#define DEST_INFO_INITIAL_CAPACITY 61 |
105 |
|
114 |
|
|
|
115 |
#define SAMPLE_MAX 10 |
116 |
|
106 |
static bool copy_internal (char const *src_name, char const *dst_name, |
117 |
static bool copy_internal (char const *src_name, char const *dst_name, |
107 |
bool new_dst, dev_t device, |
118 |
bool new_dst, dev_t device, |
108 |
struct dir_list *ancestors, |
119 |
struct dir_list *ancestors, |
Lines 457-462
Link Here
|
457 |
return lchmod (name, mode); |
468 |
return lchmod (name, mode); |
458 |
} |
469 |
} |
459 |
|
470 |
|
|
|
471 |
/* Shorten a string '/long path/long file' to 'long fi...' |
472 |
Also adds padding bytes to end of the string if necessary */ |
473 |
char *shorten_name(const char *str, size_t max_width) |
474 |
{ |
475 |
char *shortname; |
476 |
const char *filename; |
477 |
size_t len; |
478 |
|
479 |
filename = base_name (str); |
480 |
len = strlen(filename); |
481 |
shortname = (char *) xmalloc (max_width + 1); |
482 |
strncpy (shortname, filename, max_width); |
483 |
shortname[max_width] = '\0'; |
484 |
if (len > max_width) |
485 |
{ |
486 |
memset(shortname + max_width - 3, '.', 3); |
487 |
} |
488 |
else |
489 |
{ |
490 |
memset(shortname + len, ' ', max_width - len); |
491 |
} |
492 |
|
493 |
return shortname; |
494 |
} |
495 |
|
460 |
/* Copy a regular file from SRC_NAME to DST_NAME. |
496 |
/* Copy a regular file from SRC_NAME to DST_NAME. |
461 |
If the source file contains holes, copies holes and blocks of zeros |
497 |
If the source file contains holes, copies holes and blocks of zeros |
462 |
in the source file as holes in the destination file. |
498 |
in the source file as holes in the destination file. |
Lines 486-491
Link Here
|
486 |
struct stat src_open_sb; |
522 |
struct stat src_open_sb; |
487 |
bool return_val = true; |
523 |
bool return_val = true; |
488 |
bool data_copy_required = true; |
524 |
bool data_copy_required = true; |
|
|
525 |
time_t t_start; |
526 |
time_t t_last; |
527 |
time_t t_now; |
528 |
off_t last_bytes = 0; |
529 |
int progress_bar_printed = 0; |
530 |
char *shortname = NULL; |
531 |
off_t sample_window[SAMPLE_MAX]; |
532 |
off_t sample_sum = 0; |
533 |
int sample_count = 0; |
534 |
long int line_length = 0; |
535 |
#ifdef TIOCGWINSZ |
536 |
struct winsize ws; |
537 |
#endif |
489 |
|
538 |
|
490 |
source_desc = open (src_name, |
539 |
source_desc = open (src_name, |
491 |
(O_RDONLY | O_BINARY |
540 |
(O_RDONLY | O_BINARY |
Lines 706-711
Link Here
|
706 |
buf_alloc = xmalloc (buf_size + buf_alignment_slop); |
755 |
buf_alloc = xmalloc (buf_size + buf_alignment_slop); |
707 |
buf = ptr_align (buf_alloc, buf_alignment); |
756 |
buf = ptr_align (buf_alloc, buf_alignment); |
708 |
|
757 |
|
|
|
758 |
time (&t_start); |
759 |
t_last = t_start; |
760 |
|
709 |
for (;;) |
761 |
for (;;) |
710 |
{ |
762 |
{ |
711 |
word *wp = NULL; |
763 |
word *wp = NULL; |
Lines 787-792
Link Here
|
787 |
file. Unfortunately that doesn't work for certain files in |
839 |
file. Unfortunately that doesn't work for certain files in |
788 |
/proc with linux kernels from at least 2.6.9 .. 2.6.29. */ |
840 |
/proc with linux kernels from at least 2.6.9 .. 2.6.29. */ |
789 |
} |
841 |
} |
|
|
842 |
|
843 |
time (&t_now); |
844 |
|
845 |
/* Progress bar stuff */ |
846 |
if (! x->pbar_show || t_now - t_start < x->pbar_delay) |
847 |
{ |
848 |
continue; |
849 |
} |
850 |
|
851 |
if (! progress_bar_printed) |
852 |
{ |
853 |
/* Column width check code copied from ls.c */ |
854 |
char const *p = getenv ("COLUMNS"); |
855 |
if (p && *p) |
856 |
{ |
857 |
long int tmp_long; |
858 |
if (xstrtol (p, NULL, 0, &tmp_long, NULL) == LONGINT_OK |
859 |
&& 0 < tmp_long && tmp_long <= INT_MAX) |
860 |
{ |
861 |
line_length = tmp_long; |
862 |
} |
863 |
else |
864 |
{ |
865 |
error (0, 0, |
866 |
_("ignoring invalid width in environment \ |
867 |
variable COLUMNS: %s"), |
868 |
quotearg (p)); |
869 |
} |
870 |
} |
871 |
|
872 |
#ifdef TIOCGWINSZ |
873 |
if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) |
874 |
{ |
875 |
line_length = ws.ws_col; |
876 |
} |
877 |
#endif |
878 |
if (line_length < 50) |
879 |
{ |
880 |
continue; |
881 |
} |
882 |
|
883 |
/* Take a short filename for progress bar */ |
884 |
shortname = shorten_name(src_name, line_length - 48); |
885 |
progress_bar_printed = 1; |
886 |
} |
887 |
|
888 |
if (t_now == t_last) |
889 |
{ |
890 |
continue; |
891 |
} |
892 |
|
893 |
if (sample_count == SAMPLE_MAX) |
894 |
{ |
895 |
int i; |
896 |
|
897 |
sample_sum -= sample_window[0]; |
898 |
for (i = 0; i < SAMPLE_MAX - 1; i++) |
899 |
{ |
900 |
sample_window[i] = sample_window[i + 1]; |
901 |
} |
902 |
} |
903 |
else |
904 |
{ |
905 |
sample_count++; |
906 |
} |
907 |
|
908 |
{ |
909 |
char str_size[LONGEST_HUMAN_READABLE + 1]; |
910 |
char str_speed[LONGEST_HUMAN_READABLE + 1]; |
911 |
char etabuf[64]; |
912 |
time_t t_temp; |
913 |
|
914 |
sample_window[sample_count - 1] = (n_read_total - last_bytes) / |
915 |
(t_now - t_last); |
916 |
sample_sum += sample_window[sample_count - 1]; |
917 |
|
918 |
/* Calculate the remaining time */ |
919 |
t_temp = (src_open_sb.st_size - n_read_total) / (sample_sum / sample_count); |
920 |
|
921 |
/* Don't print the progress bar if the estimated remaining |
922 |
time is low. */ |
923 |
if (progress_bar_printed == 1 && t_temp < x->pbar_min_est) |
924 |
{ |
925 |
continue; |
926 |
} |
927 |
progress_bar_printed = 2; |
928 |
|
929 |
strftime(etabuf, sizeof etabuf, "%H:%M.%S", |
930 |
gmtime(&t_temp)); |
931 |
printf (_("%s | %3lu%% | %9s | %9s/s | ETA %s\r"), shortname, |
932 |
(unsigned long)(n_read_total * 100 / src_open_sb.st_size), |
933 |
human_readable(src_open_sb.st_size, str_size, human_autoscale|human_base_1024|human_space_before_unit|human_SI|human_B, 1, 1), |
934 |
human_readable(sample_sum / sample_count, str_speed, human_autoscale|human_base_1024|human_space_before_unit|human_SI|human_B, 1, 1), |
935 |
etabuf); |
936 |
fflush (stdout); |
937 |
t_last = t_now; |
938 |
last_bytes = n_read_total; |
939 |
} |
940 |
} |
941 |
|
942 |
/* Print a newline if progress bar is enabled and has been shown */ |
943 |
if (progress_bar_printed == 2) |
944 |
{ |
945 |
printf ("%s | 100%%\n", shortname); |
790 |
} |
946 |
} |
791 |
|
947 |
|
792 |
/* If the file ends with a `hole', we need to do something to record |
948 |
/* If the file ends with a `hole', we need to do something to record |
Lines 900-905
Link Here
|
900 |
return_val = false; |
1056 |
return_val = false; |
901 |
} |
1057 |
} |
902 |
|
1058 |
|
|
|
1059 |
if (shortname != NULL) |
1060 |
{ |
1061 |
free (shortname); |
1062 |
} |
1063 |
|
903 |
free (buf_alloc); |
1064 |
free (buf_alloc); |
904 |
free (name_alloc); |
1065 |
free (name_alloc); |
905 |
return return_val; |
1066 |
return return_val; |