Skip to content

feat(storage): add MMC storage vendor identification via sysfs#700

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/eaglefrom
add-uos:develop/eagle
Jul 7, 2026
Merged

feat(storage): add MMC storage vendor identification via sysfs#700
deepin-bot[bot] merged 1 commit into
linuxdeepin:develop/eaglefrom
add-uos:develop/eagle

Conversation

@add-uos

@add-uos add-uos commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Read manfid/oemid/name from sysfs for MMC storage devices and resolve vendor names using MANFID/OEMID lookup tables. Add safeReadSysFsFile() utility with path traversal protection.

Log: 添加MMC存储设备厂商识别功能,通过sysfs读取manfid/oemid识别厂商
PMS: BUG-368319
Influence: MMC/eMMC存储设备的厂商信息不再为空,可正确显示对应厂商名称

Summary by Sourcery

Add vendor identification for MMC/eMMC storage devices using sysfs data and introduce a safe sysfs file reading utility.

New Features:

  • Resolve MMC/eMMC storage vendor names from sysfs manfid/oemid fields using lookup tables.
  • Update MMC storage device name and vendor information in DeviceStorage based on sysfs attributes when available.

Bug Fixes:

  • Ensure MMC/eMMC storage devices no longer show empty vendor information by populating names from sysfs.

Enhancements:

  • Add helper methods to map raw MANFID/OEMID values to human-readable vendor names.

@sourcery-ai

sourcery-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds MMC/eMMC vendor identification by reading manfid/oemid/name from sysfs with a new safe sysfs file reader, and maps IDs to vendor names via lookup tables in DeviceStorage.

Sequence diagram for MMC vendor identification via sysfs

sequenceDiagram
    participant DeviceStorage
    participant Common
    participant Sysfs

    DeviceStorage->>DeviceStorage: setHwinfoInfo(mapInfo)
    DeviceStorage->>DeviceStorage: check m_Driver contains mmcblk
    DeviceStorage->>DeviceStorage: read SysFS Device Link
    DeviceStorage->>Common: safeReadSysFsFile(sysfsDeviceLink, name, err)
    Common->>Sysfs: read name
    Sysfs-->>Common: name content
    Common-->>DeviceStorage: name or err
    DeviceStorage->>DeviceStorage: set m_Name if err empty

    DeviceStorage->>Common: safeReadSysFsFile(sysfsDeviceLink, manfid, err)
    Common->>Sysfs: read manfid
    Sysfs-->>Common: manfid content
    Common-->>DeviceStorage: manfid or err
    DeviceStorage->>DeviceStorage: getManfName(manfIdRaw)
    DeviceStorage->>DeviceStorage: set m_Vendor from MANFID_TABLE

    DeviceStorage->>Common: safeReadSysFsFile(sysfsDeviceLink, oemid, err)
    Common->>Sysfs: read oemid
    Sysfs-->>Common: oemid content
    Common-->>DeviceStorage: oemid or err
    DeviceStorage->>DeviceStorage: [m_Vendor empty] getOemName(oemIdRaw)
    DeviceStorage->>DeviceStorage: set m_Vendor from OEMID_TABLE
Loading

File-Level Changes

Change Details Files
Add MMC/eMMC vendor identification using sysfs manfid/oemid/name and vendor lookup tables in DeviceStorage.
  • Introduce MANFID_TABLE and OEMID_TABLE mapping hex ID strings to vendor names.
  • In setHwinfoInfo, when the driver is mmcblk, read name, manfid, and oemid from the sysfs device link using Common::safeReadSysFsFile.
  • Populate m_Name from the sysfs name file and m_Vendor by resolving manfid first, then oemid if manfid resolution fails.
  • Add helper methods oemIdHexToAscii, getManfName, and getOemName to normalize hex ID strings and map them through the lookup tables.
deepin-devicemanager/src/DeviceManager/DeviceStorage.cpp
deepin-devicemanager/src/DeviceManager/DeviceStorage.h
Introduce a safe sysfs file-reading utility to prevent path traversal and ensure controlled reads.
  • Add Common::safeReadSysFsFile API declaration in commonfunction.h.
  • Implement safeReadSysFsFile in commonfunction.cpp with baseDir and fileName validation against /sys, path traversal checks, and canonical path resolution.
  • Restrict reading to regular files under /sys (excluding symlinks), limit read length to 64 bytes, and trim the resulting UTF-8 content.
  • Include QFileInfo and QDir to support path validation and canonicalization.
deepin-devicemanager/src/commonfunction.cpp
deepin-devicemanager/src/commonfunction.h

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In Common::safeReadSysFsFile, the isFile()/isSymLink() check and error message don’t align (you currently reject symlinks while saying "or symlink"); consider clarifying the intent (e.g., explicitly allow regular files and/or symlinks) and also handle the case where canonicalFilePath() returns an empty string for non‑existent paths before proceeding.
  • DeviceStorage::oemIdHexToAscii is declared public but never used; consider either removing it or making it private and adding a focused use site to avoid exposing dead API.
  • The global MANFID_TABLE and OEMID_TABLE maps are initialized at static scope; to avoid static initialization order issues and keep their scope tight, consider wrapping them in helper functions with function‑local static const maps.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Common::safeReadSysFsFile`, the `isFile()/isSymLink()` check and error message don’t align (you currently reject symlinks while saying "or symlink"); consider clarifying the intent (e.g., explicitly allow regular files and/or symlinks) and also handle the case where `canonicalFilePath()` returns an empty string for non‑existent paths before proceeding.
- `DeviceStorage::oemIdHexToAscii` is declared public but never used; consider either removing it or making it private and adding a focused use site to avoid exposing dead API.
- The global `MANFID_TABLE` and `OEMID_TABLE` maps are initialized at static scope; to avoid static initialization order issues and keep their scope tight, consider wrapping them in helper functions with function‑local `static const` maps.

## Individual Comments

### Comment 1
<location path="deepin-devicemanager/src/DeviceManager/DeviceStorage.cpp" line_range="870-873" />
<code_context>
+}
+
+// 通过manfid获取厂商名称
+QString DeviceStorage::getManfName(const QString &rawManfId)
+{
+    QString cleanId = rawManfId.trimmed().toLower();
+    cleanId.remove("0x"); // 去除0x前缀
+    return MANFID_TABLE.value(cleanId, rawManfId);
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** Removing "0x" this way will also strip any '0' and 'x' characters inside the ID

`cleanId.remove("0x")` removes all occurrences of that substring, not just a leading prefix, so IDs containing `0x` in the middle will be corrupted (e.g. `"0x10x1b"``"11b"`), breaking lookups. Restrict this to a leading prefix only, e.g.:

```cpp
QString cleanId = rawManfId.trimmed().toLower();
if (cleanId.startsWith("0x")) {
    cleanId.remove(0, 2);
}
```

Apply the same fix to `getOemName`.
</issue_to_address>

### Comment 2
<location path="deepin-devicemanager/src/commonfunction.cpp" line_range="433-435" />
<code_context>
+        return "";
+    }
+
+    if (!fullPathInfo.isFile() || fullPathInfo.isSymLink())
+    {
+        errOut = QString("Not a regular file or symlink: %1").arg(fullPath);
+        return "";
+    }
</code_context>
<issue_to_address>
**issue (bug_risk):** Logic and message around regular file vs symlink are inconsistent and may reject valid sysfs paths

The condition `!fullPathInfo.isFile() || fullPathInfo.isSymLink()` actually rejects symlinks, while the message claims regular files *or* symlinks are allowed, and sysfs commonly exposes attributes via symlinks.

To allow both, invert the logic:
```cpp
if (!fullPathInfo.isFile() && !fullPathInfo.isSymLink()) {
    errOut = QString("Not a regular file or symlink: %1").arg(fullPath);
    return "";
}
```
If symlinks are meant to be disallowed, adjust the error message to match that behavior instead.
</issue_to_address>

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.

Comment on lines +870 to +873
QString DeviceStorage::getManfName(const QString &rawManfId)
{
QString cleanId = rawManfId.trimmed().toLower();
cleanId.remove("0x"); // 去除0x前缀

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Removing "0x" this way will also strip any '0' and 'x' characters inside the ID

cleanId.remove("0x") removes all occurrences of that substring, not just a leading prefix, so IDs containing 0x in the middle will be corrupted (e.g. "0x10x1b""11b"), breaking lookups. Restrict this to a leading prefix only, e.g.:

QString cleanId = rawManfId.trimmed().toLower();
if (cleanId.startsWith("0x")) {
    cleanId.remove(0, 2);
}

Apply the same fix to getOemName.

Comment on lines +433 to +435
if (!fullPathInfo.isFile() || fullPathInfo.isSymLink())
{
errOut = QString("Not a regular file or symlink: %1").arg(fullPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Logic and message around regular file vs symlink are inconsistent and may reject valid sysfs paths

The condition !fullPathInfo.isFile() || fullPathInfo.isSymLink() actually rejects symlinks, while the message claims regular files or symlinks are allowed, and sysfs commonly exposes attributes via symlinks.

To allow both, invert the logic:

if (!fullPathInfo.isFile() && !fullPathInfo.isSymLink()) {
    errOut = QString("Not a regular file or symlink: %1").arg(fullPath);
    return "";
}

If symlinks are meant to be disallowed, adjust the error message to match that behavior instead.

@add-uos add-uos force-pushed the develop/eagle branch 2 times, most recently from d544fca to 67a0ca2 Compare July 7, 2026 05:04
Read manfid/oemid/name from sysfs for MMC storage devices and resolve
vendor names using MANFID/OEMID lookup tables. Add safeReadSysFsFile()
utility with path traversal protection.

Log: 添加MMC存储设备厂商识别功能,通过sysfs读取manfid/oemid识别厂商
PMS: BUG-368319
Influence: MMC/eMMC存储设备的厂商信息不再为空,可正确显示对应厂商名称
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:85分

■ 【总体评价】

代码实现了eMMC设备名称和厂商信息的补充读取,具备良好的安全防御机制,但存在逻辑与错误提示不符的缺陷
逻辑正确但因错误提示矛盾及代码轻微重复扣15分

■ 【详细分析】

  • 1.语法逻辑(存在错误)✕

commonfunction.cppsafeReadSysFsFile 函数中,判断条件 if (!fullPathInfo.isFile() || fullPathInfo.isSymLink()) 的逻辑与错误提示信息 "Not a regular file or symlink" 相互矛盾。根据Qt文档,当文件为指向普通文件的符号链接时,isFile() 返回 true,此时 isSymLink() 也返回 true,导致条件成立并返回错误。错误信息字面意思是“既不是普通文件也不是符号链接”,但实际触发的场景是“它是符号链接”。此外,在 /sys 虚拟文件系统中,部分属性文件可能以符号链接形式存在,此逻辑会将其误拒。
潜在问题:错误提示具有误导性,增加后续排查难度;过度拒绝合法的符号链接文件可能导致扩展使用时功能异常
建议:修正错误提示为 "Is a symbolic link or not a regular file: %1",或根据业务需求调整判断逻辑,若允许跟随符号链接则移除 isSymLink() 判断

  • 2.代码质量(良好)✓

新增的 MANFID_TABLEOEMID_TABLE 映射表结构清晰,注释明确。getManfNamegetOemName 函数职责单一。但存在轻微的代码重复,两个函数内部的字符串清理逻辑(trimmed().toLower().remove("0x"))完全一致。另外,DeviceStorage.cpp 中大括号放置风格不统一,if (!sysfsDeviceLink.isEmpty()) 的大括号换行,而 if (err.isEmpty()) 的大括号在同一行。
潜在问题:字符串清理逻辑重复;代码风格局部不一致
建议:提取一个 static QString cleanHexId(const QString &rawId) 私有辅助函数统一处理字符串清理;统一代码块的大括号放置规范

  • 3.代码性能(高效)✓

safeReadSysFsFile 函数限制了最大读取长度为 64 字节,对于读取 sysfs 中的短标识符(如 namemanfid)非常合理,避免了不必要的内存分配。虽然连续三次调用该函数会重复执行 canonicalFilePath() 带来极微小的系统调用开销,但在设备管理器这种非高频触发的场景下完全在可接受范围内。QMap 查找在小数据量下性能损耗可忽略不计。
建议:无需优化

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
代码在路径遍历防御上表现优秀。safeReadSysFsFile 函数采用了多层防御策略:首先校验 baseDir 必须以 /sys/ 开头并拦截 ..;其次严格限制 fileName 不能包含路径分隔符和穿越符;最后通过 canonicalFilePath() 解析真实路径并二次校验其是否逃逸出 /sys/ 目录。这套组合拳有效阻断了任何形式的目录穿越攻击。
建议:保持现有的安全检查逻辑,无需额外修复

■ 【改进建议代码示例】

--- a/deepin-devicemanager/src/commonfunction.cpp
+++ b/deepin-devicemanager/src/commonfunction.cpp
@@ -426,8 +426,14 @@ QString Common::safeReadSysFsFile(const QString &baseDir, const QString &fileNa
         return "";
     }
 
-    if (!fullPathInfo.isFile() || fullPathInfo.isSymLink())
+    if (!fullPathInfo.isFile())
     {
-        errOut = QString("Not a regular file or symlink: %1").arg(fullPath);
+        errOut = QString("Target is not a regular file: %1").arg(fullPath);
+        return "";
+    }
+    if (fullPathInfo.isSymLink())
+    {
+        errOut = QString("Target is a symbolic link (not allowed): %1").arg(fullPath);
         return "";
     }
 

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos, lzwind

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

@add-uos

add-uos commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot deepin-bot Bot merged commit 6b2485f into linuxdeepin:develop/eagle Jul 7, 2026
23 checks passed
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.

3 participants