]>
Commit | Line | Data |
---|---|---|
dbfc1835 | 1 | diff -ru coreutils-8.4.orig/src/copy.c coreutils-8.4/src/copy.c |
2 | --- coreutils-8.4.orig/src/copy.c 2010-01-25 16:03:29.606930239 +0100 | |
f2e36e57 | 3 | +++ coreutils-8.4/src/copy.c 2010-01-26 15:37:24.544158220 +0100 |
dbfc1835 | 4 | @@ -457,6 +457,56 @@ |
5 | return lchmod (name, mode); | |
6 | } | |
7 | ||
8 | +/* BEGIN progress mod */ | |
9 | +static void file_progress_bar ( char * _cDest, int _iBarLength, int _iProgress, int _iTotal ) | |
10 | +{ | |
11 | + // write number to progress bar | |
12 | + float fPercent = ( float ) _iProgress / ( float ) _iTotal * 100.f; | |
13 | + sprintf ( _cDest + ( _iBarLength - 6 ), "%4.1f", fPercent ); | |
14 | + // remove zero | |
15 | + _cDest[_iBarLength - 2] = ' '; | |
f2e36e57 | 16 | + |
dbfc1835 | 17 | + // fill rest with '-' |
18 | + int i; | |
19 | + for ( i = 1; i <= _iBarLength - 9; i++ ) | |
20 | + { | |
21 | + if ( fPercent > ( float ) ( i - 1 ) / ( _iBarLength - 10 ) * 100.f ) | |
22 | + _cDest[i] = '|'; | |
23 | + else | |
24 | + _cDest[i] = '-'; | |
25 | + } | |
26 | +} | |
27 | + | |
28 | +int file_size_format ( char * _cDst, int _iSize, int _iCounter ) | |
29 | +{ | |
30 | + int iCounter = _iCounter; | |
31 | + double dSize = ( double ) _iSize; | |
32 | + while ( dSize >= 1000. ) | |
33 | + { | |
34 | + dSize /= 1024.; | |
35 | + iCounter++; | |
36 | + } | |
f2e36e57 | 37 | + |
dbfc1835 | 38 | + /* get unit */ |
39 | + char * sUnit; | |
40 | + if ( iCounter == 0 ) | |
41 | + sUnit = "B"; | |
42 | + else if ( iCounter == 1 ) | |
43 | + sUnit = "KiB"; | |
44 | + else if ( iCounter == 2 ) | |
45 | + sUnit = "MiB"; | |
46 | + else if ( iCounter == 3 ) | |
47 | + sUnit = "GiB"; | |
48 | + else if ( iCounter == 4 ) | |
49 | + sUnit = "TiB"; | |
50 | + else | |
51 | + sUnit = "N/A"; | |
52 | + | |
53 | + /* write number */ | |
54 | + return sprintf ( _cDst, "%5.1f %s", dSize, sUnit ); | |
55 | +} | |
56 | +/* END progress mod */ | |
57 | + | |
58 | /* Copy a regular file from SRC_NAME to DST_NAME. | |
59 | If the source file contains holes, copies holes and blocks of zeros | |
60 | in the source file as holes in the destination file. | |
f2e36e57 | 61 | @@ -706,8 +756,146 @@ |
dbfc1835 | 62 | buf_alloc = xmalloc (buf_size + buf_alignment_slop); |
63 | buf = ptr_align (buf_alloc, buf_alignment); | |
64 | ||
dbfc1835 | 65 | + /* BEGIN progress mod */ |
66 | + /* create a field of 6 lines */ | |
f2e36e57 | 67 | + char ** cProgressField = ( char ** ) calloc ( 6, sizeof ( char * ) ); |
dbfc1835 | 68 | + /* get console width */ |
f2e36e57 | 69 | + int iBarLength = 80; |
dbfc1835 | 70 | + struct winsize win; |
71 | + if ( ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &win) == 0 && win.ws_col > 0 ) | |
72 | + iBarLength = win.ws_col; | |
73 | + /* create rows */ | |
f2e36e57 | 74 | + int it; |
dbfc1835 | 75 | + for ( it = 0; it < 6; it++ ) |
76 | + { | |
77 | + cProgressField[it] = ( char * ) malloc ( iBarLength + 1 ); | |
78 | + /* init with spaces */ | |
79 | + int j; | |
80 | + for ( j = 0; j < iBarLength; j++ ) | |
81 | + cProgressField[it][j] = ' '; | |
82 | + cProgressField[it][iBarLength] = '\0'; | |
83 | + } | |
f2e36e57 | 84 | + |
dbfc1835 | 85 | + /* global progress bar? */ |
86 | + if ( g_iTotalSize ) | |
87 | + { | |
88 | + /* init global progress bar */ | |
89 | + cProgressField[2][0] = '['; | |
90 | + cProgressField[2][iBarLength - 8] = ']'; | |
91 | + cProgressField[2][iBarLength - 7] = ' '; | |
92 | + cProgressField[2][iBarLength - 1] = '%'; | |
f2e36e57 | 93 | + |
dbfc1835 | 94 | + /* total size */ |
95 | + cProgressField[1][iBarLength - 11] = '/'; | |
96 | + file_size_format ( cProgressField[1] + iBarLength - 9, g_iTotalSize, 1 ); | |
f2e36e57 | 97 | + |
dbfc1835 | 98 | + /* show how many files were written */ |
99 | + int sum_length = sprintf ( cProgressField[1], "%d files copied so far...", g_iFilesCopied ); | |
100 | + cProgressField[1][sum_length] = ' '; | |
101 | + } | |
f2e36e57 | 102 | + |
dbfc1835 | 103 | + /* truncate filename? */ |
104 | + int fn_length; | |
105 | + if ( strlen ( src_name ) > iBarLength - 22 ) | |
106 | + fn_length = | |
107 | + sprintf ( cProgressField[4], "...%s", src_name + ( strlen ( src_name ) - iBarLength + 25 ) ); | |
108 | + else | |
109 | + fn_length = sprintf ( cProgressField[4], "%s", src_name ); | |
110 | + cProgressField[4][fn_length] = ' '; | |
f2e36e57 | 111 | + |
dbfc1835 | 112 | + /* filesize */ |
113 | + cProgressField[4][iBarLength - 11] = '/'; | |
114 | + file_size_format ( cProgressField[4] + iBarLength - 9, src_open_sb.st_size, 0 ); | |
f2e36e57 | 115 | + |
116 | + int iCountDown = 1; | |
dbfc1835 | 117 | + char * sProgressBar = cProgressField[5]; |
118 | + sProgressBar[0] = '['; | |
119 | + sProgressBar[iBarLength - 8] = ']'; | |
120 | + sProgressBar[iBarLength - 7] = ' '; | |
121 | + sProgressBar[iBarLength - 1] = '%'; | |
f2e36e57 | 122 | + |
123 | + /* this will always save the time in between */ | |
124 | + struct timeval last_time; | |
125 | + gettimeofday ( & last_time, NULL ); | |
126 | + int last_size = g_iTotalWritten; | |
dbfc1835 | 127 | + /* END progress mod */ |
f2e36e57 | 128 | + |
dca140ed | 129 | while (true) |
dbfc1835 | 130 | { |
131 | + if (progress) { | |
132 | + /* BEGIN progress mod */ | |
133 | + /* update countdown */ | |
134 | + iCountDown--; | |
135 | + if ( iCountDown < 0 ) | |
136 | + iCountDown = 100; | |
f2e36e57 | 137 | + |
dbfc1835 | 138 | + /* just print one line with the percentage, but not always */ |
139 | + if ( iCountDown == 0 ) | |
140 | + { | |
f2e36e57 | 141 | + /* calculate current speed */ |
142 | + struct timeval cur_time; | |
143 | + gettimeofday ( & cur_time, NULL ); | |
144 | + int cur_size = g_iTotalWritten + n_read_total / 1024; | |
145 | + int usec_elapsed = cur_time.tv_usec - last_time.tv_usec; | |
146 | + double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
147 | + sec_elapsed += ( double ) ( cur_time.tv_sec - last_time.tv_sec ); | |
148 | + int copy_speed = ( int ) ( ( double ) ( cur_size - last_size ) | |
149 | + / sec_elapsed ); | |
150 | + char s_copy_speed[20]; | |
151 | + file_size_format ( s_copy_speed, copy_speed, 1 ); | |
152 | + /* update vars */ | |
153 | + last_time = cur_time; | |
154 | + last_size = cur_size; | |
155 | + | |
156 | + /* how many time has passed since the start? */ | |
157 | + int isec_elapsed = cur_time.tv_sec - g_oStartTime.tv_sec; | |
158 | + int sec_remaining = ( int ) ( ( double ) isec_elapsed / cur_size | |
159 | + * g_iTotalSize ) - isec_elapsed; | |
160 | + int min_remaining = sec_remaining / 60; | |
161 | + sec_remaining -= min_remaining * 60; | |
162 | + int hours_remaining = min_remaining / 60; | |
163 | + min_remaining -= hours_remaining * 60; | |
164 | + /* print out */ | |
165 | + sprintf ( cProgressField[3], | |
166 | + "Copying at %s/s (about %dh %dm %ds remaining)", s_copy_speed, | |
167 | + hours_remaining, min_remaining, sec_remaining ); | |
168 | + | |
dbfc1835 | 169 | + int fs_len; |
170 | + if ( g_iTotalSize ) | |
171 | + { | |
172 | + /* global progress bar */ | |
173 | + file_progress_bar ( cProgressField[2], iBarLength, | |
174 | + g_iTotalWritten + n_read_total / 1024, g_iTotalSize ); | |
f2e36e57 | 175 | + |
dbfc1835 | 176 | + /* print the global status */ |
177 | + fs_len = file_size_format ( cProgressField[1] + iBarLength - 21, | |
178 | + g_iTotalWritten + n_read_total / 1024, 1 ); | |
179 | + cProgressField[1][iBarLength - 21 + fs_len] = ' '; | |
180 | + } | |
f2e36e57 | 181 | + |
dbfc1835 | 182 | + /* current progress bar */ |
183 | + file_progress_bar ( sProgressBar, iBarLength, n_read_total, src_open_sb.st_size ); | |
f2e36e57 | 184 | + |
dbfc1835 | 185 | + /* print the status */ |
186 | + fs_len = file_size_format ( cProgressField[4] + iBarLength - 21, n_read_total, 0 ); | |
187 | + cProgressField[4][iBarLength - 21 + fs_len] = ' '; | |
f2e36e57 | 188 | + |
dbfc1835 | 189 | + /* print the field */ |
190 | + for ( it = g_iTotalSize ? 0 : 3; it < 6; it++ ) | |
191 | + { | |
f2e36e57 | 192 | + printf ( "\033[K%s\n", cProgressField[it] ); |
dbfc1835 | 193 | + if ( strlen ( cProgressField[it] ) < iBarLength ) |
194 | + printf ( "" ); | |
195 | + } | |
196 | + if ( g_iTotalSize ) | |
197 | + printf ( "\r\033[6A" ); | |
198 | + else | |
199 | + printf ( "\r\033[3A" ); | |
200 | + fflush ( stdout ); | |
201 | + } | |
202 | + /* END progress mod */ | |
203 | + } | |
f2e36e57 | 204 | + |
dbfc1835 | 205 | word *wp = NULL; |
206 | ||
207 | ssize_t n_read = read (source_desc, buf, buf_size); | |
f2e36e57 | 208 | @@ -788,6 +976,19 @@ |
dbfc1835 | 209 | /proc with linux kernels from at least 2.6.9 .. 2.6.29. */ |
210 | } | |
211 | } | |
212 | +if (progress) { | |
213 | + /* BEGIN progress mod */ | |
214 | + /* update total size */ | |
215 | + g_iTotalWritten += n_read_total / 1024; | |
216 | + g_iFilesCopied++; | |
f2e36e57 | 217 | + |
dbfc1835 | 218 | + int i; |
219 | + for ( i = 0; i < 6; i++ ) | |
220 | + free ( cProgressField[i] ); | |
221 | + free ( cProgressField ); | |
222 | + /* END progress mod */ | |
223 | +} | |
224 | + | |
225 | ||
226 | /* If the file ends with a `hole', we need to do something to record | |
227 | the length of the file. On modern systems, calling ftruncate does | |
228 | diff -ru coreutils-8.4.orig/src/copy.h coreutils-8.4/src/copy.h | |
229 | --- coreutils-8.4.orig/src/copy.h 2010-01-25 16:03:29.606930239 +0100 | |
f2e36e57 | 230 | +++ coreutils-8.4/src/copy.h 2010-01-26 15:35:30.934163303 +0100 |
dbfc1835 | 231 | @@ -222,6 +222,9 @@ |
232 | Create destination directories as usual. */ | |
233 | bool symbolic_link; | |
234 | ||
235 | + /* if true, draw a nice progress bar on screen */ | |
236 | + bool progress_bar; | |
237 | + | |
238 | /* If true, do not copy a nondirectory that has an existing destination | |
239 | with the same or newer modification time. */ | |
240 | bool update; | |
f2e36e57 | 241 | @@ -280,4 +283,15 @@ |
dbfc1835 | 242 | bool chown_failure_ok (struct cp_options const *); |
243 | mode_t cached_umask (void); | |
244 | ||
245 | +/* BEGIN progress mod */ | |
246 | +int file_size_format ( char * _cDst, int _iSize, int _iCounter ); | |
247 | + | |
248 | +long g_iTotalSize; | |
249 | +long g_iTotalWritten; | |
250 | +int g_iFilesCopied; | |
f2e36e57 | 251 | +struct timeval g_oStartTime; |
252 | +int g_iTotalFiles; | |
dbfc1835 | 253 | +bool progress; |
254 | +/* END progress mod */ | |
255 | + | |
256 | #endif | |
257 | diff -ru coreutils-8.4.orig/src/cp.c coreutils-8.4/src/cp.c | |
258 | --- coreutils-8.4.orig/src/cp.c 2010-01-25 16:03:29.596930015 +0100 | |
52480cbc | 259 | +++ coreutils-8.4/src/cp.c 2010-01-26 15:42:02.274161757 +0100 |
260 | @@ -139,6 +139,7 @@ | |
dbfc1835 | 261 | {"target-directory", required_argument, NULL, 't'}, |
262 | {"update", no_argument, NULL, 'u'}, | |
263 | {"verbose", no_argument, NULL, 'v'}, | |
264 | + {"progress-bar", no_argument, NULL, 'g'}, | |
265 | {GETOPT_HELP_OPTION_DECL}, | |
266 | {GETOPT_VERSION_OPTION_DECL}, | |
267 | {NULL, 0, NULL, 0} | |
52480cbc | 268 | @@ -176,6 +177,7 @@ |
dbfc1835 | 269 | -f, --force if an existing destination file cannot be\n\ |
270 | opened, remove it and try again (redundant if\n\ | |
271 | the -n option is used)\n\ | |
272 | + -g, --progress-bar add progress-bar\n\ | |
273 | -i, --interactive prompt before overwrite (overrides a previous -n\n\ | |
274 | option)\n\ | |
275 | -H follow command-line symbolic links in SOURCE\n\ | |
52480cbc | 276 | @@ -612,6 +614,57 @@ |
dbfc1835 | 277 | quote (file[n_files - 1])); |
278 | } | |
f2e36e57 | 279 | |
dbfc1835 | 280 | + struct timeval start_time; |
f2e36e57 | 281 | +if (progress) { |
dbfc1835 | 282 | + /* BEGIN progress mod */ |
283 | + g_iTotalSize = 0; | |
284 | + g_iFilesCopied = 0; | |
285 | + g_iTotalWritten = 0; | |
f2e36e57 | 286 | + |
dbfc1835 | 287 | + /* save time */ |
288 | + gettimeofday ( & start_time, NULL ); | |
f2e36e57 | 289 | + g_oStartTime = start_time; |
290 | + | |
291 | + printf ( "Calculating total size... \r" ); | |
292 | + fflush ( stdout ); | |
293 | + long iTotalSize = 0; | |
294 | + int iFiles = n_files; | |
295 | + if ( ! target_directory ) | |
296 | + iFiles = n_files - 1; | |
297 | + int j; | |
298 | + for (j = 0; j < iFiles; j++) | |
299 | + { | |
52480cbc | 300 | + /* call du -s for each file */ |
301 | + /* create command */ | |
302 | + char command[1024]; | |
303 | + sprintf ( command, "du -s \"%s\"", file[j] ); | |
304 | + /* TODO: replace all quote signs in file[i] */ | |
305 | + | |
306 | + FILE *fp; | |
307 | + char output[1024]; | |
308 | + | |
309 | + /* run command */ | |
310 | + fp = popen(command, "r"); | |
311 | + if (fp == NULL || fgets(output, sizeof(output)-1, fp) == NULL) { | |
312 | + printf("failed to run du.\n" ); | |
313 | + } | |
314 | + else | |
315 | + { | |
316 | + /* isolate size */ | |
317 | + strchr ( output, '\t' )[0] = '\0'; | |
318 | + iTotalSize += atol ( output ); | |
f2e36e57 | 319 | + |
52480cbc | 320 | + printf ( "Calculating total size... %d\r", iTotalSize ); |
f2e36e57 | 321 | + fflush ( stdout ); |
52480cbc | 322 | + } |
f2e36e57 | 323 | + |
52480cbc | 324 | + /* close */ |
325 | + pclose(fp); | |
f2e36e57 | 326 | + } |
327 | + g_iTotalSize = iTotalSize; | |
dbfc1835 | 328 | + /* END progress mod */ |
329 | +} | |
f2e36e57 | 330 | + |
dbfc1835 | 331 | if (target_directory) |
332 | { | |
f2e36e57 | 333 | /* cp file1...filen edir |
52480cbc | 334 | @@ -754,6 +807,46 @@ |
dbfc1835 | 335 | ok = copy (source, new_dest, 0, x, &unused, NULL); |
336 | } | |
f2e36e57 | 337 | |
338 | +if (progress) { | |
dbfc1835 | 339 | + /* BEGIN progress mod */ |
340 | + /* remove everything */ | |
341 | + int i; | |
342 | + if ( g_iTotalSize ) | |
343 | + { | |
344 | + for ( i = 0; i < 6; i++ ) | |
345 | + printf ( "\033[K\n" ); | |
346 | + printf ( "\r\033[6A" ); | |
347 | + } | |
348 | + else | |
349 | + { | |
350 | + for ( i = 0; i < 3; i++ ) | |
351 | + printf ( "\033[K\n" ); | |
352 | + printf ( "\r\033[3A" ); | |
353 | + } | |
f2e36e57 | 354 | + |
dbfc1835 | 355 | + /* save time */ |
356 | + struct timeval end_time; | |
357 | + gettimeofday ( & end_time, NULL ); | |
358 | + int usec_elapsed = end_time.tv_usec - start_time.tv_usec; | |
359 | + double sec_elapsed = ( double ) usec_elapsed / 1000000.f; | |
360 | + sec_elapsed += ( double ) ( end_time.tv_sec - start_time.tv_sec ); | |
f2e36e57 | 361 | + |
dbfc1835 | 362 | + /* get total size */ |
363 | + char sTotalWritten[20]; | |
364 | + file_size_format ( sTotalWritten, g_iTotalSize, 1 ); | |
365 | + /* TODO: using g_iTotalWritten would be more correct, but is less accurate */ | |
f2e36e57 | 366 | + |
dbfc1835 | 367 | + /* calculate speed */ |
368 | + int copy_speed = ( int ) ( ( double ) g_iTotalWritten / sec_elapsed ); | |
369 | + char s_copy_speed[20]; | |
370 | + file_size_format ( s_copy_speed, copy_speed, 1 ); | |
f2e36e57 | 371 | + |
dbfc1835 | 372 | + /* good-bye message */ |
f2e36e57 | 373 | + printf ( "%d files (%s) copied in %.1f seconds (%s/s).\n", g_iFilesCopied, sTotalWritten, |
dbfc1835 | 374 | + sec_elapsed, s_copy_speed ); |
375 | + /* END progress mod */ | |
376 | +} | |
f2e36e57 | 377 | + |
dbfc1835 | 378 | return ok; |
379 | } | |
f2e36e57 | 380 | |
52480cbc | 381 | @@ -785,6 +878,7 @@ |
dbfc1835 | 382 | x->recursive = false; |
383 | x->sparse_mode = SPARSE_AUTO; | |
384 | x->symbolic_link = false; | |
385 | + x->progress_bar = false; | |
386 | x->set_mode = false; | |
387 | x->mode = 0; | |
388 | ||
52480cbc | 389 | @@ -923,7 +1017,7 @@ |
dbfc1835 | 390 | we'll actually use backup_suffix_string. */ |
391 | backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX"); | |
392 | ||
393 | - while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T", | |
394 | + while ((c = getopt_long (argc, argv, "abdfgHilLnprst:uvxPRS:T", | |
395 | long_opts, NULL)) | |
396 | != -1) | |
397 | { | |
52480cbc | 398 | @@ -975,6 +1069,10 @@ |
dbfc1835 | 399 | x.unlink_dest_after_failed_open = true; |
400 | break; | |
f2e36e57 | 401 | |
dbfc1835 | 402 | + case 'g': |
403 | + progress = true; | |
404 | + break; | |
f2e36e57 | 405 | + |
dbfc1835 | 406 | case 'H': |
407 | x.dereference = DEREF_COMMAND_LINE_ARGUMENTS; | |
dbfc1835 | 408 | break; |