Skip to content

Commit f77fd1c

Browse files
committed
Issue Hogjects#178 fixed.
Please enter the commit message for your changes. Lines starting with '' will be ignored, and an empty message aborts the commit. On branch less-deps-feature-win-tweaks Your branch is up to date with 'origin/less-deps-feature-win-tweaks'. Changes to be committed: modified: src/lufus/writing/flash_usb.py
1 parent 205d3b3 commit f77fd1c

1 file changed

Lines changed: 38 additions & 7 deletions

File tree

src/lufus/writing/flash_usb.py

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ def _status(msg: str) -> None:
5151
try:
5252
iso_size = os.path.getsize(iso_path)
5353
_status(f"File size: {iso_size:,} bytes ({iso_size / (1024**3):.2f} GiB)")
54+
if progress_cb:
55+
progress_cb(2)
5456

5557
if iso_path.lower().endswith(".iso"):
5658
_status(f"Validating ISO9660 signature for: {iso_path}")
@@ -62,8 +64,15 @@ def _status(msg: str) -> None:
6264
else:
6365
_status(f"Not an ISO file ({os.path.basename(iso_path)}), skipping ISO signature check")
6466

67+
if progress_cb:
68+
progress_cb(5)
69+
6570
_status("Checking if image contains installation markers...")
66-
if is_windows_iso(iso_path):
71+
iso_type = detect_iso_type(iso_path)
72+
if progress_cb:
73+
progress_cb(8)
74+
75+
if iso_type == IsoType.WINDOWS:
6776
_status("Windows Installation media detected, routing to flash_windows (ISO mode)")
6877
return flash_windows(
6978
device,
@@ -73,12 +82,14 @@ def _status(msg: str) -> None:
7382
status_cb=status_cb,
7483
)
7584

76-
iso_type = detect_iso_type(iso_path)
7785
if iso_type == IsoType.LINUX:
7886
_status("Linux Installation media detected, will use dd for flashing")
7987
else:
8088
_status("Generic or unknown image, will use dd for flashing")
8189

90+
if progress_cb:
91+
progress_cb(10)
92+
8293
dd_args = [
8394
"dd",
8495
f"if={iso_path}",
@@ -93,7 +104,11 @@ def _status(msg: str) -> None:
93104
_status(f"Writing {iso_size:,} bytes to {shlex.quote(device)}, this may take several minutes...")
94105

95106
try:
96-
process = subprocess.Popen(dd_args, stderr=subprocess.PIPE, stdout=subprocess.DEVNULL)
107+
# Use LC_ALL=C to ensure "bytes" is the keyword for progress parsing
108+
# and set a consistent output format across different locales.
109+
env = os.environ.copy()
110+
env["LC_ALL"] = "C"
111+
process = subprocess.Popen(dd_args, stderr=subprocess.PIPE, stdout=subprocess.DEVNULL, env=env)
97112
except FileNotFoundError:
98113
log.error("Flash failed: 'dd' utility not found. Install coreutils.")
99114
_status("Flash failed: 'dd' utility not found. Install coreutils.")
@@ -104,27 +119,43 @@ def _status(msg: str) -> None:
104119
buf = b""
105120
last_pct = -1
106121
while True:
107-
chunk = process.stderr.readline()
122+
# Read in small chunks to handle \r progress updates from dd without blocking
123+
# until a newline (\n) is received. status=progress usually emits \r.
124+
try:
125+
chunk = process.stderr.read(128)
126+
except Exception as e:
127+
log.warning("Error reading dd stderr: %s", e)
128+
break
129+
108130
if not chunk:
109131
break
110132
buf += chunk
133+
# Split by \r or \n to catch all progress updates
111134
parts = re.split(rb"[\r\n]", buf)
135+
# The last part might be incomplete, keep it in the buffer
112136
buf = parts[-1]
137+
113138
for line in parts[:-1]:
114139
line = line.strip()
115140
if not line:
116141
continue
117142
m = re.match(rb"^(\d+)\s+bytes", line)
118143
if m and iso_size > 0:
119144
bytes_done = int(m.group(1))
120-
pct = min(int(bytes_done * 100 / iso_size), 99)
145+
# Scale progress to 10-95% range to leave room for early steps and final sync
146+
pct_raw = min(int(bytes_done * 100 / iso_size), 100)
147+
pct = 10 + int(pct_raw * 0.85)
148+
121149
if pct != last_pct:
122-
_status(f"dd progress: {bytes_done:,} / {iso_size:,} bytes ({pct}%)")
150+
_status(f"dd progress: {bytes_done:,} / {iso_size:,} bytes ({pct_raw}%)")
123151
last_pct = pct
124152
if progress_cb:
125153
progress_cb(pct)
126154
else:
127-
log.warning("dd stderr: %s", line.decode("utf-8", errors="replace"))
155+
# Filter out common dd output lines to avoid logging noise
156+
line_str = line.decode("utf-8", errors="replace")
157+
if not any(x in line_str for x in ["records in", "records out", "copied"]):
158+
log.warning("dd stderr: %s", line_str)
128159

129160
process.wait()
130161
_status(f"dd process exited with return code {process.returncode}")

0 commit comments

Comments
 (0)