feat: 修改逻辑

这个提交包含在:
HA
2026-04-26 23:21:40 +08:00
父节点 abeb6f2e80
当前提交 2db4f4b530
共有 3 个文件被更改,包括 32 次插入58 次删除

查看文件

@@ -27,7 +27,7 @@ CONF_FILE="${SCRIPT_DIR}/backup.conf"
# ---- 默认值 ----
# 公共配置(统一以 COMMON_ 前缀,与 backup.conf 一致)
COMMON_SOURCE_PATHS=""
COMMON_TMP_DIR="/tmp/backup"
COMMON_TMP_DIR="/tmp/backup_script"
COMMON_ARCHIVE_PREFIX="backup"
COMMON_CLEAN_LOCAL="true"
COMMON_RETENTION_DAYS=0
@@ -79,7 +79,7 @@ Methods:
Common options:
-C, --config FILE 指定配置文件路径(默认:脚本所在目录下 backup.conf
-s, --source PATHS 要备份的源路径,多个用空格分隔,需引号包裹
-t, --tmp-dir DIR 本地临时目录(默认:/tmp/backup
-t, --tmp-dir DIR 本地临时目录(默认:/tmp/backup_script
-p, --prefix NAME 归档文件名前缀默认backup
--keep-local 上传后保留本地归档
--retention DAYS 远端保留天数,0 表示不清理
@@ -424,17 +424,34 @@ create_archive() {
}
cleanup_local() {
dbg "cleanup_local: COMMON_CLEAN_LOCAL=$COMMON_CLEAN_LOCAL 文件数=${#ARCHIVE_FILES[@]}"
dbg "cleanup_local: COMMON_CLEAN_LOCAL=$COMMON_CLEAN_LOCAL COMMON_TMP_DIR=$COMMON_TMP_DIR PREFIX=$COMMON_ARCHIVE_PREFIX"
if [[ "$COMMON_CLEAN_LOCAL" != "true" ]]; then
dbg "cleanup_local: 跳过删除"
return 0
fi
local p
for p in "${ARCHIVE_FILES[@]}"; do
if [[ -f "$p" ]]; then
rm -f "$p" && log "已删除本地:$p"
fi
# 安全栅栏:必备字段不能为空,避免出现 rm -rf /* 这类灾难
if [[ -z "$COMMON_TMP_DIR" || -z "$COMMON_ARCHIVE_PREFIX" ]]; then
warn "COMMON_TMP_DIR 或 COMMON_ARCHIVE_PREFIX 为空,拒绝清理"
return 0
fi
if [[ ! -d "$COMMON_TMP_DIR" ]]; then
dbg "cleanup_local: 目录不存在,跳过"
return 0
fi
# 仅清理所有以 COMMON_ARCHIVE_PREFIX 开头的文件/目录。
# 这样既能带走本次的归档/分卷/sha,也能扫掉上次失败遗留同样以该前缀开头
# 中间产物(如 *.tar.gz、*.tar.gz.split-tmp.* 等),同时不会误伤同目录下的其它文件。
local count=0 p
shopt -s nullglob
for p in "${COMMON_TMP_DIR%/}/${COMMON_ARCHIVE_PREFIX}"*; do
rm -rf -- "$p" && count=$((count+1))
done
shopt -u nullglob
if [[ $count -gt 0 ]]; then
log "已清理本地以 \"${COMMON_ARCHIVE_PREFIX}\" 开头的文件/目录 ${count} 项(位于 ${COMMON_TMP_DIR}"
else
dbg "cleanup_local: 没有匹配 ${COMMON_ARCHIVE_PREFIX}* 的文件"
fi
}
# ---------- SMB ----------
@@ -701,9 +718,6 @@ rclone_upload() {
done
ok "已上传全部 ${#ARCHIVE_FILES[@]} 个文件到 ${remote_dir}/"
# 远端 SHA256 校验:拉取远端 hash,与本地 .sha256 清单比对
rclone_verify_remote "$remote_dir" || return 1
if [[ "$COMMON_RETENTION_DAYS" -gt 0 ]]; then
rclone_retention
else
@@ -711,49 +725,6 @@ rclone_upload() {
fi
}
rclone_verify_remote() {
local remote_dir="$1"
local sha_local
# 在 ARCHIVE_FILES 中找到 .sha256 清单cleanup 之前)
for f in "${ARCHIVE_FILES[@]}"; do
if [[ "$f" == *.sha256 ]]; then sha_local="$f"; break; fi
done
if [[ -z "$sha_local" || ! -f "$sha_local" ]]; then
warn "未找到本地 SHA256 清单,跳过远端校验"
return 0
fi
log "远端 SHA256 校验:${remote_dir}/"
local remote_sha
remote_sha="$(rclone_cmd hashsum SHA256 "$remote_dir" 2>/dev/null)" || {
err "rclone hashsum 执行失败(远端可能不支持 SHA256,可手动下载后用 sha256sum -c 校验)"
return 1
}
dbg "远端 hash 输出: $remote_sha"
# 本地清单格式: "<hash> <filename>";远端 rclone hashsum 输出同样格式但顺序可能不同
# 逐行比对:以文件名为 key,hash 必须一致
local fname expect actual
while IFS= read -r line; do
[[ -z "$line" ]] && continue
expect="${line%% *}"
fname="${line##* }"
# 跳过清单文件自身(不会出现在 ARCHIVE 主体里,但保险)
[[ "$fname" == "$(basename "$sha_local")" ]] && continue
actual="$(echo "$remote_sha" | awk -v f="$fname" '$2==f{print $1; exit}')"
if [[ -z "$actual" ]]; then
err "远端缺少文件:$fname"
return 1
fi
if [[ "$expect" != "$actual" ]]; then
err "远端 SHA256 不匹配:$fname (本地=$expect 远端=$actual)"
return 1
fi
dbg " 校验通过:$fname"
done < "$sha_local"
ok "远端 SHA256 校验全部通过"
}
rclone_retention() {
dbg "rclone_retention: COMMON_RETENTION_DAYS=$COMMON_RETENTION_DAYS"
local parent="${RCLONE_REMOTE}:${RCLONE_PATH%/}"