diff --git a/src/runner.py b/src/runner.py index 65077be..a38179b 100644 --- a/src/runner.py +++ b/src/runner.py @@ -122,6 +122,10 @@ def run_once(cfg, source_path=None, dry_run=False): local_file = source_path logger.info("使用本地源: %s", local_file) else: + # 访问 169 共享前,先确保已用配置的凭据建立 SMB 连接 + # (169 不认识 114 本地账户,必须显式以 169\Administrator 建连, + # 否则读 UNC 会 WinError 5 拒绝访问) + source_watcher.ensure_share_connected(cfg) if not source_watcher.has_changed(unc, meta_path): return local_file = source_watcher.download(unc, cache) diff --git a/src/source_watcher.py b/src/source_watcher.py index 75a9501..9133c7a 100644 --- a/src/source_watcher.py +++ b/src/source_watcher.py @@ -3,6 +3,7 @@ import json import logging import os import shutil +import subprocess import time from datetime import datetime from pathlib import Path @@ -51,6 +52,58 @@ def save_baseline(meta_path, meta): json.dump(meta, f) +def ensure_share_connected(cfg): + """访问 169 共享前,显式以配置的账户建立 SMB 连接。 + + 169 只认识自身的账户(如 Administrator),不认识 114 的本地账户 + (peng / svc_app / LocalSystem 的计算机账户),直接读 UNC 会 + WinError 5 拒绝访问。故在访问源文件前用 ``net use`` 以 169\\\\ + (+密码) 建连。 + + 实现要点(与验证脚本一致): + - 先 delete 可能已存在的旧连接,避免“多个不同的用户名/密码”冲突; + - 再以指定账户+密码建新连接(169 的 LimitBlankPasswordUse=0, + 允许空密码网络登录)。 + 建连失败不抛异常:仅告警,交由 has_changed/download 既有的 + “源不可达则跳过本轮”逻辑处理,不会让循环崩溃。 + """ + share_cfg = cfg.get("source_share") or {} + if not share_cfg.get("enabled", False): + return + if os.name != "nt": + logger.debug("非 Windows 环境,跳过 net use 共享连接") + return + server = share_cfg.get("server") + username = share_cfg.get("username") + password = share_cfg.get("password", "") + if not server or not username: + logger.warning("source_share 配置不完整(缺 server/username),跳过建连") + return + + # 1) 清理可能已存在的旧连接(忽略失败) + try: + subprocess.run(["net", "use", server, "/delete", "/y"], + capture_output=True, timeout=30) + except Exception as e: # noqa: BLE001 + logger.debug("清理旧共享连接时异常(可忽略): %s", e) + + # 2) 用指定账户 + 密码建立新连接 + # 注:net use 输出为中文 GBK 编码,按字节捕获后容错解码,避免 UTF-8 + # 解码崩溃(不影响建连结果,仅用于失败时记录日志)。 + cmd = ["net", "use", server, password, f"/user:{username}"] + try: + res = subprocess.run(cmd, capture_output=True, timeout=30) + except Exception as e: # noqa: BLE001 + logger.warning("建立共享连接异常: %s", e) + return + if res.returncode != 0: + raw = res.stderr or res.stdout + msg = raw.decode("gbk", "replace").strip() if raw else "" + logger.warning("共享连接认证失败(源将不可达): %s", msg) + return + logger.info("已用 %s 身份建立到 %s 的共享连接", username, server) + + def has_changed(path, meta_path): try: cur = get_source_meta(path)