最近准备重写android/external中自带的fsck工具,因为这个工具对于内存的占用太厉害了,在一些极端的大容量小簇的情况下会导致系统奔溃,所以准备重写一个。
Android自带的fsck在检查的时候会为每一个簇分配一个struct fatentry结构体,在后面的检查中构成簇链(cluster chain)。这种方法虽然内存占用比较多,但是处理比较快速,而且适应性较强,可以处理任何情况,也算是一方面的优点吧。
(1)fat表的检查
Fsck基本分为下面四个阶段:
1.读FAT,并进行fat表的对比(为了保证fat表的完整性,会保持多份fat表)
2.处理cluster chain。对于错误情况进行交互式的处理。
3.处理文件目录项和文件
4.处理一些无主(没有相应目录项)的数据,写入到LOST.DIR中
5.写入fat表
我本来不想罗列代码,但是对于一个码农来说,无代码的泛泛而论都显得十分空洞。我是一懒的人,就用下面的表格来代表图。
Boot sector(MBR)
Reserved
FAT表
Root directory
Data区
很多时候大家都将前两个统称为reserved区。关于fat表的描述网络上都有很多的讲解,在此不再赘述。
for (cl = CLUST_FIRST; cl < boot->NumClusters;)
switch (boot->ClustMask) {
case CLUST32_MASK:
fat[cl].next = p[0] + (p[1] << 8)
+ (p[2] << 16) + (p[3] << 24);
fat[cl].next &= boot->ClustMask;
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
p += 4;
break;
case CLUST16_MASK:
fat[cl].next = p[0] + (p[1] << 8);
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
p += 2;
break;
default:
fat[cl].next = (p[0] + (p[1] << 8)) & 0x0fff;
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
if (cl >= boot->NumClusters)
break;
fat[cl].next = ((p[1] >> 4) + (p[2] << 4)) & 0x0fff;
ret |= checkclnum(boot, no, cl, &fat[cl].next);
cl++;
p += 3;
break;
}
上面的代码摘自external/fsck_msdos/fat.c文件。上面的代码根据fat表中的信息来初始化fatentry链表。可以说是fat表的一个更加直观的表现。需要注意的是FAT32中每一个表项占4个字节(也是32bit),FAT16占2个字节(16bit),FAT12占1.5个字节(12bit).对于前两种的处理稍微简单。对于FAT12处理则稍微复杂一点,因为FAT表中的表项是按1.5字节对齐的。上面的宏CLUST_FIRST等于2.为什么等于2呢?因为0和1在fat表都有特殊的意义。comparefat函数比较简单。
在checkfat的过程中要处理的集中情况,下面是我先罗列的几种正常的情况(关于FAT的组织形式,可以去看我的博客)。