feat: offline_note sur partitions NTFS verrouillées

Distingue volume verrouillé (Windows hibernate/Fast Startup)
de ntfsresize absent. Champ offline_note dans le payload JSON.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gilles Soulier
2026-05-28 20:45:26 +02:00
co-authored by Claude Sonnet 4.6
parent 2ac5a3b2de
commit 29a63be483
+43 -25
View File
@@ -428,24 +428,37 @@ def _ext4_space(dev):
return None return None
def _ntfs_space(dev): def _ntfs_space(dev):
# ntfsresize -i indique la taille minimale ≈ espace utilisé try:
out = run(["ntfsresize", "--info", "--force", dev]) r = subprocess.run(
if not out: ["ntfsresize", "--info", "--force", dev],
return None capture_output=True, text=True, timeout=15,
total = used = None )
for line in out.splitlines(): combined = r.stdout + r.stderr
if "Current volume size:" in line: if r.returncode != 0:
m = re.search(r"(\d+)\s+bytes", line) locked_markers = ("hibernated", "fast restart", "Windows is", "hiberfil",
if m: "unclean", "Refusing to operate")
total = int(m.group(1)) if any(m in combined for m in locked_markers):
if "You might resize at" in line: note = "Volume NTFS verrouillé — Windows en veille ou Fast Startup actif"
m = re.search(r"(\d+)\s+bytes", line) else:
if m: note = "Lecture NTFS impossible (ntfsresize indisponible ou erreur)"
used = int(m.group(1)) dprint(f"NTFS {dev} : {note}")
if total and used: return {"offline_note": note}
return {"size_bytes": total, "used_bytes": used, "free_bytes": total - used, total = used = None
"used_percent": int(used / total * 100) if total else 0} for line in combined.splitlines():
return None if "Current volume size:" in line:
m = re.search(r"(\d+)\s+bytes", line)
if m: total = int(m.group(1))
if "You might resize at" in line:
m = re.search(r"(\d+)\s+bytes", line)
if m: used = int(m.group(1))
if total and used:
return {"size_bytes": total, "used_bytes": used, "free_bytes": total - used,
"used_percent": int(used / total * 100) if total else 0}
return {"offline_note": "Taille NTFS non déterminée"}
except FileNotFoundError:
return {"offline_note": "ntfsresize non installé — sudo apt install ntfs-3g"}
except Exception as e:
return {"offline_note": f"Erreur lecture NTFS : {e}"}
def _btrfs_space(dev): def _btrfs_space(dev):
out = run(["btrfs", "filesystem", "show", dev]) out = run(["btrfs", "filesystem", "show", dev])
@@ -484,6 +497,7 @@ def build_partitions(children, df_map, lvm_map, home_done):
"free_bytes": None, "free_human": None, "free_bytes": None, "free_human": None,
"used_percent": None, "used_percent": None,
"mountpoint": mountpoint, "mountpoint": mountpoint,
"offline_note": None,
"home_users": None, "home_users": None,
"lvm": None, "lvm": None,
} }
@@ -504,13 +518,17 @@ def build_partitions(children, df_map, lvm_map, home_done):
if fstype in ("ext2", "ext3", "ext4", "ntfs", "btrfs"): if fstype in ("ext2", "ext3", "ext4", "ntfs", "btrfs"):
space = get_offline_space(f"/dev/{name}", fstype) space = get_offline_space(f"/dev/{name}", fstype)
if space: if space:
part["used_bytes"] = space["used_bytes"] if "offline_note" in space:
part["used_human"] = bytes_human(space["used_bytes"]) part["offline_note"] = space["offline_note"]
part["free_bytes"] = space["free_bytes"] dprint(f" partition {name} : {space['offline_note']}")
part["free_human"] = bytes_human(space["free_bytes"]) else:
part["used_percent"] = space["used_percent"] part["used_bytes"] = space["used_bytes"]
dprint(f" partition {name} offline : " part["used_human"] = bytes_human(space["used_bytes"])
f"{part['used_human']} / {part['size_human']} ({part['used_percent']}%)") part["free_bytes"] = space["free_bytes"]
part["free_human"] = bytes_human(space["free_bytes"])
part["used_percent"] = space["used_percent"]
dprint(f" partition {name} offline : "
f"{part['used_human']} / {part['size_human']} ({part['used_percent']}%)")
# /home users sur cette partition # /home users sur cette partition
if mountpoint == "/home" and not home_done[0]: if mountpoint == "/home" and not home_done[0]: