Skip to content

[BUG] 139(旧上传路径)和 Teldrive 覆盖上传时先删除原文件,上传失败或被取消后原文件丢失 #3329

Open

Description

@thetapilla

请确认以下事项

  • 我已确认阅读并同意 AGPL-3.0 第15条 。
    本程序不提供任何明示或暗示的担保,使用风险由您自行承担。

  • 我已确认阅读并同意 AGPL-3.0 第16条 。
    无论何种情况,版权持有人或其他分发者均不对使用本程序所造成的任何损失承担责任。

  • 我确认我的描述清晰,语法礼貌,能帮助开发者快速定位问题,并符合社区规则。

  • 我已确认阅读了OpenList文档。

  • 我已确认没有重复的问题或讨论。

  • 我已确认是OpenList的问题,而不是其他原因(例如 网络 ,依赖或操作)。

  • 我认为此问题必须由OpenList处理,而非第三方。

  • 我已确认这个问题在最新版本中没有被修复。

  • 我没有阅读这个清单,只是闭眼选中了所有的复选框,请关闭这个 Issue 。

OpenList 版本(必填)

v4.2.9

使用的存储驱动(必填)

中国移动云盘(139,存储类型为 personal,或 family / group 且开启了 use_old_stream_upload);Teldrive

问题描述(必填)

覆盖上传同名文件时,这两个驱动在新内容上传之前就把原文件删除了。上传一旦失败或被取消(网络中断、客户端断开、分片上传会话被中止或回收等),原文件已经没了,新文件也没有传上去,数据丢失。

  1. Teldrive:Put 一开始发现目标已存在,就直接 Remove,然后才开始上传。

    if obj, err := d.getFile(dstDir.GetPath(), file.GetName(), file.IsDir()); err == nil {
    if err = d.Remove(ctx, obj); err != nil {
    return err
    }
    }

  2. 139 旧上传路径(存储类型 personal,或 family / group 开启了 use_old_stream_upload):上传前先把同名旧文件改名、再删除。

    // 旧上传路径
    switch d.Addition.Type {
    case MetaPersonal, MetaGroup, MetaFamily:
    // 处理冲突
    // 获取文件列表
    files, err := d.List(ctx, dstDir, model.ListArgs{})
    if err != nil {
    return err
    }
    // 删除旧文件
    for _, file := range files {
    if file.GetName() == stream.GetName() {
    log.Debugf("[139] conflict: removing old: %s", file.GetName())
    // 删除前重命名旧文件,避免仍旧冲突
    err = d.Rename(ctx, file, stream.GetName()+random.String(4))
    if err != nil {
    return err
    }
    err = d.Remove(ctx, file)
    if err != nil {
    return err
    }
    break
    }
    }

    作为对比,139 的新上传路径是在上传完成之后才删除旧文件、再把新文件改回原名,没有这个问题:

    // 处理冲突
    if resp.Data.FileName != stream.GetName() {
    log.Debugf("[139] conflict detected: %s != %s", resp.Data.FileName, stream.GetName())
    // 给服务器一定时间处理数据,避免无法刷新文件列表
    time.Sleep(time.Millisecond * 500)
    // 刷新并获取文件列表
    files, err := d.List(ctx, dstDir, model.ListArgs{Refresh: true})
    if err != nil {
    return err
    }
    // 删除旧文件
    for _, file := range files {
    if file.GetName() == stream.GetName() {
    log.Debugf("[139] conflict: removing old: %s", file.GetName())
    // 删除前重命名旧文件,避免仍旧冲突
    err = d.Rename(ctx, file, stream.GetName()+random.String(4))
    if err != nil {
    return err
    }
    err = d.Remove(ctx, file)
    if err != nil {
    return err
    }
    break
    }
    }
    // 重命名新文件
    for _, file := range files {
    if file.GetName() == resp.Data.FileName {
    log.Debugf("[139] conflict: renaming new: %s => %s", file.GetName(), stream.GetName())
    err = d.Rename(ctx, file, stream.GetName())
    if err != nil {
    return err
    }
    break
    }
    }
    }

修复思路(供参考):

日志(必填)

无。这是在排查 #3178(取消的上传误删文件)时,通过代码审查发现的同类问题。我手头没有 139 和 Teldrive 账号,未实际运行复现。

配置文件内容(必填)

不适用:未实际运行,问题来自代码审查。

复现链接(可选)

无(需要对应网盘的账号)。按代码推测的复现步骤:

  1. 在 Teldrive 存储中已有文件 a.bin(139 同理,存储类型为 personal);
  2. 在网页上用同名文件 a.bin 覆盖上传,文件大一些,便于中途操作;
  3. 上传进行中取消上传或断开网络;
  4. 刷新列表:原来的 a.bin 已经不存在。

AI生成内容

  • 我使用了AI工具生成此内容
  • 我没有使用AI工具生成此内容

AI模型是

Claude Opus 5.5(Claude Code)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions