当前位置: 首页 > news >正文

Linux fat_add_cluster FAT32簇链与shortname生成

Linux fat_add_cluster FAT32簇链与shortname生成

FAT32文件系统使用FAT(File Allocation Table)表来管理文件数据的簇分配。每个文件对应一条簇链,簇链中的每一簇指向文件数据的一个逻辑块,最后一个簇的值范围为0xFFFFFFF8-0xFFFFFFF(EOC标记)。fat_add_cluster()是FAT32簇分配的核心函数,负责扩展文件的簇链。

簇分配函数fat_add_cluster()实现在fatent.c中:

int fat_add_cluster(struct inode *inode)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
struct super_block *sb = inode->i_sb;
struct fat_entry fatent;
unsigned long count;
int err;
int nr_cluster;

nr_cluster = EXTRA_ENTRY_OFFSET +
(sbi->fat_bits == 32 ? 1 : 0);

fatent_init(&fatent);
err = fat_alloc_clusters(inode, &nr_cluster, &count);
if (err)
return err;

fatent.fat_inode = MSDOS_SB(sb)->fat_inode;
fatent.bh = NULL;
fatent.entry = 0;
fatent.nr_bhs = 0;

在调用fat_alloc_clusters()分配新簇之前,需要确定FAT表需要预留多少个簇。对于FAT32,需要额外预留1个簇用于写入EOC标记。fat_alloc_clusters()扫描FAT表,从空闲簇中分配连续(或非连续)的簇:

int fat_alloc_clusters(struct inode *inode, int *cluster_count,
unsigned long *total)
{
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
struct super_block *sb = inode->i_sb;
struct fat_entry fatent;
unsigned long search_start, search_end;
int err;

fatent_init(&fatent);
search_start = sbi->fat_clusters;
search_end = search_start + *cluster_count;

if (sbi->free_clusters == 0)
return -ENOSPC;

if (sbi->free_cluseters < *cluster_count)
*cluster_count = sbi->free_cluseters;

err = fat_ent_read(inode, &fatent, &search_start);
if (err && err != -ENOENT)
return err;

for (; search_start < search_end; search_start++) {
err = fat_ent_read(inode, &fatent, search_start);
if (err)
goto out;

if (fatent.entry != FAT_ENT_FREE)
continue;

err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, FAT_ENT_EOF);
if (err)
goto out;

(*total)++;
fat_cache_add(inode, *total - 1, fatent.entry);
}

sbi->free_clusters -= *total;
fat_sync_fsinfo(sbi);
return 0;
}

fat_alloc_clusters()从search_start开始线性扫描FAT表,查找空闲簇(FAT entry值为0)。每个空闲簇被标记为FAT_ENT_EOF(FAT32下为0x0FFFFFFF)以临时占用。然后递减free_clusters计数并同步FSInfo扇区。fat_cache_add()将新分配的簇加入inode的fat_cache,用于后续的快速簇链遍历。

分配完成后,fat_add_cluster()将新簇链接到文件的已有簇链末尾:

if (sbi->fat_bits == 32) {
struct fat_entry fatent_prev;
u32 prev_entry;

fatent_prev.fat_inode = MSDOS_SB(sb)->fat_inode;
fatent_prev.bh = NULL;
fatent_prev.entry = 0;

prev_entry = fat_get_entry(inode, inode->i_blocks >> sbi->sec_per_clus_bits);
fat_ent_read(inode, &fatent_prev, prev_entry);
fat_ent_write(inode, &fatent_prev, fatent.entry, fatent.entry);
fat_ent_write(inode, &fatent, FAT_ENT_EOF, FAT_ENT_EOF);
}

fat_cache_inval_inode(inode);
inode->i_blocks += nr_cluster << sbi->sec_per_clus_bits;
return 0;
}

关键操作是读取文件的最后一个簇号(通过fat_get_entry()根据i_blocks计算出的逻辑簇号位置),然后将该簇的FAT表项更新指向新分配的簇号,再将新簇的FAT表项设置为EOC标记,形成完整的簇链。

FAT32目录项中的文件名存储采用shortname(短文件名)和longname(长文件名)两种编码方式。shortname使用8.3格式(8个字符文件名+3个字符扩展名),全部大写ASCII字符。longname通过一系列连续的目录项(LDIR entry)存储,每个LDIR entry包含文件名的一部分。

shortname的生成函数为fat_make_shortname():

static int fat_make_shortname(struct msdos_sb_info *sbi,
const unsigned char *name,
unsigned char *shortname,
int *shortlen)
{
int i, j;
int dotpos;
unsigned char buf[12];
int len = strlen(name);
unsigned char c;

dotpos = fat_find_dot(name, len);
memset(buf, ' ', 11);

for (i = 0; i < dotpos; i++) {
c = name[i];
if (c == '.' || i >= 8)
break;
c = fat_toupper(sbi, c);
if (!fat_valid_shortname_char(c))
c = '_';
if (i < 8)
buf[i] = c;
}

i = dotpos + 1;
for (j = 0; j < 3 && i < len; j++, i++) {
c = name[i];
c = fat_toupper(sbi, c);
if (!fat_valid_shortname_char(c))
c = '_';
buf[8 + j] = c;
}

memcpy(shortname, buf, 11);
*shortlen = 11;
return 0;
}

生成逻辑:以文件名中的第一个点(dot)为界,左侧最多8个字符填充到buf[0-7],右侧最多3个字符填充到buf[8-10]。所有字符通过fat_toupper()转换为大写,非法字符(包括小写字母在非VFAT模式下)替换为下划线。

当生成的shortname与同一目录中的已有shortname冲突时,fat_add_shortname_hook()生成变体:

static int fat_add_shortname_hook(struct inode *dir,
unsigned char *shortname,
int *shortlen)
{
struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
int i;
int base_len = min_t(int, 8, *shortlen);
unsigned char base[8];
unsigned char tail[4];
int num;

memcpy(base, shortname, base_len);
for (num = 1; num < 100000; num++) {
snprintf(tail, 4, "~%d", num);
memcpy(shortname, base, base_len - strlen(tail));
memcpy(shortname + base_len - strlen(tail), tail, strlen(tail));
if (!fat_find_exact_shortname(dir, shortname, *shortlen))
return 0;
}
return -EINVAL;
}

变体规则是保留文件名的前N个字符后接"~N"(如FILE~1、FILE~2),直到生成一个在目录中唯一的短名。生成上限为99999个变体,超过仍冲突则返回-EINVAL。

FAT目录项写入时,longname的checksum与shortname关联。fat_checksum()函数对shortname的11个字节计算校验和,每个longname目录项包含该checksum用于一致性验证。当删除或重命名操作修改shortname时,longname的checksum必须同步更新。

http://www.jsqmd.com/news/1015793/

相关文章:

  • DeepLab_v3评估指标详解:mIoU、像素准确率等关键指标计算
  • MTK平台DWS配置GPIO,这10个选项别再乱勾了(附EintMode中断避坑指南)
  • Flask部署PyTorch模型时,我踩过的5个坑和解决办法(附打包exe避雷指南)
  • 在飞腾FT2000+上编译openEuler内核,卡在exiting boot services?手把手教你用系统自带config避坑
  • ArcMap地图导出AI格式后,在Illustrator里编辑总失败?试试这个保姆级避坑流程
  • 哪个豆包可以生成 word 文档?AI 导出鸭助力文档一键生成,高效便捷超实用
  • iOS 15+ WebView/Safari 下 WebSocket 神秘断连?手把手教你定位并关闭‘permessage-deflate’压缩头
  • uaal-example完全指南:如何将Unity无缝集成到iOS和Android原生应用中
  • GPR数据切片(Slice)实战:从3D数据到清晰成像,关键参数设置与避坑指南
  • 从热失控到封装熔断:一张SOA图背后的5个MOSFET“死亡陷阱”与实测避坑
  • STC8G1K08A-8PIN开发踩坑记:为什么P54引脚不能当普通IO用?一个实习生的血泪教训
  • Prometheus日志里总报‘无序时间戳’?别慌,这5个配置坑你肯定踩过
  • 别再乱改文件夹权限了!一次搞懂SFTP的chroot目录所有权和权限设置(附CentOS 7.3实战)
  • 哪个 ChatGPT 和 Gemini 可以生成 word 文档,AI 导出鸭一键导出更省心
  • 为什么团队氛围越来越差?答案藏在“烂苹果效应”里
  • Outlook邮件变‘隐形’?可能是你的显卡驱动或字体颜色在捣鬼
  • PyTorch DataLoader报错‘stack expects each tensor to be equal size’?别慌,手把手教你排查图片数据集里的‘通道数刺客’
  • 2025_NIPS_Ensemble-based Deep Reinforcement Learning for Vehicle Routing Problems under Distribut...
  • 2026成都高端名酒回收市场深度观察:哪里更靠谱? - 优质品牌商家
  • VASP能带计算踩坑实录:为什么我的能带图总是断开的?(附vaspkit 303避坑指南)
  • 别再为`code been used`和字段名抓狂了!微信米大师2.0接入的这两个坑,我帮你填平了
  • Fable5做代码分析实测
  • SH9认知曲率的严格定义与Ω_c阈值猜想的几何推导(世毫九实验室学术研究版)
  • deepseek 怎么复制表格?AI 导出鸭助力表格搬运
  • Silvaco TCAD电极定义报错?手把手教你排查‘Cannot find the electrode’问题(附完整PIN二极管仿真流程)
  • 避坑指南:VSpy连接ValueCAN硬件时,你一定会遇到的6个问题及解决方法(附License/固件更新处理)
  • JDK17升级踩坑记:CentOS上‘JCE cannot authenticate the provider BC’报错,我用这招轻松搞定
  • 从‘通信中断’到精准定位:CAN总线三大经典短路故障的排查心法与避坑指南
  • 2026年6月怀化市鹤城区黄金回收测评:哪家价格更高、更靠谱、更专业?(黄金/铂金/白银/K金/金条五家门店实测)2026年6月15最新版 - 空空是也
  • 手把手教你用DRV8313驱动三相无刷电机:从数据手册到PCB布局的避坑指南