19.3 对FAT的支持(harib16c)

发布时间 2023-04-04 18:33:54作者: 浩泽郎

19.3 对FAT的支持(harib16c)

问题:可以正确显示文件开头的512字节的内容,但大于512字节的部分不能正确显示(可能会显示其他文件)。

问题本质:磁盘可能将大于512字节的文件离散的保存在不同磁盘中。

解决办法:磁盘中保存了文件的下一段的地址。该记录(FAT,file allocation table,文件分配表)位于从0柱面、0磁头、2扇区开始的9个扇区中,由19.1 type命令(harib16a)中对磁盘映像在内存中的存储位置可知,该记录在内存中的地址是0x000200~0x0013ff

下方便是磁盘映像中的FAT,由于FAT使用了微软的压缩算法,故需要解压。

解压算法:

压缩后 ---> 压缩后

直白的说,第一个字节(03)和第三个字节(00)的数据不变,将第二个字节的数据(40)拆开,分别与第一个字节和第三个字节进行拼接。

经过此番操作,解压后的FAT如下:

这里说明自己对为什么这么做可以节省空间的理解,FAT用于储存离散存储的文件块之间的线性关系,直白点说就是文件的下一段存储在哪个地方(扇区),故本质是存储磁盘号。有前面的知识,共2880个扇区,一个字节肯定是存不下(8位,无负数最大能表示的十进制值为256,此处不严谨,应考虑补码、类型等内容,但总之只用一个字节表示不了),但使用两个字节(WORD,沿用书上)16位又有些浪费(无负数最大能表示65536,同上,不严谨,参考数量级即可)。因此压缩,即用1.5字节(12位,4096)存储。参考书中,磁盘共2880个扇区,正常使用WORD保存扇区号,FAT共需 2880×2=5760个字节,即一个FAT要占用12个扇区。 压缩后,3个字节可以保存2个扇区号,即存放1个扇区号需要的空间变为1.5个字节。因此,FAT总共需要2880×1.5=4320字节,一个FAT只占用9个扇区。 一张软盘中一共有2份FAT,因此经过压缩后,总共可以节省6个扇区的空间

还有一点小思考,保持三字节存两扇区号的压缩方式不变,为什么不直接从中间一刀切,即将第二个字节的高四位直接并入第一个字节中,从其操作来说,似乎(只是在脑海中验证,并未写实际代码)开销差不多,代码的可读性也差不多?,不知道微软为什么要采用这种交叉的方式?

解压的代码如下:

void file_readfat(int *fat, unsigned char *img)
/* 将磁盘映像中的FAT解压缩 */
{
	int i, j = 0;
	for (i = 0; i < 2880; i += 2) {
		fat[i + 0] = (img[j + 0]      | img[j + 1] << 8) & 0xfff;/* 最后相与的目的是限制为 1.5字节*/
		fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff;
		j += 3;
	}
	return;
}

代码解析如下:

  • bootpack.h节选
void file_loadfile(int clustno, int size, char *buf, int *fat, char *img)
{
	int i;
	for (;;) {
		if (size <= 512) {/* (注释错误)文件大小不大于一个扇区 */
			for (i = 0; i < size; i++) {
				buf[i] = img[clustno * 512 + i];
			}
			break;
		}
		for (i = 0; i < 512; i++) {/* 文件大小大于一个扇区 */
			buf[i] = img[clustno * 512 + i];
		}
		size -= 512;
		buf += 512;
		clustno = fat[clustno];/* 寻找文件下一个存放的扇区 */
	}
	return;
}

注意:上面对于小于512的判断的作用是错误的(不全面),正确得应该是,一个一个扇区加载文件,若不够一个扇区(小于512),则只加载一部分(由size来确定加载到那部分)。整个文件小于一个扇区(512字节)的情况包含在其中