From 29a63be483b670bf12f55714783931836ec582f9 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Thu, 28 May 2026 20:45:26 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20offline=5Fnote=20sur=20partitions=20NTF?= =?UTF-8?q?S=20verrouill=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distingue volume verrouillé (Windows hibernate/Fast Startup) de ntfsresize absent. Champ offline_note dans le payload JSON. Co-Authored-By: Claude Sonnet 4.6 --- inventaire.py | 68 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/inventaire.py b/inventaire.py index f7a6372..1a85ac4 100644 --- a/inventaire.py +++ b/inventaire.py @@ -428,24 +428,37 @@ def _ext4_space(dev): return None def _ntfs_space(dev): - # ntfsresize -i indique la taille minimale ≈ espace utilisé - out = run(["ntfsresize", "--info", "--force", dev]) - if not out: - return None - total = used = None - for line in out.splitlines(): - 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 None + try: + r = subprocess.run( + ["ntfsresize", "--info", "--force", dev], + capture_output=True, text=True, timeout=15, + ) + combined = r.stdout + r.stderr + if r.returncode != 0: + locked_markers = ("hibernated", "fast restart", "Windows is", "hiberfil", + "unclean", "Refusing to operate") + if any(m in combined for m in locked_markers): + note = "Volume NTFS verrouillé — Windows en veille ou Fast Startup actif" + else: + note = "Lecture NTFS impossible (ntfsresize indisponible ou erreur)" + dprint(f"NTFS {dev} : {note}") + return {"offline_note": note} + total = used = None + for line in combined.splitlines(): + 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): 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, "used_percent": None, "mountpoint": mountpoint, + "offline_note": None, "home_users": 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"): space = get_offline_space(f"/dev/{name}", fstype) if space: - part["used_bytes"] = space["used_bytes"] - part["used_human"] = bytes_human(space["used_bytes"]) - 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']}%)") + if "offline_note" in space: + part["offline_note"] = space["offline_note"] + dprint(f" partition {name} : {space['offline_note']}") + else: + part["used_bytes"] = space["used_bytes"] + part["used_human"] = bytes_human(space["used_bytes"]) + 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 if mountpoint == "/home" and not home_done[0]: