news 2026/6/14 12:25:10

Linux ntfs3 attr lookup与非驻留属性流读取

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux ntfs3 attr lookup与非驻留属性流读取

Linux ntfs3 attr lookup与非驻留属性流读取

ntfs3是Linux内核中用于读写NTFS文件系统的驱动,支持NTFS 3.1版本的全部特性。NTFS的核心数据存储模型基于属性(Attribute),每个文件由一个或多个属性记录组成,所有属性存储在MFT(Master File Table)记录中。

每个MFT记录由固定头(FILE record header)后跟一系列属性组成。属性的布局由标准属性头定义:

struct ATTR_RECORD {
__le32 type; /* 属性类型编码 */
__le32 length; /* 属性记录总长度 */
u8 non_resident; /* 0=驻留, 1=非驻留 */
u8 name_len; /* 属性名称长度 (UTF-16) */
__le16 name_off; /* 属性名称偏移 */
__le16 flags; /* 标志位 */
__le16 instance; /* 实例号,用于去重 */
union {
struct { /* 驻留属性 */
__le32 value_length;
__le16 value_off;
u8 reserved[2];
} resident;
struct { /* 非驻留属性 */
__le64 vcn_start;
__le64 vcn_end;
__le16 mapping_pairs_off;
u8 compression_unit;
u8 reserved[4];
__le64 alloc_size;
__le64 data_size;
__le64 valid_data_size;
__le64 total_size;
} non_resident;
} w;
};

属性类型包括:ATTR_STANDARD_INFORMATION(0x10)、ATTR_LIST(0x20)、ATTR_NAME(0x30)、ATTR_DATA(0x80)等。当属性数据小于MFT记录内的可用空间时,数据驻留在MFT记录内(resident);当数据较大时,通过运行列表(runlist)映射到磁盘簇(non-resident)。

属性查找的入口函数是ntfs3的attr.c中的相关函数:

struct ATTR_RECORD *mi_get_attr(struct mft_inode *mi,
enum ATTR_TYPE type,
const __le16 *name,
int name_len)
{
struct ATTR_RECORD *attr;
u32 asize, t32;

attr = mi->r_attr;
while ((u8 *)attr < (u8 *)mi->r_attr + mi->struct_size - 8) {
if (!attr->type)
break;
asize = le32_to_cpu(attr->length);
if (asize < sizeof(struct ATTR_RECORD))
break;

if (attr->type == type) {
if (name_len) {
if (attr->name_len != name_len)
goto next;
if (memcmp(attr + 1, name, name_len * sizeof(__le16)))
goto next;
}
return attr;
}
next:
attr = (struct ATTR_RECORD *)((u8 *)attr + asize);
}
return NULL;
}

函数从MFT记录的r_attr起始位置开始遍历,逐属性比较type和name(如果指定了name_len)。匹配成功返回ATTR_RECORD指针。遍历在遇到type==0的结束标记或超出MFT记录边界时终止。

当非驻留属性被定位后,读取属性数据需要通过runlist将VCN(Virtual Cluster Number)映射为LCN(Logical Cluster Number)。runlist解码函数ntfs3从mapping pairs array中解析运行列表:

int ni_read_attr_data(struct ntfs_inode *ni, loff_t vbo,
void *buffer, size_t bytes, pgoff_t *pgn)
{
struct ntfs_sb_info *sbi = ni->mi.sbi;
struct ATTR_RECORD *attr;
struct runs_tree *run;
u64 vcn, vcn_next;
u64 lcn, len;
u32 clst_per_page;
size_t bytes_read = 0;
int err;

attr = ni->attr;
if (!attr->non_resident) {
bytes = min(bytes, (size_t)(le32_to_cpu(attr->w.resident.value_length)
- vbo));
memcpy(buffer, (u8*)attr + le16_to_cpu(attr->w.resident.value_off)
+ vbo, bytes);
return bytes;
}

run = &ni->run;
clst_per_page = PAGE_SIZE >> sbi->cluster_bits;

while (bytes > 0) {
vcn = vbo >> sbi->cluster_bits;
err = run_lookup(run, vcn, &lcn, &len, &vcn_next);
if (err)
return err;

if (lcn == SPARSE_LCN) {
memcpy(buffer, page_address(ZERO_PAGE(0)),
min_t(size_t, bytes, len << sbi->cluster_bits));
} else {
while (bytes > 0 && vcn_next > vcn) {
u32 bytes_in_cluster;
struct buffer_head *bh;

bh = ntfs_bread(sbi, lcn + (vcn & (clst_per_page - 1)));
if (!bh)
return -EIO;

bytes_in_cluster = min_t(u32, bytes, sbi->cluster_size);
memcpy(buffer, bh->b_data, bytes_in_cluster);
brelse(bh);

vbo += bytes_in_cluster;
buffer += bytes_in_cluster;
bytes -= bytes_in_cluster;
bytes_read += bytes_in_cluster;
vcn++;
}
}
}
return bytes_read;
}

对于非驻留属性,ntfs3首先通过run_lookup()获取指定VCN对应的运行段(run segment),返回LCN(起始簇号)、len(连续簇数)和vcn_next(下一个运行段的起始VCN)。SPARSE_LCN表示稀疏簇,直接返回全零。正常簇通过ntfs_bread()读取磁盘块。

mapping pairs array的解析在run_unpack()中完成:

int run_unpack(struct runs_tree *run, struct ntfs_sb_info *sbi,
CLST ino, CLST svcn, CLST evcn,
const u8 *run_buf, int run_buf_size)
{
CLST vcn = svcn, lcn, len;
const u8 *ptr = run_buf;
const u8 *end = run_buf + run_buf_size;

while (ptr < end) {
u8 cl = *ptr >> 4;
u8 ll = *ptr & 0xF;
if (!cl && !ll)
break;
ptr++;
if (ptr + cl + ll > end)
return -EINVAL;

vcn += get_compressed(ptr, cl);
ptr += cl;
lcn = get_compressed(ptr, ll);
ptr += ll;

ntfs_run_add(run, vcn, lcn, 1);
vcn++;
}
return 0;
}

runlist中的每个条目由压缩编码表示:1字节的头部包含cl(VCN差异的字节数)和ll(LCN的字节数)。VCN差异使用游程编码,LCN使用有符号差分编码。run_unpack()逐个解码并填充运行树。

当属性名称存在(如ADS,Alternate Data Stream),mi_get_attr()的name参数指向UTF-16编码的属性名。ntfs3的listxattr调用枚举所有ADS属性,通过遍历MFT记录中的$DATA属性查找name_len>0的条目。

NTFS的压缩和稀疏属性通过ATTR_FLAG_COMPRESSED和ATTR_FLAG_SPARSED标志识别。在非驻留属性中,compression_unit字段指定压缩单元的大小(以簇为单位)。ntfs3的读路径检测到压缩标志后,调用ntfs_decompress()进行运行时解压缩。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 12:25:08

Linux panic内核恐慌与kmsg_dump注册回调

Linux panic内核恐慌与kmsg_dump注册回调panic是Linux内核的终极异常处理函数。当内核检测到无法恢复的错误时&#xff0c;调用panic()终止系统运行。panic()的实现位于kernel/panic.c中&#xff0c;承载了信息转储、notifier回调、kmsg_dump输出和最终停机等一系列操作。__set…

作者头像 李华
网站建设 2026/6/14 12:24:43

MPC8309通信处理器实战:从核心架构到驱动开发与调试

1. 从手册到实战&#xff1a;深度解析MPC8309通信处理器的核心架构与设计哲学如果你是一名嵌入式网络设备开发者&#xff0c;或者正在为你的工业控制、智能网关项目寻找一颗高集成度、高性价比的通信处理器核心&#xff0c;那么飞思卡尔&#xff08;现恩智浦&#xff09;的Powe…

作者头像 李华
网站建设 2026/6/14 12:24:40

ATM IMA技术原理与MPC8323E实现详解

1. 项目概述&#xff1a;ATM IMA技术与MPC8323E的深度耦合在宽带接入、企业网络回程以及某些传统的电信传输场景中&#xff0c;我们常常会遇到一个经典矛盾&#xff1a;上层应用&#xff08;比如一个高速的ATM虚电路&#xff09;需要稳定且较高的带宽&#xff0c;但底层可用的物…

作者头像 李华
网站建设 2026/6/14 12:24:34

MPC8245硬件手册勘误解析:从PCI配置到SDRAM时序的避坑指南

1. 项目概述与勘误背景在嵌入式系统开发&#xff0c;尤其是基于PowerPC架构的早期网络通信、工控设备设计中&#xff0c;一份准确无误的硬件参考手册就是工程师的“圣经”。我最近在为一个老旧的通信网关设备进行维护和功能升级&#xff0c;其核心处理器正是Freescale&#xff…

作者头像 李华
网站建设 2026/6/14 12:24:01

Unity游戏去马赛克终极指南:3分钟恢复完整视觉体验

Unity游戏去马赛克终极指南&#xff1a;3分钟恢复完整视觉体验 【免费下载链接】UniversalUnityDemosaics A collection of universal demosaic BepInEx plugins for games made in Unity3D engine 项目地址: https://gitcode.com/gh_mirrors/un/UniversalUnityDemosaics …

作者头像 李华