Optimize file_manager buffering and regex patterns

- Add stdbuf -oL to rsync commands for immediate line-buffered output
  Fixes choppy/delayed progress updates in status file during transfers

- Switch from grep -P to -E with [0-9]+ patterns for POSIX compatibility
  Eliminates 'stray \ before d' warnings and improves portability
  More explicit and readable than \d+ shortcuts

- Update comments about rsync progress format differences:
  Running transfers show ETA, completed files show actual transfer time
This commit is contained in:
mgutt
2025-10-26 02:13:45 +01:00
parent a33f8c44d3
commit 58ec118854
+9 -7
View File
@@ -64,17 +64,19 @@ function mb_strimhalf($text, $width, $trim_marker = "") {
function parse_rsync_progress($status, $action_label) {
// obtain filename line like "/mnt/disk6/images/image.jpg"
$file_line = exec("tac $status | grep -m1 -v -E -C1 '\\d+%.*\\d+:\\d+:\\d+' | tr -s ' \\t' ' ' || echo ''");
$file_line = exec("tac $status | grep -m1 -v -E -C1 '[0-9]+%.*[0-9]+:[0-9]+:[0-9]+' | tr -s ' \\t' ' ' || echo ''");
$text[0] = $action_label . "... ";
if ($file_line) {
$text[0] .= htmlspecialchars(mb_strimhalf($file_line, 70, '...'), ENT_QUOTES, 'UTF-8');
}
// obtain progress line like:
// currently running: " 7.77G 66% 28.61MB/s 0:02:11"
// finished transfer: " 7.78G 66% 23.39MB/s 0:05:17 (xfr#2907, ir-chk=2990/5913)"
// currently running (showing total ETA):
// " 37.91G 4% 58.59MB/s 3:47:20"
// transfer of single file finished (ETA changes temporarily to estimated time)
// " 37.93G 4% 53.80MB/s 0:11:12 (xfr#32, to-chk=554/596)"
// note: we do not loop with PHP as there could be a huge amount of progress lines b
$progress_line = exec("tac $status | grep -m1 -E -C1 '\\d+%.*\\d+:\\d+:\\d+' | tr -s ' \\t' ' ' || echo ''");
$progress_line = exec("tac $status | grep -m1 -E -C1 '[0-9]+%.*[0-9]+:[0-9]+:[0-9]+' | tr -s ' \\t' ' ' || echo ''");
if ($progress_line) {
$parts = explode(' ', $progress_line);
if (count($parts) >= 4) {
@@ -242,7 +244,7 @@ while (true) {
$target = validname($target, false);
if ($target) {
$mkpath = isdir($target) ? '--mkpath' : '';
exec("rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 ".quoted($source)." ".escapeshellarg($target)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!", $pid);
exec("stdbuf -oL rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 ".quoted($source)." ".escapeshellarg($target)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!", $pid);
} else {
$reply['error'] = 'Invalid target name';
}
@@ -355,13 +357,13 @@ while (true) {
// - missing directories are created in --backup-dir (like using --mkpath)
if ($use_rsync_rename) {
$parent_dir = dirname(validname($source[0]));
$cmd = "rsync -r --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --delete --backup --backup-dir=".escapeshellarg($target)." ".quoted_rsync_include($source)." --exclude='*' ".escapeshellarg($empty_dir)." ".escapeshellarg($parent_dir)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!";
$cmd = "stdbuf -oL rsync -r --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --delete --backup --backup-dir=".escapeshellarg($target)." ".quoted_rsync_include($source)." --exclude='*' ".escapeshellarg($empty_dir)." ".escapeshellarg($parent_dir)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!";
exec($cmd, $pid);
// use rsync copy-delete
} else {
$delete_empty_dirs = true; // cleanup needed: rsync --remove-source-files leaves empty directories
$cmd = "rsync -ahPIX$H $sparse $exist $mkpath --no-inc-recursive --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --remove-source-files ".quoted($source)." ".escapeshellarg($target)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!";
$cmd = "stdbuf -oL rsync -ahPIX$H $sparse $exist $mkpath --no-inc-recursive --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --remove-source-files ".quoted($source)." ".escapeshellarg($target)." | tr '\\r' '\\n' | tee -a $status >/dev/null 2>$error & echo \$!";
exec($cmd, $pid);
}