utils.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import json
  2. import os
  3. import subprocess
  4. def sudo_getsize(path):
  5. """Retourne la taille d'un fichier via sudo stat si non accessible directement."""
  6. try:
  7. return os.path.getsize(path)
  8. except OSError:
  9. result = subprocess.run(
  10. ["sudo", "stat", "--format=%s", path],
  11. capture_output=True, text=True,
  12. )
  13. if result.returncode == 0:
  14. try:
  15. return int(result.stdout.strip())
  16. except ValueError:
  17. pass
  18. return 0
  19. def sudo_getmtime(path):
  20. """Retourne le mtime d'un fichier via sudo stat si non accessible directement."""
  21. try:
  22. return os.path.getmtime(path)
  23. except OSError:
  24. result = subprocess.run(
  25. ["sudo", "stat", "--format=%Y", path],
  26. capture_output=True, text=True,
  27. )
  28. if result.returncode == 0:
  29. try:
  30. return float(result.stdout.strip())
  31. except ValueError:
  32. pass
  33. return 0.0
  34. def unique_archive_name(base_name, backup_dir):
  35. """Retourne un nom d'archive unique (ajoute _2, _3… si le nom du jour est déjà pris)."""
  36. name = base_name
  37. i = 2
  38. while sudo_exists(os.path.join(backup_dir, name + ".tar")):
  39. name = f"{base_name}_{i}"
  40. i += 1
  41. return name
  42. def sudo_exists(path):
  43. """Vérifie l'existence d'un fichier via sudo si non accessible directement."""
  44. if os.path.exists(path):
  45. return True
  46. result = subprocess.run(
  47. ["sudo", "stat", path],
  48. capture_output=True,
  49. )
  50. return result.returncode == 0
  51. def sudo_read_backup_info(archive_path):
  52. """Lit backup_info.json depuis un .tar root-owned via sudo tar -xOf."""
  53. result = subprocess.run(
  54. ["sudo", "tar", "-xOf", archive_path, "backup_info.json"],
  55. capture_output=True,
  56. )
  57. if result.returncode == 0:
  58. try:
  59. return json.loads(result.stdout)
  60. except Exception:
  61. pass
  62. return {}
  63. def batch_list_archives(backup_dir):
  64. """Retourne {name: {size_bytes, mtime}} pour tous les .tar — UN seul appel sudo find."""
  65. result = subprocess.run(
  66. ["sudo", "find", backup_dir, "-maxdepth", "1", "-name", "*.tar",
  67. "-printf", "%f\t%s\t%T@\n"],
  68. capture_output=True, text=True,
  69. )
  70. stats = {}
  71. for line in result.stdout.splitlines():
  72. parts = line.strip().split("\t")
  73. if len(parts) == 3:
  74. fname, size_str, mtime_str = parts
  75. if fname.endswith(".tar"):
  76. name = fname[:-4]
  77. try:
  78. stats[name] = {"size_bytes": int(size_str), "mtime": float(mtime_str)}
  79. except ValueError:
  80. pass
  81. return stats
  82. def sudo_listdir(directory):
  83. """Liste les fichiers d'un répertoire via sudo find si non accessible directement."""
  84. try:
  85. return os.listdir(directory)
  86. except OSError:
  87. result = subprocess.run(
  88. ["sudo", "find", directory, "-maxdepth", "1", "-mindepth", "1",
  89. "-printf", "%f\n"],
  90. capture_output=True, text=True,
  91. )
  92. if result.returncode == 0:
  93. return [f for f in result.stdout.strip().split("\n") if f]
  94. return []