Skip to content

6.5.121#3567

Merged
deepin-bot[bot] merged 3 commits intolinuxdeepin:masterfrom
Johnson-zs:master
Feb 6, 2026
Merged

6.5.121#3567
deepin-bot[bot] merged 3 commits intolinuxdeepin:masterfrom
Johnson-zs:master

Conversation

@Johnson-zs
Copy link
Contributor

@Johnson-zs Johnson-zs commented Feb 6, 2026

Summary by Sourcery

Introduce centralized management of filesystem permissions for anonymous directory shares and ensure permissions are restored when anonymous sharing is disabled or removed.

New Features:

  • Add AnonymousPermissionManager utility to record, adjust, and persist filesystem permissions used for anonymous directory and home shares.

Bug Fixes:

  • Ensure directory and home directory permissions are correctly restored when an anonymous share is removed or converted to a non-anonymous share from both the widget and context menu flows.
  • Include total item count reporting for trash cleaning jobs in file operation progress notifications.

Enhancements:

  • Refine dirshare permission handling to rely on AnonymousPermissionManager instead of in-place chmod logic, improving robustness and user-modification safety.

When removing an anonymous share, the directory permissions were not
being restored to their original state. This fix implements a permission
management system that records original permissions when setting up
anonymous shares and restores them when shares are removed.

Key changes:
1. Added AnonymousPermissionManager class to handle permission recording
and restoration
2. Records original permissions when enabling anonymous sharing
3. Restores permissions when removing anonymous shares or switching to
non-anonymous
4. Handles home directory permissions for anonymous access
5. Prevents restoration if user manually modified permissions
6. Uses JSON configuration file to persist permission records across
sessions

Log: Fixed directory permission restoration after removing anonymous
shares

Influence:
1. Test anonymous share creation and verify permissions are set
correctly
2. Test removing anonymous shares and verify permissions are restored
3. Test switching from anonymous to non-anonymous sharing
4. Verify home directory permissions are handled correctly
5. Test permission restoration when user manually modifies permissions
6. Verify permission records persist after application restart

fix: 修复移除匿名共享后目录权限未恢复的问题

移除匿名共享时,目录权限未能恢复到原始状态。此修复实现了权限管理系统,在
设置匿名共享时记录原始权限,并在移除共享时恢复权限。

主要变更:
1. 新增 AnonymousPermissionManager 类处理权限记录和恢复
2. 启用匿名共享时记录原始权限
3. 移除匿名共享或切换到非匿名时恢复权限
4. 处理匿名访问所需的用户主目录权限
5. 防止在用户手动修改权限后进行恢复
6. 使用 JSON 配置文件持久化权限记录

Log: 修复移除匿名共享后目录权限恢复问题

Influence:
1. 测试匿名共享创建并验证权限设置正确
2. 测试移除匿名共享并验证权限恢复
3. 测试从匿名切换到非匿名共享
4. 验证用户主目录权限正确处理
5. 测试用户手动修改权限后的恢复行为
6. 验证权限记录在应用重启后持久化

Bug: https://pms.uniontech.com/bug-view-350345.html
Added kCleanTrashType to the condition that handles progress
notifications for move to trash and restore operations. This ensures
that when cleaning trash, the progress calculation uses the correct
metric (number of source URLs) instead of the default file count,
providing accurate progress reporting for trash cleaning operations.

Influence:
1. Test trash cleaning operations to verify progress bar updates
correctly
2. Compare progress reporting between trash cleaning and other file
operations
3. Verify that trash cleaning completes without progress calculation
errors

fix: 将清理回收站类型添加到进度通知逻辑中

在移动至回收站和恢复操作的处理条件中添加了 kCleanTrashType 类型。这确保
在清理回收站时,进度计算使用正确的指标(源 URL 数量)而不是默认的文件计
数,为回收站清理操作提供准确的进度报告。

Influence:
1. 测试回收站清理操作,验证进度条正确更新
2. 比较回收站清理与其他文件操作的进度报告
3. 验证回收站清理完成时没有进度计算错误
@deepin-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: Johnson-zs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@github-actions
Copy link

github-actions bot commented Feb 6, 2026

TAG Bot

TAG: 6.5.121
EXISTED: no
DISTRIBUTION: unstable

@sourcery-ai
Copy link

sourcery-ai bot commented Feb 6, 2026

Reviewer's Guide

Introduces an AnonymousPermissionManager to centrally track and safely restore filesystem permissions for anonymous directory shares, updates dirshare UI and menu flows to use it (including handling transitions between anonymous and non-anonymous shares and unsharing), and fixes file operation progress notifications for trash cleaning jobs.

Sequence diagram for updating a share from anonymous to non-anonymous

sequenceDiagram
    actor User
    participant ShareControlWidget
    participant UserShareHelper
    participant AnonymousPermissionManager

    User ->> ShareControlWidget: toggle share options
    activate ShareControlWidget

    ShareControlWidget->>ShareControlWidget: filePath = url.toLocalFile()
    ShareControlWidget->>UserShareHelper: shareInfoByPath(filePath)
    UserShareHelper-->>ShareControlWidget: oldShareInfo
    ShareControlWidget->>ShareControlWidget: wasAnonymous = oldShareInfo[kAnonymous]

    ShareControlWidget->>ShareControlWidget: shareFolder()
    alt shareFolder fails and not isShared(filePath)
        ShareControlWidget-->>ShareControlWidget: disable share UI
        ShareControlWidget-->>User: share disabled
    else share still exists
        ShareControlWidget->>ShareControlWidget: isNowAnonymous = (shareAnonymousSelector index == 1)
        alt wasAnonymous and not isNowAnonymous
            ShareControlWidget->>AnonymousPermissionManager: restoreDirectoryPermissions(filePath)
            ShareControlWidget->>AnonymousPermissionManager: restoreHomeDirectoryIfNoAnonymousShares()
        else other transitions
            Note over ShareControlWidget,AnonymousPermissionManager: Non-anonymous to anonymous handled inside shareFolder
        end
    end
    deactivate ShareControlWidget
Loading

Sequence diagram for unsharing an anonymous directory via menu or widget

sequenceDiagram
    actor User
    participant UI as ShareControlWidget_or_DirShareMenuScene
    participant UserShareHelper
    participant AnonymousPermissionManager

    User ->> UI: unshare directory
    activate UI

    UI->>UI: filePath = url.toLocalFile() or u.path()
    UI->>UserShareHelper: shareInfoByPath(filePath)
    UserShareHelper-->>UI: shareInfo
    UI->>UI: wasAnonymous = shareInfo[kAnonymous]

    UI->>UserShareHelper: removeShareByPath(filePath)
    UserShareHelper-->>UI: success flag

    alt success and wasAnonymous
        UI->>AnonymousPermissionManager: restoreDirectoryPermissions(filePath)
        UI->>AnonymousPermissionManager: restoreHomeDirectoryIfNoAnonymousShares()
    else not anonymous or failure
        UI-->>User: unshare failed or no permission changes
    end

    deactivate UI
Loading

Class diagram for AnonymousPermissionManager and updated dirshare components

classDiagram
    direction TB

    class AnonymousPermissionManager {
        <<singleton>>
        +static char kJsonVersion
        +static char kJsonShares
        +static char kJsonHomeDirectory
        +static char kJsonPath
        +static char kJsonOriginal
        +static char kJsonExpected
        +static AnonymousPermissionManager instance()
        +bool setAnonymousPermissions(QString filePath, DirectoryType type, bool writable)
        +bool restoreDirectoryPermissions(QString filePath)
        +bool restoreHomeDirectoryIfNoAnonymousShares()
        +void cleanRecord(QString filePath)
        -AnonymousPermissionManager(QObject parent)
        -bool loadFromFile()
        -bool saveToFile()
        -QFile~Permissions~ getExpectedPermissions(QFile~Permissions~ original)
        -QFile~Permissions~ getHomeExpectedPermissions(QFile~Permissions~ original)
        -int getCurrentAnonymousShareCount() const
        -QString configFilePath
        -QMap~QString, PermissionRecord~ shareRecords
        -HomeDirectoryRecord homeRecord
    }

    class DirectoryType {
        <<enumeration>>
        kSharedDirectory
        kHomeDirectory
    }

    class PermissionRecord {
        QFile~Permissions~ original
        QFile~Permissions~ expected
    }

    class HomeDirectoryRecord {
        QString path
        QFile~Permissions~ original
        QFile~Permissions~ expected
    }

    class ShareControlWidget {
        +void updateShare()
        +bool shareFolder()
        +bool unshareFolder()
        -QUrl url
        -QComboBox sharePermissionSelector
        -QComboBox shareAnonymousSelector
    }

    class DirShareMenuScene {
        +bool triggered(QAction action)
    }

    class UserShareHelper {
        +QVariantMap shareInfoByPath(QString filePath)
        +bool isShared(QString filePath)
        +bool removeShareByPath(QString filePath)
    }

    AnonymousPermissionManager --> DirectoryType
    AnonymousPermissionManager --> PermissionRecord
    AnonymousPermissionManager --> HomeDirectoryRecord

    ShareControlWidget ..> AnonymousPermissionManager : uses
    ShareControlWidget ..> UserShareHelper : uses

    DirShareMenuScene ..> AnonymousPermissionManager : uses
    DirShareMenuScene ..> UserShareHelper : uses
Loading

Flow diagram for AnonymousPermissionManager permission lifecycle

flowchart TB
    start([Start anonymous share setup])
    checkType{Directory type?}
    sharedPath([Shared directory])
    homePath([Home directory])

    start --> checkType
    checkType -->|kSharedDirectory| sharedPath
    checkType -->|kHomeDirectory| homePath

    sharedPath --> recordShared[Record PermissionRecord
original = current
expected = getExpectedPermissions or add ExeGroup ExeOther]
    recordShared --> setSharedPerms{"setPermissions(expected) success?"}
    setSharedPerms -->|no| failShared[[Fail and remove record]]
    setSharedPerms -->|yes| saveShared[Save shareRecords to JSON]
    saveShared --> endShared([Anonymous shared directory active])

    homePath --> recordHome{homeRecord.path empty?}
    recordHome -->|yes| setHomeRecord[Store path, original, expected = getHomeExpectedPermissions]
    recordHome -->|no| skipHomeRecord[Use existing homeRecord]
    setHomeRecord --> setHomePerms
    skipHomeRecord --> setHomePerms

    setHomePerms[Set home directory permissions to expected] --> homePermsOk{setPermissions success?}
    homePermsOk -->|no| failHome[[Fail to set home permissions]]
    homePermsOk -->|yes| saveHome[Save homeRecord to JSON]
    saveHome --> endHome([Home directory prepared for anonymous shares])

    subgraph Restore_directory_after_unshare
        restoreStart([Unshare anonymous directory]) --> hasRecord{shareRecords contains path?}
        hasRecord -->|no| restoreEndSkip([Skip restore])
        hasRecord -->|yes| comparePerms{current == expected?}
        comparePerms -->|no| userModified[[User modified perms, cleanRecord]]
        comparePerms -->|yes| setOriginal[Set permissions to original]
        setOriginal --> restored{setPermissions success?}
        restored -->|yes| cleanRecordNode[cleanRecord and save]
        restored -->|no| restoreFail[[Failed to restore directory]]
        cleanRecordNode --> restoreEnd([Directory restored])
    end

    subgraph Restore_home_when_no_anonymous_shares
        homeRestoreStart([Check home restore]) --> hasHome{homeRecord.path empty?}
        hasHome -->|yes| homeRestoreSkip([Nothing to restore])
        hasHome -->|no| countShares[getCurrentAnonymousShareCount]
        countShares --> hasShares{count > 0?}
        hasShares -->|yes| keepHome([Keep home permissions])
        hasShares -->|no| compareHomePerms{current == expected?}
        compareHomePerms -->|no| clearHomeRecord[[User modified home perms, clear homeRecord]]
        compareHomePerms -->|yes| restoreHomePerms[Set home permissions to original]
        restoreHomePerms --> homeRestored{setPermissions success?}
        homeRestored -->|yes| clearHomeRecord2[Clear homeRecord and save]
        homeRestored -->|no| homeRestoreFail[[Failed to restore home directory]]
    end
Loading

File-Level Changes

Change Details Files
Introduce AnonymousPermissionManager for recording, applying, and restoring permissions for anonymous shares and home directory, persisted in a JSON config file.
  • Added a singleton QObject-based AnonymousPermissionManager with APIs to set permissions for shared/home directories, restore them, and clear records.
  • Implemented logic to compute expected permissions for writable/read-only anonymous shares and for the home directory, modifying QFile permissions accordingly.
  • Added JSON-backed persistence of permission records using QStandardPaths config location and QSaveFile for atomic writes, including load/save of share records and a single home-directory record.
  • Implemented safety checks to skip restore if permissions differ from the last expected state, assuming user manually changed them, and to only restore home permissions when no anonymous shares remain.
src/plugins/common/dfmplugin-dirshare/utils/anonymouspermissionmanager.h
src/plugins/common/dfmplugin-dirshare/utils/anonymouspermissionmanager.cpp
Refactor ShareControlWidget to use AnonymousPermissionManager for anonymous share permission handling and to correctly restore permissions when changing share type or unsharing.
  • Replaced direct chmod-like permission changes on shared and home directories with calls to AnonymousPermissionManager::setAnonymousPermissions for anonymous shares.
  • Captured previous share info before updates to detect transitions from anonymous to non-anonymous sharing and trigger directory and home-directory permission restoration via AnonymousPermissionManager.
  • Adjusted paths from url.path() to url.toLocalFile() when working with filesystem permissions and share info lookups.
  • On unshare, captured whether the share was anonymous, then removed the share and restored directory and possibly home directory permissions if appropriate.
src/plugins/common/dfmplugin-dirshare/widget/sharecontrolwidget.cpp
Ensure menu-based share removal also restores permissions for anonymous shares using AnonymousPermissionManager.
  • Included AnonymousPermissionManager in the dirshare menu scene and used it when handling the remove-share action.
  • When removing a share from the context menu, looked up the share info to see if it was anonymous, then restored directory and home-directory permissions on success.
src/plugins/common/dfmplugin-dirshare/dirsharemenu/dirsharemenuscene.cpp
Improve progress notification total-size calculation to handle trash cleaning jobs similarly to move-to-trash and restore operations.
  • Extended the condition that sets notification total size to the number of source URLs to also cover CleanTrash jobs in AbstractWorker::emitProgressChangedNotify.
src/plugins/common/dfmplugin-fileoperations/fileoperations/fileoperationutils/abstractworker.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot
Copy link
Contributor

deepin pr auto review

这份代码审查主要针对 dde-file-manager 中关于匿名共享目录权限管理的改进,以及清理回收站时通知逻辑的修复。以下是详细的审查意见:

1. 语法与逻辑审查

anonymouspermissionmanager.cpp.h

  • 逻辑一致性:代码逻辑清晰,通过 AnonymousPermissionManager 单例类统一管理匿名共享时的权限修改和恢复,解决了原先在多处直接修改权限导致难以追踪和恢复的问题。
  • 原子性操作saveToFile 使用了 QSaveFile,这非常好。它保证了写入配置文件时的原子性,防止因程序崩溃或写入过程中断导致配置文件损坏。
  • 权限恢复判断restoreDirectoryPermissions 中增加了检查 current != record.expected 的逻辑。这是一个很好的改进,防止在用户手动修改了共享目录权限后,程序取消共享时错误地将权限覆盖回原始值。
  • JSON 键值定义:在头文件中使用 static constexpr char 定义 JSON 键值,避免了硬编码字符串,提高了代码的可维护性。

dirsharemenuscene.cpp

  • 逻辑正确性:在移除共享时,先检查是否为匿名共享,如果是,则调用 AnonymousPermissionManager 进行恢复。逻辑正确,符合预期。

sharecontrolwidget.cpp

  • 状态转换处理:在 updateShare 中增加了从匿名共享切换到非匿名共享时的权限恢复逻辑。这填补了原先逻辑的漏洞,即用户在界面上切换共享类型时,权限没有被正确还原。
  • 路径获取:代码中多处将 url.path() 修改为 url.toLocalFile()。这是正确的,因为 path() 可能包含协议前缀(如 file:),而文件系统操作需要本地绝对路径。

abstractworker.cpp

  • 逻辑补全:在 emitProgressChangedNotify 中为 kCleanTrashType 添加了处理分支。逻辑上,清理回收站操作确实是基于文件数量而非总大小来计算进度的,这与 kMoveToTrashType 保持一致,修改合理。

2. 代码质量

  • 日志记录:大量使用了 fmInfo, fmWarning, fmDebug,这对于调试和追踪权限变化非常有帮助。
  • 注释:关键逻辑处有清晰的注释(例如解释为什么需要修改 Home 目录权限),提高了可读性。
  • 代码结构:将权限管理逻辑提取到独立的 AnonymousPermissionManager 类中,符合单一职责原则,显著提高了代码的模块化程度。

3. 代码性能

  • 文件 I/O
    • loadFromFilesaveToFile 涉及文件读写。考虑到配置文件通常很小,且操作频率不高(仅在创建/取消共享时),目前的同步 I/O 方式是可以接受的。
    • QSaveFile 的使用虽然会引入一次临时文件写入和重命名,但对于配置文件来说,开销可以忽略不计,换来了数据安全性。
  • QMap 使用:使用 QMap<QString, PermissionRecord> 存储共享记录。查找和插入的时间复杂度为 O(log n)。对于用户共享目录的数量(通常很少),性能完全足够。

4. 代码安全

  • 权限管理
    • 风险点:代码中直接修改文件系统权限(setPermissions)。虽然代码增加了检查用户是否手动修改过权限的逻辑,但在高并发或极端情况下(例如用户在取消共享的瞬间手动修改权限),仍存在极小的竞态条件风险。
    • 建议:目前的逻辑已经处理了大部分情况。如果需要更严格的保障,可以考虑在 restoreDirectoryPermissions 前加锁,或者增加更详细的权限位比对(不仅仅是比对整个 expected,而是比对程序实际修改的那几位权限)。
  • 路径安全
    • 使用 QFileInfo 检查文件存在性,防止操作不存在的路径。
    • 代码中显式检查 getuid() != 0,避免修改 /root 目录的权限,这是一个很好的安全边界检查。
  • JSON 解析
    • loadFromFile 中对 JSON 文件进行了有效性检查(doc.isNull(), doc.isObject()),防止加载损坏的配置文件导致程序崩溃。
  • 类型转换
    • static_cast<QFile::Permissions>(shareObj[kJsonOriginal].toInt()):从 JSON 读取整数并转换为权限枚举。如果 JSON 文件被篡改,包含无效的整数值,QFilesetPermissions 行为通常是安全的(忽略无效位),但最好在加载时验证整数值是否在有效权限掩码范围内(例如 0x7770o777)。

5. 改进建议

  1. JSON 数据验证
    loadFromFile 中,建议增加对 kJsonOriginalkJsonExpected 值的合法性校验。

    // 示例代码片段
    int permInt = shareObj[kJsonOriginal].toInt();
    // 简单的掩码检查,确保没有设置无效位
    if (permInt & ~0xFFFF) { 
        fmWarning() << "Invalid permission value in config:" << permInt;
        continue; // 跳过该记录或重置为默认值
    }
    record.original = static_cast<QFile::Permissions>(permInt);
  2. 异常处理
    setAnonymousPermissions 中,如果 setPermissions 失败,目前只是返回 false 并记录警告。调用者(如 sharecontrolwidget.cpp)会忽略这个返回值继续执行 UserShareHelperInstance->share(...)

    • 建议:如果权限设置失败,是否应该阻止共享操作的继续?因为权限设置失败意味着匿名用户可能无法访问。建议在 sharecontrolwidget.cpp::shareFolder 中检查 setAnonymousPermissions 的返回值,如果失败则提示用户并终止共享流程。
  3. 配置文件版本控制
    代码中定义了 kJsonVersion = 1,但在 loadFromFile 中并未读取并检查版本号。

    • 建议:在加载时读取版本号,如果未来配置结构发生变化,可以根据版本号进行兼容性处理或提示用户配置已过期。
  4. 命名空间与宏
    DPDIRSHARE_BEGIN_NAMESPACEDPDIRSHARE_END_NAMESPACE 使用良好。建议确保 anonymouspermissionmanager.cpp 中也包含了定义这些宏的头文件,或者确认这是项目全局宏。

总结

整体来看,这是一次高质量的代码提交。它有效地解决了匿名共享权限遗留的问题,代码结构清晰,考虑了边界情况(如用户手动修改权限、Root 用户等),并使用了安全的文件操作方式。主要的改进点在于增加 JSON 数据的健壮性校验以及考虑权限设置失败时的错误处理流程。

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • In restoreHomeDirectoryIfNoAnonymousShares, getCurrentAnonymousShareCount() only uses the persisted shareRecords map, so stale entries (e.g., shares removed outside this code path or after an app restart) will block home-permission restoration; consider reconciling against actual current shares or pruning non-existent paths when loading.
  • restoreDirectoryPermissions assumes the directory still exists and calls QFileInfo(filePath).permissions() and QFile::setPermissions unconditionally; it might be safer to explicitly handle non-existent paths (e.g., log and clean the record) to avoid leaving orphaned records in the JSON.
  • The comment on getCurrentAnonymousShareCount() says it gets the count from UserShareHelper, but the implementation just returns shareRecords.size(); either update the comment or wire this through to the actual share source to avoid confusion about what the count represents.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `restoreHomeDirectoryIfNoAnonymousShares`, `getCurrentAnonymousShareCount()` only uses the persisted `shareRecords` map, so stale entries (e.g., shares removed outside this code path or after an app restart) will block home-permission restoration; consider reconciling against actual current shares or pruning non-existent paths when loading.
- `restoreDirectoryPermissions` assumes the directory still exists and calls `QFileInfo(filePath).permissions()` and `QFile::setPermissions` unconditionally; it might be safer to explicitly handle non-existent paths (e.g., log and clean the record) to avoid leaving orphaned records in the JSON.
- The comment on `getCurrentAnonymousShareCount()` says it gets the count from `UserShareHelper`, but the implementation just returns `shareRecords.size()`; either update the comment or wire this through to the actual share source to avoid confusion about what the count represents.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Johnson-zs
Copy link
Contributor Author

/forcemerge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Feb 6, 2026

This pr force merged! (status: blocked)

@deepin-bot deepin-bot bot merged commit 34ea71f into linuxdeepin:master Feb 6, 2026
21 of 22 checks passed
@deepin-bot
Copy link
Contributor

deepin-bot bot commented Feb 6, 2026

TAG Bot

Tag created successfully

📋 Tag Details
  • Tag Name: 6.5.121
  • Tag SHA: f35739592d6edc6e60fe761bdb26636999be7bf4
  • Commit SHA: 6f706ee6da0d52f6ec2c8c56cf056f3f315afdc1
  • Tag Message:
    Release dde-file-manager 6.5.121
    
    
  • Tagger:
    • Name: Johnson-zs
  • Distribution: unstable

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants