103 lines
2.9 KiB
Go
103 lines
2.9 KiB
Go
package filesystem
|
|
|
|
import (
|
|
"context"
|
|
|
|
model "github.com/cloudreve/Cloudreve/v3/models"
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
|
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
|
)
|
|
|
|
/* ================
|
|
存储策略迁移
|
|
================
|
|
*/
|
|
|
|
// Relocate 将目标文件转移到当前存储策略下
|
|
func (fs *FileSystem) Relocate(ctx context.Context, files []model.File, policy *model.Policy) error {
|
|
// 重设存储策略为要转移的目的策略
|
|
fs.Policy = policy
|
|
if err := fs.DispatchHandler(); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 将目前文件根据存储策略分组
|
|
fileGroup := fs.GroupFileByPolicy(ctx, files)
|
|
|
|
// 按照存储策略分组处理每个文件
|
|
for _, fileList := range fileGroup {
|
|
// 如果存储策略一样,则跳过
|
|
if fileList[0].GetPolicy().ID == fs.Policy.ID {
|
|
util.Log().Debug("Skip relocating %d file(s), since they are already in desired policy.",
|
|
len(fileList))
|
|
continue
|
|
}
|
|
|
|
// 获取当前存储策略的处理器
|
|
currentPolicy, _ := model.GetPolicyByID(fileList[0].PolicyID)
|
|
currentHandler, err := getNewPolicyHandler(¤tPolicy)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 记录转移完毕需要删除的文件
|
|
toBeDeleted := make([]model.File, 0, len(fileList))
|
|
|
|
// 循环处理每一个文件
|
|
// for id, r := 0, len(fileList); id < r; id++ {
|
|
for id, _ := range fileList {
|
|
// 验证文件是否符合新存储策略的规定
|
|
if err := HookValidateFile(ctx, fs, fileList[id]); err != nil {
|
|
util.Log().Debug("File %q failed to pass validators in new policy %q, skipping.",
|
|
fileList[id].Name, err)
|
|
continue
|
|
}
|
|
|
|
// 为文件生成新存储策略下的物理路径
|
|
savePath := fs.GenerateSavePath(ctx, fileList[id])
|
|
|
|
// 获取原始文件
|
|
src, err := currentHandler.Get(ctx, fileList[id].SourceName)
|
|
if err != nil {
|
|
util.Log().Debug("Failed to get file %q: %s, skipping.",
|
|
fileList[id].Name, err)
|
|
continue
|
|
}
|
|
|
|
// 转存到新的存储策略
|
|
if err := fs.Handler.Put(ctx, &fsctx.FileStream{
|
|
File: src,
|
|
SavePath: savePath,
|
|
Size: fileList[id].Size,
|
|
}); err != nil {
|
|
util.Log().Debug("Failed to migrate file %q: %s, skipping.",
|
|
fileList[id].Name, err)
|
|
continue
|
|
}
|
|
|
|
toBeDeleted = append(toBeDeleted, *fileList[id])
|
|
|
|
// 更新文件信息
|
|
fileList[id].Relocate(savePath, fs.Policy.ID)
|
|
}
|
|
|
|
// 排除带有软链接的文件
|
|
toBeDeletedClean, err := model.RemoveFilesWithSoftLinks(toBeDeleted)
|
|
if err != nil {
|
|
util.Log().Warning("Failed to check soft links: %s", err)
|
|
}
|
|
|
|
deleteSourceNames := make([]string, 0, len(toBeDeleted))
|
|
for i := 0; i < len(toBeDeletedClean); i++ {
|
|
deleteSourceNames = append(deleteSourceNames, toBeDeletedClean[i].SourceName)
|
|
}
|
|
|
|
// 删除原始策略中的文件
|
|
if _, err := currentHandler.Delete(ctx, deleteSourceNames); err != nil {
|
|
util.Log().Warning("Cannot delete files in origin policy after relocating: %s", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|