fix: distinguish supported network backup mounts from local filesystems
This commit is contained in:
+30
-3
@@ -3,7 +3,7 @@ import datetime as dt
|
||||
from contextlib import closing
|
||||
import hashlib
|
||||
import os
|
||||
from pathlib import Path
|
||||
from pathlib import Path, PurePosixPath
|
||||
import re
|
||||
import secrets
|
||||
import shutil
|
||||
@@ -27,6 +27,33 @@ class Backups:
|
||||
last=self.a.setting('backup_last', None),
|
||||
history=self.a.setting('backup_history', [])[-20:][::-1])
|
||||
|
||||
@staticmethod
|
||||
def network_mount(folder):
|
||||
if os.name == 'nt':
|
||||
return folder.drive.startswith('\\\\')
|
||||
try:
|
||||
records = Path('/proc/self/mountinfo').read_text().splitlines()
|
||||
except OSError:
|
||||
return False
|
||||
return Backups.linux_network_mount(PurePosixPath(str(folder)), records)
|
||||
|
||||
@staticmethod
|
||||
def linux_network_mount(folder, records):
|
||||
matches = []
|
||||
for line in records:
|
||||
left, separator, right = line.partition(' - ')
|
||||
fields, detail = left.split(), right.split()
|
||||
if not separator or len(fields) < 5 or not detail:
|
||||
continue
|
||||
mount = PurePosixPath(re.sub(r'\\([0-7]{3})', lambda m: chr(int(m[1], 8)), fields[4]))
|
||||
if folder.is_relative_to(mount):
|
||||
matches.append((len(mount.parts), detail[0]))
|
||||
# The nearest mount wins: a tmpfs inside an NFS share is still local.
|
||||
filesystem = max(matches, default=(0, ''), key=lambda x:x[0])[1]
|
||||
return filesystem in {'cifs', 'smb3', 'nfs', 'nfs4', 'davfs',
|
||||
'fuse.sshfs', 'fuse.rclone', 'fuse.davfs', 'fuse.davfs2',
|
||||
'fuse.wdfs', 'fuse.s3fs', 'fuse.goofys'}
|
||||
|
||||
def network_folder(self, text):
|
||||
if not text:
|
||||
return None
|
||||
@@ -39,8 +66,8 @@ class Backups:
|
||||
if not folder.is_dir():
|
||||
raise self.a.Problem('备份目录不存在,请先在服务器挂载网络存储并授予服务账号写入权限')
|
||||
# A disconnected mount must not silently become a local-only cloud backup.
|
||||
if not any(os.path.ismount(p) for p in (folder, *folder.parents) if p != Path(p.anchor)):
|
||||
raise self.a.Problem('该目录尚未检测到独立挂载;请先连接网络盘,不能把本机目录当作云端成功')
|
||||
if not self.network_mount(folder):
|
||||
raise self.a.Problem('该目录未检测到支持的网络挂载,请先连接 NFS、SMB、WebDAV 或 rclone 网络盘')
|
||||
if folder == (self.a.DATA/'managed-backups').resolve():
|
||||
raise self.a.Problem('网络副本与本机备份目录不能相同')
|
||||
return folder
|
||||
|
||||
Reference in New Issue
Block a user