From ba415acd37c4c59a3bdc2cd7f32a34c3ddbc5df7 Mon Sep 17 00:00:00 2001 From: stkevintan Date: Thu, 27 Nov 2025 18:21:54 +0800 Subject: [PATCH] add hard link support for smb --- app/modules/filemanager/storages/smb.py | 35 ++++++++++++++++++++++++- app/modules/filemanager/transhandler.py | 8 ++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/modules/filemanager/storages/smb.py b/app/modules/filemanager/storages/smb.py index 6924f62d..55862500 100644 --- a/app/modules/filemanager/storages/smb.py +++ b/app/modules/filemanager/storages/smb.py @@ -37,6 +37,7 @@ class SMB(StorageBase, metaclass=WeakSingleton): transtype = { "move": "移动", "copy": "复制", + "link": "硬链接", } # 文件块大小,默认10MB @@ -635,7 +636,39 @@ class SMB(StorageBase, metaclass=WeakSingleton): return False def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool: - pass + """ + 硬链接文件 + Samba服务器需要开启 unix extensions 支持 + """ + try: + self._check_connection() + src_path = self._normalize_path(fileitem.path) + dst_path = self._normalize_path(target_file) + + # 检查源文件是否存在 + if not smbclient.path.exists(src_path): + raise FileNotFoundError(f"源文件不存在: {src_path}") + + # 确保目标路径的父目录存在 + dst_parent = "\\".join(dst_path.rsplit("\\", 1)[:-1]) + if dst_parent and not smbclient.path.exists(dst_parent): + logger.info(f"【SMB】创建目标目录: {dst_parent}") + smbclient.makedirs(dst_parent, exist_ok=True) + + # 尝试创建硬链接 + smbclient.link(src_path, dst_path) + logger.info(f"【SMB】硬链接创建成功: {src_path} -> {dst_path}") + return True + + except SMBResponseException as e: + # SMB协议错误,可能不支持硬链接 + logger.error(f"【SMB】创建硬链接失败(当前Samba服务器可能不支持硬链接): {e}") + return False + except Exception as e: + logger.error(f"【SMB】创建硬链接失败: {e}") + return False + + def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool: pass diff --git a/app/modules/filemanager/transhandler.py b/app/modules/filemanager/transhandler.py index 550fb0a2..44b9e269 100644 --- a/app/modules/filemanager/transhandler.py +++ b/app/modules/filemanager/transhandler.py @@ -418,6 +418,9 @@ class TransHandler: return None, f"{fileitem.path} {fileitem.storage} 下载失败" elif fileitem.storage == target_storage: # 同一网盘 + if not source_oper.is_support_transtype(transfer_type): + return None, f"存储 {fileitem.storage} 不支持 {transfer_type} 整理方式" + if transfer_type == "copy": # 复制文件到新目录 target_fileitem = target_oper.get_folder(target_file.parent) @@ -438,6 +441,11 @@ class TransHandler: return None, f"【{target_storage}】{fileitem.path} 移动文件失败" else: return None, f"【{target_storage}】{target_file.parent} 目录获取失败" + elif transfer_type == "link": + if source_oper.link(fileitem, target_file): + return target_oper.get_item(target_file), "" + else: + return None, f"【{target_storage}】{fileitem.path} 创建硬链接失败" else: return None, f"不支持的整理方式:{transfer_type}"