Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions lib/compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,23 +184,33 @@ char *do_big_num(int64 num, int human_flag, const char *fract)
if (human_flag > 1) {
unsigned int mult = human_flag == 2 ? 1000 : 1024;

if (abs_num >= mult) {
const char* units = " KMGTPE";
uint64_t powi = 1;
char units[] = "\0KMGTPE";
char *unit = units;
uint64_t powi = 1;

for (;;) {
if (abs_num / mult < powi)
break;
for (;;) {
if (abs_num / mult < powi)
break;

if (units[1] == '\0')
break;
if (unit[1] == '\0')
break;

powi *= mult;
++unit;
}
unit[1] = '\0';

if (powi > 1) {
unsigned int powj = 1, precision = 2;

powi *= mult;
++units;
for (; precision > 0; precision--) {
powj *= 10;
if (abs_num / powi < powj)
break;
}

snprintf(bufs[n], sizeof bufs[0], "%.2f%c",
(double) num / powi, *units);
snprintf(bufs[n], sizeof bufs[0], "%.*f%s%s", precision,
(double) num / powi, unit, *unit && mult == 1024 ? "i" : "");
return bufs[n];
}
}
Expand Down
21 changes: 5 additions & 16 deletions progress.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ static unsigned long msdiff(struct timeval *t1, struct timeval *t2)
static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_last)
{
char rembuf[64], eol[128];
const char *units;
unsigned long diff;
double rate, remain;
int pct;
Expand All @@ -93,26 +92,16 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_l
/* Compute stats based on the starting info. */
if (!ph_start.time.tv_sec || !(diff = msdiff(&ph_start.time, now)))
diff = 1;
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff / 1024.0;
rate = (double) (ofs - ph_start.ofs) * 1000.0 / diff;
/* Switch to total time taken for our last update. */
remain = (double) diff / 1000.0;
} else {
strlcpy(eol, " ", sizeof eol);
/* Compute stats based on recent progress. */
if (!(diff = msdiff(&ph_list[oldest_hpos].time, now)))
diff = 1;
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 / diff / 1024.0;
remain = rate ? (double) (size - ofs) / rate / 1000.0 : 0.0;
}

if (rate > 1024*1024) {
rate /= 1024.0 * 1024.0;
units = "GB/s";
} else if (rate > 1024) {
rate /= 1024.0;
units = "MB/s";
} else {
units = "kB/s";
rate = (double) (ofs - ph_list[oldest_hpos].ofs) * 1000.0 / diff;
remain = rate ? (double) (size - ofs) / rate : 0.0;
}

if (remain < 0 || remain > 9999.0 * 3600.0)
Expand All @@ -127,8 +116,8 @@ static void rprint_progress(OFF_T ofs, OFF_T size, struct timeval *now, int is_l
output_needs_newline = 0;
pct = ofs == size ? 100 : (int) (100.0 * ofs / size);
rput_progress();
rprintf(FCLIENT, "%15s %3d%% %7.2f%s %s%s",
human_num(ofs), pct, rate, units, rembuf, eol);
rprintf(FCLIENT, "%15sB %3d%% %7sB/s %s%s", human_num(ofs), pct,
rate >= INT64_MAX ? ">MAX " : human_num((int64)rate), rembuf, eol);
if (!is_last && !quiet) {
output_needs_newline = 1;
rflush(FCLIENT);
Expand Down
18 changes: 11 additions & 7 deletions rsync.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -3616,7 +3616,11 @@ sign) if you want the local shell to expand it.
The unit letters that are appended in levels 2 and 3 are: `K` (kilo), `M`
(mega), `G` (giga), `T` (tera), `P` (peta) or `E` (exa). For example, a
1234567-byte file would output as 1.23M in level-2 (assuming that a
period is your local decimal point).
period is your local decimal point). Dynamic precision is applied, so the
three most-significant digits are shown (for example: 3.45M -> 46.7M ->
523M -> 1.24G -> ...).
Additionally an `i` is appended in level-3 to indicate the binary base.
The same file would output as 1.17Mi in level-3.

Backward compatibility note: versions of rsync prior to 3.1.0 (September 2013) do not
support human-readable level 1, and they default to level 0. Thus,
Expand Down Expand Up @@ -3784,10 +3788,10 @@ sign) if you want the local shell to expand it.
While rsync is transferring a regular file, it updates a progress line that
looks like this:

> 782448 63% 110.64kB/s 0:00:04
> 782,448B 63% 113,295B/s 0:00:04

In this example, the receiver has reconstructed 782448 bytes or 63% of the
sender's file, which is being reconstructed at a rate of 110.64 kilobytes
In this example, the receiver has reconstructed 782,448 bytes or 63% of the
sender's file, which is being reconstructed at a rate of 113,295 bytes
per second, and the transfer will finish in 4 seconds if the current rate
is maintained until the end.

Expand All @@ -3801,11 +3805,11 @@ sign) if you want the local shell to expand it.
When the file transfer finishes, rsync replaces the progress line with a
summary line that looks like this:

> 1,238,099 100% 146.38kB/s 0:00:08 (xfr#5, to-chk=169/396)
> 1,238,099B 100% 149,893B/s 0:00:08 (xfr#5, to-chk=169/396)

In this example, the file was 1,238,099 bytes long in total, the average
rate of transfer for the whole file was 146.38 kilobytes per second over
the 8 seconds that it took to complete, it was the 5th transfer of a
rate of transfer for the whole file was 149,893 bytes per second over the
8 seconds that it took to complete, it was the 5th transfer of a
regular file during the current rsync session, and there are 169 more files
for the receiver to check (to see if they are up-to-date or not) remaining
out of the 396 total files in the file-list.
Expand Down
27 changes: 25 additions & 2 deletions testsuite/output-options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ def out(*args, want_rc=0, env=None, text=True):
# --- --progress shows a percentage ------------------------------------------
rmtree(TODIR)
p = out('-a', '--progress', f'{src}/', f'{TODIR}/')
if '100%' not in p.stdout:
test_fail(f"--progress did not show a percentage:\n{p.stdout}")
progress_re = r'[\d.,]+B\s+100%\s+[\d.,]+B/s\s+\d+:\d\d:\d\d'
if not re.search(progress_re, p.stdout):
test_fail(f"--progress did not show the expected final shape:\n{p.stdout}")

# --quiet must suppress the progress carriage return as well as its text.
rmtree(TODIR)
Expand All @@ -121,6 +122,28 @@ def out(*args, want_rc=0, env=None, text=True):
if re.search(suffix_re, plain):
test_fail(f"--stats without -h unexpectedly used a unit suffix:\n{plain}")

rmtree(TODIR)
human_binary = out('-a', '-hh', '--stats', f'{src}/', f'{TODIR}/').stdout
if 'Total file size: 48.8Ki bytes' not in human_binary:
test_fail(f"-hh did not use dynamic binary-unit precision:\n{human_binary}")

rmtree(src)
rmtree(TODIR)
makepath(src)
make_data_file(src / 'threshold', 1024)
threshold = out('-a', '-hh', '--stats', f'{src}/', f'{TODIR}/').stdout
if 'Total file size: 1.00Ki bytes' not in threshold:
test_fail(f"-hh did not show an exact-threshold binary unit:\n{threshold}")

rmtree(src)
rmtree(TODIR)
makepath(src)
make_data_file(src / 'below-threshold', 1000)
below_threshold = out('-a', '-hh', '--stats', f'{src}/', f'{TODIR}/').stdout
if 'Total file size: 1,000 bytes' not in below_threshold:
test_fail("-hh should preserve raw byte formatting below the binary-unit "
f"threshold:\n{below_threshold}")

# --- -8 / --8-bit-output leaves high-bit filename bytes unescaped ------------
# rsync escapes non-printable name bytes as \#NNN; -8 prints 8-bit bytes raw.
# This needs a filename containing a high-bit byte and a C locale (where such a
Expand Down
Loading