From 5d106c9dc655f6f7be6c19ebaa6a2e02beaf3654 Mon Sep 17 00:00:00 2001 From: allebonvi Date: Thu, 2 Jul 2026 11:12:39 +0200 Subject: [PATCH] Usa API Win32 per verificare share --- src/bakrest/server_check.py | 24 ++++++++++++------------ tests/test_server_check.py | 34 ++++++++++++++++------------------ 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/bakrest/server_check.py b/src/bakrest/server_check.py index 04a4552..4c923ad 100644 --- a/src/bakrest/server_check.py +++ b/src/bakrest/server_check.py @@ -2,7 +2,7 @@ from __future__ import annotations import json import socket -import subprocess +import ctypes from dataclasses import asdict, dataclass from datetime import datetime, timezone from pathlib import Path @@ -10,6 +10,10 @@ from pathlib import Path from .config import BackupConfig +INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF +FILE_ATTRIBUTE_DIRECTORY = 0x00000010 + + @dataclass(frozen=True) class ServerStatus: reachable: bool @@ -60,19 +64,15 @@ def check_backup_target(config: BackupConfig) -> ServerStatus: def share_is_reachable(destination: str, timeout_seconds: int) -> bool: - probe = destination.rstrip("\\/") + "\\." - command = ["cmd.exe", "/d", "/c", f'if exist "{probe}" (exit /b 0) else (exit /b 1)'] + del timeout_seconds + normalized = destination.rstrip("\\/") try: - completed = subprocess.run( - command, - capture_output=True, - text=True, - timeout=max(timeout_seconds, 1), - check=False, - ) - except (OSError, subprocess.TimeoutExpired): + attributes = ctypes.windll.kernel32.GetFileAttributesW(str(normalized)) + except OSError: return False - return completed.returncode == 0 + if attributes == INVALID_FILE_ATTRIBUTES: + return False + return bool(attributes & FILE_ATTRIBUTE_DIRECTORY) def write_status(path: Path, status: ServerStatus, pending_count: int) -> None: diff --git a/tests/test_server_check.py b/tests/test_server_check.py index f72b1ff..a75d4e7 100644 --- a/tests/test_server_check.py +++ b/tests/test_server_check.py @@ -1,32 +1,30 @@ from __future__ import annotations -import subprocess - -from bakrest.server_check import share_is_reachable +from bakrest.server_check import FILE_ATTRIBUTE_DIRECTORY, INVALID_FILE_ATTRIBUTES, share_is_reachable -def test_share_is_reachable_returns_true_on_zero_exit(monkeypatch) -> None: - def fake_run(*args, **kwargs): - return subprocess.CompletedProcess(args[0], 0) - - monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run) +def test_share_is_reachable_returns_true_for_directory_attributes(monkeypatch) -> None: + monkeypatch.setattr( + "bakrest.server_check.ctypes.windll.kernel32.GetFileAttributesW", + lambda path: FILE_ATTRIBUTE_DIRECTORY, + ) assert share_is_reachable("\\\\server\\share", 3) -def test_share_is_reachable_returns_false_on_nonzero_exit(monkeypatch) -> None: - def fake_run(*args, **kwargs): - return subprocess.CompletedProcess(args[0], 1) - - monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run) +def test_share_is_reachable_returns_false_for_invalid_attributes(monkeypatch) -> None: + monkeypatch.setattr( + "bakrest.server_check.ctypes.windll.kernel32.GetFileAttributesW", + lambda path: INVALID_FILE_ATTRIBUTES, + ) assert not share_is_reachable("\\\\server\\share", 3) -def test_share_is_reachable_returns_false_on_timeout(monkeypatch) -> None: - def fake_run(*args, **kwargs): - raise subprocess.TimeoutExpired(args[0], 3) - - monkeypatch.setattr("bakrest.server_check.subprocess.run", fake_run) +def test_share_is_reachable_returns_false_for_non_directory(monkeypatch) -> None: + monkeypatch.setattr( + "bakrest.server_check.ctypes.windll.kernel32.GetFileAttributesW", + lambda path: 0, + ) assert not share_is_reachable("\\\\server\\share", 3)